server side cleanups and fixed for pandora_client sync

This commit is contained in:
j 2011-04-06 20:57:25 +02:00
parent 7af971288f
commit 4328d54450
8 changed files with 88 additions and 61 deletions

View file

@ -8,7 +8,7 @@ import models
class FileAdmin(admin.ModelAdmin): class FileAdmin(admin.ModelAdmin):
search_fields = ['name', 'video_codec'] search_fields = ['name', 'folder','oshash', 'video_codec']
list_display = ['available', 'is_main', '__unicode__', 'itemId'] list_display = ['available', 'is_main', '__unicode__', 'itemId']
list_display_links = ('__unicode__', ) list_display_links = ('__unicode__', )
@ -21,7 +21,7 @@ admin.site.register(models.File, FileAdmin)
class InstanceAdmin(admin.ModelAdmin): class InstanceAdmin(admin.ModelAdmin):
search_fields = ['name', 'folder', 'volume__name'] search_fields = ['name', 'folder', 'volume__name', 'file__oshash']
form = InstanceAdminForm form = InstanceAdminForm
admin.site.register(models.Instance, InstanceAdmin) admin.site.register(models.Instance, InstanceAdmin)

View file

@ -47,11 +47,8 @@ class AspectRatio(fractions.Fraction):
def stream(video, target, profile, info): def stream(video, target, profile, info):
if not os.path.exists(target): if not os.path.exists(target):
fdir = os.path.dirname(target) ox.makedirs(os.path.dirname(target))
if not os.path.exists(fdir):
os.makedirs(fdir)
dar = AspectRatio(info['video'][0]['display_aspect_ratio'])
''' '''
WebM look into WebM look into
lag lag
@ -109,36 +106,27 @@ def stream(video, target, profile, info):
audiochannels = 1 audiochannels = 1
bpp = 0.17 bpp = 0.17
fps = AspectRatio(info['video'][0]['framerate'])
width = int(dar * height) if info['video'] and 'display_aspect_ratio' in info['video'][0]:
width += width % 2 fps = AspectRatio(info['video'][0]['framerate'])
bitrate = height*width*fps*bpp/1000 dar = AspectRatio(info['video'][0]['display_aspect_ratio'])
aspect = dar.ratio width = int(dar * height)
#use 1:1 pixel aspect ratio if dar is close to that width += width % 2
if abs(width/height - dar) < 0.02:
aspect = '%s:%s' % (width, height)
if info['audio']: bitrate = height*width*fps*bpp/1000
audio_settings = ['-ar', str(audiorate), '-aq', str(audioquality)] aspect = dar.ratio
if audiochannels and 'channels' in info['audio'][0] and info['audio'][0]['channels'] > audiochannels: #use 1:1 pixel aspect ratio if dar is close to that
audio_settings += ['-ac', str(audiochannels)] if abs(width/height - dar) < 0.02:
if audiobitrate: aspect = '%s:%s' % (width, height)
audio_settings += ['-ab', audiobitrate]
if format == 'mp4':
audio_settings += ['-acodec', 'libfaac']
else:
audio_settings += ['-acodec', 'libvorbis']
else:
audio_settings = ['-an']
if info['video']:
video_settings = [ video_settings = [
'-vb', '%dk'%bitrate, '-g', '%d' % int(fps*2), '-vb', '%dk'%bitrate, '-g', '%d' % int(fps*2),
'-s', '%dx%d'%(width, height), '-s', '%dx%d'%(width, height),
'-aspect', aspect, '-aspect', aspect,
#'-vf', 'yadif',
] ]
if format == 'mp4': if format == 'mp4':
#quicktime does not support bpyramid #quicktime does not support bpyramid
''' '''
@ -185,6 +173,19 @@ def stream(video, target, profile, info):
else: else:
video_settings = ['-vn'] video_settings = ['-vn']
if info['audio']:
audio_settings = ['-ar', str(audiorate), '-aq', str(audioquality)]
if audiochannels and 'channels' in info['audio'][0] and info['audio'][0]['channels'] > audiochannels:
audio_settings += ['-ac', str(audiochannels)]
if audiobitrate:
audio_settings += ['-ab', audiobitrate]
if format == 'mp4':
audio_settings += ['-acodec', 'libfaac']
else:
audio_settings += ['-acodec', 'libvorbis']
else:
audio_settings = ['-an']
ffmpeg = FFMPEG2THEORA.replace('2theora', '') ffmpeg = FFMPEG2THEORA.replace('2theora', '')
cmd = [ffmpeg, '-y', '-i', video] \ cmd = [ffmpeg, '-y', '-i', video] \
+ audio_settings \ + audio_settings \
@ -199,12 +200,16 @@ def stream(video, target, profile, info):
cmd += [target] cmd += [target]
print cmd print cmd
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT) p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=open('/dev/null', 'w'),
stderr=subprocess.STDOUT)
p.communicate() p.communicate()
if format == 'mp4': if format == 'mp4':
cmd = ['qt-faststart', "%s.mp4"%target, target] cmd = ['qt-faststart', "%s.mp4"%target, target]
print cmd print cmd
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT) p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=open('/dev/null', 'w'),
stderr=subprocess.STDOUT)
p.communicate() p.communicate()
os.unlink("%s.mp4"%target) os.unlink("%s.mp4"%target)
return True return True
@ -212,7 +217,8 @@ def stream(video, target, profile, info):
def run_command(cmd, timeout=10): def run_command(cmd, timeout=10):
#print cmd #print cmd
p = subprocess.Popen(cmd, stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT) p = subprocess.Popen(cmd, stdout=open('/dev/null', 'w'),
stderr=subprocess.STDOUT)
while timeout > 0: while timeout > 0:
time.sleep(0.2) time.sleep(0.2)
timeout -= 0.2 timeout -= 0.2
@ -236,8 +242,7 @@ def frame(videoFile, frame, position, width=128, redo=False):
if exists(videoFile): if exists(videoFile):
frameFolder = os.path.dirname(frame) frameFolder = os.path.dirname(frame)
if redo or not exists(frame): if redo or not exists(frame):
if not exists(frameFolder): ox.makedirs(frameFolder)
os.makedirs(frameFolder)
cmd = ['oxframe', '-i', videoFile, '-o', frame, '-p', str(position), '-x', str(width)] cmd = ['oxframe', '-i', videoFile, '-o', frame, '-p', str(position), '-x', str(width)]
run_command(cmd) run_command(cmd)

