forked from 0x2620/pandora
server side cleanups and fixed for pandora_client sync
This commit is contained in:
parent
7af971288f
commit
4328d54450
8 changed files with 88 additions and 61 deletions
|
@ -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)
|
||||||
|
|
|
@ -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'])
|
|
||||||
|
if info['video'] and 'display_aspect_ratio' in info['video'][0]:
|
||||||
|
fps = AspectRatio(info['video'][0]['framerate'])
|
||||||
|
|
||||||
width = int(dar * height)
|
dar = AspectRatio(info['video'][0]['display_aspect_ratio'])
|
||||||
width += width % 2
|
width = int(dar * height)
|
||||||
|
width += width % 2
|
||||||
|
|
||||||
bitrate = height*width*fps*bpp/1000
|
bitrate = height*width*fps*bpp/1000
|
||||||
aspect = dar.ratio
|
aspect = dar.ratio
|
||||||
#use 1:1 pixel aspect ratio if dar is close to that
|
#use 1:1 pixel aspect ratio if dar is close to that
|
||||||
if abs(width/height - dar) < 0.02:
|
if abs(width/height - dar) < 0.02:
|
||||||
aspect = '%s:%s' % (width, height)
|
aspect = '%s:%s' % (width, height)
|
||||||
|
|
||||||
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']
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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'],
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue