forked from 0x2620/pandora
remove torrent backend
This commit is contained in:
parent
9355ae691d
commit
83df2c0011
12 changed files with 29 additions and 142 deletions
|
@ -1399,10 +1399,8 @@
|
||||||
corner of the screen
|
corner of the screen
|
||||||
"resolutions": List of video resolutions. Supported values are 96, 144,
|
"resolutions": List of video resolutions. Supported values are 96, 144,
|
||||||
240, 288, 360, 432, 480, 720 and 1080.
|
240, 288, 360, 432, 480, 720 and 1080.
|
||||||
"torrent": If true, video downloads are offered via BitTorrent
|
|
||||||
*/
|
*/
|
||||||
"video": {
|
"video": {
|
||||||
"torrent": false,
|
|
||||||
"formats": ["webm", "mp4"],
|
"formats": ["webm", "mp4"],
|
||||||
// fixme: this should be named "ratio" or "defaultRatio",
|
// fixme: this should be named "ratio" or "defaultRatio",
|
||||||
// as it also applies to clip lists (on load)
|
// as it also applies to clip lists (on load)
|
||||||
|
|
|
@ -1876,10 +1876,8 @@
|
||||||
corner of the screen
|
corner of the screen
|
||||||
"resolutions": List of video resolutions. Supported values are 96, 144,
|
"resolutions": List of video resolutions. Supported values are 96, 144,
|
||||||
240, 288, 360, 432, 480, 720 and 1080.
|
240, 288, 360, 432, 480, 720 and 1080.
|
||||||
"torrent": If true, video downloads are offered via BitTorrent
|
|
||||||
*/
|
*/
|
||||||
"video": {
|
"video": {
|
||||||
"torrent": false,
|
|
||||||
"formats": ["webm", "mp4"],
|
"formats": ["webm", "mp4"],
|
||||||
"previewRatio": 1.375,
|
"previewRatio": 1.375,
|
||||||
"resolutions": [240, 480]
|
"resolutions": [240, 480]
|
||||||
|
|
|
@ -1334,10 +1334,8 @@
|
||||||
corner of the screen
|
corner of the screen
|
||||||
"resolutions": List of video resolutions. Supported values are 96, 144,
|
"resolutions": List of video resolutions. Supported values are 96, 144,
|
||||||
240, 288, 360, 432, 480, 720 and 1080.
|
240, 288, 360, 432, 480, 720 and 1080.
|
||||||
"torrent": If true, video downloads are offered via BitTorrent
|
|
||||||
*/
|
*/
|
||||||
"video": {
|
"video": {
|
||||||
"torrent": true,
|
|
||||||
"formats": ["webm", "mp4"],
|
"formats": ["webm", "mp4"],
|
||||||
"previewRatio": 1.3333333333,
|
"previewRatio": 1.3333333333,
|
||||||
//supported resolutions are
|
//supported resolutions are
|
||||||
|
|
|
@ -1272,13 +1272,11 @@ examples (config.SITENAME.jsonc) that are part of this pan.do/ra distribution.
|
||||||
corner of the screen
|
corner of the screen
|
||||||
"resolutions": List of video resolutions. Supported values are 96, 144,
|
"resolutions": List of video resolutions. Supported values are 96, 144,
|
||||||
240, 288, 360, 432, 480, 720 and 1080.
|
240, 288, 360, 432, 480, 720 and 1080.
|
||||||
"torrent": If true, video downloads are offered via BitTorrent
|
|
||||||
*/
|
*/
|
||||||
"video": {
|
"video": {
|
||||||
"downloadFormat": "webm",
|
"downloadFormat": "webm",
|
||||||
"formats": ["webm", "mp4"],
|
"formats": ["webm", "mp4"],
|
||||||
"previewRatio": 1.3333333333,
|
"previewRatio": 1.3333333333,
|
||||||
"resolutions": [240, 480],
|
"resolutions": [240, 480]
|
||||||
"torrent": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Migration(migrations.Migration):
|
||||||
('poster_width', models.IntegerField(default=0)),
|
('poster_width', models.IntegerField(default=0)),
|
||||||
('poster_frame', models.FloatField(default=-1)),
|
('poster_frame', models.FloatField(default=-1)),
|
||||||
('icon', models.ImageField(blank=True, default=None, upload_to=item.models.get_icon_path)),
|
('icon', models.ImageField(blank=True, default=None, upload_to=item.models.get_icon_path)),
|
||||||
('torrent', models.FileField(blank=True, default=None, max_length=1000, upload_to=item.models.get_torrent_path)),
|
('torrent', models.FileField(blank=True, default=None, max_length=1000)),
|
||||||
('stream_info', oxdjango.fields.DictField(default={}, editable=False)),
|
('stream_info', oxdjango.fields.DictField(default={}, editable=False)),
|
||||||
('stream_aspect', models.FloatField(default=1.3333333333333333)),
|
('stream_aspect', models.FloatField(default=1.3333333333333333)),
|
||||||
],
|
],
|
||||||
|
|
19
pandora/item/migrations/0005_auto_20230710_0852.py
Normal file
19
pandora/item/migrations/0005_auto_20230710_0852.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.10 on 2023-07-10 08:52
|
||||||
|
|
||||||
|
import django.core.serializers.json
|
||||||
|
from django.db import migrations, models
|
||||||
|
import oxdjango.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('item', '0004_json_cache'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='item',
|
||||||
|
name='torrent',
|
||||||
|
),
|
||||||
|
]
|
|
@ -157,9 +157,6 @@ def get_icon_path(f, x):
|
||||||
def get_poster_path(f, x):
|
def get_poster_path(f, x):
|
||||||
return get_path(f, 'poster.jpg')
|
return get_path(f, 'poster.jpg')
|
||||||
|
|
||||||
def get_torrent_path(f, x):
|
|
||||||
return get_path(f, 'torrent.torrent')
|
|
||||||
|
|
||||||
class Item(models.Model):
|
class Item(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
@ -185,7 +182,6 @@ class Item(models.Model):
|
||||||
|
|
||||||
icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path)
|
icon = models.ImageField(default=None, blank=True, upload_to=get_icon_path)
|
||||||
|
|
||||||
torrent = models.FileField(default=None, blank=True, max_length=1000, upload_to=get_torrent_path)
|
|
||||||
stream_info = JSONField(default=dict, editable=False)
|
stream_info = JSONField(default=dict, editable=False)
|
||||||
|
|
||||||
# stream related fields
|
# stream related fields
|
||||||
|
@ -1306,90 +1302,6 @@ class Item(models.Model):
|
||||||
self.files.filter(selected=True).update(selected=False)
|
self.files.filter(selected=True).update(selected=False)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_torrent(self, request):
|
|
||||||
if self.torrent:
|
|
||||||
self.torrent.seek(0)
|
|
||||||
data = ox.torrent.bdecode(self.torrent.read())
|
|
||||||
url = request.build_absolute_uri("%s/torrent/" % self.get_absolute_url())
|
|
||||||
if url.startswith('https://'):
|
|
||||||
url = 'http' + url[5:]
|
|
||||||
data['url-list'] = ['%s%s' % (url, u.split('torrent/')[1]) for u in data['url-list']]
|
|
||||||
return ox.torrent.bencode(data)
|
|
||||||
|
|
||||||
def make_torrent(self):
|
|
||||||
if not settings.CONFIG['video'].get('torrent'):
|
|
||||||
return
|
|
||||||
streams = self.streams()
|
|
||||||
if streams.count() == 0:
|
|
||||||
return
|
|
||||||
base = self.path('torrent')
|
|
||||||
base = os.path.abspath(os.path.join(settings.MEDIA_ROOT, base))
|
|
||||||
if not isinstance(base, bytes):
|
|
||||||
base = base.encode('utf-8')
|
|
||||||
if os.path.exists(base):
|
|
||||||
shutil.rmtree(base)
|
|
||||||
ox.makedirs(base)
|
|
||||||
|
|
||||||
filename = utils.safe_filename(ox.decode_html(self.get('title')))
|
|
||||||
base = self.path('torrent/%s' % filename)
|
|
||||||
base = os.path.abspath(os.path.join(settings.MEDIA_ROOT, base))
|
|
||||||
size = 0
|
|
||||||
duration = 0.0
|
|
||||||
if streams.count() == 1:
|
|
||||||
v = streams[0]
|
|
||||||
media_path = v.media.path
|
|
||||||
extension = media_path.split('.')[-1]
|
|
||||||
url = "%s/torrent/%s.%s" % (self.get_absolute_url(),
|
|
||||||
quote(filename.encode('utf-8')),
|
|
||||||
extension)
|
|
||||||
video = "%s.%s" % (base, extension)
|
|
||||||
if not isinstance(media_path, bytes):
|
|
||||||
media_path = media_path.encode('utf-8')
|
|
||||||
if not isinstance(video, bytes):
|
|
||||||
video = video.encode('utf-8')
|
|
||||||
media_path = os.path.relpath(media_path, os.path.dirname(video))
|
|
||||||
os.symlink(media_path, video)
|
|
||||||
size = v.media.size
|
|
||||||
duration = v.duration
|
|
||||||
else:
|
|
||||||
url = "%s/torrent/" % self.get_absolute_url()
|
|
||||||
part = 1
|
|
||||||
ox.makedirs(base)
|
|
||||||
for v in streams:
|
|
||||||
media_path = v.media.path
|
|
||||||
extension = media_path.split('.')[-1]
|
|
||||||
video = "%s/%s.Part %d.%s" % (base, filename, part, extension)
|
|
||||||
part += 1
|
|
||||||
if not isinstance(media_path, bytes):
|
|
||||||
media_path = media_path.encode('utf-8')
|
|
||||||
if not isinstance(video, bytes):
|
|
||||||
video = video.encode('utf-8')
|
|
||||||
media_path = os.path.relpath(media_path, os.path.dirname(video))
|
|
||||||
os.symlink(media_path, video)
|
|
||||||
size += v.media.size
|
|
||||||
duration += v.duration
|
|
||||||
video = base
|
|
||||||
|
|
||||||
torrent = '%s.torrent' % base
|
|
||||||
url = "http://%s%s" % (settings.CONFIG['site']['url'], url)
|
|
||||||
meta = {
|
|
||||||
'filesystem_encoding': 'utf-8',
|
|
||||||
'target': torrent,
|
|
||||||
'url-list': url,
|
|
||||||
}
|
|
||||||
if duration:
|
|
||||||
meta['playtime'] = ox.format_duration(duration*1000)[:-4]
|
|
||||||
|
|
||||||
# slightly bigger torrent file but better for streaming
|
|
||||||
piece_size_pow2 = 15 # 1 mbps -> 32KB pieces
|
|
||||||
if size / duration >= 1000000:
|
|
||||||
piece_size_pow2 = 16 # 2 mbps -> 64KB pieces
|
|
||||||
meta['piece_size_pow2'] = piece_size_pow2
|
|
||||||
|
|
||||||
ox.torrent.create_torrent(video, settings.TRACKER_URL, meta)
|
|
||||||
self.torrent.name = torrent[len(settings.MEDIA_ROOT)+1:]
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def audio_tracks(self):
|
def audio_tracks(self):
|
||||||
tracks = [f['language']
|
tracks = [f['language']
|
||||||
for f in self.files.filter(selected=True).filter(Q(is_video=True) | Q(is_audio=True)).values('language')
|
for f in self.files.filter(selected=True).filter(Q(is_video=True) | Q(is_audio=True)).values('language')
|
||||||
|
@ -1440,7 +1352,6 @@ class Item(models.Model):
|
||||||
self.select_frame()
|
self.select_frame()
|
||||||
self.make_poster()
|
self.make_poster()
|
||||||
self.make_icon()
|
self.make_icon()
|
||||||
self.make_torrent()
|
|
||||||
self.rendered = streams.count() > 0
|
self.rendered = streams.count() > 0
|
||||||
self.save()
|
self.save()
|
||||||
if self.rendered:
|
if self.rendered:
|
||||||
|
|
|
@ -24,10 +24,6 @@ urls = [
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', views.video),
|
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', views.video),
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<track>.+)\.(?P<format>webm|ogv|mp4)$', views.video),
|
re_path(r'^(?P<id>[A-Z0-9].*)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<track>.+)\.(?P<format>webm|ogv|mp4)$', views.video),
|
||||||
|
|
||||||
#torrent
|
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/torrent$', views.torrent),
|
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/torrent/(?P<filename>.*?)$', views.torrent),
|
|
||||||
|
|
||||||
#export
|
#export
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/json$', views.item_json),
|
re_path(r'^(?P<id>[A-Z0-9].*)/json$', views.item_json),
|
||||||
re_path(r'^(?P<id>[A-Z0-9].*)/xml$', views.item_xml),
|
re_path(r'^(?P<id>[A-Z0-9].*)/xml$', views.item_xml),
|
||||||
|
|
|
@ -1046,27 +1046,6 @@ def download(request, id, resolution=None, format='webm', part=None):
|
||||||
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % quote(filename.encode('utf-8'))
|
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % quote(filename.encode('utf-8'))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def torrent(request, id, filename=None):
|
|
||||||
item = get_object_or_404(models.Item, public_id=id)
|
|
||||||
if not item.access(request.user):
|
|
||||||
return HttpResponseForbidden()
|
|
||||||
if not item.torrent:
|
|
||||||
raise Http404
|
|
||||||
if not filename or filename.endswith('.torrent'):
|
|
||||||
response = HttpResponse(item.get_torrent(request),
|
|
||||||
content_type='application/x-bittorrent')
|
|
||||||
filename = utils.safe_filename("%s.torrent" % item.get('title'))
|
|
||||||
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % quote(filename.encode('utf-8'))
|
|
||||||
return response
|
|
||||||
while filename.startswith('/'):
|
|
||||||
filename = filename[1:]
|
|
||||||
filename = filename.replace('/../', '/')
|
|
||||||
filename = item.path('torrent/%s' % filename)
|
|
||||||
filename = os.path.abspath(os.path.join(settings.MEDIA_ROOT, filename))
|
|
||||||
response = HttpFileResponse(filename)
|
|
||||||
response['Content-Disposition'] = "attachment; filename*=UTF-8''%s" % \
|
|
||||||
quote(os.path.basename(filename.encode('utf-8')))
|
|
||||||
return response
|
|
||||||
|
|
||||||
def video(request, id, resolution, format, index=None, track=None):
|
def video(request, id, resolution, format, index=None, track=None):
|
||||||
resolution = int(resolution)
|
resolution = int(resolution)
|
||||||
|
@ -1288,12 +1267,6 @@ def atom_xml(request):
|
||||||
el.text = "1:1"
|
el.text = "1:1"
|
||||||
|
|
||||||
if has_capability(request.user, 'canDownloadVideo'):
|
if has_capability(request.user, 'canDownloadVideo'):
|
||||||
if item.torrent:
|
|
||||||
el = ET.SubElement(entry, "link")
|
|
||||||
el.attrib['rel'] = 'enclosure'
|
|
||||||
el.attrib['type'] = 'application/x-bittorrent'
|
|
||||||
el.attrib['href'] = '%s/torrent/' % page_link
|
|
||||||
el.attrib['length'] = '%s' % ox.get_torrent_size(item.torrent.path)
|
|
||||||
# FIXME: loop over streams
|
# FIXME: loop over streams
|
||||||
# for s in item.streams().filter(resolution=max(settings.CONFIG['video']['resolutions'])):
|
# for s in item.streams().filter(resolution=max(settings.CONFIG['video']['resolutions'])):
|
||||||
for s in item.streams().filter(source=None):
|
for s in item.streams().filter(source=None):
|
||||||
|
|
|
@ -232,9 +232,6 @@ XACCELREDIRECT = False
|
||||||
SITE_CONFIG = join(PROJECT_ROOT, 'config.jsonc')
|
SITE_CONFIG = join(PROJECT_ROOT, 'config.jsonc')
|
||||||
DEFAULT_CONFIG = join(PROJECT_ROOT, 'config.pandora.jsonc')
|
DEFAULT_CONFIG = join(PROJECT_ROOT, 'config.pandora.jsonc')
|
||||||
|
|
||||||
#used if CONFIG['canDownloadVideo'] is set
|
|
||||||
TRACKER_URL = "udp://tracker.openbittorrent.com:80"
|
|
||||||
|
|
||||||
DATA_SERVICE = ''
|
DATA_SERVICE = ''
|
||||||
POSTER_PRECEDENCE = ()
|
POSTER_PRECEDENCE = ()
|
||||||
POSTER_ONLY_PORTRAIT = ()
|
POSTER_ONLY_PORTRAIT = ()
|
||||||
|
|
|
@ -895,7 +895,12 @@ pandora.ui.infoView = function(data, isMixed) {
|
||||||
} else if (capability.name == 'canPlayVideo') {
|
} else if (capability.name == 'canPlayVideo') {
|
||||||
pandora.UI.set({itemView: ui.videoView});
|
pandora.UI.set({itemView: ui.videoView});
|
||||||
} else if (capability.name == 'canDownloadVideo') {
|
} else if (capability.name == 'canDownloadVideo') {
|
||||||
document.location.href = '/' + ui.item + '/torrent/';
|
pandora.ui.downloadVideoDialog({
|
||||||
|
item: ui.item,
|
||||||
|
rightsLevel: data.rightsLevel,
|
||||||
|
title: data.title,
|
||||||
|
video: data.video
|
||||||
|
}).open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1399,14 +1399,8 @@ pandora.getCurrentFrameAnnotation = function(data) {
|
||||||
}());
|
}());
|
||||||
|
|
||||||
pandora.getDownloadLink = function(item, rightslevel) {
|
pandora.getDownloadLink = function(item, rightslevel) {
|
||||||
var torrent = pandora.site.video.torrent,
|
var url = '/' + item + '/download/';
|
||||||
url;
|
if (pandora.site.video.downloadFormat) {
|
||||||
if (arguments.length == 2 && torrent &&
|
|
||||||
pandora.hasCapability('canSeeItem', 'guest') < rightslevel) {
|
|
||||||
torrent = false;
|
|
||||||
}
|
|
||||||
url = '/' + item + (torrent ? '/torrent/' : '/download/');
|
|
||||||
if (!torrent && pandora.site.video.downloadFormat) {
|
|
||||||
url += Ox.max(pandora.site.video.resolutions) + 'p.' + pandora.site.video.downloadFormat;
|
url += Ox.max(pandora.site.video.resolutions) + 'p.' + pandora.site.video.downloadFormat;
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
|
Loading…
Reference in a new issue