View file

@ -74,10 +74,26 @@ class File(models.Model):
return self.name return self.name
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.name= self.get_name() instance = self.get_instance()
if instance:
if instance.name.lower().startswith('extras/'):
self.is_extra = True
self.is_main = False
elif instance.name.lower().startswith('versions/'):
self.is_version = True
self.is_main = False
else:
self.is_extra = False
self.is_main = True
else:
self.is_main = False
self.is_extra = False
self.is_version = False
self.name = self.get_name()
self.folder = self.get_folder() self.folder = self.get_folder()
if self.name and not self.sort_name: self.sort_name = utils.sort_string(canonicalTitle(self.name))
self.sort_name = utils.sort_string(canonicalTitle(self.name))
if self.info: if self.info:
for key in ('duration', 'size'): for key in ('duration', 'size'):
setattr(self, key, self.info.get(key, 0)) setattr(self, key, self.info.get(key, 0))
@ -126,16 +142,6 @@ class File(models.Model):
if not self.is_audio and not self.is_video and self.name.endswith('.srt'): if not self.is_audio and not self.is_video and self.name.endswith('.srt'):
self.is_subtitle = True self.is_subtitle = True
if self.name and self.name.lower().startswith('extras/'):
self.is_extra = True
self.is_main = False
elif self.name and self.name.lower().startswith('versions/'):
self.is_version = True
self.is_main = False
else:
self.is_extra = False
self.is_main = True
self.part = self.get_part() self.part = self.get_part()
self.type = self.get_type() self.type = self.get_type()
@ -290,6 +296,11 @@ class File(models.Model):
return 'subtitle' return 'subtitle'
return 'unknown' return 'unknown'
def get_instance(self):
if self.instances.all().count() > 0:
return self.instances.all()[0]
return None
def get_folder(self): def get_folder(self):
name = os.path.splitext(self.get_name())[0] name = os.path.splitext(self.get_name())[0]
if self.item: if self.item:
@ -307,6 +318,8 @@ class File(models.Model):
return u'' return u''
def get_name(self): def get_name(self):
if self.is_extra:
return self.get_instance().name
if self.item: if self.item:
name = self.item.get('title', 'Untitled') name = self.item.get('title', 'Untitled')
name = re.sub(r'[:\\/]', '_', name) name = re.sub(r'[:\\/]', '_', name)

View file

@ -47,6 +47,7 @@ def update_or_create_instance(volume, f):
updated=True updated=True
if updated: if updated:
instance.save() instance.save()
instance.file.save()
else: else:
instance = models.Instance() instance = models.Instance()
instance.volume = volume instance.volume = volume
@ -54,6 +55,7 @@ def update_or_create_instance(volume, f):
for key in _INSTANCE_KEYS: for key in _INSTANCE_KEYS:
setattr(instance, key, f[key]) setattr(instance, key, f[key])
instance.save() instance.save()
instance.file.save()
return instance return instance
@task(ignore_resulsts=True, queue='default') @task(ignore_resulsts=True, queue='default')

View file

