mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-11-10 18:19:15 +00:00
Move bencoded info dicts from mysql torrent_info table to info_dict directory. DB change!
IMPORTANT!!! Make sure to run utils/infodict_mysql2file.py before upgrading the database.
This commit is contained in:
parent
418856a4bf
commit
fd0a02b95c
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -14,16 +14,15 @@ __pycache__
|
||||||
|
|
||||||
# Databases
|
# Databases
|
||||||
*.sql
|
*.sql
|
||||||
test.db
|
/test.db
|
||||||
|
|
||||||
# Webserver
|
# Webserver
|
||||||
uwsgi.sock
|
/uwsgi.sock
|
||||||
|
|
||||||
# Application
|
# Application
|
||||||
install/*
|
/install/*
|
||||||
config.py
|
/config.py
|
||||||
/test_torrent_batch
|
/test_torrent_batch
|
||||||
torrents
|
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
*.swp
|
*.swp
|
||||||
|
|
2
info_dicts/.gitignore
vendored
Normal file
2
info_dicts/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
57
migrations/versions/b61e4f6a88cc_del_torrents_info.py
Normal file
57
migrations/versions/b61e4f6a88cc_del_torrents_info.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
"""Remove bencoded info dicts from mysql
|
||||||
|
|
||||||
|
Revision ID: b61e4f6a88cc
|
||||||
|
Revises: 500117641608
|
||||||
|
Create Date: 2017-08-29 01:45:08.357936
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b61e4f6a88cc'
|
||||||
|
down_revision = '500117641608'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
print("--- WARNING ---")
|
||||||
|
print("This migration drops the torrent_info tables.")
|
||||||
|
print("You will lose all of your .torrent files if you have not converted them beforehand.")
|
||||||
|
print("Use the migration script at utils/infodict_mysql2file.py")
|
||||||
|
print("Type OKAY and hit Enter to continue, CTRL-C to abort.")
|
||||||
|
print("--- WARNING ---")
|
||||||
|
try:
|
||||||
|
if input() != "OKAY":
|
||||||
|
sys.exit(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
op.drop_table('sukebei_torrents_info')
|
||||||
|
op.drop_table('nyaa_torrents_info')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.create_table('nyaa_torrents_info',
|
||||||
|
sa.Column('info_dict', mysql.MEDIUMBLOB(), nullable=True),
|
||||||
|
sa.Column('torrent_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['torrent_id'], ['nyaa_torrents.id'], name='nyaa_torrents_info_ibfk_1', ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('torrent_id'),
|
||||||
|
mysql_collate='utf8_bin',
|
||||||
|
mysql_default_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_row_format='COMPRESSED'
|
||||||
|
)
|
||||||
|
op.create_table('sukebei_torrents_info',
|
||||||
|
sa.Column('info_dict', mysql.MEDIUMBLOB(), nullable=True),
|
||||||
|
sa.Column('torrent_id', mysql.INTEGER(display_width=11), autoincrement=False, nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['torrent_id'], ['sukebei_torrents.id'], name='sukebei_torrents_info_ibfk_1', ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('torrent_id'),
|
||||||
|
mysql_collate='utf8_bin',
|
||||||
|
mysql_default_charset='utf8',
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_row_format='COMPRESSED'
|
||||||
|
)
|
|
@ -1,13 +1,11 @@
|
||||||
import binascii
|
import binascii
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import os.path
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
|
||||||
from nyaa import backend, bencode, forms, models, utils
|
from nyaa import backend, forms, models
|
||||||
from nyaa.extensions import db
|
|
||||||
from nyaa.views.torrents import _create_upload_category_choices
|
from nyaa.views.torrents import _create_upload_category_choices
|
||||||
|
|
||||||
api_blueprint = flask.Blueprint('api', __name__, url_prefix='/api')
|
api_blueprint = flask.Blueprint('api', __name__, url_prefix='/api')
|
||||||
|
@ -120,142 +118,6 @@ def v2_api_upload():
|
||||||
return flask.jsonify({'errors': mapped_errors}), 400
|
return flask.jsonify({'errors': mapped_errors}), 400
|
||||||
|
|
||||||
|
|
||||||
# #################################### TEMPORARY ####################################
|
|
||||||
|
|
||||||
from orderedset import OrderedSet # noqa: E402 isort:skip
|
|
||||||
|
|
||||||
|
|
||||||
@api_blueprint.route('/ghetto_import', methods=['POST'])
|
|
||||||
def ghetto_import():
|
|
||||||
if flask.request.remote_addr != '127.0.0.1':
|
|
||||||
return flask.error(403)
|
|
||||||
|
|
||||||
torrent_file = flask.request.files.get('torrent')
|
|
||||||
|
|
||||||
try:
|
|
||||||
torrent_dict = bencode.decode(torrent_file)
|
|
||||||
# field.data.close()
|
|
||||||
except (bencode.MalformedBencodeException, UnicodeError):
|
|
||||||
return 'Malformed torrent file', 500
|
|
||||||
|
|
||||||
try:
|
|
||||||
forms._validate_torrent_metadata(torrent_dict)
|
|
||||||
except AssertionError as e:
|
|
||||||
return 'Malformed torrent metadata ({})'.format(e.args[0]), 500
|
|
||||||
|
|
||||||
try:
|
|
||||||
tracker_found = forms._validate_trackers(torrent_dict) # noqa F841
|
|
||||||
except AssertionError as e:
|
|
||||||
return 'Malformed torrent trackers ({})'.format(e.args[0]), 500
|
|
||||||
|
|
||||||
bencoded_info_dict = bencode.encode(torrent_dict['info'])
|
|
||||||
info_hash = utils.sha1_hash(bencoded_info_dict)
|
|
||||||
|
|
||||||
# Check if the info_hash exists already in the database
|
|
||||||
torrent = models.Torrent.by_info_hash(info_hash)
|
|
||||||
if not torrent:
|
|
||||||
return 'This torrent does not exists', 500
|
|
||||||
|
|
||||||
if torrent.has_torrent:
|
|
||||||
return 'This torrent already has_torrent', 500
|
|
||||||
|
|
||||||
# Torrent is legit, pass original filename and dict along
|
|
||||||
torrent_data = forms.TorrentFileData(filename=os.path.basename(torrent_file.filename),
|
|
||||||
torrent_dict=torrent_dict,
|
|
||||||
info_hash=info_hash,
|
|
||||||
bencoded_info_dict=bencoded_info_dict)
|
|
||||||
|
|
||||||
# The torrent has been validated and is safe to access with ['foo'] etc - all relevant
|
|
||||||
# keys and values have been checked for (see UploadForm in forms.py for details)
|
|
||||||
info_dict = torrent_data.torrent_dict['info']
|
|
||||||
|
|
||||||
changed_to_utf8 = backend._replace_utf8_values(torrent_data.torrent_dict)
|
|
||||||
|
|
||||||
torrent_filesize = info_dict.get('length') or sum(
|
|
||||||
f['length'] for f in info_dict.get('files'))
|
|
||||||
|
|
||||||
# In case no encoding, assume UTF-8.
|
|
||||||
torrent_encoding = torrent_data.torrent_dict.get('encoding', b'utf-8').decode('utf-8')
|
|
||||||
|
|
||||||
# Store bencoded info_dict
|
|
||||||
torrent.info = models.TorrentInfo(info_dict=torrent_data.bencoded_info_dict)
|
|
||||||
torrent.has_torrent = True
|
|
||||||
|
|
||||||
# To simplify parsing the filelist, turn single-file torrent into a list
|
|
||||||
torrent_filelist = info_dict.get('files')
|
|
||||||
|
|
||||||
used_path_encoding = changed_to_utf8 and 'utf-8' or torrent_encoding
|
|
||||||
|
|
||||||
parsed_file_tree = dict()
|
|
||||||
if not torrent_filelist:
|
|
||||||
# If single-file, the root will be the file-tree (no directory)
|
|
||||||
file_tree_root = parsed_file_tree
|
|
||||||
torrent_filelist = [{'length': torrent_filesize, 'path': [info_dict['name']]}]
|
|
||||||
else:
|
|
||||||
# If multi-file, use the directory name as root for files
|
|
||||||
file_tree_root = parsed_file_tree.setdefault(
|
|
||||||
info_dict['name'].decode(used_path_encoding), {})
|
|
||||||
|
|
||||||
# Parse file dicts into a tree
|
|
||||||
for file_dict in torrent_filelist:
|
|
||||||
# Decode path parts from utf8-bytes
|
|
||||||
path_parts = [path_part.decode(used_path_encoding) for path_part in file_dict['path']]
|
|
||||||
|
|
||||||
filename = path_parts.pop()
|
|
||||||
current_directory = file_tree_root
|
|
||||||
|
|
||||||
for directory in path_parts:
|
|
||||||
current_directory = current_directory.setdefault(directory, {})
|
|
||||||
|
|
||||||
# Don't add empty filenames (BitComet directory)
|
|
||||||
if filename:
|
|
||||||
current_directory[filename] = file_dict['length']
|
|
||||||
|
|
||||||
parsed_file_tree = utils.sorted_pathdict(parsed_file_tree)
|
|
||||||
|
|
||||||
json_bytes = json.dumps(parsed_file_tree, separators=(',', ':')).encode('utf8')
|
|
||||||
torrent.filelist = models.TorrentFilelist(filelist_blob=json_bytes)
|
|
||||||
|
|
||||||
db.session.add(torrent)
|
|
||||||
db.session.flush()
|
|
||||||
|
|
||||||
# Store the users trackers
|
|
||||||
trackers = OrderedSet()
|
|
||||||
announce = torrent_data.torrent_dict.get('announce', b'').decode('ascii')
|
|
||||||
if announce:
|
|
||||||
trackers.add(announce)
|
|
||||||
|
|
||||||
# List of lists with single item
|
|
||||||
announce_list = torrent_data.torrent_dict.get('announce-list', [])
|
|
||||||
for announce in announce_list:
|
|
||||||
trackers.add(announce[0].decode('ascii'))
|
|
||||||
|
|
||||||
# Remove our trackers, maybe? TODO ?
|
|
||||||
|
|
||||||
# Search for/Add trackers in DB
|
|
||||||
db_trackers = OrderedSet()
|
|
||||||
for announce in trackers:
|
|
||||||
tracker = models.Trackers.by_uri(announce)
|
|
||||||
|
|
||||||
# Insert new tracker if not found
|
|
||||||
if not tracker:
|
|
||||||
tracker = models.Trackers(uri=announce)
|
|
||||||
db.session.add(tracker)
|
|
||||||
db.session.flush()
|
|
||||||
|
|
||||||
db_trackers.add(tracker)
|
|
||||||
|
|
||||||
# Store tracker refs in DB
|
|
||||||
for order, tracker in enumerate(db_trackers):
|
|
||||||
torrent_tracker = models.TorrentTrackers(torrent_id=torrent.id,
|
|
||||||
tracker_id=tracker.id, order=order)
|
|
||||||
db.session.add(torrent_tracker)
|
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return 'success'
|
|
||||||
|
|
||||||
|
|
||||||
# ####################################### INFO #######################################
|
# ####################################### INFO #######################################
|
||||||
ID_PATTERN = '^[0-9]+$'
|
ID_PATTERN = '^[0-9]+$'
|
||||||
INFO_HASH_PATTERN = '^[0-9a-fA-F]{40}$' # INFO_HASH as string
|
INFO_HASH_PATTERN = '^[0-9a-fA-F]{40}$' # INFO_HASH as string
|
||||||
|
|
|
@ -162,9 +162,10 @@ def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
|
||||||
|
|
||||||
# Delete exisiting torrent which is marked as deleted
|
# Delete exisiting torrent which is marked as deleted
|
||||||
if torrent_data.db_id is not None:
|
if torrent_data.db_id is not None:
|
||||||
models.Torrent.query.filter_by(id=torrent_data.db_id).delete()
|
oldtorrent = models.Torrent.by_id(torrent_data.db_id)
|
||||||
|
_delete_torrent_file(oldtorrent)
|
||||||
|
db.session.delete(oldtorrent)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
_delete_cached_torrent_file(torrent_data.db_id)
|
|
||||||
|
|
||||||
# The torrent has been validated and is safe to access with ['foo'] etc - all relevant
|
# The torrent has been validated and is safe to access with ['foo'] etc - all relevant
|
||||||
# keys and values have been checked for (see UploadForm in forms.py for details)
|
# keys and values have been checked for (see UploadForm in forms.py for details)
|
||||||
|
@ -195,7 +196,15 @@ def handle_torrent_upload(upload_form, uploading_user=None, fromAPI=False):
|
||||||
uploader_ip=ip_address(flask.request.remote_addr).packed)
|
uploader_ip=ip_address(flask.request.remote_addr).packed)
|
||||||
|
|
||||||
# Store bencoded info_dict
|
# Store bencoded info_dict
|
||||||
torrent.info = models.TorrentInfo(info_dict=torrent_data.bencoded_info_dict)
|
info_hash = torrent_data.info_hash.hex().lower()
|
||||||
|
path = os.path.join(app.config['BASE_DIR'], 'info_dicts',
|
||||||
|
info_hash[0:2], info_hash[2:4])
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
path = os.path.join(path, info_hash)
|
||||||
|
with open(path, 'wb') as fp:
|
||||||
|
fp.write(torrent_data.bencoded_info_dict)
|
||||||
|
|
||||||
torrent.stats = models.Statistic()
|
torrent.stats = models.Statistic()
|
||||||
torrent.has_torrent = True
|
torrent.has_torrent = True
|
||||||
|
|
||||||
|
@ -361,9 +370,10 @@ def tracker_api(info_hashes, method):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _delete_cached_torrent_file(torrent_id):
|
def _delete_torrent_file(torrent):
|
||||||
# Note: obviously temporary
|
info_hash = torrent.info_hash_as_hex
|
||||||
cached_torrent = os.path.join(app.config['BASE_DIR'],
|
path = os.path.join(app.config['BASE_DIR'], 'info_dicts',
|
||||||
'torrent_cache', str(torrent_id) + '.torrent')
|
info_hash[0:2], info_hash[2:4], info_hash)
|
||||||
if os.path.exists(cached_torrent):
|
|
||||||
os.remove(cached_torrent)
|
if os.path.exists(path):
|
||||||
|
os.remove(path)
|
||||||
|
|
|
@ -170,11 +170,6 @@ class TorrentBase(DeclarativeHelperBase):
|
||||||
backref='torrents', lazy="joined",
|
backref='torrents', lazy="joined",
|
||||||
primaryjoin=join_sql.format(cls.__flavor__))
|
primaryjoin=join_sql.format(cls.__flavor__))
|
||||||
|
|
||||||
@declarative.declared_attr
|
|
||||||
def info(cls):
|
|
||||||
return db.relationship(cls._flavor_prefix('TorrentInfo'), uselist=False,
|
|
||||||
cascade="all, delete-orphan", back_populates='torrent')
|
|
||||||
|
|
||||||
@declarative.declared_attr
|
@declarative.declared_attr
|
||||||
def filelist(cls):
|
def filelist(cls):
|
||||||
return db.relationship(cls._flavor_prefix('TorrentFilelist'), uselist=False,
|
return db.relationship(cls._flavor_prefix('TorrentFilelist'), uselist=False,
|
||||||
|
@ -235,7 +230,7 @@ class TorrentBase(DeclarativeHelperBase):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def info_hash_as_hex(self):
|
def info_hash_as_hex(self):
|
||||||
return self.info_hash.hex()
|
return self.info_hash.hex().lower()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def magnet_uri(self):
|
def magnet_uri(self):
|
||||||
|
@ -290,22 +285,6 @@ class TorrentFilelistBase(DeclarativeHelperBase):
|
||||||
back_populates='filelist')
|
back_populates='filelist')
|
||||||
|
|
||||||
|
|
||||||
class TorrentInfoBase(DeclarativeHelperBase):
|
|
||||||
__tablename_base__ = 'torrents_info'
|
|
||||||
|
|
||||||
__table_args__ = {'mysql_row_format': 'COMPRESSED'}
|
|
||||||
|
|
||||||
@declarative.declared_attr
|
|
||||||
def torrent_id(cls):
|
|
||||||
return db.Column(db.Integer, db.ForeignKey(
|
|
||||||
cls._table_prefix('torrents.id'), ondelete="CASCADE"), primary_key=True)
|
|
||||||
info_dict = db.Column(MediumBlobType, nullable=True)
|
|
||||||
|
|
||||||
@declarative.declared_attr
|
|
||||||
def torrent(cls):
|
|
||||||
return db.relationship(cls._flavor_prefix('Torrent'), uselist=False, back_populates='info')
|
|
||||||
|
|
||||||
|
|
||||||
class StatisticBase(DeclarativeHelperBase):
|
class StatisticBase(DeclarativeHelperBase):
|
||||||
__tablename_base__ = 'statistics'
|
__tablename_base__ = 'statistics'
|
||||||
|
|
||||||
|
@ -806,15 +785,6 @@ class SukebeiTorrentFilelist(TorrentFilelistBase, db.Model):
|
||||||
__flavor__ = 'Sukebei'
|
__flavor__ = 'Sukebei'
|
||||||
|
|
||||||
|
|
||||||
# TorrentInfo
|
|
||||||
class NyaaTorrentInfo(TorrentInfoBase, db.Model):
|
|
||||||
__flavor__ = 'Nyaa'
|
|
||||||
|
|
||||||
|
|
||||||
class SukebeiTorrentInfo(TorrentInfoBase, db.Model):
|
|
||||||
__flavor__ = 'Sukebei'
|
|
||||||
|
|
||||||
|
|
||||||
# Statistic
|
# Statistic
|
||||||
class NyaaStatistic(StatisticBase, db.Model):
|
class NyaaStatistic(StatisticBase, db.Model):
|
||||||
__flavor__ = 'Nyaa'
|
__flavor__ = 'Nyaa'
|
||||||
|
@ -882,7 +852,6 @@ class SukebeiReport(ReportBase, db.Model):
|
||||||
if config['SITE_FLAVOR'] == 'nyaa':
|
if config['SITE_FLAVOR'] == 'nyaa':
|
||||||
Torrent = NyaaTorrent
|
Torrent = NyaaTorrent
|
||||||
TorrentFilelist = NyaaTorrentFilelist
|
TorrentFilelist = NyaaTorrentFilelist
|
||||||
TorrentInfo = NyaaTorrentInfo
|
|
||||||
Statistic = NyaaStatistic
|
Statistic = NyaaStatistic
|
||||||
TorrentTrackers = NyaaTorrentTrackers
|
TorrentTrackers = NyaaTorrentTrackers
|
||||||
MainCategory = NyaaMainCategory
|
MainCategory = NyaaMainCategory
|
||||||
|
@ -895,7 +864,6 @@ if config['SITE_FLAVOR'] == 'nyaa':
|
||||||
elif config['SITE_FLAVOR'] == 'sukebei':
|
elif config['SITE_FLAVOR'] == 'sukebei':
|
||||||
Torrent = SukebeiTorrent
|
Torrent = SukebeiTorrent
|
||||||
TorrentFilelist = SukebeiTorrentFilelist
|
TorrentFilelist = SukebeiTorrentFilelist
|
||||||
TorrentInfo = SukebeiTorrentInfo
|
|
||||||
Statistic = SukebeiStatistic
|
Statistic = SukebeiStatistic
|
||||||
TorrentTrackers = SukebeiTorrentTrackers
|
TorrentTrackers = SukebeiTorrentTrackers
|
||||||
MainCategory = SukebeiMainCategory
|
MainCategory = SukebeiMainCategory
|
||||||
|
|
|
@ -118,7 +118,7 @@ def create_default_metadata_base(torrent, trackers=None, webseeds=None):
|
||||||
return metadata_base
|
return metadata_base
|
||||||
|
|
||||||
|
|
||||||
def create_bencoded_torrent(torrent, metadata_base=None):
|
def create_bencoded_torrent(torrent, bencoded_info, metadata_base=None):
|
||||||
''' Creates a bencoded torrent metadata for a given torrent,
|
''' Creates a bencoded torrent metadata for a given torrent,
|
||||||
optionally using a given metadata_base dict (note: 'info' key will be
|
optionally using a given metadata_base dict (note: 'info' key will be
|
||||||
popped off the dict) '''
|
popped off the dict) '''
|
||||||
|
@ -135,7 +135,6 @@ def create_bencoded_torrent(torrent, metadata_base=None):
|
||||||
prefix = bencode.encode(prefixed_dict)
|
prefix = bencode.encode(prefixed_dict)
|
||||||
suffix = bencode.encode(suffixed_dict)
|
suffix = bencode.encode(suffixed_dict)
|
||||||
|
|
||||||
bencoded_info = torrent.info.info_dict
|
|
||||||
bencoded_torrent = prefix[:-1] + b'4:info' + bencoded_info + suffix[1:]
|
bencoded_torrent = prefix[:-1] + b'4:info' + bencoded_info + suffix[1:]
|
||||||
|
|
||||||
return bencoded_torrent
|
return bencoded_torrent
|
||||||
|
|
|
@ -319,7 +319,7 @@ def download_torrent(torrent_id):
|
||||||
if torrent.deleted and not (flask.g.user and flask.g.user.is_moderator):
|
if torrent.deleted and not (flask.g.user and flask.g.user.is_moderator):
|
||||||
flask.abort(404)
|
flask.abort(404)
|
||||||
|
|
||||||
torrent_file, torrent_file_size = _get_cached_torrent_file(torrent)
|
torrent_file, torrent_file_size = _make_torrent_file(torrent)
|
||||||
disposition = 'inline; filename="{0}"; filename*=UTF-8\'\'{0}'.format(
|
disposition = 'inline; filename="{0}"; filename*=UTF-8\'\'{0}'.format(
|
||||||
quote(torrent.torrent_name.encode('utf-8')))
|
quote(torrent.torrent_name.encode('utf-8')))
|
||||||
|
|
||||||
|
@ -472,18 +472,15 @@ def _create_upload_category_choices():
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
def _get_cached_torrent_file(torrent):
|
|
||||||
# Note: obviously temporary
|
|
||||||
cached_torrent = os.path.join(app.config['BASE_DIR'],
|
|
||||||
'torrent_cache', str(torrent.id) + '.torrent')
|
|
||||||
if not os.path.exists(cached_torrent):
|
|
||||||
with open(cached_torrent, 'wb') as out_file:
|
|
||||||
metadata_base = torrents.create_default_metadata_base(torrent)
|
|
||||||
# Replace the default comment with url to the torrent page
|
|
||||||
metadata_base['comment'] = flask.url_for('torrents.view',
|
|
||||||
torrent_id=torrent.id,
|
|
||||||
_external=True)
|
|
||||||
|
|
||||||
out_file.write(torrents.create_bencoded_torrent(torrent, metadata_base))
|
def _make_torrent_file(torrent):
|
||||||
|
info_hash = torrent.info_hash_as_hex
|
||||||
|
path = os.path.join(app.config['BASE_DIR'], 'info_dicts',
|
||||||
|
info_hash[0:2], info_hash[2:4], info_hash)
|
||||||
|
|
||||||
return open(cached_torrent, 'rb'), os.path.getsize(cached_torrent)
|
with open(path, 'rb') as fp:
|
||||||
|
bencoded_info = fp.read()
|
||||||
|
|
||||||
|
data = torrents.create_bencoded_torrent(torrent, bencoded_info)
|
||||||
|
|
||||||
|
return data, len(data)
|
||||||
|
|
1
torrent_cache/.gitignore
vendored
1
torrent_cache/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
*.torrent
|
|
2
torrents/.gitignore
vendored
Normal file
2
torrents/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
53
utils/infodict_mysql2file.py
Executable file
53
utils/infodict_mysql2file.py
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import MySQLdb
|
||||||
|
import MySQLdb.cursors
|
||||||
|
|
||||||
|
if len(sys.argv) < 3 or len(sys.argv) > 4:
|
||||||
|
print("Usage: {0} <prefix(nyaa|sukebei)> <outdir> [offset]".format(sys.argv[0]))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
ofs = 0
|
||||||
|
prefix = sys.argv[1]
|
||||||
|
outdir = sys.argv[2]
|
||||||
|
if not os.path.exists(outdir):
|
||||||
|
os.makedirs(outdir)
|
||||||
|
if len(sys.argv) == 4:
|
||||||
|
ofs = int(sys.argv[3])
|
||||||
|
|
||||||
|
|
||||||
|
db = MySQLdb.connect(host='localhost',
|
||||||
|
user='test',
|
||||||
|
passwd='test123',
|
||||||
|
db='nyaav2',
|
||||||
|
cursorclass=MySQLdb.cursors.SSCursor)
|
||||||
|
cur = db.cursor()
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"""SELECT
|
||||||
|
id,
|
||||||
|
info_hash,
|
||||||
|
info_dict
|
||||||
|
FROM
|
||||||
|
{0}_torrents
|
||||||
|
JOIN {0}_torrents_info ON torrent_id = id
|
||||||
|
LIMIT 18446744073709551610 OFFSET {1}
|
||||||
|
""".format(prefix, ofs))
|
||||||
|
|
||||||
|
for row in cur:
|
||||||
|
id = row[0]
|
||||||
|
info_hash = row[1].hex().lower()
|
||||||
|
info_dict = row[2]
|
||||||
|
|
||||||
|
path = os.path.join(outdir, info_hash[0:2], info_hash[2:4])
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
path = os.path.join(path, info_hash)
|
||||||
|
|
||||||
|
with open(path, 'wb') as fp:
|
||||||
|
fp.write(info_dict)
|
||||||
|
|
||||||
|
ofs += 1
|
||||||
|
print(ofs)
|
Loading…
Reference in a new issue