diff --git a/modules/allocine/browser.py b/modules/allocine/browser.py index c6a682b7..748b2d49 100644 --- a/modules/allocine/browser.py +++ b/modules/allocine/browser.py @@ -17,14 +17,16 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . - -from weboob.capabilities.base import NotAvailable, NotLoaded +from weboob.capabilities.collection import Collection +from weboob.capabilities.video import BaseVideo +from weboob.capabilities.image import BaseImage +from weboob.capabilities.base import NotAvailable, NotLoaded, find_object from weboob.capabilities.cinema import Movie, Person from weboob.deprecated.browser import Browser from weboob.tools.json import json import base64 import hashlib -from datetime import datetime +from datetime import datetime, date, timedelta import time import urllib @@ -190,7 +192,7 @@ class AllocineBrowser(Browser): for cast in jres['castMember']: if cast['activity']['$'] not in roles: roles[cast['activity']['$']] = [] - person_to_append = (u'%s'%cast['person']['code'], cast['person']['name']) + person_to_append = (u'%s' % cast['person']['code'], cast['person']['name']) roles[cast['activity']['$']].append(person_to_append) movie = Movie(id, title) @@ -281,7 +283,6 @@ class AllocineBrowser(Browser): movie_to_append = (u'%s' % (m['movie']['code']), u'(%s) %s' % (pyear, m['movie']['originalTitle'])) roles[m['activity']['$']].append(movie_to_append) - person = Person(id, name) person.real_name = real_name person.birth_date = birth_date @@ -443,3 +444,120 @@ class AllocineBrowser(Browser): biography = unicode(jres['biography']) return biography + + def get_categories_movies(self, category): + params = [('partner', self.PARTNER_KEY), + ('format', 'json'), + ('mediafmt', 'mp4'), + ('filter', category) + ] + res = self.__do_request('movielist', params) + if res is None: + return + result = json.loads(res) + for movie in result['feed']['movie']: + if 'trailer' not in movie or 'productionYear' not in movie: + continue + yield self.parse_movie(movie) + + def get_categories_videos(self, category): + params = [('partner', self.PARTNER_KEY), + ('format', 'json'), + ('mediafmt', 'mp4'), + ('filter', category) + ] + res = self.__do_request('videolist', params) + if res is None: + return + result = json.loads(res) + for episode in result['feed']['media']: + if 'title' in episode: + yield self.parse_video(episode, category) + + def parse_video(self, _video, category): + video = BaseVideo(u'%s#%s' % (_video['code'], category)) + video.title = unicode(_video['title']) + video._video_code = unicode(_video['code']) + video.ext = u'mp4' + if 'runtime' in _video: + video.duration = timedelta(seconds=int(_video['runtime'])) + if 'description' in _video: + video.description = unicode(_video['description']) + renditions = sorted(_video['rendition'], key=lambda x: 'bandwidth' in x and x['bandwidth']['code'], reverse=True) + video.url = unicode(max(renditions, key=lambda x: 'bandwidth' in x)['href']) + return video + + def parse_movie(self, movie): + video = BaseVideo(u'%s#%s' % (movie['code'], 'movie')) + video.title = unicode(movie['trailer']['name']) + video._video_code = unicode(movie['trailer']['code']) + video.ext = u'mp4' + video.thumbnail = BaseImage(movie['poster']['href']) + video.thumbnail.url = unicode(movie['poster']['href']) + tdate = movie['release']['releaseDate'].split('-') + day = 1 + month = 1 + year = 1901 + if len(tdate) > 2: + year = int(tdate[0]) + month = int(tdate[1]) + day = int(tdate[2]) + + video.date = date(year, month, day) + if 'userRating' in movie['statistics']: + video.rating = movie['statistics']['userRating'] + elif 'pressRating' in movie['statistics']: + video.rating = movie['statistics']['pressRating']*2 + video.rating_max = 5 + if 'synopsis' in movie: + video.description = unicode(movie['synopsis'].replace('

', '').replace('

', '')) + elif 'synopsisShort' in movie: + video.description = unicode(movie['synopsisShort'].replace('

', '').replace('

', '')) + if 'castingShort' in movie: + if 'directors' in movie['castingShort']: + video.author = unicode(movie['castingShort']['directors']) + if 'runtime' in movie: + video.duration = timedelta(seconds=int(movie['runtime'])) + return video + + def get_movie_from_id(self, _id): + params = [('partner', self.PARTNER_KEY), + ('format', 'json'), + ('mediafmt', 'mp4'), + ('filter', 'movie'), + ('code', _id), + ] + res = self.__do_request('movie', params) + if res is None: + return + result = json.loads(res) + return self.parse_video(result['movie']) + + def get_video_from_id(self, _id, category): + return find_object(self.get_categories_videos(category), id=u'%s#%s' % (_id, category)) + + def get_video_url(self, code): + params = [('partner', self.PARTNER_KEY), + ('format', 'json'), + ('mediafmt', 'mp4'), + ('code', code), + ('profile', 'large'), + ] + res = self.__do_request('media', params) + if res is None: + return + result = json.loads(res) + renditions = sorted(result['media']['rendition'], key=lambda x: 'bandwidth' in x and x['bandwidth']['code'], reverse=True) + return max(renditions, key=lambda x: 'bandwidth' in x)['href'] + + def get_emissions(self, basename): + params = [('partner', self.PARTNER_KEY), + ('format', 'json'), + ('filter', 'acshow'), + ] + res = self.__do_request('termlist', params) + if res is None: + return + result = json.loads(res) + for emission in result['feed']['term']: + yield Collection([basename, unicode(emission['nameShort'])], unicode(emission['$'])) diff --git a/modules/allocine/module.py b/modules/allocine/module.py index 0b7eb44b..aec9cd16 100644 --- a/modules/allocine/module.py +++ b/modules/allocine/module.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . +from weboob.capabilities.video import CapVideo, BaseVideo +from weboob.capabilities.collection import CapCollection, CollectionNotFound, Collection from weboob.capabilities.cinema import CapCinema, Person, Movie from weboob.tools.backend import Module @@ -25,7 +27,7 @@ from .browser import AllocineBrowser __all__ = ['AllocineModule'] -class AllocineModule(Module, CapCinema): +class AllocineModule(Module, CapCinema, CapVideo, CapCollection): NAME = 'allocine' MAINTAINER = u'Julien Veyssier' EMAIL = 'julien.veyssier@aiur.fr' @@ -108,7 +110,72 @@ class AllocineModule(Module, CapCinema): return movie + def fill_video(self, video, fields): + if 'url' in fields: + with self.browser: + if not isinstance(video, BaseVideo): + video = self.get_video(self, video.id) + + if hasattr(video, '_video_code'): + video.url = self.browser.get_video_url(video._video_code) + + if 'thumbnail' in fields and video and video.thumbnail: + with self.browser: + video.thumbnail.data = self.browser.readurl(video.thumbnail.url) + return video + + def get_video(self, _id): + with self.browser: + split_id = _id.split('#') + if split_id[-1] == 'movir': + return self.browser.get_movie_from_id(split_id[0]) + return self.browser.get_video_from_id(split_id[0], split_id[-1]) + + def iter_resources(self, objs, split_path): + with self.browser: + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield Collection([u'comingsoon'], u'Films prochainement au cinéma') + yield Collection([u'nowshowing'], u'Films au cinéma') + yield Collection([u'acshow'], u'Émissions') + yield Collection([u'interview'], u'Interviews') + if collection.path_level == 1: + if collection.basename == u'acshow': + emissions = self.browser.get_emissions(collection.basename) + if emissions: + for emission in emissions: + yield emission + elif collection.basename == u'interview': + videos = self.browser.get_categories_videos(collection.basename) + if videos: + for video in videos: + yield video + else: + videos = self.browser.get_categories_movies(collection.basename) + if videos: + for video in videos: + yield video + if collection.path_level == 2: + videos = self.browser.get_categories_videos(':'.join(collection.split_path)) + if videos: + for video in videos: + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if collection.path_level == 1 and (collection.basename in + [u'comingsoon', u'nowshowing', u'acshow', u'interview']): + return + + if collection.path_level == 2 and collection.parent_path == [u'acshow']: + return + + raise CollectionNotFound(collection.split_path) + OBJECTS = { Person: fill_person, - Movie: fill_movie + Movie: fill_movie, + BaseVideo: fill_video } diff --git a/modules/allocine/test.py b/modules/allocine/test.py index 811ca844..d9b1db79 100644 --- a/modules/allocine/test.py +++ b/modules/allocine/test.py @@ -18,6 +18,7 @@ # along with weboob. If not, see . from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo import re @@ -85,3 +86,33 @@ class AllocineTest(BackendTest): assert len(persons_ids) > 0 for person_id in persons_ids: assert person_id + + def test_emissions(self): + l = list(self.backend.iter_resources([BaseVideo], [u'acshow'])) + assert len(l) + l1 = list(self.backend.iter_resources([BaseVideo], l[0].split_path)) + assert len(l1) + v = l1[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url, 'URL for video "%s" not found' % (v.id)) + + def test_interview(self): + l = list(self.backend.iter_resources([BaseVideo], [u'interview'])) + assert len(l) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url, 'URL for video "%s" not found' % (v.id)) + + def test_comingsoon(self): + l = list(self.backend.iter_resources([BaseVideo], [u'comingsoon'])) + assert len(l) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url, 'URL for video "%s" not found' % (v.id)) + + def test_nowshowing(self): + l = list(self.backend.iter_resources([BaseVideo], [u'nowshowing'])) + assert len(l) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url, 'URL for video "%s" not found' % (v.id))