@ -66,6 +66,7 @@ def update(request):
''' '''
data = json.loads(request.POST['data']) data = json.loads(request.POST['data'])
user = request.user user = request.user
upload_only = data.get('upload', False)
response = json_response({'info': [], 'data': [], 'file': []}) response = json_response({'info': [], 'data': [], 'file': []})
volume = None volume = None
@ -91,15 +92,18 @@ def update(request):
del info[key] del info[key]
instance.file.info = info instance.file.info = info
instance.file.save() instance.file.save()
if not upload_only:
files = models.Instance.objects.filter(volume__user=user, file__available=False) files = models.Instance.objects.filter(volume__user=user, file__available=False)
if volume: if volume:
files = files.filter(volume=volume) files = files.filter(volume=volume)
response['data']['info'] = [f.file.oshash for f in files.filter(file__info='{}')] response['data']['info'] = [f.file.oshash for f in files.filter(file__info='{}')]
#needs some flag to find those that are actually used main is to generic #needs some flag to find those that are actually used main is to generic
response['data']['data'] = [f.file.oshash for f in files.filter(file__is_video=True, file__is_main=True)] response['data']['data'] = [f.file.oshash for f in files.filter(file__is_video=True,
response['data']['data'] += [f.file.oshash for f in files.filter(file__is_audio=True, file__is_main=True)] file__is_main=True)]
response['data']['file'] = [f.file.oshash for f in files.filter(file__is_subtitle=True)] response['data']['data'] += [f.file.oshash for f in files.filter(file__is_audio=True,
file__is_main=True)]
response['data']['file'] = [f.file.oshash for f in files.filter(file__is_subtitle=True,
name__endswith='.srt')]
return render_to_json_response(response) return render_to_json_response(response)
actions.register(update, cache=False) actions.register(update, cache=False)

View file

@ -550,7 +550,7 @@ class Item(models.Model):
for key in self.facet_keys: for key in self.facet_keys:
current_values = self.get(key, []) current_values = self.get(key, [])
if not isinstance(current_values, list): if not isinstance(current_values, list):
current_values = [current_values] current_values = [unicode(current_values)]
current_values = list(set(current_values)) current_values = list(set(current_values))
saved_values = [i.value for i in Facet.objects.filter(item=self, key=key)] saved_values = [i.value for i in Facet.objects.filter(item=self, key=key)]
removed_values = filter(lambda i: i not in current_values, saved_values) removed_values = filter(lambda i: i not in current_values, saved_values)
@ -632,8 +632,7 @@ class Item(models.Model):
cmd = [] cmd = []
if os.path.exists(stream.video.path): if os.path.exists(stream.video.path):
os.unlink(stream.video.path) os.unlink(stream.video.path)
elif not os.path.exists(os.path.dirname(stream.video.path)): ox.makedirs(os.path.dirname(stream.video.path))
os.makedirs(os.path.dirname(stream.video.path))
if len(files.values()) > 1: if len(files.values()) > 1:
if len(files.values()) > 4: if len(files.values()) > 4:
print "FIXME: to many files for this item, not merging entire tv shows" print "FIXME: to many files for this item, not merging entire tv shows"
@ -753,8 +752,7 @@ class Item(models.Model):
posters = self.local_posters() posters = self.local_posters()
timeline = self.path('timeline.64.png') timeline = self.path('timeline.64.png')
timeline = os.path.abspath(os.path.join(settings.MEDIA_ROOT, timeline)) timeline = os.path.abspath(os.path.join(settings.MEDIA_ROOT, timeline))
if not os.path.exists(os.path.join(settings.MEDIA_ROOT,self.path())): ox.makedirs(os.path.join(settings.MEDIA_ROOT,self.path()))
os.makedirs(os.path.join(settings.MEDIA_ROOT,self.path()))
for poster in posters: for poster in posters:
frame = posters[poster] frame = posters[poster]
cmd = [settings.ITEM_POSTER, cmd = [settings.ITEM_POSTER,

View file

@ -102,6 +102,8 @@ def parse_title(_title, searchTitle = False):
if year and title.endswith(year): if year and title.endswith(year):
title = title[:-len(year)].strip() title = title[:-len(year)].strip()
title = normalizeTitle(title) title = normalizeTitle(title)
if searchTitle and year:
title = u"%s %s" % (title, year)
return title return title
@ -180,7 +182,9 @@ def parse_path(path):
r['season'], r['episode'] = parse_season_episode(path) r['season'], r['episode'] = parse_season_episode(path)
r['series_title'] = parse_series_title(path) r['series_title'] = parse_series_title(path)
r['imdbId'] = ox.web.imdb.guess(search_title, ', '.join(r['director']), timeout=-1) #FIXME: use oxdata/id/?title=title&director=director&year=year
#r['imdbId'] = ox.web.imdb.guess(search_title, ', '.join(r['director']), timeout=-1)
r['imdbId'] = ox.web.imdb.guess(search_title, timeout=-1)
r['oxdbId'] = oxdb_id(r['title'], r['director'], r.get('year', ''), r['oxdbId'] = oxdb_id(r['title'], r['director'], r.get('year', ''),
r.get('season', ''), r.get('episode', ''), r.get('season', ''), r.get('episode', ''),
episode_title=r['episode_title'], episode_title=r['episode_title'],

View file

@ -27,6 +27,7 @@ ADMINS = (
DEFAULT_FROM_EMAIL='admin@' + URL.split('/')[0] DEFAULT_FROM_EMAIL='admin@' + URL.split('/')[0]
#DEFAULT_FROM_EMAIL='admin@example.com' #DEFAULT_FROM_EMAIL='admin@example.com'
SERVER_EMAIL=DEFAULT_FROM_EMAIL
MANAGERS = ADMINS MANAGERS = ADMINS