2020-07-12 10:14:35 +03:00
|
|
|
import functools
|
2017-07-28 20:01:19 +03:00
|
|
|
import os
|
2018-07-17 05:52:54 -06:00
|
|
|
from urllib.parse import quote, urlencode
|
2017-07-28 20:01:19 +03:00
|
|
|
|
2018-02-04 14:56:29 +02:00
|
|
|
import flask
|
2017-08-01 21:02:08 +03:00
|
|
|
from flask import current_app as app
|
|
|
|
|
2017-05-12 20:51:49 +02:00
|
|
|
from orderedset import OrderedSet
|
|
|
|
|
2017-08-01 21:02:08 +03:00
|
|
|
from nyaa import bencode
|
2017-05-12 20:51:49 +02:00
|
|
|
|
|
|
|
USED_TRACKERS = OrderedSet()
|
|
|
|
|
2017-05-22 23:01:23 +02:00
|
|
|
|
2017-05-12 20:51:49 +02:00
|
|
|
def read_trackers_from_file(file_object):
|
|
|
|
USED_TRACKERS.clear()
|
|
|
|
|
|
|
|
for line in file_object:
|
|
|
|
line = line.strip()
|
2017-11-22 10:02:22 +02:00
|
|
|
if line and not line.startswith('#'):
|
2017-05-12 20:51:49 +02:00
|
|
|
USED_TRACKERS.add(line)
|
|
|
|
return USED_TRACKERS
|
|
|
|
|
|
|
|
|
|
|
|
def read_trackers():
|
|
|
|
tracker_list_file = os.path.join(app.config['BASE_DIR'], 'trackers.txt')
|
|
|
|
|
|
|
|
if os.path.exists(tracker_list_file):
|
|
|
|
with open(tracker_list_file, 'r') as in_file:
|
|
|
|
return read_trackers_from_file(in_file)
|
|
|
|
|
|
|
|
|
|
|
|
def default_trackers():
|
|
|
|
if not USED_TRACKERS:
|
|
|
|
read_trackers()
|
|
|
|
return USED_TRACKERS[:]
|
|
|
|
|
|
|
|
|
2017-07-30 00:00:39 +03:00
|
|
|
def get_trackers_and_webseeds(torrent):
|
2017-05-13 15:46:08 +02:00
|
|
|
trackers = OrderedSet()
|
2017-07-30 00:00:39 +03:00
|
|
|
webseeds = OrderedSet()
|
2017-05-13 15:46:08 +02:00
|
|
|
|
|
|
|
# Our main one first
|
|
|
|
main_announce_url = app.config.get('MAIN_ANNOUNCE_URL')
|
|
|
|
if main_announce_url:
|
|
|
|
trackers.add(main_announce_url)
|
2017-05-12 20:51:49 +02:00
|
|
|
|
2017-05-13 15:46:08 +02:00
|
|
|
# then the user ones
|
2017-07-30 00:00:39 +03:00
|
|
|
torrent_trackers = torrent.trackers # here be webseeds too
|
2017-05-12 20:51:49 +02:00
|
|
|
for torrent_tracker in torrent_trackers:
|
2017-07-30 00:00:39 +03:00
|
|
|
tracker = torrent_tracker.tracker
|
|
|
|
|
|
|
|
# separate potential webseeds
|
|
|
|
if tracker.is_webseed:
|
|
|
|
webseeds.add(tracker.uri)
|
|
|
|
else:
|
|
|
|
trackers.add(tracker.uri)
|
2017-05-12 20:51:49 +02:00
|
|
|
|
2017-05-13 15:46:08 +02:00
|
|
|
# and finally our tracker list
|
|
|
|
trackers.update(default_trackers())
|
|
|
|
|
2017-07-30 00:00:39 +03:00
|
|
|
return list(trackers), list(webseeds)
|
2017-05-12 20:51:49 +02:00
|
|
|
|
2017-05-16 12:47:06 +03:00
|
|
|
|
2017-05-24 23:19:08 -07:00
|
|
|
def get_default_trackers():
|
2017-05-16 00:46:25 -07:00
|
|
|
trackers = OrderedSet()
|
|
|
|
|
|
|
|
# Our main one first
|
|
|
|
main_announce_url = app.config.get('MAIN_ANNOUNCE_URL')
|
|
|
|
if main_announce_url:
|
|
|
|
trackers.add(main_announce_url)
|
|
|
|
|
|
|
|
# and finally our tracker list
|
|
|
|
trackers.update(default_trackers())
|
|
|
|
|
|
|
|
return list(trackers)
|
|
|
|
|
2017-05-12 20:51:49 +02:00
|
|
|
|
2020-07-12 10:14:35 +03:00
|
|
|
@functools.lru_cache(maxsize=1024*4)
|
|
|
|
def _create_magnet(display_name, info_hash, max_trackers=5, trackers=None):
|
2017-05-24 23:19:08 -07:00
|
|
|
# Unless specified, we just use default trackers
|
2017-05-12 20:51:49 +02:00
|
|
|
if trackers is None:
|
2017-05-24 23:19:08 -07:00
|
|
|
trackers = get_default_trackers()
|
2017-05-12 20:51:49 +02:00
|
|
|
|
|
|
|
magnet_parts = [
|
2020-07-12 10:14:35 +03:00
|
|
|
('dn', display_name)
|
2017-05-12 20:51:49 +02:00
|
|
|
]
|
2018-07-21 22:01:19 +03:00
|
|
|
magnet_parts.extend(
|
|
|
|
('tr', tracker_url)
|
|
|
|
for tracker_url in trackers[:max_trackers]
|
|
|
|
)
|
|
|
|
|
2020-07-12 10:14:35 +03:00
|
|
|
return ''.join([
|
|
|
|
'magnet:?xt=urn:btih:', info_hash,
|
|
|
|
'&', urlencode(magnet_parts, quote_via=quote)
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
def create_magnet(torrent):
|
2018-07-21 22:01:19 +03:00
|
|
|
# Since we accept both models.Torrents and ES objects,
|
|
|
|
# we need to make sure the info_hash is a hex string
|
|
|
|
info_hash = torrent.info_hash
|
|
|
|
if isinstance(info_hash, (bytes, bytearray)):
|
|
|
|
info_hash = info_hash.hex()
|
|
|
|
|
2020-07-12 10:14:35 +03:00
|
|
|
return _create_magnet(torrent.display_name, info_hash)
|
2017-05-12 20:51:49 +02:00
|
|
|
|
|
|
|
|
2017-07-30 00:00:39 +03:00
|
|
|
def create_default_metadata_base(torrent, trackers=None, webseeds=None):
|
|
|
|
if trackers is None or webseeds is None:
|
|
|
|
db_trackers, db_webseeds = get_trackers_and_webseeds(torrent)
|
|
|
|
|
|
|
|
trackers = db_trackers if trackers is None else trackers
|
|
|
|
webseeds = db_webseeds if webseeds is None else webseeds
|
2017-05-12 20:51:49 +02:00
|
|
|
|
|
|
|
metadata_base = {
|
|
|
|
'created by': 'NyaaV2',
|
2018-02-04 14:56:29 +02:00
|
|
|
'creation date': int(torrent.created_utc_timestamp),
|
|
|
|
'comment': flask.url_for('torrents.view',
|
|
|
|
torrent_id=torrent.id,
|
|
|
|
_external=True)
|
2017-05-12 20:51:49 +02:00
|
|
|
# 'encoding' : 'UTF-8' # It's almost always UTF-8 and expected, but if it isn't...
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(trackers) > 0:
|
|
|
|
metadata_base['announce'] = trackers[0]
|
|
|
|
if len(trackers) > 1:
|
|
|
|
# Yes, it's a list of lists with a single element inside.
|
2017-11-22 10:02:22 +02:00
|
|
|
metadata_base['announce-list'] = [[tracker] for tracker in trackers]
|
2017-05-12 20:51:49 +02:00
|
|
|
|
2017-07-30 00:00:39 +03:00
|
|
|
# Add webseeds
|
|
|
|
if webseeds:
|
|
|
|
metadata_base['url-list'] = webseeds
|
|
|
|
|
2017-05-12 20:51:49 +02:00
|
|
|
return metadata_base
|
|
|
|
|
|
|
|
|
2017-08-29 02:17:39 +02:00
|
|
|
def create_bencoded_torrent(torrent, bencoded_info, metadata_base=None):
|
2017-05-12 20:51:49 +02:00
|
|
|
''' Creates a bencoded torrent metadata for a given torrent,
|
|
|
|
optionally using a given metadata_base dict (note: 'info' key will be
|
|
|
|
popped off the dict) '''
|
|
|
|
if metadata_base is None:
|
|
|
|
metadata_base = create_default_metadata_base(torrent)
|
|
|
|
|
|
|
|
metadata_base['encoding'] = torrent.encoding
|
|
|
|
|
|
|
|
# Make sure info doesn't exist on the base
|
|
|
|
metadata_base.pop('info', None)
|
|
|
|
prefixed_dict = {key: metadata_base[key] for key in metadata_base if key < 'info'}
|
|
|
|
suffixed_dict = {key: metadata_base[key] for key in metadata_base if key > 'info'}
|
|
|
|
|
|
|
|
prefix = bencode.encode(prefixed_dict)
|
|
|
|
suffix = bencode.encode(suffixed_dict)
|
|
|
|
|
2017-05-14 20:14:49 +03:00
|
|
|
bencoded_torrent = prefix[:-1] + b'4:info' + bencoded_info + suffix[1:]
|
2017-05-12 20:51:49 +02:00
|
|
|
|
|
|
|
return bencoded_torrent
|