forked from 0x2620/pandora
merge
This commit is contained in:
commit
c6f11433f9
7 changed files with 159 additions and 111 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
37
pandora/item/management/commands/update_external.py
Normal file
37
pandora/item/management/commands/update_external.py
Normal file
|
@ -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
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue