forked from 0x2620/pandora
download parts and source
This commit is contained in:
parent
6af2a1cbe6
commit
ae2e3e45c6
10 changed files with 82 additions and 15 deletions
|
@ -38,6 +38,7 @@
|
||||||
"canAddItems": {"staff": true, "admin": true},
|
"canAddItems": {"staff": true, "admin": true},
|
||||||
"canAddDocuments": {"staff": true, "admin": true},
|
"canAddDocuments": {"staff": true, "admin": true},
|
||||||
"canDownloadVideo": {"guest": -1, "member": -1, "friend": -1, "staff": -1, "admin": -1},
|
"canDownloadVideo": {"guest": -1, "member": -1, "friend": -1, "staff": -1, "admin": -1},
|
||||||
|
"canDownloadSource": {"guest": -1, "member": -1, "friend": -1, "staff": -1, "admin": -1},
|
||||||
"canEditAnnotations": {"staff": true, "admin": true},
|
"canEditAnnotations": {"staff": true, "admin": true},
|
||||||
"canEditEntities": {"staff": true, "admin": true},
|
"canEditEntities": {"staff": true, "admin": true},
|
||||||
"canEditDocuments": {"staff": true, "admin": true},
|
"canEditDocuments": {"staff": true, "admin": true},
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"canAddItems": {"researcher": true, "staff": true, "admin": true},
|
"canAddItems": {"researcher": true, "staff": true, "admin": true},
|
||||||
"canAddDocuments": {"researcher": true, "staff": true, "admin": true},
|
"canAddDocuments": {"researcher": true, "staff": true, "admin": true},
|
||||||
"canDownloadVideo": {"guest": -1, "member": -1, "researcher": 3, "staff": 3, "admin": 3},
|
"canDownloadVideo": {"guest": -1, "member": -1, "researcher": 3, "staff": 3, "admin": 3},
|
||||||
|
"canDownloadSource": {"guest": -1, "member": -1, "researcher": -1, "staff": -1, "admin": -1},
|
||||||
"canEditAnnotations": {"staff": true, "admin": true},
|
"canEditAnnotations": {"staff": true, "admin": true},
|
||||||
"canEditDocuments": {"researcher": true, "staff": true, "admin": true},
|
"canEditDocuments": {"researcher": true, "staff": true, "admin": true},
|
||||||
"canEditEntities": {"staff": true, "admin": true},
|
"canEditEntities": {"staff": true, "admin": true},
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"canAddItems": {"member": true, "staff": true, "admin": true},
|
"canAddItems": {"member": true, "staff": true, "admin": true},
|
||||||
"canAddDocuments": {"member": true, "staff": true, "admin": true},
|
"canAddDocuments": {"member": true, "staff": true, "admin": true},
|
||||||
"canDownloadVideo": {"guest": 0, "member": 0, "staff": 4, "admin": 4},
|
"canDownloadVideo": {"guest": 0, "member": 0, "staff": 4, "admin": 4},
|
||||||
|
"canDownloadSource": {"guest": -1, "member": -1, "staff": 4, "admin": 4},
|
||||||
"canEditAnnotations": {"staff": true, "admin": true},
|
"canEditAnnotations": {"staff": true, "admin": true},
|
||||||
"canEditEntities": {"staff": true, "admin": true},
|
"canEditEntities": {"staff": true, "admin": true},
|
||||||
"canEditDocuments": {"staff": true, "admin": true},
|
"canEditDocuments": {"staff": true, "admin": true},
|
||||||
|
|
|
@ -45,6 +45,7 @@ examples (config.SITENAME.jsonc) that are part of this pan.do/ra distribution.
|
||||||
"canAddItems": {"member": true, "staff": true, "admin": true},
|
"canAddItems": {"member": true, "staff": true, "admin": true},
|
||||||
"canAddDocuments": {"member": true, "staff": true, "admin": true},
|
"canAddDocuments": {"member": true, "staff": true, "admin": true},
|
||||||
"canDownloadVideo": {"guest": 1, "member": 1, "staff": 4, "admin": 4},
|
"canDownloadVideo": {"guest": 1, "member": 1, "staff": 4, "admin": 4},
|
||||||
|
"canDownloadSource": {"member": 1, "staff": 4, "admin": 4},
|
||||||
"canEditAnnotations": {"staff": true, "admin": true},
|
"canEditAnnotations": {"staff": true, "admin": true},
|
||||||
"canEditDocuments": {"staff": true, "admin": true},
|
"canEditDocuments": {"staff": true, "admin": true},
|
||||||
"canEditEntities": {"staff": true, "admin": true},
|
"canEditEntities": {"staff": true, "admin": true},
|
||||||
|
|
|
@ -639,6 +639,9 @@ class Item(models.Model):
|
||||||
if self.poster_height:
|
if self.poster_height:
|
||||||
i['posterRatio'] = self.poster_width / self.poster_height
|
i['posterRatio'] = self.poster_width / self.poster_height
|
||||||
|
|
||||||
|
if 'source' in keys:
|
||||||
|
i['source'] = self.files.filter(selected=True).exclude(data='').exists()
|
||||||
|
|
||||||
streams = self.streams()
|
streams = self.streams()
|
||||||
i['durations'] = [s.duration for s in streams]
|
i['durations'] = [s.duration for s in streams]
|
||||||
i['duration'] = sum(i['durations'])
|
i['duration'] = sum(i['durations'])
|
||||||
|
|
|
@ -16,6 +16,7 @@ urlpatterns = [
|
||||||
url(r'^(?P<id>[A-Z0-9].*)/download$', views.download),
|
url(r'^(?P<id>[A-Z0-9].*)/download$', views.download),
|
||||||
url(r'^(?P<id>[A-Z0-9].*)/download/$', views.download),
|
url(r'^(?P<id>[A-Z0-9].*)/download/$', views.download),
|
||||||
url(r'^(?P<id>[A-Z0-9].*)/download/source/(?P<part>\d+)?$', views.download_source),
|
url(r'^(?P<id>[A-Z0-9].*)/download/source/(?P<part>\d+)?$', views.download_source),
|
||||||
|
url(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p(?P<part>\d+)\.(?P<format>webm|ogv|mp4)$', views.download),
|
||||||
url(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p\.(?P<format>webm|ogv|mp4)$', views.download),
|
url(r'^(?P<id>[A-Z0-9].*)/download/(?P<resolution>\d+)p\.(?P<format>webm|ogv|mp4)$', views.download),
|
||||||
|
|
||||||
#video
|
#video
|
||||||
|
|
|
@ -992,6 +992,8 @@ def download_source(request, id, part=None):
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
parts = ['%s - %s ' % (item.get('title'), settings.SITENAME), item.public_id]
|
parts = ['%s - %s ' % (item.get('title'), settings.SITENAME), item.public_id]
|
||||||
|
if len(streams) > 1:
|
||||||
|
parts.append('.Part %d' % (part + 1))
|
||||||
parts.append('.')
|
parts.append('.')
|
||||||
parts.append(f.extension)
|
parts.append(f.extension)
|
||||||
filename = ''.join(parts)
|
filename = ''.join(parts)
|
||||||
|
@ -1002,7 +1004,7 @@ def download_source(request, id, 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 download(request, id, resolution=None, format='webm'):
|
def download(request, id, resolution=None, format='webm', part=None):
|
||||||
item = get_object_or_404(models.Item, public_id=id)
|
item = get_object_or_404(models.Item, public_id=id)
|
||||||
if not resolution or int(resolution) not in settings.CONFIG['video']['resolutions']:
|
if not resolution or int(resolution) not in settings.CONFIG['video']['resolutions']:
|
||||||
resolution = max(settings.CONFIG['video']['resolutions'])
|
resolution = max(settings.CONFIG['video']['resolutions'])
|
||||||
|
@ -1010,14 +1012,22 @@ def download(request, id, resolution=None, format='webm'):
|
||||||
resolution = int(resolution)
|
resolution = int(resolution)
|
||||||
if not item.access(request.user) or not item.rendered:
|
if not item.access(request.user) or not item.rendered:
|
||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
if part is not None:
|
||||||
|
part = int(part) - 1
|
||||||
|
streams = item.streams()
|
||||||
|
if part > len(streams):
|
||||||
|
raise Http404
|
||||||
ext = '.%s' % format
|
ext = '.%s' % format
|
||||||
parts = ['%s - %s ' % (item.get('title'), settings.SITENAME), item.public_id]
|
parts = ['%s - %s ' % (item.get('title'), settings.SITENAME), item.public_id]
|
||||||
if resolution != max(settings.CONFIG['video']['resolutions']):
|
if resolution != max(settings.CONFIG['video']['resolutions']):
|
||||||
parts.append('.%dp' % resolution)
|
parts.append('.%dp' % resolution)
|
||||||
|
if part is not None:
|
||||||
|
parts.append('.Part %d' % (part + 1))
|
||||||
parts.append(ext)
|
parts.append(ext)
|
||||||
filename = ''.join(parts)
|
filename = ''.join(parts)
|
||||||
video = NamedTemporaryFile(suffix=ext)
|
video = NamedTemporaryFile(suffix=ext)
|
||||||
content_type = mimetypes.guess_type(video.name)[0]
|
content_type = mimetypes.guess_type(video.name)[0]
|
||||||
|
if part is None:
|
||||||
r = item.merge_streams(video.name, resolution, format)
|
r = item.merge_streams(video.name, resolution, format)
|
||||||
if not r:
|
if not r:
|
||||||
return HttpResponseForbidden()
|
return HttpResponseForbidden()
|
||||||
|
@ -1026,6 +1036,11 @@ def download(request, id, resolution=None, format='webm'):
|
||||||
response['Content-Length'] = os.path.getsize(video.name)
|
response['Content-Length'] = os.path.getsize(video.name)
|
||||||
else:
|
else:
|
||||||
response = HttpFileResponse(r, content_type=content_type)
|
response = HttpFileResponse(r, content_type=content_type)
|
||||||
|
else:
|
||||||
|
stream = streams[part].get(resolution, format)
|
||||||
|
path = stream.media.path
|
||||||
|
content_type = mimetypes.guess_type(path)[0]
|
||||||
|
response = HttpFileResponse(path, content_type=content_type)
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
'mp4': 'MP4',
|
'mp4': 'MP4',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
parts = Ox.max(options.video.map(function(video) {
|
||||||
|
return video.index
|
||||||
|
})),
|
||||||
|
|
||||||
$content = Ox.Element()
|
$content = Ox.Element()
|
||||||
.css({margin: '16px'}),
|
.css({margin: '16px'}),
|
||||||
|
|
||||||
|
@ -27,6 +31,9 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
.css({marginBottom: '16px'})
|
.css({marginBottom: '16px'})
|
||||||
.appendTo($content),
|
.appendTo($content),
|
||||||
|
|
||||||
|
$format,
|
||||||
|
$resolution,
|
||||||
|
|
||||||
$form = window.$form = Ox.Form({
|
$form = window.$form = Ox.Form({
|
||||||
items: [
|
items: [
|
||||||
Ox.Select({
|
Ox.Select({
|
||||||
|
@ -36,7 +43,10 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
id: format,
|
id: format,
|
||||||
title: formats[format]
|
title: formats[format]
|
||||||
};
|
};
|
||||||
}),
|
}).concat(!options.out && options.source ? [{
|
||||||
|
id: 'source',
|
||||||
|
title: Ox._('Source')
|
||||||
|
}] : []),
|
||||||
label: Ox._('Format'),
|
label: Ox._('Format'),
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
value: pandora.site.video.downloadFormat,
|
value: pandora.site.video.downloadFormat,
|
||||||
|
@ -44,9 +54,14 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
})
|
})
|
||||||
.bindEvent({
|
.bindEvent({
|
||||||
change: function(data) {
|
change: function(data) {
|
||||||
|
if (data.value == 'source') {
|
||||||
|
$resolution.hide()
|
||||||
|
} else {
|
||||||
|
$resolution.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Ox.Select({
|
$resolution = Ox.Select({
|
||||||
id: 'resolution',
|
id: 'resolution',
|
||||||
items: pandora.site.video.resolutions.map(function(resolution) {
|
items: pandora.site.video.resolutions.map(function(resolution) {
|
||||||
return {
|
return {
|
||||||
|
@ -63,7 +78,25 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
change: function(data) {
|
change: function(data) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]
|
].concat(parts ? [
|
||||||
|
Ox.Select({
|
||||||
|
id: 'part',
|
||||||
|
items: Ox.range(parts + 1).map(function(resolution, idx) {
|
||||||
|
return {
|
||||||
|
id: idx + 1,
|
||||||
|
title: 'Part ' + (idx+1)
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
label: Ox._('Part'),
|
||||||
|
labelWidth: 120,
|
||||||
|
value: 1,
|
||||||
|
width: 240
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
change: function(data) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
] : [])
|
||||||
}).appendTo($content),
|
}).appendTo($content),
|
||||||
|
|
||||||
failed = false,
|
failed = false,
|
||||||
|
@ -115,10 +148,18 @@ pandora.ui.downloadVideoDialog = function(options) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (values.format == 'source') {
|
||||||
|
url = '/' + options.item
|
||||||
|
+ '/download/source/'
|
||||||
|
+ (values.part ? values.part : '')
|
||||||
} else {
|
} else {
|
||||||
url = '/' + options.item
|
url = '/' + options.item
|
||||||
+ '/download/' + values.resolution
|
+ '/download/' + values.resolution
|
||||||
+ 'p.' + values.format
|
+ 'p'
|
||||||
|
+ (values.part ? values.part : '')
|
||||||
|
+ '.' + values.format
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (url) {
|
if (url) {
|
||||||
that.close();
|
that.close();
|
||||||
|
|
|
@ -189,7 +189,9 @@ pandora.ui.editor = function(data) {
|
||||||
pandora.ui.downloadVideoDialog({
|
pandora.ui.downloadVideoDialog({
|
||||||
item: ui.item,
|
item: ui.item,
|
||||||
rightsLevel: rightsLevel,
|
rightsLevel: rightsLevel,
|
||||||
title: data.title
|
source: data.source && pandora.hasCapability('canDownloadSource'),
|
||||||
|
title: data.title,
|
||||||
|
video: data.video
|
||||||
}).open();
|
}).open();
|
||||||
},
|
},
|
||||||
downloadselection: function(selection) {
|
downloadselection: function(selection) {
|
||||||
|
|
|
@ -2359,6 +2359,7 @@ pandora.VIDEO_OPTIONS_KEYS = [
|
||||||
'rendered',
|
'rendered',
|
||||||
'rightslevel',
|
'rightslevel',
|
||||||
'size',
|
'size',
|
||||||
|
'source',
|
||||||
'streams',
|
'streams',
|
||||||
'title',
|
'title',
|
||||||
'videoRatio'
|
'videoRatio'
|
||||||
|
|
Loading…
Reference in a new issue