From 966c5d435ae5e774d1ad7f1e6ca83576ba591ccc Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Fri, 10 Sep 2010 17:12:22 +0200 Subject: [PATCH] more poster --- pandora/backend/models.py | 220 +++++++++++++++++++--------------- pandora/backend/tasks.py | 5 + pandora/backend/views.py | 25 ++-- pandora/static/js/timeline.js | 2 +- 4 files changed, 147 insertions(+), 105 deletions(-) diff --git a/pandora/backend/models.py b/pandora/backend/models.py index eeb8a0fcf..ab7d591ec 100644 --- a/pandora/backend/models.py +++ b/pandora/backend/models.py @@ -160,6 +160,9 @@ class Movie(models.Model): self.updateSort() self.updateFacets() + ''' + JSON cache related functions + ''' _public_fields = { 'movieId': 'id', 'title': 'title', @@ -188,8 +191,6 @@ class Movie(models.Model): 'votes': 'votes', 'alternative_titles': 'alternative_titles', 'connections_json': 'connections', - 'poster_width': 'posterWidth', - 'poster_height': 'posterHeight' } def get_poster(self): poster = {} @@ -204,6 +205,35 @@ class Movie(models.Model): ''' return poster + def get_posters(self): + posters = {} + for p in self.poster_urls.all(): + if p.service not in posters: + posters[p.service] = [] + posters[p.service].append({'url': p.url, 'width': p.width, 'height': p.height}) + local_posters = self.local_posters().keys() + if local_posters: + posters['local'] = [] + for p in local_posters: + url = p.replace(settings.MEDIA_ROOT, settings.MEDIA_URL) + width = 640 + height = 1024 + posters['local'].append({'url': url, 'width': width, 'height': height}) + return posters + + def get_stream(self): + stream = {} + if self.streams.all().count(): + s = self.streams.all()[0] + if s.video and s.info: + stream['duration'] = s.info['duration'] + if 'video' in s.info and s.info['video']: + stream['aspectRatio'] = s.info['video'][0]['width'] / s.info['video'][0]['height'] + + stream['baseUrl'] = os.path.dirname(s.video.url) + stream['profiles'] = list(set(map(lambda s: int(os.path.splitext(s['profile'])[0][:-1]), self.streams.all().values('profile')))) + return stream + def get_json(self, fields=None): movie = {} for key in self._public_fields: @@ -220,25 +250,13 @@ class Movie(models.Model): if not fields: movie['stream'] = self.get_stream() movie['poster'] = self.get_poster() + movie['posters'] = self.get_posters() if fields: for f in fields: if f.endswith('.length') and f[:-7] in ('cast', 'genre', 'trivia'): movie[f] = getattr(self.sort, f[:-7]) return movie - def get_stream(self): - stream = {} - if self.streams.all().count(): - s = self.streams.all()[0] - if s.video and s.info: - stream['duration'] = s.info['duration'] - if 'video' in s.info and s.info['video']: - stream['aspectRatio'] = s.info['video'][0]['width'] / s.info['video'][0]['height'] - - stream['baseUrl'] = os.path.dirname(s.video.url) - stream['profiles'] = list(set(map(lambda s: int(os.path.splitext(s['profile'])[0][:-1]), self.streams.all().values('profile')))) - return stream - def fields(self): fields = {} for f in self._meta.fields: @@ -254,13 +272,10 @@ class Movie(models.Model): self.get('series title', ''), self.get('episode title', ''), self.get('season', ''), self.get('episode', '')) - def frame(self, position, width=128): - stream = self.streams.filter(profile=settings.VIDEO_PROFILE+'.webm')[0] - path = os.path.join(settings.MEDIA_ROOT, movieid_path(self.movieId), 'frame', "%d"%width, "%s.jpg"%position) - if not os.path.exists(path): - extract.frame(stream.video.path, path, position, width) - return path + ''' + Search related functions + ''' def updateFind(self): try: f = self.find @@ -387,79 +402,15 @@ class Movie(models.Model): else: Facet.objects.filter(movie=self, key='year').delete() - def updatePosterUrls(self): - _current = {} - for s in settings.POSTER_SERVICES: - url = s + '?movieId=' + self.movieId - try: - data = json.loads(ox.net.readUrlUnicode(url)) - except: - continue - for service in data: - if service not in _current: - _current[service] = [] - for poster in data[service]: - _current[service].append(poster) - #FIXME: remove urls that are no longer listed - for service in _current: - for poster in _current[service]: - p, created = PosterUrl.objects.get_or_create(movie=self, url=poster['url'], service=service) - if created: - p.width = poster['width'] - p.height = poster['height'] - p.save() - - def poster_delete(self): - path = self.poster.path - self.poster.delete() - for f in glob(path.replace('.jpg', '*.jpg')): - os.unlink(f) - - def poster_download(self): - if not self.poster: - url = self.poster_url - if not url: - self.updatePosterUrls() - if self.poster_urls.count() > 0: - url = self.poster_urls.all().order_by('-height')[0].url - if url: - print url - data = ox.net.readUrl(url) - self.poster.save('poster.jpg', ContentFile(data)) - self.save() - else: - local_posters = self.make_local_posters() - if local_posters: - with open(local_posters[0]) as f: - self.poster.save('poster.jpg', ContentFile(f.read())) - - def local_posters(self): - part = 1 - posters = {} - for f in self.files.filter(is_main=True, available=True): - for frame in f.frames.all(): - path = os.path.join(movieid_path(self.movieId), 'poster.pandora.%s.%s.jpg'%(part, frame.position)) - path = os.path.abspath(os.path.join(settings.MEDIA_ROOT, path)) - posters[path] = frame.frame.path - part += 1 - return posters - - def make_local_posters(self): - posters = self.local_posters() - for poster in posters: - frame = posters[poster] - cmd = ['oxposter', - '-t', self.get('title'), - '-d', ', '.join(self.get('directors', ['Unknown Director'])), - '-f', frame, - '-p', poster - ] - if len(self.movieId) == 7: - cmd += ['-i', self.movieId] - cmd += ['-o', self.oxdbId] - p = subprocess.Popen(cmd) - p.wait() - return posters.keys() + ''' + Video related functions + ''' + def frame(self, position, width=128): + stream = self.streams.filter(profile=settings.VIDEO_PROFILE+'.webm')[0] + path = os.path.join(settings.MEDIA_ROOT, movieid_path(self.movieId), 'frame', "%d"%width, "%s.jpg"%position) + if not os.path.exists(path): + extract.frame(stream.video.path, path, position, width) + return path @property def timeline_prefix(self): @@ -498,6 +449,87 @@ class Movie(models.Model): self.available = True self.save() + ''' + Poster related functions + ''' + def update_poster_urls(self): + _current = {} + for s in settings.POSTER_SERVICES: + url = s + '?movieId=' + self.movieId + try: + data = json.loads(ox.net.readUrlUnicode(url)) + except: + continue + for service in data: + if service not in _current: + _current[service] = [] + for poster in data[service]: + _current[service].append(poster) + #FIXME: remove urls that are no longer listed + for service in _current: + for poster in _current[service]: + p, created = PosterUrl.objects.get_or_create(movie=self, url=poster['url'], service=service) + if created: + p.width = poster['width'] + p.height = poster['height'] + p.save() + + def delete_poster(self): + path = self.poster.path + self.poster.delete() + for f in glob(path.replace('.jpg', '*.jpg')): + os.unlink(f) + + def download_poster(self, force=True): + if not self.poster or force: + url = self.poster_url + if not url: + self.update_poster_urls() + if self.poster_urls.count() > 0: + url = self.poster_urls.all().order_by('-height')[0].url + if url: + data = ox.net.readUrl(url) + if force: + self.delete_poster() + self.poster.save('poster.jpg', ContentFile(data)) + self.save() + else: + if force: + self.delete_poster() + local_posters = self.make_local_posters() + if local_posters: + with open(local_posters[0]) as f: + self.poster.save('poster.jpg', ContentFile(f.read())) + + def local_posters(self): + part = 1 + posters = {} + for f in self.files.filter(is_main=True, available=True): + for frame in f.frames.all(): + path = os.path.join(movieid_path(self.movieId), 'poster.pandora.%s.%s.jpg'%(part, frame.position)) + path = os.path.abspath(os.path.join(settings.MEDIA_ROOT, path)) + posters[path] = frame.frame.path + part += 1 + return posters + + def make_local_posters(self): + posters = self.local_posters() + for poster in posters: + frame = posters[poster] + cmd = ['oxposter', + '-t', self.get('title'), + '-d', ', '.join(self.get('directors', ['Unknown Director'])), + '-f', frame, + '-p', poster + ] + if len(self.movieId) == 7: + cmd += ['-i', self.movieId] + cmd += ['-o', self.oxdbId] + p = subprocess.Popen(cmd) + p.wait() + return posters.keys() + + class MovieFind(models.Model): """ used to search movies, all search values are in here diff --git a/pandora/backend/tasks.py b/pandora/backend/tasks.py index cf2b93568..2249cdcf3 100644 --- a/pandora/backend/tasks.py +++ b/pandora/backend/tasks.py @@ -12,6 +12,11 @@ import models def cronjob(**kwargs): print "do some cleanup stuff once a day" +@task(ignore_resulsts=True, queue='default') +def updatePoster(movieId): + movie = models.Movie.objects.get(movieId=movieId) + movie.download_poster(True) + @task(ignore_resulsts=True, queue='default') def updateImdb(imdbId): movie = models.Movie.objects.get(movieId=imdbId) diff --git a/pandora/backend/views.py b/pandora/backend/views.py index 455eb7108..eb33ad0dd 100644 --- a/pandora/backend/views.py +++ b/pandora/backend/views.py @@ -78,6 +78,7 @@ def api_hello(request): return {'status': {'code': int, 'text': string}, 'data': {user: object}} ''' + #data = json.loads(request.POST['data']) response = json_response({}) if request.user.is_authenticated(): response['data']['user'] = getUserJSON(request.user) @@ -278,7 +279,7 @@ def api_getItem(request): itemId = json.loads(request.POST['data']) item = get_object_or_404_json(models.Movie, movieId=itemId) #FIXME: check permissions - response['data'] = {'item': item.json} + response['data'] = {'item': item.get_json()} return render_to_json_response(response) @login_required_json @@ -464,20 +465,24 @@ def api_setPoster(request): #parse path and return info param data {id: movieId, url: string} return {'status': {'code': int, 'text': string}, - data: {poster: url}} + data: {poster: {url,width,height}}} ''' data = json.loads(request.POST['data']) item = get_object_or_404_json(models.Movie, movieId=data['id']) if item.editable(request.user): - #FIXME: check that poster is from allowed url - item.poster_url = data['url'] - if item.poster: - item.poster.delete() - item.save() - response = json_response(status=200, text='ok') - response['data']['poster'] = item.get_poster() + valid_urls = [p.url for p in item.poster_urls.all()] + if data['url'] in valid_urls: + item.poster_url = data['url'] + if item.poster: + item.poster.delete() + item.save() + tasks.updatePoster.delay(item.movieId) + response = json_response(status=200, text='ok') + response['data']['poster'] = item.get_poster() + else: + response = json_response(status=403, text='invalid poster url') else: - response = json_response(status=403, text='permissino denied') + response = json_response(status=403, text='permission denied') return render_to_json_response(response) def api_getImdbId(request): diff --git a/pandora/static/js/timeline.js b/pandora/static/js/timeline.js index 395b2651e..a4e0a1ca5 100644 --- a/pandora/static/js/timeline.js +++ b/pandora/static/js/timeline.js @@ -34,7 +34,7 @@ $(function() { position = duration/2; videoWidth += videoWidth%2; - videoUrl = video.baseUrl + "/96p." + ($.support.video.webm ? "webm": "mp4"); + videoUrl = video.baseUrl + "/" + video.profiles[0] + "p." + ($.support.video.webm ? "webm": "mp4"); //resizeVideoPlayers(pageWidth);