mirror of
https://github.com/sb745/NyaaV3.git
synced 2026-01-08 19:55:46 +02:00
Compare commits
28 commits
d94a7e1864
...
e5fa3a4434
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5fa3a4434 | ||
|
|
e97b3add03 | ||
|
|
8f1b59d705 | ||
|
|
1823254ce7 | ||
|
|
42ec86b8d7 | ||
|
|
4270ca8dd7 | ||
|
|
9250b742e1 | ||
|
|
d87adc528c | ||
|
|
e50efa5449 | ||
|
|
6f4634c0f6 | ||
|
|
9630016e4e | ||
|
|
fdaa324135 | ||
|
|
ff4dc572f3 | ||
|
|
5bb38ce959 | ||
|
|
27cc656842 | ||
|
|
653cf1af86 | ||
|
|
4fe13c1df3 | ||
|
|
0c7733ca83 | ||
|
|
d207184183 | ||
|
|
f5a7820e44 | ||
|
|
146e629895 | ||
|
|
b1ae89fa08 | ||
|
|
e9cd4598d0 | ||
|
|
4b3d506e15 | ||
|
|
97aef583d6 | ||
|
|
9106977fad | ||
|
|
f898ad3d56 | ||
|
|
c2513fd931 |
19 changed files with 148 additions and 72 deletions
30
README.md
30
README.md
|
|
@ -1,13 +1,13 @@
|
|||
# NyaaV3 [](https://www.python.org) 
|
||||
# NyaaV3 [](https://www.python.org) 
|
||||
|
||||
## Setting up for development
|
||||
This project uses Python 3.13. The codebase has been updated from the original Python 3.7 version to use modern Python features and updated dependencies.
|
||||
This project uses Python 3.14. The codebase has been updated from the original Python 3.7 version to use modern Python features and updated dependencies.
|
||||
This guide assumes you are using Linux and are somewhat capable with the commandline.
|
||||
Running Nyaa on Windows may be possible, but it's currently unsupported.
|
||||
|
||||
### Major changes from NyaaV2
|
||||
- Updated from Python 3.7 to Python 3.13
|
||||
- Updated all dependencies to their latest versions
|
||||
- Updated from Python 3.7 to Python 3.14
|
||||
- Updated all dependencies
|
||||
- Modernized code patterns for Flask 3.0 and SQLAlchemy 2.0
|
||||
- Replaced deprecated Flask-Script, orderedset and `flask.Markup` with Flask CLI, orderly-set and markupsafe
|
||||
- Implemented mail error handling
|
||||
|
|
@ -23,13 +23,13 @@ The `tests` folder contains tests for the the `nyaa` module and the webserver. T
|
|||
- Run `python dev.py test` while in the repository directory.
|
||||
|
||||
### Setting up Pyenv
|
||||
pyenv eases the use of different Python versions, and as not all Linux distros offer 3.13 packages, it's right up our alley.
|
||||
pyenv eases the use of different Python versions, and as not all Linux distros offer 3.14 packages, it's right up our alley.
|
||||
- Install [dependencies](https://github.com/pyenv/pyenv/wiki/Common-build-problems)
|
||||
- Install [pyenv](https://github.com/pyenv/pyenv/blob/master/README.md#installation)
|
||||
- Install [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv/blob/master/README.md)
|
||||
- Install Python 3.13 with `pyenv` and create a virtualenv for the project:
|
||||
- `pyenv install 3.13.2`
|
||||
- `pyenv virtualenv 3.13.2 nyaa`
|
||||
- Install Python 3.14 with `pyenv` and create a virtualenv for the project:
|
||||
- `pyenv install 3.14.2`
|
||||
- `pyenv virtualenv 3.14.2 nyaa`
|
||||
- `pyenv activate nyaa`
|
||||
- Install dependencies with `pip install -r requirements.txt`
|
||||
- Copy `config.example.py` into `config.py`
|
||||
|
|
@ -59,7 +59,7 @@ Continue below to learn about database migrations and enabling the advanced sear
|
|||
## Database migrations
|
||||
> [!WARNING]
|
||||
> The database migration feature has been updated but will no longer be supported in NyaaV3.
|
||||
- Database migrations are done with [Flask-Migrate](https://flask-migrate.readthedocs.io/), a wrapper around [Alembic](http://alembic.zzzcomputing.com/en/latest/).
|
||||
- Database migrations are done using [Flask-Migrate](https://flask-migrate.readthedocs.io/), a wrapper around [Alembic](http://alembic.zzzcomputing.com/en/latest/).
|
||||
- The migration system has been updated to use Flask CLI instead of the deprecated Flask-Script.
|
||||
- If someone has made changes in the database schema and included a new migration script:
|
||||
- If your database has never been marked by Alembic (you're on a database from before the migrations), run `python db_migrate.py db stamp head` before pulling the new migration script(s).
|
||||
|
|
@ -77,7 +77,7 @@ Continue below to learn about database migrations and enabling the advanced sear
|
|||
## Setting up and enabling Elasticsearch
|
||||
|
||||
### Installing Elasticsearch
|
||||
- Install JDK with `sudo apt-get install openjdk-8-jdk`
|
||||
- Install JDK with `sudo apt-get install openjdk-21-jdk`
|
||||
- Install Elasticsearch
|
||||
- [From packages](https://www.elastic.co/guide/en/elasticsearch/reference/current/deb.html)
|
||||
- Enable the service:
|
||||
|
|
@ -85,6 +85,7 @@ Continue below to learn about database migrations and enabling the advanced sear
|
|||
- `sudo systemctl start elasticsearch.service`
|
||||
- or [simply extracting the archives and running the files](https://www.elastic.co/guide/en/elasticsearch/reference/current/_installation.html), if you don't feel like permanently installing ES
|
||||
- Run `curl -XGET 'localhost:9200'` and make sure ES is running
|
||||
- You may need to set `xpack.security.enabled: false` in your `elasticsearch.yml` file if curl output is empty
|
||||
- Install [Kibana](https://www.elastic.co/products/kibana) as a search debug frontend for ES (*optional*)
|
||||
|
||||
### Enabling MySQL Binlogging
|
||||
|
|
@ -99,7 +100,10 @@ Continue below to learn about database migrations and enabling the advanced sear
|
|||
- Copy the example configuration (`es_sync_config.example.json`) as `es_sync_config.json` and adjust options in it to your liking (verify the connection options!)
|
||||
- Connect to mysql as root
|
||||
- Verify that the result of `SHOW VARIABLES LIKE 'binlog_format';` is `ROW`
|
||||
- Execute `GRANT REPLICATION SLAVE ON *.* TO 'username'@'localhost';` to allow your configured user access to the binlog
|
||||
- Execute `GRANT REPLICATION SLAVE ON *.* TO 'nyaav3'@'localhost';` to allow your configured user access to the binlog and one of the following:
|
||||
- For MySQL: `GRANT REPLICATION CLIENT ON *.* TO 'nyaauser'@'localhost';`
|
||||
- For MariaDB: `GRANT BINLOG MONITOR ON *.* TO 'nyaauser'@'localhost';`
|
||||
- Run `./create_es.sh` to create the indices for the torrents: `nyaa` and `sukebei`
|
||||
|
||||
### Setting up ES
|
||||
- Run `./create_es.sh` to create the indices for the torrents: `nyaa` and `sukebei`
|
||||
|
|
@ -116,8 +120,8 @@ However, take note that binglog is not necessary for simple ES testing and devel
|
|||
|
||||
### Setting up sync_es.py
|
||||
`sync_es.py` keeps the Elasticsearch indices updated by reading the binlog and pushing the changes to the ES indices.
|
||||
- Make sure `es_sync_config.json` is configured with the user you grated the `REPLICATION` permissions
|
||||
- Run `import_to_es.py` and copy the outputted JSON into the file specified by `save_loc` in your `es_sync_config.json`
|
||||
- Make sure `es_sync_config.json` is configured with the user you granted the `REPLICATION` permissions
|
||||
- Run `python import_to_es.py /path/to/file.json` and copy the outputted JSON into the file specified by `save_loc` in your `es_sync_config.json` file
|
||||
- Run `sync_es.py` as-is *or*, for actual deployment, set it up as a service and run it, preferably as the system/root
|
||||
- Make sure `sync_es.py` runs within the venv with the right dependencies!
|
||||
|
||||
|
|
|
|||
12
SECURITY.md
Normal file
12
SECURITY.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2025-12 | :white_check_mark: |
|
||||
| 2025-03 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report high risk security vulnerabilities privately.
|
||||
|
|
@ -88,7 +88,7 @@ RECAPTCHA_PRIVATE_KEY = '***'
|
|||
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
if USE_MYSQL:
|
||||
SQLALCHEMY_DATABASE_URI = ('mysql://test:test123@localhost/nyaav3?charset=utf8mb4')
|
||||
SQLALCHEMY_DATABASE_URI = ('mysql://nyaauser:nyaapass@localhost/nyaav3?charset=utf8mb4')
|
||||
else:
|
||||
SQLALCHEMY_DATABASE_URI = (
|
||||
'sqlite:///' + os.path.join(BASE_DIR, 'test.db') + '?check_same_thread=False')
|
||||
|
|
@ -98,7 +98,7 @@ else:
|
|||
###########
|
||||
|
||||
# 'smtp' or 'mailgun'
|
||||
MAIL_BACKEND = 'mailgun'
|
||||
MAIL_BACKEND = 'smtp'
|
||||
MAIL_FROM_ADDRESS = 'Sender Name <sender@domain.com>'
|
||||
|
||||
# Mailgun settings
|
||||
|
|
@ -180,7 +180,7 @@ ES_MAX_SEARCH_RESULT = 1000
|
|||
# ES index name generally (nyaa or sukebei)
|
||||
ES_INDEX_NAME = SITE_FLAVOR
|
||||
# ES hosts
|
||||
ES_HOSTS = ['localhost:9200']
|
||||
ES_HOSTS = ['http://localhost:9200']
|
||||
|
||||
################
|
||||
## Commenting ##
|
||||
|
|
@ -232,5 +232,6 @@ CACHE_THRESHOLD = 8192
|
|||
# RATELIMIT_STORAGE_URL="redis://host:port"
|
||||
RATELIMIT_KEY_PREFIX="nyaaratelimit_"
|
||||
|
||||
# Use this to show the commit hash in the footer (see layout.html)
|
||||
# The commit hash is automatically shown in the footer if .git folder is present (see layout.html)
|
||||
# Use this to manually show the hash
|
||||
# COMMIT_HASH="[enter your commit hash here]";
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
"save_loc": "/tmp/pos.json",
|
||||
"mysql_host": "127.0.0.1",
|
||||
"mysql_port": 3306,
|
||||
"mysql_user": "nyaa",
|
||||
"mysql_password": "some_password",
|
||||
"mysql_user": "nyaauser",
|
||||
"mysql_password": "nyaapass",
|
||||
"database": "nyaav3",
|
||||
"internal_queue_depth": 10000,
|
||||
"es_chunk_size": 10000,
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ import progressbar
|
|||
from elasticsearch import Elasticsearch
|
||||
from elasticsearch.client import IndicesClient
|
||||
from elasticsearch import helpers
|
||||
from sqlalchemy import text
|
||||
|
||||
from nyaa import create_app, models
|
||||
from nyaa.extensions import db
|
||||
|
||||
app = create_app('config')
|
||||
es = Elasticsearch(hosts=app.config['ES_HOSTS'], timeout=30)
|
||||
es = Elasticsearch(hosts=app.config['ES_HOSTS'], request_timeout=30)
|
||||
ic = IndicesClient(es)
|
||||
|
||||
def pad_bytes(in_bytes, size):
|
||||
|
|
@ -98,14 +99,15 @@ FLAVORS = [
|
|||
|
||||
# Get binlog status from mysql
|
||||
with app.app_context():
|
||||
master_status = db.engine.execute('SHOW MASTER STATUS;').fetchone()
|
||||
with db.engine.begin() as connection:
|
||||
master_status = connection.execute(text('SHOW MASTER STATUS;')).fetchone()
|
||||
|
||||
position_json = {
|
||||
'log_file': master_status[0],
|
||||
'log_pos': master_status[1]
|
||||
}
|
||||
|
||||
print('Save the following in the file configured in your ES sync config JSON:')
|
||||
print('Save the following in the file configured in es_sync_config.json:')
|
||||
print(json.dumps(position_json))
|
||||
|
||||
for flavor, torrent_class in FLAVORS:
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ a.text-purple:hover, a.text-purple:active, a.text-purple:focus {
|
|||
|
||||
#comment {
|
||||
height: 8em;
|
||||
min-height: 8em;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
|
|
@ -454,7 +455,8 @@ h6:hover .header-anchor {
|
|||
|
||||
/* Dark theme */
|
||||
|
||||
body.dark {
|
||||
body.dark,
|
||||
body.dark .form-control {
|
||||
color: #afafaf;
|
||||
}
|
||||
|
||||
|
|
@ -636,6 +638,12 @@ blockquote {
|
|||
font-size: inherit;
|
||||
}
|
||||
|
||||
/* Make <mark>s a bit more prominent */
|
||||
mark, .mark {
|
||||
background-color: #fff6c9;
|
||||
padding: .2em;
|
||||
}
|
||||
|
||||
/* Hide and resize some things on tiny screens to improve usability. */
|
||||
@media (max-width: 767px) {
|
||||
.hdr-size, .hdr-date, .hdr-downloads,
|
||||
|
|
|
|||
6
nyaa/static/js/bootstrap-select.js
vendored
6
nyaa/static/js/bootstrap-select.js
vendored
|
|
@ -804,8 +804,10 @@
|
|||
title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;
|
||||
}
|
||||
|
||||
//strip all HTML tags and trim the result, then unescape any escaped tags
|
||||
this.$button.attr('title', htmlUnescape($.trim(title.replace(/<[^>]*>?/g, ''))));
|
||||
//strip all HTML tags in a DOM-safe way and trim the result, then unescape any escaped tags
|
||||
var $tmp = $('<div>').html(title);
|
||||
var plainTitle = $tmp.text();
|
||||
this.$button.attr('title', htmlUnescape($.trim(plainTitle)));
|
||||
this.$button.children('.filter-option').html(title);
|
||||
|
||||
this.$element.trigger('rendered.bs.select');
|
||||
|
|
|
|||
2
nyaa/static/js/lib/markdown-it-ins.min.js
vendored
Normal file
2
nyaa/static/js/lib/markdown-it-ins.min.js
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/*! markdown-it-ins 2.0.0 https://github.com//markdown-it/markdown-it-ins @license MIT */
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.markdownitIns=e()}}(function(){return function e(n,t,o){function r(s,f){if(!t[s]){if(!n[s]){var u="function"==typeof require&&require;if(!f&&u)return u(s,!0);if(i)return i(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var p=t[s]={exports:{}};n[s][0].call(p.exports,function(e){var t=n[s][1][e];return r(t?t:e)},p,p.exports,e,n,t,o)}return t[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)r(o[s]);return r}({1:[function(e,n,t){"use strict";n.exports=function(e){function n(e,n){var t,o,r,i,s,f=e.pos,u=e.src.charCodeAt(f);if(n)return!1;if(43!==u)return!1;if(o=e.scanDelims(e.pos,!0),i=o.length,s=String.fromCharCode(u),2>i)return!1;for(i%2&&(r=e.push("text","",0),r.content=s,i--),t=0;i>t;t+=2)r=e.push("text","",0),r.content=s+s,e.delimiters.push({marker:u,jump:t,token:e.tokens.length-1,level:e.level,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0}function t(e){var n,t,o,r,i,s=[],f=e.delimiters,u=e.delimiters.length;for(n=0;u>n;n++)o=f[n],43===o.marker&&-1!==o.end&&(r=f[o.end],i=e.tokens[o.token],i.type="ins_open",i.tag="ins",i.nesting=1,i.markup="++",i.content="",i=e.tokens[r.token],i.type="ins_close",i.tag="ins",i.nesting=-1,i.markup="++",i.content="","text"===e.tokens[r.token-1].type&&"+"===e.tokens[r.token-1].content&&s.push(r.token-1));for(;s.length;){for(n=s.pop(),t=n+1;t<e.tokens.length&&"ins_close"===e.tokens[t].type;)t++;t--,n!==t&&(i=e.tokens[t],e.tokens[t]=e.tokens[n],e.tokens[n]=i)}}e.inline.ruler.before("emphasis","ins",n),e.inline.ruler2.before("emphasis","ins",t)}},{}]},{},[1])(1)});
|
||||
2
nyaa/static/js/lib/markdown-it-mark.min.js
vendored
Normal file
2
nyaa/static/js/lib/markdown-it-mark.min.js
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/*! markdown-it-mark 2.0.0 https://github.com//markdown-it/markdown-it-mark @license MIT */
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.markdownitMark=e()}}(function(){return function e(n,t,o){function r(s,f){if(!t[s]){if(!n[s]){var u="function"==typeof require&&require;if(!f&&u)return u(s,!0);if(i)return i(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var p=t[s]={exports:{}};n[s][0].call(p.exports,function(e){var t=n[s][1][e];return r(t?t:e)},p,p.exports,e,n,t,o)}return t[s].exports}for(var i="function"==typeof require&&require,s=0;s<o.length;s++)r(o[s]);return r}({1:[function(e,n,t){"use strict";n.exports=function(e){function n(e,n){var t,o,r,i,s,f=e.pos,u=e.src.charCodeAt(f);if(n)return!1;if(61!==u)return!1;if(o=e.scanDelims(e.pos,!0),i=o.length,s=String.fromCharCode(u),2>i)return!1;for(i%2&&(r=e.push("text","",0),r.content=s,i--),t=0;i>t;t+=2)r=e.push("text","",0),r.content=s+s,e.delimiters.push({marker:u,jump:t,token:e.tokens.length-1,level:e.level,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0}function t(e){var n,t,o,r,i,s=[],f=e.delimiters,u=e.delimiters.length;for(n=0;u>n;n++)o=f[n],61===o.marker&&-1!==o.end&&(r=f[o.end],i=e.tokens[o.token],i.type="mark_open",i.tag="mark",i.nesting=1,i.markup="==",i.content="",i=e.tokens[r.token],i.type="mark_close",i.tag="mark",i.nesting=-1,i.markup="==",i.content="","text"===e.tokens[r.token-1].type&&"="===e.tokens[r.token-1].content&&s.push(r.token-1));for(;s.length;){for(n=s.pop(),t=n+1;t<e.tokens.length&&"mark_close"===e.tokens[t].type;)t++;t--,n!==t&&(i=e.tokens[t],e.tokens[t]=e.tokens[n],e.tokens[n]=i)}}e.inline.ruler.before("emphasis","mark",n),e.inline.ruler2.before("emphasis","mark",t)}},{}]},{},[1])(1)});
|
||||
|
|
@ -4,8 +4,23 @@ document.addEventListener("DOMContentLoaded", function(event) { // wait for cont
|
|||
toggleDarkMode(); // toggle theme
|
||||
});
|
||||
// needs to be done here as <body> is not available when the script in the head runs
|
||||
if (typeof(Storage) !== 'undefined' && localStorage.getItem('theme') === 'dark')
|
||||
if (typeof(Storage) !== 'undefined' && localStorage.getItem('theme') === 'dark') {
|
||||
document.body.classList.add('dark');
|
||||
} else if (window.matchMedia) {
|
||||
const darkMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
if (darkMedia.matches)
|
||||
document.body.classList.add('dark');
|
||||
// Some operating systems switch to dark mode only during the evening/night:
|
||||
darkMedia.addEventListener('change', function(event) {
|
||||
// Do not overwrite if the user made a manual choice:
|
||||
if (localStorage.getItem('theme') === null) {
|
||||
if (event.matches)
|
||||
document.body.classList.add('dark');
|
||||
else
|
||||
document.body.classList.remove('dark');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -210,7 +225,7 @@ var markdownOptions = {
|
|||
linkify: true,
|
||||
typographer: true
|
||||
}
|
||||
var markdown = window.markdownit(markdownOptions);
|
||||
var markdown = window.markdownit(markdownOptions).use(window.markdownitIns).use(window.markdownitMark);
|
||||
markdown.renderer.rules.table_open = function (tokens, idx) {
|
||||
// Format tables nicer (bootstrap). Force auto-width (default is 100%)
|
||||
return '<table class="table table-striped table-bordered" style="width: auto;">';
|
||||
|
|
@ -268,6 +283,9 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||
// Info bubble stuff
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var bubble = document.getElementById('infobubble');
|
||||
if (!bubble) {
|
||||
return;
|
||||
}
|
||||
if (Number(localStorage.getItem('infobubble_dismiss_ts')) < Number(bubble.dataset.ts)) {
|
||||
bubble.removeAttribute('hidden');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
{% endif %}
|
||||
<div class="markdown-editor" id="{{ field_name }}-markdown-editor" data-field-name="{{ field_name }}">
|
||||
{{ field.label(class='control-label') }}
|
||||
<a href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet" class="small" target="_blank">Markdown supported</a>
|
||||
<a href="{{ url_for('site.help', _anchor='styling') }}" class="small" target="_blank">Markdown supported</a>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active">
|
||||
<a href="#{{ field_name }}-tab" role="tab" data-toggle="tab">
|
||||
|
|
|
|||
|
|
@ -85,6 +85,23 @@
|
|||
to have an image embedded in your comment or description. Note the <kbd>!</kbd>
|
||||
exclamation mark at the beginning, denoting that this link is an image.
|
||||
</div>
|
||||
<div>
|
||||
Quick examples:
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li><kbd>*italic text*</kbd> → <em>italic text</em></li>
|
||||
<li><kbd>**bold text**</kbd> → <strong>bold text</strong></li>
|
||||
<li><kbd>++underlined text++</kbd> → <ins>underlined text</ins></li>
|
||||
<li><kbd>==marked text==</kbd> → <mark>marked text</mark></li>
|
||||
<li><kbd>[Front page]({{url_for('main.home')}})</kbd> → <a href="{{url_for('main.home')}}">Front page</a></li>
|
||||
<li><kbd>[Spoilers](# "The spider-girl kills everyone")</kbd> → <a href="#" title="The spider-girl kills everyone">Spoilers</a></li>
|
||||
<li><kbd># Header 1</kbd> → <h1 style="display: inline-block;">Header 1</h1></li>
|
||||
<li><kbd>## Header 2</kbd> → <h2 style="display: inline-block;">Header 2</h2></li>
|
||||
<li><kbd>### Header 3</kbd> → <h3 style="display: inline-block;">Header 3</h3></li>
|
||||
<li><kbd>#### Header 4</kbd> → <h4 style="display: inline-block;">Header 4</h4></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{ linkable_header("Changing Your User's Avatar", "avatar") }}
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/8.3.1/markdown-it.min.js" integrity="sha256-3WZyZQOe+ql3pLo90lrkRtALrlniGdnf//gRpW0UQks=" crossorigin="anonymous"></script>
|
||||
<!-- markdown-it extensions (self-hosted because no cdnjs releases) -->
|
||||
<script src="{{ static_cachebuster('js/lib/markdown-it-ins.min.js') }}"></script>
|
||||
<script src="{{ static_cachebuster('js/lib/markdown-it-mark.min.js') }}"></script>
|
||||
<!-- Modified to not apply border-radius to selectpickers and stuff so our navbar looks cool -->
|
||||
{% assets "bs_js" %}
|
||||
<script src="{{ static_cachebuster('js/bootstrap-select.min.js') }}"></script>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta property="og:description" content="{{ category_name(torrent.sub_category.id_as_string) }} | {{ torrent.filesize | filesizeformat(True) }} | Uploaded by {{ uploader_name }} on {{ torrent.created_time.strftime('%Y-%m-%d') }}">
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
{% from "_formhelpers.html" import render_field %}
|
||||
{% from "_formhelpers.html" import render_field, render_markdown_editor %}
|
||||
<div class="panel panel-{% if torrent.deleted %}deleted{% elif torrent.remake %}danger{% elif torrent.trusted %}success{% else %}default{% endif %}">
|
||||
<div class="panel-heading"{% if torrent.hidden %} style="background-color: darkgray;"{% endif %}>
|
||||
<h3 class="panel-title">
|
||||
|
|
@ -177,7 +177,7 @@
|
|||
<div class="row comment-body">
|
||||
{# Escape newlines into html entities because CF strips blank newlines #}
|
||||
<div markdown-text class="comment-content" id="torrent-comment{{ comment.id }}">{{- comment.text | escape | replace('\r\n', '\n') | replace('\n', ' '|safe) -}}</div>
|
||||
{% if g.user.id == comment.user_id and comment_form %}
|
||||
{% if g.user.id == comment.user_id and comment_form and not comment.editing_limit_exceeded and (not torrent.comment_locked or g.user.is_moderator) %}
|
||||
<form class="edit-comment-box" action="{{ url_for('torrents.edit_comment', torrent_id=torrent.id, comment_id=comment.id) }}" method="POST">
|
||||
{{ comment_form.csrf_token }}
|
||||
<div class="form-group">
|
||||
|
|
@ -225,7 +225,7 @@
|
|||
{{ comment_form.csrf_token }}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ render_field(comment_form.comment, class_='form-control') }}
|
||||
{{ render_markdown_editor(comment_form.comment) }}
|
||||
</div>
|
||||
</div>
|
||||
{% if config.USE_RECAPTCHA and g.user.age < config['ACCOUNT_RECAPTCHA_AGE'] %}
|
||||
|
|
|
|||
|
|
@ -219,4 +219,6 @@ def render_rss(label, query, use_elastic, magnet_links=False):
|
|||
response.headers['Content-Type'] = 'application/xml'
|
||||
# Cache for an hour
|
||||
response.headers['Cache-Control'] = 'max-age={}'.format(1 * 5 * 60)
|
||||
# Allow cross origin access
|
||||
response.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -333,6 +333,8 @@ def download_torrent(torrent_id):
|
|||
resp.headers['Content-Type'] = 'application/x-bittorrent'
|
||||
resp.headers['Content-Disposition'] = disposition
|
||||
resp.headers['Content-Length'] = torrent_file_size
|
||||
# Allow cross origin access
|
||||
resp.headers['Access-Control-Allow-Origin'] = '*'
|
||||
return resp
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
alembic==1.14.1
|
||||
alembic==1.17.2
|
||||
appdirs==1.4.4
|
||||
argon2-cffi==23.1.0
|
||||
argon2-cffi==25.1.0
|
||||
autopep8==2.3.2
|
||||
blinker==1.9.0
|
||||
cffi==1.17.1
|
||||
click==8.1.8
|
||||
dnspython==2.7.0
|
||||
elasticsearch==8.17.1
|
||||
elasticsearch-dsl==8.17.1
|
||||
flake8==7.1.2
|
||||
flake8-isort==6.1.2
|
||||
Flask==3.1.0
|
||||
cffi==2.0.0
|
||||
click==8.3.1
|
||||
dnspython==2.8.0
|
||||
elasticsearch==8.19.2
|
||||
elasticsearch-dsl==8.18.0
|
||||
flake8==7.3.0
|
||||
flake8-isort==7.0.0
|
||||
Flask==3.1.2
|
||||
Flask-Assets==2.1.0
|
||||
Flask-DebugToolbar==0.16.0
|
||||
Flask-Migrate==4.1.0
|
||||
|
|
@ -18,42 +18,42 @@ flask-paginate==2024.4.12
|
|||
# Flask-Script removed as it's deprecated and replaced with Flask CLI
|
||||
Flask-SQLAlchemy==3.1.1
|
||||
Flask-WTF==1.2.2
|
||||
gevent==24.11.1
|
||||
greenlet==3.1.1
|
||||
isort==6.0.1
|
||||
gevent==25.9.1
|
||||
greenlet==3.3.0
|
||||
isort==7.0.0
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.5
|
||||
Mako==1.3.9
|
||||
MarkupSafe==3.0.2
|
||||
mysql-replication==1.0.9
|
||||
Jinja2==3.1.6
|
||||
Mako==1.3.10
|
||||
MarkupSafe==3.0.3
|
||||
mysql-replication==1.0.12
|
||||
mysqlclient==2.2.7
|
||||
# orderedset removed as it's deprecated and replaced with Flask CLI
|
||||
orderly-set==5.3.0
|
||||
packaging==24.2
|
||||
orderly-set==5.5.0
|
||||
packaging==25.0
|
||||
passlib==1.7.4
|
||||
progressbar33==2.4
|
||||
py==1.11.0
|
||||
pycodestyle==2.12.1
|
||||
pycparser==2.22
|
||||
PyMySQL==1.1.1
|
||||
pyparsing==3.2.1
|
||||
pytest==8.3.4
|
||||
python-dateutil==2.9.0
|
||||
pycodestyle==2.14.0
|
||||
pycparser==2.23
|
||||
PyMySQL==1.1.2
|
||||
pyparsing==3.2.5
|
||||
pytest==9.0.2
|
||||
python-dateutil==2.9.0.post0
|
||||
python-editor==1.0.4
|
||||
python-utils==3.9.1
|
||||
requests==2.32.3
|
||||
SQLAlchemy==2.0.38
|
||||
requests==2.32.5
|
||||
SQLAlchemy==2.0.45
|
||||
SQLAlchemy-FullText-Search==0.3.0
|
||||
SQLAlchemy-Utils==0.41.2
|
||||
SQLAlchemy-Utils==0.42.1
|
||||
statsd==4.0.1
|
||||
urllib3==2.3.0
|
||||
uWSGI==2.0.28
|
||||
redis==5.2.1
|
||||
webassets==2.0
|
||||
Werkzeug==3.1.3
|
||||
urllib3==2.6.2
|
||||
uWSGI==2.0.31
|
||||
redis==7.1.0
|
||||
webassets==3.0.0
|
||||
Werkzeug==3.1.4
|
||||
WTForms==3.2.1
|
||||
Flask-Caching==2.3.1
|
||||
Flask-Limiter==3.10.1
|
||||
mypy==1.15.0
|
||||
typing-extensions==4.12.2
|
||||
email-validator==2.2.0
|
||||
Flask-Limiter==4.1.1
|
||||
mypy==1.19.1
|
||||
typing-extensions==4.15.0
|
||||
email-validator==2.3.0
|
||||
|
|
@ -68,9 +68,9 @@ stats = StatsClient('localhost', 8125, prefix="sync_es")
|
|||
SAVE_LOC = config.get('save_loc', "/tmp/pos.json")
|
||||
MYSQL_HOST = config.get('mysql_host', '127.0.0.1')
|
||||
MYSQL_PORT = config.get('mysql_port', 3306)
|
||||
MYSQL_USER = config.get('mysql_user', 'root')
|
||||
MYSQL_PW = config.get('mysql_password', 'dunnolol')
|
||||
NT_DB = config.get('database', 'nyaav2')
|
||||
MYSQL_USER = config.get('mysql_user', 'nyaauser')
|
||||
MYSQL_PW = config.get('mysql_password', 'nyaapass')
|
||||
NT_DB = config.get('database', 'nyaav3')
|
||||
INTERNAL_QUEUE_DEPTH = config.get('internal_queue_depth', 10000)
|
||||
ES_CHUNK_SIZE = config.get('es_chunk_size', 10000)
|
||||
# seconds since no events happening to flush to es. remember this also
|
||||
|
|
@ -263,7 +263,7 @@ class EsPoster(ExitingThread):
|
|||
self.flush_interval = flush_interval
|
||||
|
||||
def run_happy(self):
|
||||
es = Elasticsearch(hosts=app.config['ES_HOSTS'], timeout=30)
|
||||
es = Elasticsearch(hosts=app.config['ES_HOSTS'], request_timeout=30)
|
||||
|
||||
last_save = time.time()
|
||||
since_last = 0
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@ udp://open.stealth.si:80/announce
|
|||
udp://tracker.opentrackr.org:1337/announce
|
||||
udp://tracker.coppersurfer.tk:6969/announce
|
||||
udp://exodus.desync.com:6969/announce
|
||||
wss://tracker.openwebtorrent.com
|
||||
Loading…
Add table
Reference in a new issue