From: Sebastian Golasch Date: Fri, 10 Mar 2017 14:54:45 +0000 (+0100) Subject: fix(kids-profiles): Reenables Kids profiles after NEtflix API changes X-Git-Url: http://git.code-monkey.de/?p=plugin.video.netflix.git;a=commitdiff_plain;h=dfc7738380f5ce833063ce74e2c0ab9b82b84eae fix(kids-profiles): Reenables Kids profiles after NEtflix API changes --- diff --git a/addon.xml b/addon.xml index 7decf47..3bce2b8 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po index 29e881d..128f545 100644 --- a/resources/language/English/strings.po +++ b/resources/language/English/strings.po @@ -1,7 +1,7 @@ # Kodi Media Center language file # Addon Name: Netflix # Addon id: plugin.video.netflix -# Addon version: 0.11.1 +# Addon version: 0.11.2 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/language/German/strings.po b/resources/language/German/strings.po index d980b94..1d8d3a6 100644 --- a/resources/language/German/strings.po +++ b/resources/language/German/strings.po @@ -1,7 +1,7 @@ # Kodi Media Center language file # Addon Name: Netflix # Addon id: plugin.video.netflix -# Addon version: 0.11.1 +# Addon version: 0.11.2 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/lib/Navigation.py b/resources/lib/Navigation.py index 37fa6ec..c2ee4cc 100644 --- a/resources/lib/Navigation.py +++ b/resources/lib/Navigation.py @@ -160,7 +160,15 @@ class Navigation: user_list_id : :obj:`str` Type of list to display """ - video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids', 'type': type}) + # determine if we´re in kids mode + user_data = self.call_netflix_service({'method': 'get_user_data'}) + profiles = self.call_netflix_service({'method': 'list_profiles'}) + is_kids = profiles.get(user_data['guid']).get('isKids', False) + # fetch video lists + if is_kids == True: + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids_for_kids'}) + else: + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids', 'type': type}) # check for any errors if self._is_dirty_response(response=video_list_ids): return False @@ -257,13 +265,21 @@ class Navigation: if self.kodi_helper.has_cached_item(cache_id=cache_id): video_list_ids = self.kodi_helper.get_cached_item(cache_id=cache_id) else: + # determine if we´re in Kids profile mode + user_data = self.call_netflix_service({'method': 'get_user_data'}) + profiles = self.call_netflix_service({'method': 'list_profiles'}) + is_kids = profiles.get(user_data['guid']).get('isKids', False) # fetch video lists - video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids'}) + if is_kids == True: + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids_for_kids'}) + else: + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids'}) + # check for any errors if self._is_dirty_response(response=video_list_ids): return False - # parse the video list ids - self.kodi_helper.add_cached_item(cache_id=cache_id, contents=video_list_ids) + # cache the video list ids + #self.kodi_helper.add_cached_item(cache_id=cache_id, contents=video_list_ids) # defines an order for the user list, as Netflix changes the order at every request user_list_order = ['queue', 'continueWatching', 'topTen', 'netflixOriginals', 'trendingNow', 'newRelease', 'popularTitles'] # define where to route the user diff --git a/resources/lib/NetflixHttpSubRessourceHandler.py b/resources/lib/NetflixHttpSubRessourceHandler.py index 1c6d29e..4e7e1dd 100644 --- a/resources/lib/NetflixHttpSubRessourceHandler.py +++ b/resources/lib/NetflixHttpSubRessourceHandler.py @@ -23,6 +23,7 @@ class NetflixHttpSubRessourceHandler: self.netflix_session = netflix_session self.credentials = self.kodi_helper.get_credentials() self.video_list_cache = {} + self.lolomo = None # check if we have stored credentials, if so, do the login before the user requests it # if that is done, we cache the profiles @@ -67,6 +68,7 @@ class NetflixHttpSubRessourceHandler: """ self.profiles = [] self.credentials = {'email': '', 'password': ''} + self.lolomo = None return self.netflix_session.logout() def login (self, params): @@ -143,6 +145,24 @@ class NetflixHttpSubRessourceHandler: return video_list_ids_raw return self.netflix_session.parse_video_list_ids(response_data=video_list_ids_raw) + def fetch_video_list_ids_for_kids (self, params): + """Video list ids proxy function (thanks to Netflix that we need to use a different API for Kids profiles) + + Parameters + ---------- + params : :obj:`dict` of :obj:`str` + Request params + + Returns + ------- + :obj:`list` + Transformed response of the remote call + """ + if self.lolomo == None: + self.lolomo = self.netflix_session.get_lolomo_for_kids() + response = self.netflix_session.fetch_lists_for_kids(lolomo=self.lolomo) + return response + def fetch_video_list (self, params): """Video list proxy function @@ -284,6 +304,7 @@ class NetflixHttpSubRessourceHandler: Response of the remote call """ profile_id = params.get('profile_id', [''])[0] + self.lolomo = None return self.netflix_session.switch_profile(profile_id=profile_id, account=self.credentials) def get_user_data (self, params): diff --git a/resources/lib/NetflixSession.py b/resources/lib/NetflixSession.py index 59cfd5e..6f28de1 100644 --- a/resources/lib/NetflixSession.py +++ b/resources/lib/NetflixSession.py @@ -32,7 +32,8 @@ class NetflixSession: 'adult_pin': '/pin/service', 'metadata': '/metadata', 'set_video_rating': '/setVideoRating', - 'update_my_list': '/playlistop' + 'update_my_list': '/playlistop', + 'kids': '/Kids' } """:obj:`dict` of :obj:`str` List of all static endpoints for HTML/JSON POST/GET requests""" @@ -449,13 +450,13 @@ class NetflixSession: video_lists = response_data['lists'] for video_list_id in video_lists.keys(): video_list = video_lists[video_list_id] - if video_list['context'] == 'genre': - video_list_ids['genres'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) - elif video_list['context'] == 'similars' or video_list['context'] == 'becauseYouAdded': - video_list_ids['recommendations'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) - else: - video_list_ids['user'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) - + if video_list.get('context', False) != False: + if video_list['context'] == 'genre': + video_list_ids['genres'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) + elif video_list['context'] == 'similars' or video_list['context'] == 'becauseYouAdded': + video_list_ids['recommendations'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) + else: + video_list_ids['user'].update(self.parse_video_list_ids_entry(id=video_list_id, entry=video_list)) return video_list_ids def parse_video_list_ids_entry (self, id, entry): @@ -1330,6 +1331,48 @@ class NetflixSession: response = self._path_request(paths=paths) return self._process_response(response=response, component='Search results') + def get_lolomo_for_kids (self): + """Fetches the lolomo ID for Kids profiles + + Returns + ------- + :obj:`str` + Kids Lolomo ID + """ + response = self._session_get(component='kids') + for cookie in response.cookies: + if cookie.name.find('lhpuuidh-browse-' + self.user_data['guid']) != -1 and cookie.name.rfind('-T') == -1: + start = unquote(cookie.value).rfind(':') + return unquote(cookie.value)[start+1:] + return None + + def fetch_lists_for_kids (self, lolomo, list_from=0, list_to=50): + """Fetches the JSON which contains the contents of a the video list for kids users + + Parameters + ---------- + lolomo : :obj:`str` + Lolomo ID for the Kids profile + + list_from : :obj:`int` + Start entry for pagination + + list_to : :obj:`int` + Last entry for pagination + + Returns + ------- + :obj:`dict` of :obj:`dict` of :obj:`str` + Raw Netflix API call response or api call error + """ + paths = [ + ['lists', lolomo, {'from': list_from, 'to': list_to}, ['displayName', 'context', 'genreId', 'id', 'index', 'length']] + ] + + response = self._path_request(paths=paths) + res = self._process_response(response=response, component='Kids lists') + return self.parse_video_list_ids(response_data=res['value']) + def fetch_video_list (self, list_id, list_from=0, list_to=20): """Fetches the JSON which contains the contents of a given video list @@ -2178,9 +2221,9 @@ class NetflixSession: 'profileName', 'isActive', 'isFirstUse', - 'isAccountOwner' + 'isAccountOwner', + 'isKids' ] - # values are accessible via dict (sloppy parsing successfull) if type(netflix_page_data) == dict: for profile_id in netflix_page_data.get('profiles'):