From 4884ae0503e67d0b268ffe1d4ab3e00acc424528 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 20 Oct 2011 18:15:59 +0200 Subject: [PATCH 01/13] clips --- pandora/annotation/models.py | 8 +------- pandora/clip/models.py | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index 90573746..0695f2aa 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -118,13 +118,7 @@ class Annotation(models.Model): if not self.clip and not self.layer.private or \ (self.clip and not self.layer.private and \ self.start != self.clip.start or self.end != self.clip.end): - - self.clip, created = Clip.objects.get_or_create(item=self.item, - start=self.start, - end=self.end) - if created: - clip = Clip.objects.get(pk=self.clip.pk) - clip.save() + self.clip, created = Clip.get_or_create(self.item, self.start, self.end) super(Annotation, self).save(*args, **kwargs) diff --git a/pandora/clip/models.py b/pandora/clip/models.py index 651982b1..41f1430b 100644 --- a/pandora/clip/models.py +++ b/pandora/clip/models.py @@ -8,6 +8,7 @@ from django.conf import settings from archive import extract import managers + class Clip(models.Model): ''' CREATE INDEX clip_clip_title_idx ON clip_clip (title ASC NULLS LAST); @@ -20,7 +21,7 @@ class Clip(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) - public_id = models.CharField(max_length=128, unique=True, null=True) + public_id = models.CharField(max_length=128, unique=True) item = models.ForeignKey('item.Item', related_name='clips') @@ -90,6 +91,19 @@ class Clip(models.Model): j[key] = self.item.get(key) return j - def __unicode__(self): - return u"%s/%s-%s" %(self.item, self.start, self.end) + @classmethod + def get_or_create(cls, item, start, end): + public_id = u"%s/%s-%s" %(item.itemId, start, end) + qs = cls.objects.filter(public_id=public_id) + if qs.count() == 0: + clip = Clip(item=item, start=start, end=end, public_id=public_id) + clips.save() + created = True + else: + clip = qs[0] + created = False + return clip, created + + def __unicode__(self): + return self.public_id From 95ce013aa46d725e2acd51bbe2e94aef55948e3e Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 20 Oct 2011 21:32:12 +0200 Subject: [PATCH 02/13] less requests --- static/js/pandora/ui/item.js | 345 +++++++++++++++++------------------ 1 file changed, 171 insertions(+), 174 deletions(-) diff --git a/static/js/pandora/ui/item.js b/static/js/pandora/ui/item.js index efb0078b..a5ed11fe 100644 --- a/static/js/pandora/ui/item.js +++ b/static/js/pandora/ui/item.js @@ -6,7 +6,8 @@ pandora.ui.item = function() { pandora.api.get({ id: pandora.user.ui.item, - keys: [] + keys: ['video', 'timeline'].indexOf(pandora.user.ui.itemView)>-1 ? + ['rendered', 'cuts', 'videoRatio', 'duration', 'layers', 'parts', 'size'] : [] }, pandora.user.level == 'admin' && pandora.user.ui.itemView == 'info' ? 0 : -1, function(result) { if (result.status.code == 200) { @@ -102,190 +103,186 @@ pandora.ui.item = function() { ); } else if (pandora.user.ui.itemView == 'video') { - pandora.api.get({id: pandora.user.ui.item, keys: ['layers']}, function(r) { - // fixme: duplicated - var clipsQuery = pandora.getClipsQuery(), - isClipsQuery = !!clipsQuery.conditions.length, - layers = [], - video = {}; - pandora.site.layers.forEach(function(layer, i) { - layers[i] = Ox.extend({}, layer, {items: r.data.layers[layer.id]}); - }); - pandora.site.video.resolutions.forEach(function(resolution) { - video[resolution] = Ox.range(result.data.parts).map(function(i) { - return '/' + pandora.user.ui.item + '/' - + resolution + 'p' + (i + 1) + '.' + pandora.user.videoFormat; - }); - }); - // - pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.player = Ox.VideoPanelPlayer({ - annotationsSize: pandora.user.ui.annotationsSize, - cuts: result.data.cuts || [], - duration: result.data.duration, - find: isClipsQuery ? clipsQuery.conditions[0].value : '', - getTimelineImageURL: function(i) { - return '/' + pandora.user.ui.item + '/timeline64p' + i + '.png'; - }, - height: pandora.$ui.contentPanel.size(1), - 'in': pandora.user.ui.videoPoints[pandora.user.ui.item]['in'], - muted: pandora.user.ui.videoMuted, - out: pandora.user.ui.videoPoints[pandora.user.ui.item].out, - position: pandora.user.ui.videoPoints[pandora.user.ui.item].position, - scaleToFill: pandora.user.ui.videoScale == 'fill', - showAnnotations: pandora.user.ui.showAnnotations, - showControls: pandora.user.ui.showControls, - subtitles: r.data.layers.subtitles ? - r.data.layers.subtitles.map(function(subtitle) { - return {'in': subtitle['in'], out: subtitle.out, text: subtitle.value}; - }) : [], - tooltips: true, - timeline: '/' + pandora.user.ui.item + '/timeline16p.png', - video: video, - volume: pandora.user.ui.videoVolume, - width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 - }).bindEvent({ - muted: function(data) { - pandora.UI.set('muted', data.muted); - }, - position: function(data) { - pandora.UI.set('videoPoints.' + pandora.user.ui.item + '.position', data.position); - }, - resizeannotations: function(data) { - pandora.UI.set('annotationsSize', data.annotationsSize); - }, - scale: function(data) { - pandora.UI.set('videoScale', data.scale); - }, - toggleannotations: function(data) { - pandora.UI.set('showAnnotations', data.showAnnotations); - }, - togglecontrols: function(data) { - pandora.UI.set('showControls', data.showControls); - }, - volume: function(data) { - pandora.UI.set('volume', data.volume); - }, - pandora_showannotations: function(data) { - pandora.$ui.player.options({showAnnotations: data.value}); - } - })); + // fixme: duplicated + var clipsQuery = pandora.getClipsQuery(), + isClipsQuery = !!clipsQuery.conditions.length, + layers = [], + video = {}; + pandora.site.layers.forEach(function(layer, i) { + layers[i] = Ox.extend({}, layer, {items: result.data.layers[layer.id]}); }); + pandora.site.video.resolutions.forEach(function(resolution) { + video[resolution] = Ox.range(result.data.parts).map(function(i) { + return '/' + pandora.user.ui.item + '/' + + resolution + 'p' + (i + 1) + '.' + pandora.user.videoFormat; + }); + }); + // + pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.player = Ox.VideoPanelPlayer({ + annotationsSize: pandora.user.ui.annotationsSize, + cuts: result.data.cuts || [], + duration: result.data.duration, + find: isClipsQuery ? clipsQuery.conditions[0].value : '', + getTimelineImageURL: function(i) { + return '/' + pandora.user.ui.item + '/timeline64p' + i + '.png'; + }, + height: pandora.$ui.contentPanel.size(1), + 'in': pandora.user.ui.videoPoints[pandora.user.ui.item]['in'], + muted: pandora.user.ui.videoMuted, + out: pandora.user.ui.videoPoints[pandora.user.ui.item].out, + position: pandora.user.ui.videoPoints[pandora.user.ui.item].position, + scaleToFill: pandora.user.ui.videoScale == 'fill', + showAnnotations: pandora.user.ui.showAnnotations, + showControls: pandora.user.ui.showControls, + subtitles: result.data.layers.subtitles ? + result.data.layers.subtitles.map(function(subtitle) { + return {'in': subtitle['in'], out: subtitle.out, text: subtitle.value}; + }) : [], + tooltips: true, + timeline: '/' + pandora.user.ui.item + '/timeline16p.png', + video: video, + volume: pandora.user.ui.videoVolume, + width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 + }).bindEvent({ + muted: function(data) { + pandora.UI.set('muted', data.muted); + }, + position: function(data) { + pandora.UI.set('videoPoints.' + pandora.user.ui.item + '.position', data.position); + }, + resizeannotations: function(data) { + pandora.UI.set('annotationsSize', data.annotationsSize); + }, + scale: function(data) { + pandora.UI.set('videoScale', data.scale); + }, + toggleannotations: function(data) { + pandora.UI.set('showAnnotations', data.showAnnotations); + }, + togglecontrols: function(data) { + pandora.UI.set('showControls', data.showControls); + }, + volume: function(data) { + pandora.UI.set('volume', data.volume); + }, + pandora_showannotations: function(data) { + pandora.$ui.player.options({showAnnotations: data.value}); + } + })); } else if (pandora.user.ui.itemView == 'timeline') { - pandora.api.get({id: pandora.user.ui.item, keys: ['layers']}, function(r) { - var clipsQuery = pandora.getClipsQuery(), - isClipsQuery = !!clipsQuery.conditions.length, - layers = [], - video = {}; - pandora.site.layers.forEach(function(layer) { - layers.push(Ox.extend({items: r.data.layers[layer.id]}, layer)); + var clipsQuery = pandora.getClipsQuery(), + isClipsQuery = !!clipsQuery.conditions.length, + layers = [], + video = {}; + pandora.site.layers.forEach(function(layer) { + layers.push(Ox.extend({items: result.data.layers[layer.id]}, layer)); + }); + pandora.site.video.resolutions.forEach(function(resolution) { + video[resolution] = Ox.range(result.data.parts).map(function(i) { + return '/' + pandora.user.ui.item + '/' + + resolution + 'p' + (i + 1) + '.' + pandora.user.videoFormat; }); - pandora.site.video.resolutions.forEach(function(resolution) { - video[resolution] = Ox.range(result.data.parts).map(function(i) { - return '/' + pandora.user.ui.item + '/' - + resolution + 'p' + (i + 1) + '.' + pandora.user.videoFormat; + }); + pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.editor = Ox.VideoEditor({ + annotationsSize: pandora.user.ui.annotationsSize, + cuts: result.data.cuts || [], + duration: result.data.duration, + find: isClipsQuery ? clipsQuery.conditions[0].value : '', + getFrameURL: function(position) { + return '/' + pandora.user.ui.item + '/' + Ox.last(pandora.site.video.resolutions) + 'p' + position + '.jpg'; + }, + getLargeTimelineImageURL: function(i) { + return '/' + pandora.user.ui.item + '/timeline64p' + i + '.png'; + }, + getSmallTimelineImageURL: function(i) { + return '/' + pandora.user.ui.item + '/timeline16p' + i + '.png'; + }, + height: pandora.$ui.contentPanel.size(1), + id: 'editor', + 'in': pandora.user.ui.videoPoints[pandora.user.ui.item]['in'], + layers: layers, + muted: pandora.user.ui.videoMuted, + out: pandora.user.ui.videoPoints[pandora.user.ui.item].out, + position: pandora.user.ui.videoPoints[pandora.user.ui.item].position, + posterFrame: parseInt(video.duration / 2), + showAnnotations: pandora.user.ui.showAnnotations, + showLargeTimeline: true, + // fixme: layers have value, subtitles has text? + subtitles: result.data.layers.subtitles ? + result.data.layers.subtitles.map(function(subtitle) { + return {'in': subtitle['in'], out: subtitle.out, text: subtitle.value}; + }) : [], + tooltips: true, + video: video, + videoRatio: result.data.videoRatio, + videoSize: pandora.user.ui.videoSize, + width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 + }).bindEvent({ + points: function(data) { + pandora.UI.set('videoPoints.' + pandora.user.ui.item, { + 'in': data['in'], + out: data.out, + position: pandora.user.ui.videoPoints[pandora.user.ui.item].position }); - }); - pandora.$ui.contentPanel.replaceElement(1, pandora.$ui.editor = Ox.VideoEditor({ - annotationsSize: pandora.user.ui.annotationsSize, - cuts: result.data.cuts || [], - duration: result.data.duration, - find: isClipsQuery ? clipsQuery.conditions[0].value : '', - getFrameURL: function(position) { - return '/' + pandora.user.ui.item + '/' + Ox.last(pandora.site.video.resolutions) + 'p' + position + '.jpg'; - }, - getLargeTimelineImageURL: function(i) { - return '/' + pandora.user.ui.item + '/timeline64p' + i + '.png'; - }, - getSmallTimelineImageURL: function(i) { - return '/' + pandora.user.ui.item + '/timeline16p' + i + '.png'; - }, - height: pandora.$ui.contentPanel.size(1), - id: 'editor', - 'in': pandora.user.ui.videoPoints[pandora.user.ui.item]['in'], - layers: layers, - muted: pandora.user.ui.videoMuted, - out: pandora.user.ui.videoPoints[pandora.user.ui.item].out, - position: pandora.user.ui.videoPoints[pandora.user.ui.item].position, - posterFrame: parseInt(video.duration / 2), - showAnnotations: pandora.user.ui.showAnnotations, - showLargeTimeline: true, - // fixme: layers have value, subtitles has text? - subtitles: r.data.layers.subtitles ? - r.data.layers.subtitles.map(function(subtitle) { - return {'in': subtitle['in'], out: subtitle.out, text: subtitle.value}; - }) : [], - tooltips: true, - video: video, - videoRatio: result.data.videoRatio, - videoSize: pandora.user.ui.videoSize, - width: pandora.$ui.document.width() - pandora.$ui.mainPanel.size(0) - 1 - }).bindEvent({ - points: function(data) { - pandora.UI.set('videoPoints.' + pandora.user.ui.item, { - 'in': data['in'], - out: data.out, - position: pandora.user.ui.videoPoints[pandora.user.ui.item].position - }); - }, - position: function(data) { - pandora.UI.set('videoPoints.' + pandora.user.ui.item + '.position', data.position); - }, - resize: function(data) { - Ox.print('RESIZE!!', data.size) - pandora.$ui.editor.options({ - height: data.size - }); - }, - resizeend: function(data) { - pandora.UI.set({annotationsSize: data.size}); - }, - togglesize: function(data) { - pandora.UI.set({videoSize: data.size}); - }, - addannotation: function(data) { - Ox.print('addAnnotation', data); - data.item = pandora.user.ui.item; - data.value = 'Click to edit'; - pandora.api.addAnnotation(data, function(result) { - pandora.$ui.editor.addAnnotation(data.layer, result.data); - }); - }, - removeannotations: function(data) { - pandora.api.removeAnnotations(data, function(result) { - //fixme: check for errors - pandora.$ui.editor.removeAnnotations(data.layer, data.ids); - }); - }, - toggleannotations: function(data) { - pandora.UI.set('showAnnotations', data.showAnnotations); - }, - updateannotation: function(data) { - //fixme: check that edit was successfull - pandora.api.editAnnotation(data, function(result) { - Ox.print('done updateAnnotation', result); - - }); - }, - pandora_showannotations: function(data) { - pandora.$ui.editor.options({showAnnotations: data.value}); - } - })); - that.bindEvent('resize', function(data) { - //Ox.print('resize item', data) + }, + position: function(data) { + pandora.UI.set('videoPoints.' + pandora.user.ui.item + '.position', data.position); + }, + resize: function(data) { + Ox.print('RESIZE!!', data.size) pandora.$ui.editor.options({ height: data.size }); - }); - /* - pandora.$ui.rightPanel.bindEvent('resize', function(data) { - Ox.print('... rightPanel resize', data, pandora.$ui.timelinePanel.size(1)) - pandora.$ui.editor.options({ - width: data - pandora.$ui.timelinePanel.size(1) - 1 + }, + resizeend: function(data) { + pandora.UI.set({annotationsSize: data.size}); + }, + togglesize: function(data) { + pandora.UI.set({videoSize: data.size}); + }, + addannotation: function(data) { + Ox.print('addAnnotation', data); + data.item = pandora.user.ui.item; + data.value = 'Click to edit'; + pandora.api.addAnnotation(data, function(result) { + pandora.$ui.editor.addAnnotation(data.layer, result.data); }); + }, + removeannotations: function(data) { + pandora.api.removeAnnotations(data, function(result) { + //fixme: check for errors + pandora.$ui.editor.removeAnnotations(data.layer, data.ids); + }); + }, + toggleannotations: function(data) { + pandora.UI.set('showAnnotations', data.showAnnotations); + }, + updateannotation: function(data) { + //fixme: check that edit was successfull + pandora.api.editAnnotation(data, function(result) { + Ox.print('done updateAnnotation', result); + + }); + }, + pandora_showannotations: function(data) { + pandora.$ui.editor.options({showAnnotations: data.value}); + } + })); + that.bindEvent('resize', function(data) { + //Ox.print('resize item', data) + pandora.$ui.editor.options({ + height: data.size }); - */ }); + /* + pandora.$ui.rightPanel.bindEvent('resize', function(data) { + Ox.print('... rightPanel resize', data, pandora.$ui.timelinePanel.size(1)) + pandora.$ui.editor.options({ + width: data - pandora.$ui.timelinePanel.size(1) - 1 + }); + }); + */ } else if (pandora.user.ui.itemView == 'map') { pandora.$ui.contentPanel.replaceElement(1, pandora.ui.navigationView('map', result.data.videoRatio)); From a546d07b7346fb8898c6277c8dabbbb5e6d74e90 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 20 Oct 2011 21:32:31 +0200 Subject: [PATCH 03/13] get_or_create clip --- pandora/annotation/models.py | 8 +------- pandora/archive/models.py | 5 +++-- pandora/archive/tasks.py | 22 +++++++++++++++------- pandora/clip/models.py | 24 ++++++++++++++++++++---- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index 90573746..0695f2aa 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -118,13 +118,7 @@ class Annotation(models.Model): if not self.clip and not self.layer.private or \ (self.clip and not self.layer.private and \ self.start != self.clip.start or self.end != self.clip.end): - - self.clip, created = Clip.objects.get_or_create(item=self.item, - start=self.start, - end=self.end) - if created: - clip = Clip.objects.get(pk=self.clip.pk) - clip.save() + self.clip, created = Clip.get_or_create(self.item, self.start, self.end) super(Annotation, self).save(*args, **kwargs) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index f6199e8e..1b951b5b 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -135,8 +135,9 @@ class File(models.Model): self.is_subtitle = False self.type = self.get_type() - info = ox.parse_movie_path(self.path) - self.language = info['language'] + if self.instances.count()>0: + info = ox.parse_movie_path(self.path) + self.language = info['language'] self.part = self.get_part() if self.type not in ('audio', 'video'): diff --git a/pandora/archive/tasks.py b/pandora/archive/tasks.py index f6b53cb1..89b352c7 100644 --- a/pandora/archive/tasks.py +++ b/pandora/archive/tasks.py @@ -3,16 +3,18 @@ from celery.decorators import task import ox -from item.models import get_item from django.conf import settings +from item.models import get_item +import item.tasks + import models _INSTANCE_KEYS = ('mtime', 'path') def get_or_create_item(volume, info, user): - item_info = ox.parse_movie_info(info['path']) + item_info = ox.parse_movie_path(info['path']) return get_item(item_info, user) def get_or_create_file(volume, f, user, item=None): @@ -67,17 +69,23 @@ def update_files(user, volume, files): user = models.User.objects.get(username=user) volume, created = models.Volume.objects.get_or_create(user=user, name=volume) all_files = [] + #ignore extras etc, + #imdb stlye is L/Last, First/Title (Year)/Title.. 4 + #otherwise T/Title (Year)/Title... 3 + folder_depth = settings.USE_IMDB and 4 or 3 for f in files: - #ignore extras etc, - #imdb stlye is L/Last, First/Title (Year)/Title.. 4 - #otherwise T/Title (Year)/Title... 3 - folder_depth = settings.USE_IMDB and 4 or 3 if len(f['path'].split('/')) == folder_depth: all_files.append(f['oshash']) update_or_create_instance(volume, f) #remove deleted files - models.Instance.objects.filter(volume=volume).exclude(file__oshash__in=all_files).delete() + removed = models.Instance.objects.filter(volume=volume).exclude(file__oshash__in=all_files) + ids = [i['itemId'] for i in Item.models.objects.filter( + files__instances__in=removed.filter(selected=True)).distinct().values('itemId')] + removed.delete() + for i in ids: + i = Item.models.objects.get(itemId=i) + i.update_selected() @task(queue="encoding") def process_stream(fileId): diff --git a/pandora/clip/models.py b/pandora/clip/models.py index 651982b1..f5444356 100644 --- a/pandora/clip/models.py +++ b/pandora/clip/models.py @@ -8,6 +8,7 @@ from django.conf import settings from archive import extract import managers + class Clip(models.Model): ''' CREATE INDEX clip_clip_title_idx ON clip_clip (title ASC NULLS LAST); @@ -20,7 +21,7 @@ class Clip(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) - public_id = models.CharField(max_length=128, unique=True, null=True) + public_id = models.CharField(max_length=128, unique=True) item = models.ForeignKey('item.Item', related_name='clips') @@ -52,7 +53,7 @@ class Clip(models.Model): self.title = self.item.sort.title def save(self, *args, **kwargs): - self.public_id = u"%s/%s-%s" %(self.item.itemId, self.start, self.end) + self.public_id = u"%s/%s-%s" %(self.item.itemId, float(self.start), float(self.end)) if self.duration != self.end - self.start: self.update_calculated_values() super(Clip, self).save(*args, **kwargs) @@ -90,6 +91,21 @@ class Clip(models.Model): j[key] = self.item.get(key) return j - def __unicode__(self): - return u"%s/%s-%s" %(self.item, self.start, self.end) + @classmethod + def get_or_create(cls, item, start, end): + start = float(start) + end = float(end) + public_id = u"%s/%s-%s" %(item.itemId, start, end) + qs = cls.objects.filter(public_id=public_id) + if qs.count() == 0: + clip = Clip(item=item, start=start, end=end, public_id=public_id) + clip.save() + created = True + else: + clip = qs[0] + created = False + return clip, created + + def __unicode__(self): + return self.public_id From 7e2b1910d3c75db2a0946292895b3827d7fc58a0 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 20 Oct 2011 21:33:07 +0200 Subject: [PATCH 04/13] apache config --- apache/vhost.conf.in | 2 +- pandora/user/models.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apache/vhost.conf.in b/apache/vhost.conf.in index 17f3f20b..802ba224 100644 --- a/apache/vhost.conf.in +++ b/apache/vhost.conf.in @@ -10,7 +10,7 @@ XSendFile on - XSendFileAllowAbove on + XSendFilePath __PREFIX__ Alias /.bzr __PREFIX__/.bzr diff --git a/pandora/user/models.py b/pandora/user/models.py index 3797c69b..4299a511 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -64,7 +64,6 @@ def get_ui(user_ui, user=None): ui = updateUI(ui, user_ui) if not 'lists' in ui: ui['lists'] = {} - ui['lists'][''] = copy.deepcopy(config['user']['ui']['lists']['']) def add(lists, section): ids = [] From b9c96f2a5e2d0c5596ee0a70ac135a52f5ae6ee4 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 20 Oct 2011 22:13:47 +0200 Subject: [PATCH 05/13] add title --- pandora/item/models.py | 2 +- static/js/pandora/ui/item.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandora/item/models.py b/pandora/item/models.py index 812b79a5..a3541322 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -387,7 +387,7 @@ class Item(models.Model): layers = {} for l in Layer.objects.all(): ll = layers.setdefault(l.name, []) - qs = Annotation.objects.filter(layer=l, item=self).select_related() + qs = Annotation.objects.filter(layer=l, item=self) if l.name == 'subtitles': qs = qs.exclude(value='') if l.private: diff --git a/static/js/pandora/ui/item.js b/static/js/pandora/ui/item.js index a5ed11fe..90303237 100644 --- a/static/js/pandora/ui/item.js +++ b/static/js/pandora/ui/item.js @@ -7,7 +7,7 @@ pandora.ui.item = function() { pandora.api.get({ id: pandora.user.ui.item, keys: ['video', 'timeline'].indexOf(pandora.user.ui.itemView)>-1 ? - ['rendered', 'cuts', 'videoRatio', 'duration', 'layers', 'parts', 'size'] : [] + [ 'cuts', 'duration', 'layers', 'parts', 'rendered', 'size', 'title', 'videoRatio'] : [] }, pandora.user.level == 'admin' && pandora.user.ui.itemView == 'info' ? 0 : -1, function(result) { if (result.status.code == 200) { From 05ef83825320c23cb90e6bc93532b6e9ca14700a Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 01:19:38 +0200 Subject: [PATCH 06/13] timeline names changed --- pandora/item/timelines.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pandora/item/timelines.py b/pandora/item/timelines.py index 3d8af150..33902023 100644 --- a/pandora/item/timelines.py +++ b/pandora/item/timelines.py @@ -8,8 +8,12 @@ import Image import ox +def getTiles(timeline_prefix, height=64): + files = glob('%s%sp*.png' % (timeline_prefix, height)) + return sorted(filter(lambda f: f!='%s%sp.png' % (timeline_prefix, height), files)) + def loadTimeline(timeline_prefix, height=64): - files = sorted(glob('%s%sp*.png' % (timeline_prefix, height))) + files = getTiles(timeline_prefix, height) f = Image.open(files[0]) width = f.size[0] f = Image.open(files[-1]) @@ -23,7 +27,7 @@ def loadTimeline(timeline_prefix, height=64): return timeline def makeTiles(timeline_prefix, height=16, width=3600): - files = glob('%s64p*.png' % timeline_prefix) + files = getTiles(timeline_prefix, 64) fps = 25 part_step = 60 output_width = width @@ -53,7 +57,7 @@ def makeTimelineOverview(timeline_prefix, width, inpoint=0, outpoint=0, duration timeline_file = '%s%sp.png' % (timeline_prefix, height) if outpoint > 0: - timeline_file = '%s.overview.%s.%d-%d.png' % (timeline_prefix, height, inpoint, outpoint) + timeline_file = '%s%sp.%d-%d.png' % (timeline_prefix, height, inpoint, outpoint) timeline = loadTimeline(timeline_prefix) duration = timeline.size[0] @@ -70,14 +74,16 @@ def makeTimelineOverview(timeline_prefix, width, inpoint=0, outpoint=0, duration timeline = timeline.crop((inpoint, 0, outpoint, timeline.size[1])).resize((width, height), Image.ANTIALIAS) timeline.save(timeline_file) - def join_timelines(timelines, prefix): height = 64 width = 1500 + for f in glob('%s*'%prefix): + os.unlink(f) + tiles = [] for timeline in timelines: - tiles += sorted(glob('%s%sp*.png'%(timeline, height))) + tiles += getTiles(timeline, height) timeline = Image.new("RGB", (2 * width, height)) From aa24971401a9f45eede28e5428d145d670f2a597 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 01:52:21 +0200 Subject: [PATCH 07/13] match new place --- pandora/archive/tasks.py | 8 ++++---- pandora/place/views.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pandora/archive/tasks.py b/pandora/archive/tasks.py index 89b352c7..fefee553 100644 --- a/pandora/archive/tasks.py +++ b/pandora/archive/tasks.py @@ -5,7 +5,7 @@ import ox from django.conf import settings -from item.models import get_item +from item.models import get_item, Item import item.tasks import models @@ -80,11 +80,11 @@ def update_files(user, volume, files): #remove deleted files removed = models.Instance.objects.filter(volume=volume).exclude(file__oshash__in=all_files) - ids = [i['itemId'] for i in Item.models.objects.filter( - files__instances__in=removed.filter(selected=True)).distinct().values('itemId')] + ids = [i['itemId'] for i in Item.objects.filter( + files__instances__in=removed.filter(file__selected=True)).distinct().values('itemId')] removed.delete() for i in ids: - i = Item.models.objects.get(itemId=i) + i = Item.objects.get(itemId=i) i.update_selected() @task(queue="encoding") diff --git a/pandora/place/views.py b/pandora/place/views.py index 06718071..a3375218 100644 --- a/pandora/place/views.py +++ b/pandora/place/views.py @@ -59,7 +59,7 @@ def addPlace(request): value = tuple(value) setattr(place, key, value) place.save() - #tasks.update_matches.delay(place.id) + tasks.update_matches.delay(place.id) response = json_response(place.json()) else: response = json_response(status=403, From 53436967ed37fd09123d0e66f4d9c0760337752a Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 11:50:31 +0200 Subject: [PATCH 08/13] timelines without folders --- pandora/item/timelines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora/item/timelines.py b/pandora/item/timelines.py index 33902023..d37473c7 100644 --- a/pandora/item/timelines.py +++ b/pandora/item/timelines.py @@ -78,6 +78,7 @@ def join_timelines(timelines, prefix): height = 64 width = 1500 + ox.makedirs(os.path.dirname(prefix)) for f in glob('%s*'%prefix): os.unlink(f) @@ -105,7 +106,6 @@ def join_timelines(timelines, prefix): timeline_name = '%s%sp%04d.png' % (prefix, height, i) timeline.crop((0, 0, pos, height)).save(timeline_name) - ox.makedirs(os.path.dirname(prefix)) makeTiles(prefix, 16, 3600) makeTimelineOverview(prefix, 1920, height=16) makeTimelineOverview(prefix, 1920, height=64) From 1bec444f66a8496445190fcf283efb0577bc7408 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 11:53:39 +0200 Subject: [PATCH 09/13] always update sort_path --- pandora/archive/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 1b951b5b..81318f5b 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -75,7 +75,6 @@ class File(models.Model): def set_state(self): self.path = self.create_path() - self.sort_path= utils.sort_string(self.path) if not os.path.splitext(self.path)[-1] in ( '.srt', '.rar', '.sub', '.idx', '.txt', '.jpg', '.png', '.nfo') \ @@ -146,6 +145,7 @@ class File(models.Model): def save(self, *args, **kwargs): if self.auto: self.set_state() + self.sort_path= utils.sort_string(self.path) if self.is_subtitle: self.available = self.data and True or False else: From b9b861a3e89124d625114034cdc5a62e0052ee55 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 20:02:36 +0200 Subject: [PATCH 10/13] save color/cuts per stream --- pandora/archive/models.py | 5 +++++ pandora/item/models.py | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 81318f5b..2a5e2e55 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -442,6 +442,9 @@ class Stream(models.Model): duration = models.FloatField(default=0) aspect_ratio = models.FloatField(default=0) + cuts = fields.TupleField(default=[]) + color = fields.TupleField(default=[]) + @property def timeline_prefix(self): return os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline') @@ -484,6 +487,8 @@ class Stream(models.Model): def make_timeline(self): if self.available and not self.source: extract.timeline(self.video.path, self.timeline_prefix) + self.cuts = tuple(extract.cuts(self.timeline_prefix)) + self.color = tuple(extract.average_color(self.timeline_prefix)) def save(self, *args, **kwargs): if self.video and not self.info: diff --git a/pandora/item/models.py b/pandora/item/models.py index a3541322..3cde9962 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -850,8 +850,22 @@ class Item(models.Model): def update_timeline(self, force=False): streams = self.streams() self.make_timeline() - self.data['cuts'] = extract.cuts(self.timeline_prefix) - self.data['color'] = extract.average_color(self.timeline_prefix) + if streams.count() == 1: + self.data['color'] = streams[0].color + self.data['cuts'] = streams[0].cuts + else: + #self.data['color'] = extract.average_color(self.timeline_prefix) + #self.data['cuts'] = extract.cuts(self.timeline_prefix) + self.data['cuts'] = [] + offset = 0 + color = [0, 0, 0] + n = streams.count() + for s in streams: + for c in s.cuts: + self.data['cuts'].append(c+offset) + color = map(lambda a,b: (a+b)/n, color,ox.image.getRGB(s.color)) + offset += s.duration + self.data['color'] = ox.image.getHSL(color) #extract.timeline_strip(self, self.data['cuts'], stream.info, self.timeline_prefix[:-8]) self.select_frame() self.make_local_poster() From f33f4ba45e5bb4d010befd1ba8c166ec54dd3b71 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 20:05:39 +0200 Subject: [PATCH 11/13] save --- pandora/archive/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandora/archive/models.py b/pandora/archive/models.py index 2a5e2e55..449083a0 100644 --- a/pandora/archive/models.py +++ b/pandora/archive/models.py @@ -489,6 +489,7 @@ class Stream(models.Model): extract.timeline(self.video.path, self.timeline_prefix) self.cuts = tuple(extract.cuts(self.timeline_prefix)) self.color = tuple(extract.average_color(self.timeline_prefix)) + self.save() def save(self, *args, **kwargs): if self.video and not self.info: From 055a2b6482bd7c113dde51671973c7cc4fb087dc Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 20:10:24 +0200 Subject: [PATCH 12/13] more timeline names --- pandora/archive/extract.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandora/archive/extract.py b/pandora/archive/extract.py index 2fd42a51..984461e2 100644 --- a/pandora/archive/extract.py +++ b/pandora/archive/extract.py @@ -334,7 +334,8 @@ def cuts(prefix): height = 64 width = 1500 pixels = [] - for image in sorted(glob("%s.%d.*.png" % (prefix, height))): + timelines = sorted(filter(lambda t: t!= '%s%sp.png'%(prefix,height), glob("%s%sp*.png"%(prefix, height)))) + for image in timelines: timeline = Image.open(image) frames += timeline.size[0] pixels.append(timeline.load()) @@ -418,7 +419,7 @@ def timeline_strip(item, cuts, info, prefix): if len(line_image) > frame: timeline_image.paste(line_image[frame], (x, 0)) if x == timeline_width - 1: - timeline_file = '%sstrip.64.%04d.png' % (prefix, i) + timeline_file = '%sStrip64p%04d.png' % (prefix, i) if _debug: print 'writing', timeline_file timeline_image.save(timeline_file) From 624a69a89fdd301fff7c9d7e0d02d336f6eaad7b Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 21 Oct 2011 20:12:09 +0200 Subject: [PATCH 13/13] more timeline names --- pandora/archive/extract.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandora/archive/extract.py b/pandora/archive/extract.py index 984461e2..1cf41cd6 100644 --- a/pandora/archive/extract.py +++ b/pandora/archive/extract.py @@ -288,7 +288,8 @@ def average_color(prefix, start=0, end=0): if end: start = int(start * 25) end = int(end * 25) - for image in sorted(glob("%s.%d.*.png" % (prefix, height))): + timelines = sorted(filter(lambda t: t!= '%s%sp.png'%(prefix,height), glob("%s%sp*.png"%(prefix, height)))) + for image in timelines: start_offset = 0 timeline = Image.open(image) frames += timeline.size[0]