mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-12-22 14:30:01 +00:00
Remove v1 upload api and update notice
This commit is contained in:
parent
b241dd5508
commit
f04c3e1cf3
|
@ -6,6 +6,9 @@ from nyaa import models, forms
|
||||||
from nyaa import bencode, backend, utils
|
from nyaa import bencode, backend, utils
|
||||||
from nyaa import torrents
|
from nyaa import torrents
|
||||||
|
|
||||||
|
# For _create_upload_category_choices
|
||||||
|
from nyaa import routes
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -42,87 +45,7 @@ def api_require_user(f):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def validate_user(upload_request):
|
|
||||||
auth_info = None
|
|
||||||
try:
|
|
||||||
if 'auth_info' in upload_request.files:
|
|
||||||
auth_info = json.loads(upload_request.files['auth_info'].read().decode('utf-8'))
|
|
||||||
if 'username' not in auth_info.keys() or 'password' not in auth_info.keys():
|
|
||||||
return False, None, None
|
|
||||||
|
|
||||||
username = auth_info['username']
|
|
||||||
password = auth_info['password']
|
|
||||||
user = models.User.by_username(username)
|
|
||||||
|
|
||||||
if not user:
|
|
||||||
user = models.User.by_email(username)
|
|
||||||
|
|
||||||
if not user or password != user.password_hash or \
|
|
||||||
user.status == models.UserStatusType.INACTIVE:
|
|
||||||
return False, None, None
|
|
||||||
|
|
||||||
return True, user, None
|
|
||||||
else:
|
|
||||||
return False, None, None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return False, None, e
|
|
||||||
|
|
||||||
|
|
||||||
def _create_upload_category_choices():
|
|
||||||
''' Turns categories in the database into a list of (id, name)s '''
|
|
||||||
choices = [('', '[Select a category]')]
|
|
||||||
for main_cat in models.MainCategory.query.order_by(models.MainCategory.id):
|
|
||||||
choices.append((main_cat.id_as_string, main_cat.name, True))
|
|
||||||
for sub_cat in main_cat.sub_categories:
|
|
||||||
choices.append((sub_cat.id_as_string, ' - ' + sub_cat.name))
|
|
||||||
return choices
|
|
||||||
|
|
||||||
|
|
||||||
# #################################### API ROUTES ####################################
|
# #################################### API ROUTES ####################################
|
||||||
def api_upload(upload_request, user):
|
|
||||||
form_info = None
|
|
||||||
try:
|
|
||||||
form_info = json.loads(upload_request.files['torrent_info'].read().decode('utf-8'))
|
|
||||||
|
|
||||||
form_info_as_dict = []
|
|
||||||
for k, v in form_info.items():
|
|
||||||
if k in ['is_anonymous', 'is_hidden', 'is_remake', 'is_complete', 'is_trusted']:
|
|
||||||
if v:
|
|
||||||
form_info_as_dict.append((k, v))
|
|
||||||
else:
|
|
||||||
form_info_as_dict.append((k, v))
|
|
||||||
# Hack for while v1 is still being used: default trusted to true
|
|
||||||
if not [x for x in form_info_as_dict if x[0] == 'is_trusted']:
|
|
||||||
form_info_as_dict.append(('is_trusted', True))
|
|
||||||
form_info = ImmutableMultiDict(form_info_as_dict)
|
|
||||||
except Exception as e:
|
|
||||||
return flask.make_response(flask.jsonify(
|
|
||||||
{'Failure': ['Invalid data. See HELP in api_uploader.py']}), 400)
|
|
||||||
|
|
||||||
try:
|
|
||||||
torrent_file = upload_request.files['torrent_file']
|
|
||||||
torrent_file = ImmutableMultiDict([('torrent_file', torrent_file)])
|
|
||||||
except Exception as e:
|
|
||||||
return flask.make_response(flask.jsonify(
|
|
||||||
{'Failure': ['No torrent file was attached.']}), 400)
|
|
||||||
|
|
||||||
form = forms.UploadForm(CombinedMultiDict((torrent_file, form_info)), meta={'csrf': False})
|
|
||||||
form.category.choices = _create_upload_category_choices()
|
|
||||||
|
|
||||||
if upload_request.method == 'POST' and form.validate():
|
|
||||||
torrent = backend.handle_torrent_upload(form, user, True)
|
|
||||||
|
|
||||||
return flask.make_response(flask.jsonify({'Success': int('{0}'.format(torrent.id))}), 200)
|
|
||||||
else:
|
|
||||||
return_error_messages = []
|
|
||||||
for error_name, error_messages in form.errors.items():
|
|
||||||
return_error_messages.extend(error_messages)
|
|
||||||
|
|
||||||
return flask.make_response(flask.jsonify({'Failure': return_error_messages}), 400)
|
|
||||||
|
|
||||||
# V2 below
|
|
||||||
|
|
||||||
|
|
||||||
# Map UploadForm fields to API keys
|
# Map UploadForm fields to API keys
|
||||||
UPLOAD_API_FORM_KEYMAP = {
|
UPLOAD_API_FORM_KEYMAP = {
|
||||||
|
@ -150,6 +73,7 @@ UPLOAD_API_DEFAULTS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@api_blueprint.route('/upload', methods=['POST'])
|
||||||
@api_blueprint.route('/v2/upload', methods=['POST'])
|
@api_blueprint.route('/v2/upload', methods=['POST'])
|
||||||
@basic_auth_user
|
@basic_auth_user
|
||||||
@api_require_user
|
@api_require_user
|
||||||
|
@ -170,7 +94,7 @@ def v2_api_upload():
|
||||||
|
|
||||||
# Flask-WTF (very helpfully!!) automatically grabs the request form, so force a None formdata
|
# Flask-WTF (very helpfully!!) automatically grabs the request form, so force a None formdata
|
||||||
upload_form = forms.UploadForm(None, data=mapped_dict, meta={'csrf': False})
|
upload_form = forms.UploadForm(None, data=mapped_dict, meta={'csrf': False})
|
||||||
upload_form.category.choices = _create_upload_category_choices()
|
upload_form.category.choices = routes._create_upload_category_choices()
|
||||||
|
|
||||||
if upload_form.validate():
|
if upload_form.validate():
|
||||||
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
torrent = backend.handle_torrent_upload(upload_form, flask.g.user)
|
||||||
|
|
|
@ -133,9 +133,6 @@ def get_category_id_map():
|
||||||
# Routes start here #
|
# Routes start here #
|
||||||
|
|
||||||
|
|
||||||
app.register_blueprint(api_handler.api_blueprint, url_prefix='/api')
|
|
||||||
|
|
||||||
|
|
||||||
def chain_get(source, *args):
|
def chain_get(source, *args):
|
||||||
''' Tries to return values from source by the given keys.
|
''' Tries to return values from source by the given keys.
|
||||||
Returns None if none match.
|
Returns None if none match.
|
||||||
|
@ -767,10 +764,5 @@ def site_help():
|
||||||
|
|
||||||
|
|
||||||
# #################################### API ROUTES ####################################
|
# #################################### API ROUTES ####################################
|
||||||
@app.route('/api/upload', methods=['POST'])
|
|
||||||
def api_upload():
|
app.register_blueprint(api_handler.api_blueprint, url_prefix='/api')
|
||||||
is_valid_user, user, debug = api_handler.validate_user(flask.request)
|
|
||||||
if not is_valid_user:
|
|
||||||
return flask.make_response(flask.jsonify({"Failure": "Invalid username or password."}), 400)
|
|
||||||
api_response = api_handler.api_upload(flask.request, user)
|
|
||||||
return api_response
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<p><strong>5/21 Update:</strong> We've updated our upload API to v2 (v1 still works). See documentation <b><a href="https://github.com/nyaadevs/nyaa/blob/master/utils/api_uploader_v2.py">here</a></b>.</p>
|
<p><strong>2017-05-22 Update:</strong> We've updated our upload API to v2 (v1 <b>is now disabled!</b>). See documentation <b><a href="https://github.com/nyaadevs/nyaa/blob/master/utils/api_uploader_v2.py">here</a></b>.</p>
|
||||||
<p><strong>5/17 Update:</strong> We've added faster and more accurate search! In addition to your typical keyword search in both English and other languages, you can also now use powerful operators
|
<p><strong>2017-05-17 Update:</strong> We've added faster and more accurate search! In addition to your typical keyword search in both English and other languages, you can also now use powerful operators
|
||||||
like <kbd>clockwork planet -horrible</kbd> or <kbd>commie|horrible|cartel yowamushi</kbd> to search. For all supported operators, please click <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#_simple_query_string_syntax">here</a>. More features are coming soon!</p><br>
|
like <kbd>clockwork planet -horrible</kbd> or <kbd>commie|horrible|cartel yowamushi</kbd> to search. For all supported operators, please click <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#_simple_query_string_syntax">here</a>. More features are coming soon!</p><br>
|
||||||
<p>We welcome you to provide feedback at <a href="irc://irc.rizon.net/nyaa-dev">#nyaa-dev@irc.rizon.net</a></p>
|
<p>We welcome you to provide feedback at <a href="irc://irc.rizon.net/nyaa-dev">#nyaa-dev@irc.rizon.net</a></p>
|
||||||
<p>Our GitHub: <a href="https://github.com/nyaadevs" target="_blank">https://github.com/nyaadevs</a> - creating <a href="https://github.com/nyaadevs/nyaa/issues">issues</a> for features and faults is recommendable!</p>
|
<p>Our GitHub: <a href="https://github.com/nyaadevs" target="_blank">https://github.com/nyaadevs</a> - creating <a href="https://github.com/nyaadevs/nyaa/issues">issues</a> for features and faults is recommendable!</p>
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
# Uploads a single torrent file
|
|
||||||
# Works on nyaa.si and sukebei.nyaa.si
|
|
||||||
|
|
||||||
# Consider using api_uploader_v2.py instead
|
|
||||||
# It has a nice command line interface
|
|
||||||
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
'''
|
|
||||||
The POST payload to the api endpoint (/api/upload) should be multipart/form-data containing three fields
|
|
||||||
|
|
||||||
'auth_info': file containing "{
|
|
||||||
'username': str,
|
|
||||||
'password': str
|
|
||||||
}",
|
|
||||||
|
|
||||||
'torrent_info': {
|
|
||||||
'category': str, # see below
|
|
||||||
'display_name': str, # optional
|
|
||||||
'information': str,
|
|
||||||
'description': str,
|
|
||||||
'is_anonymous': boolean,
|
|
||||||
'is_hidden': boolean,
|
|
||||||
'is_remake': boolean,
|
|
||||||
'is_complete': boolean,
|
|
||||||
'is_trusted': boolean #optional
|
|
||||||
},
|
|
||||||
|
|
||||||
'torrent_file': multi part file format
|
|
||||||
|
|
||||||
|
|
||||||
A successful request should return {'Success': int(torrent_id)}
|
|
||||||
A failed request should return {'Failure': ["Failure 1", "Failure 2"...]]}
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
# ########################################### HELP ############################################
|
|
||||||
# ################################# CATEGORIES MUST BE EXACT ##################################
|
|
||||||
'''
|
|
||||||
# Nyaa categories only for now, but api still works for sukebei
|
|
||||||
|
|
||||||
Anime
|
|
||||||
Anime - AMV : '1_1'
|
|
||||||
Anime - English : '1_2'
|
|
||||||
Anime - Non-English : '1_3'
|
|
||||||
Anime - Raw : '1_4'
|
|
||||||
Audio
|
|
||||||
Lossless : '2_1'
|
|
||||||
Lossy : '2_2'
|
|
||||||
Literature
|
|
||||||
Literature - English-translated : '3_1'
|
|
||||||
Literature - Non-English : '3_2'
|
|
||||||
Literature - Non-English-Translated : '3_3'
|
|
||||||
Literature - Raw : '3_4'
|
|
||||||
Live Action
|
|
||||||
Live Action - English-translated : '4_1'
|
|
||||||
Live Action - Idol/Promotional Video : '4_2'
|
|
||||||
Live Action - Non-English-translated : '4_3'
|
|
||||||
Live Action - Raw : '4_4'
|
|
||||||
Pictures
|
|
||||||
Pictures - Graphics : '5_1'
|
|
||||||
Pictures - Photos : '5_2'
|
|
||||||
Software
|
|
||||||
Software - Applications : '6_1'
|
|
||||||
Software - Games : '6_2'
|
|
||||||
'''
|
|
||||||
# ################################# CATEGORIES MUST BE EXACT ##################################
|
|
||||||
|
|
||||||
# ###################################### EXAMPLE REQUEST ######################################
|
|
||||||
'''
|
|
||||||
# Required
|
|
||||||
username = ''
|
|
||||||
password = ''
|
|
||||||
torrent_file = '/path/to/my.torrent'
|
|
||||||
category = '1_2'
|
|
||||||
|
|
||||||
#Optional
|
|
||||||
display_name = ''
|
|
||||||
information = 'API HOWTO'
|
|
||||||
description = 'Visit #nyaa-dev@irc.rizon.net'
|
|
||||||
|
|
||||||
# Defaults to False, change to True to set
|
|
||||||
is_anonymous : False,
|
|
||||||
is_hidden : False,
|
|
||||||
is_remake : False,
|
|
||||||
is_complete : False
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
# ######################################## CHANGE HERE ########################################
|
|
||||||
|
|
||||||
url = 'https://nyaa.si/api/upload' # or 'https://sukebei.nyaa.si/api/upload' or 'http://127.0.0.1:5500/api/upload'
|
|
||||||
|
|
||||||
# Required
|
|
||||||
username = ''
|
|
||||||
password = ''
|
|
||||||
torrent_file = ''
|
|
||||||
category = ''
|
|
||||||
|
|
||||||
# Optional
|
|
||||||
display_name = ''
|
|
||||||
information = ''
|
|
||||||
description = ''
|
|
||||||
is_anonymous = False
|
|
||||||
is_hidden = False
|
|
||||||
is_remake = False
|
|
||||||
is_complete = False
|
|
||||||
is_trusted = True # This will only work if a user is trusted, otherwise the option is ignored
|
|
||||||
|
|
||||||
auth_info = {
|
|
||||||
'username' : username,
|
|
||||||
'password' : password
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata={
|
|
||||||
'category' : category,
|
|
||||||
'display_name' : display_name,
|
|
||||||
'information' : information,
|
|
||||||
'description' : description,
|
|
||||||
'is_anonymous' : is_anonymous,
|
|
||||||
'is_hidden' : is_hidden,
|
|
||||||
'is_remake' : is_remake,
|
|
||||||
'is_complete' : is_complete,
|
|
||||||
'is_trusted' : is_trusted
|
|
||||||
}
|
|
||||||
|
|
||||||
files = {
|
|
||||||
'auth_info' : (json.dumps(auth_info)),
|
|
||||||
'torrent_info' : (json.dumps(metadata)),
|
|
||||||
'torrent_file' : ('{0}'.format(torrent_file), open(torrent_file, 'rb'), 'application/octet-stream')
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, files=files)
|
|
||||||
json_response = response.json()
|
|
||||||
print(json_response)
|
|
||||||
# A successful request should print {'Success': int(torrent_id)}
|
|
|
@ -9,7 +9,7 @@ NYAA_HOST = 'https://nyaa.si'
|
||||||
SUKEBEI_HOST = 'https://sukebei.nyaa.si'
|
SUKEBEI_HOST = 'https://sukebei.nyaa.si'
|
||||||
|
|
||||||
API_BASE = '/api'
|
API_BASE = '/api'
|
||||||
API_UPLOAD = API_BASE + '/v2/upload'
|
API_UPLOAD = API_BASE + '/upload'
|
||||||
|
|
||||||
NYAA_CATS = '''1_1 - Anime - AMV
|
NYAA_CATS = '''1_1 - Anime - AMV
|
||||||
1_2 - Anime - English
|
1_2 - Anime - English
|
||||||
|
|
Loading…
Reference in a new issue