diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index 74e76eff..0322057d 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -109,12 +109,13 @@ class Annotation(models.Model): return self.value def set_public_id(self): - public_id = Annotation.objects.filter(item=self.item, id__lt=self.id).count() - self.public_id = "%s/%s" % (self.item.itemId, ox.to26(public_id)) - Annotation.objects.filter(id=self.id).update(public_id=self.public_id) + if self.id: + public_id = Annotation.objects.filter(item=self.item, id__lt=self.id).count() + self.public_id = "%s/%s" % (self.item.itemId, ox.to26(public_id)) + Annotation.objects.filter(id=self.id).update(public_id=self.public_id) def save(self, *args, **kwargs): - set_public_id = not self.id + set_public_id = not self.id or not self.public_id #no clip or update clip if not self.clip and not self.layer.private or \ @@ -160,5 +161,5 @@ class Annotation(models.Model): return j def __unicode__(self): - return u"%s/%s-%s" %(self.item, self.start, self.end) + return u"%s %s-%s" %(self.public_id, self.start, self.end) diff --git a/pandora/archive/extract.py b/pandora/archive/extract.py index 8133946e..1c952ffe 100644 --- a/pandora/archive/extract.py +++ b/pandora/archive/extract.py @@ -294,11 +294,12 @@ def average_color(prefix, start=0, end=0): 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).convert('RGB') - frames += timeline.size[0] - if start and frames < start: + if start and frames + 1500 < start: + frames += 1500 continue - elif start and frames > start > frames-timeline.size[0]: + timeline = Image.open(image) + frames += timeline.size[0] + if start and frames > start > frames-timeline.size[0]: start_offset = start - (frames-timeline.size[0]) box = (start_offset, 0, timeline.size[0], height) timeline = timeline.crop(box) @@ -307,7 +308,7 @@ def average_color(prefix, start=0, end=0): box = (0, 0, end_offset, height) timeline = timeline.crop(box) - p = np.asarray(timeline, dtype=np.float32) + p = np.asarray(timeline.convert('RGB'), dtype=np.float32) p = np.sum(p, axis=0) / height #average color per frame pixels.append(p) diff --git a/pandora/item/management/commands/update_external.py b/pandora/item/management/commands/update_external.py new file mode 100644 index 00000000..34959a2e --- /dev/null +++ b/pandora/item/management/commands/update_external.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from optparse import make_option + +import os +from os.path import join, dirname, basename, splitext, exists + +from django.core.management.base import BaseCommand, CommandError +from django.conf import settings + +import monkey_patch.models +from ... import models + + +class Command(BaseCommand): + """ + rebuild sort/search cache for all items. + """ + help = 'listen to rabbitmq and execute encoding tasks.' + args = '' + option_list = BaseCommand.option_list + ( + make_option('--all', action='store_true', dest='all', + default=False, help='update all items, otherwise oldes N'), + make_option('-n', '--items', action='store', dest='items', type=int, + default=30, help='number of items ot update'), + ) + + def handle(self, **options): + offset = 0 + chunk = options['all'] and 100 or options['items'] + count = pos = models.Item.objects.count() + while options['all'] and offset <= count or offset < options['items']: + for i in models.Item.objects.all().order_by('modified')[offset:offset+chunk]: + print pos, i.itemId, i.modified + i.update_external() + pos -= 1 + offset += chunk diff --git a/pandora/item/models.py b/pandora/item/models.py index 57a16f34..59079703 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -13,7 +13,7 @@ import uuid import unicodedata from urllib import quote -from django.db import models +from django.db import models, transaction from django.db.models import Count, Q, Sum from django.core.files.base import ContentFile from django.conf import settings @@ -340,6 +340,8 @@ class Item(models.Model): #FIXME: should this really happen for annotations? for a in self.annotations.all(): a.item = other + a.public_id = None + a.save() if hasattr(self, 'files'): for f in self.files.all(): @@ -516,45 +518,46 @@ class Item(models.Model): else: ItemFind.objects.filter(item=self, key=key).delete() - for key in settings.CONFIG['itemKeys']: - i = key['id'] - if i == 'title': - save(i, u'\n'.join([self.get('title', 'Untitled'), - self.get('originalTitle', '')])) - elif i == 'rightslevel': - save(i, self.level) - elif i == 'filename': - save(i, - '\n'.join([f.path for f in self.files.all()])) - elif key['type'] == 'layer': - qs = Annotation.objects.filter(layer__name=i, item=self).order_by('start') - save(i, '\n'.join([l.value for l in qs])) - elif i != '*' and i not in self.facet_keys: - value = self.get(i) - if isinstance(value, list): - value = u'\n'.join(value) - save(i, value) + with transaction.commit_on_success(): + for key in settings.CONFIG['itemKeys']: + i = key['id'] + if i == 'title': + save(i, u'\n'.join([self.get('title', 'Untitled'), + self.get('originalTitle', '')])) + elif i == 'rightslevel': + save(i, self.level) + elif i == 'filename': + save(i, + '\n'.join([f.path for f in self.files.all()])) + elif key['type'] == 'layer': + qs = Annotation.objects.filter(layer__name=i, item=self).order_by('start') + save(i, '\n'.join([l.value for l in qs])) + elif i != '*' and i not in self.facet_keys: + value = self.get(i) + if isinstance(value, list): + value = u'\n'.join(value) + save(i, value) - for key in self.facet_keys: - if key == 'character': - values = self.get('cast', '') - if values: - values = filter(lambda x: x.strip(), - [f['character'] for f in values]) + for key in self.facet_keys: + if key == 'character': + values = self.get('cast', '') + if values: + values = filter(lambda x: x.strip(), + [f['character'] for f in values]) + values = list(set(values)) + elif key == 'name': + values = [] + for k in map(lambda x: x['id'], + filter(lambda x: x.get('sort') == 'person', + settings.CONFIG['itemKeys'])): + values += self.get(k, []) values = list(set(values)) - elif key == 'name': - values = [] - for k in map(lambda x: x['id'], - filter(lambda x: x.get('sort') == 'person', - settings.CONFIG['itemKeys'])): - values += self.get(k, []) - values = list(set(values)) - else: - values = self.get(key, '') - if isinstance(values, list): - save(key, '\n'.join(values)) - else: - save(key, values) + else: + values = self.get(key, '') + if isinstance(values, list): + save(key, '\n'.join(values)) + else: + save(key, values) def update_sort(self): try: @@ -933,7 +936,7 @@ class Item(models.Model): def make_timeline(self): streams = self.streams() - if len(streams) > 1: + if streams.count() > 1: timelines = [s.timeline_prefix for s in self.streams()] join_timelines(timelines, self.timeline_prefix) @@ -1041,61 +1044,63 @@ class Item(models.Model): return icon def load_subtitles(self): - layer = Layer.objects.get(name='subtitles') - Annotation.objects.filter(layer=layer,item=self).delete() - offset = 0 - language = '' - subtitles = self.files.filter(selected=True, is_subtitle=True, available=True) - languages = [f.language for f in subtitles] - if languages: - if 'en' in languages: - language = 'en' - elif '' in languages: - language = '' - else: - language = languages[0] + with transaction.commit_on_success(): + layer = Layer.objects.get(name='subtitles') + Annotation.objects.filter(layer=layer,item=self).delete() + offset = 0 + language = '' + subtitles = self.files.filter(selected=True, is_subtitle=True, available=True) + languages = [f.language for f in subtitles] + if languages: + if 'en' in languages: + language = 'en' + elif '' in languages: + language = '' + else: + language = languages[0] - #loop over all videos - for f in self.files.filter(Q(is_audio=True)|Q(is_video=True)) \ - .filter(selected=True).order_by('part'): - subtitles_added = False - prefix = os.path.splitext(f.path)[0] - if f.instances.all().count() > 0: - user = f.instances.all()[0].volume.user - else: - #FIXME: allow annotations from no user instead? - user = User.objects.all().order_by('id')[0] - #if there is a subtitle with the same prefix, import - q = subtitles.filter(path__startswith=prefix, - language=language) - if q.count() == 1: - s = q[0] - for data in s.srt(offset): - subtitles_added = True - annotation = Annotation( - item=self, - layer=layer, - start=data['in'], - end=data['out'], - value=data['value'], - user=user - ) - annotation.save() - #otherwise add empty 5 seconds annotation every minute - if not subtitles_added: - for i in range(int (offset / 60) * 60 + 60, - int(offset + f.duration) - 5, - 60): - annotation = Annotation( - item=self, - layer=layer, - start=i, - end=i + 5, - value='', - user=user - ) - annotation.save() - offset += f.duration + #loop over all videos + for f in self.files.filter(Q(is_audio=True)|Q(is_video=True)) \ + .filter(selected=True).order_by('part'): + subtitles_added = False + prefix = os.path.splitext(f.path)[0] + if f.instances.all().count() > 0: + user = f.instances.all()[0].volume.user + else: + #FIXME: allow annotations from no user instead? + user = User.objects.all().order_by('id')[0] + #if there is a subtitle with the same prefix, import + q = subtitles.filter(path__startswith=prefix, + language=language) + if q.count() == 1: + s = q[0] + for data in s.srt(offset): + subtitles_added = True + annotation = Annotation( + item=self, + layer=layer, + start=data['in'], + end=data['out'], + value=data['value'], + user=user + ) + annotation.save() + #otherwise add empty 5 seconds annotation every minute + if not subtitles_added: + start = offset and int (offset / 60) * 60 + 60 or 0 + for i in range(start, + int(offset + f.duration) - 5, + 60): + annotation = Annotation( + item=self, + layer=layer, + start=i, + end=i + 5, + value='', + user=user + ) + annotation.save() + offset += f.duration self.update_find() def delete_item(sender, **kwargs): diff --git a/static/js/pandora/clipList.js b/static/js/pandora/clipList.js index 49b8970d..df28a63a 100644 --- a/static/js/pandora/clipList.js +++ b/static/js/pandora/clipList.js @@ -154,8 +154,9 @@ pandora.ui.clipList = function(videoRatio) { poster: '/' + item + '/' + height + 'p' + points[0] + '.jpg', rewind: true, video: partsAndPoints.parts.map(function(i) { - return '/' + item + '/96p' + (i + 1) - + '.' + pandora.user.videoFormat; + var part = (i + 1), + prefix = pandora.site.site.videoprefix.replace('PART', part); + return prefix + '/' + item + '/96p' + part + '.' + pandora.user.videoFormat; }), width: width }) diff --git a/static/js/pandora/clipPlayer.js b/static/js/pandora/clipPlayer.js index 98d32732..0bce6762 100644 --- a/static/js/pandora/clipPlayer.js +++ b/static/js/pandora/clipPlayer.js @@ -35,17 +35,19 @@ pandora.ui.clipPlayer = function() { length = range[1] - range[0], data = []; result.data.items.forEach(function(item, i) { - var id = item.id.split('/')[0] + var id = item.id.split('/')[0]; pandora.api.get({id: id, keys: ['durations']}, function(result) { //Ox.print('API get item', id, 'result', result.data); var points = [item['in'], item.out], partsAndPoints = pandora.getVideoPartsAndPoints(result.data.durations, points); data[i] = { parts: partsAndPoints.parts.map(function(i) { - return '/' + id + '/96p' + (i + 1) + '.' + pandora.user.videoFormat; + var part = (i + 1), + prefix = pandora.site.site.videoprefix.replace('PART', part); + return prefix + '/' + id + '/96p' + part + '.' + pandora.user.videoFormat; }), points: partsAndPoints.points - } + }; if (++counter == length) { callback(data); } diff --git a/static/js/pandora/itemClips.js b/static/js/pandora/itemClips.js index 82e1c5a8..b42401bb 100644 --- a/static/js/pandora/itemClips.js +++ b/static/js/pandora/itemClips.js @@ -91,8 +91,9 @@ pandora.ui.itemClips = function(options) { poster: '/' + self.options.id + '/' + self.height + 'p' + points[0] + '.jpg', rewind: true, video: partsAndPoints.parts.map(function(i) { - return '/' + self.options.id + '/96p' + (i + 1) - + '.' + pandora.user.videoFormat; + var part = (i + 1), + prefix = pandora.site.site.videoprefix.replace('PART', part); + return prefix + '/' + self.options.id + '/96p' + part + '.' + pandora.user.videoFormat; }), width: self.width }) @@ -105,4 +106,4 @@ pandora.ui.itemClips = function(options) { return that; -}; \ No newline at end of file +};