From: Sebastian Golasch Date: Thu, 16 Mar 2017 15:20:20 +0000 (+0100) Subject: feat(core): Add license, adapt to API changes, fix issues with KIDS profiles, fix... X-Git-Url: http://git.code-monkey.de/?p=plugin.video.netflix.git;a=commitdiff_plain;h=ac8e4930d5a58324df62285b0c5c440833784ad4 feat(core): Add license, adapt to API changes, fix issues with KIDS profiles, fix issues with prefetching and network unavailability, fix issues with cached lists between profiles --- diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e3fa8b2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Sebastian Golasch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addon.xml b/addon.xml index 3bce2b8..9cdf234 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -26,7 +26,14 @@ all MIT - http://www.kodinerds.net/ + http://www.kodinerds.net/index.php/Thread/55607-Inputstream-Agile-Betatest-Netflix/ https://github.com/asciidisco/plugin.video.netflix + v0.11.3 (2017-3-16) + - Added spanish and slowenian language files + - Added license file + - Adapted to latest API changes from Netflix + - Fixed issues with entering KIDS profiles + - Fixed prefetching started before network was available + - Fixed issues with cached lists when switching profiles diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po index 128f545..1d45254 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.2 +# Addon version: 0.11.3 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/language/German/strings.po b/resources/language/German/strings.po index 1d8d3a6..515cc5f 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.2 +# Addon version: 0.11.3 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/language/Slovak/strings.po b/resources/language/Slovak/strings.po index 2654d71..527d29d 100644 --- a/resources/language/Slovak/strings.po +++ b/resources/language/Slovak/strings.po @@ -1,7 +1,7 @@ # Kodi Media Center language file # Addon Name: Netflix # Addon id: plugin.video.netflix -# Addon version: 0.11.2 +# Addon version: 0.11.3 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/language/Spanish/strings.po b/resources/language/Spanish/strings.po index 572f8aa..b841a3b 100644 --- a/resources/language/Spanish/strings.po +++ b/resources/language/Spanish/strings.po @@ -1,7 +1,7 @@ # Kodi Media Center language file # Addon Name: Netflix # Addon id: plugin.video.netflix -# Addon version: 0.11.2 +# Addon version: 0.11.3 # Addon Provider: libdev + jojo + asciidisco msgid "" msgstr "" diff --git a/resources/lib/Navigation.py b/resources/lib/Navigation.py index c2ee4cc..1c9a9ab 100644 --- a/resources/lib/Navigation.py +++ b/resources/lib/Navigation.py @@ -145,7 +145,8 @@ class Navigation: bool If no results are available """ - search_contents = self.call_netflix_service({'method': 'search', 'term': term}) + user_data = self.call_netflix_service({'method': 'get_user_data'}) + search_contents = self.call_netflix_service({'method': 'search', 'term': term, 'guid': user_data['guid'], 'cache': True}) # check for any errors if self._is_dirty_response(response=search_contents): return False @@ -182,17 +183,11 @@ class Navigation: season_id : :obj:`str` ID of the season episodes should be displayed for """ - cache_id = 'episodes_' + season_id - if self.kodi_helper.has_cached_item(cache_id=cache_id): - episode_list = self.kodi_helper.get_cached_item(cache_id=cache_id) - else: - episode_list = self.call_netflix_service({'method': 'fetch_episodes_by_season', 'season_id': season_id}) - # check for any errors - if self._is_dirty_response(response=episode_list): - return False - # parse the raw Netflix data - self.kodi_helper.add_cached_item(cache_id=cache_id, contents=episode_list) - + user_data = self.call_netflix_service({'method': 'get_user_data'}) + episode_list = self.call_netflix_service({'method': 'fetch_episodes_by_season', 'season_id': season_id, 'guid': user_data['guid'], 'cache': True}) + # check for any errors + if self._is_dirty_response(response=episode_list): + return False # sort seasons by number (they´re coming back unsorted from the api) episodes_sorted = [] for episode_id in episode_list: @@ -215,19 +210,14 @@ class Navigation: bool If no seasons are available """ - cache_id = 'season_' + show_id - if self.kodi_helper.has_cached_item(cache_id=cache_id): - season_list = self.kodi_helper.get_cached_item(cache_id=cache_id) - else: - season_list = self.call_netflix_service({'method': 'fetch_seasons_for_show', 'show_id': show_id}) - # check for any errors - if self._is_dirty_response(response=season_list): - return False - # check if we have sesons, announced shows that are not available yet have none - if len(season_list) == 0: - return self.kodi_helper.build_no_seasons_available() - # parse the seasons raw response from Netflix - self.kodi_helper.add_cached_item(cache_id=cache_id, contents=season_list) + user_data = self.call_netflix_service({'method': 'get_user_data'}) + season_list = self.call_netflix_service({'method': 'fetch_seasons_for_show', 'show_id': show_id, 'guid': user_data['guid'], 'cache': True}) + # check for any errors + if self._is_dirty_response(response=season_list): + return False + # check if we have sesons, announced shows that are not available yet have none + if len(season_list) == 0: + return self.kodi_helper.build_no_seasons_available() # sort seasons by index by default (they´re coming back unsorted from the api) seasons_sorted = [] for season_id in season_list: @@ -246,40 +236,29 @@ class Navigation: type : :obj:`str` None or 'queue' f.e. when it´s a special video lists """ - if self.kodi_helper.has_cached_item(cache_id=video_list_id): - video_list = self.kodi_helper.get_cached_item(cache_id=video_list_id) - else: - video_list = self.call_netflix_service({'method': 'fetch_video_list', 'list_id': video_list_id}) - # check for any errors - if self._is_dirty_response(response=video_list): - return False - # parse the video list ids - if len(video_list) > 0: - self.kodi_helper.add_cached_item(cache_id=video_list_id, contents=video_list) + user_data = self.call_netflix_service({'method': 'get_user_data'}) + video_list = self.call_netflix_service({'method': 'fetch_video_list', 'list_id': video_list_id, 'guid': user_data['guid'] ,'cache': True}) + # check for any errors + if self._is_dirty_response(response=video_list): + return False actions = {'movie': 'play_video', 'show': 'season_list'} return self.kodi_helper.build_video_listing(video_list=video_list, actions=actions, type=type, build_url=self.build_url) def show_video_lists (self): """List the users video lists (recommendations, my list, etc.)""" - cache_id='main_menu' - if self.kodi_helper.has_cached_item(cache_id=cache_id): - video_list_ids = self.kodi_helper.get_cached_item(cache_id=cache_id) + # 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 + if is_kids == True: + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids_for_kids', 'guid': user_data['guid'], 'cache': True}) 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 - 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 - # cache the video list ids - #self.kodi_helper.add_cached_item(cache_id=cache_id, contents=video_list_ids) + video_list_ids = self.call_netflix_service({'method': 'fetch_video_list_ids', 'guid': user_data['guid'], 'cache': True}) + + # check for any errors + if self._is_dirty_response(response=video_list_ids): + return False # 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 @@ -433,7 +412,11 @@ class Navigation: # check and switch the profile if needed if self.check_for_designated_profile_change(params=params): self.kodi_helper.invalidate_memcache() - self.call_netflix_service({'method': 'switch_profile', 'profile_id': params['profile_id']}) + profile_id = params.get('profile_id', None) + if profile_id == None: + user_data = self.call_netflix_service({'method': 'get_user_data'}) + profile_id = user_data['guid'] + self.call_netflix_service({'method': 'switch_profile', 'profile_id': profile_id}) # check login, in case of main menu if 'action' not in params: self.establish_session(account=credentials) @@ -454,9 +437,12 @@ class Navigation: """ # check if we need to switch the user user_data = self.call_netflix_service({'method': 'get_user_data'}) + profiles = self.call_netflix_service({'method': 'list_profiles'}) if 'guid' not in user_data: return False current_profile_id = user_data['guid'] + if profiles.get(current_profile_id).get('isKids', False) == True: + return True return 'profile_id' in params and current_profile_id != params['profile_id'] def parse_paramters (self, paramstring): @@ -553,11 +539,19 @@ class Navigation: Netflix Service RPC result """ url_values = urllib.urlencode(params) + # check for cached items + if self.kodi_helper.has_cached_item(cache_id=url_values) and params.get('cache', False) == True: + self.log(msg='Fetching item from cache: (cache_id=' + url_values + ')') + return self.kodi_helper.get_cached_item(cache_id=url_values) url = self.get_netflix_service_url() full_url = url + '?' + url_values data = urllib2.urlopen(full_url).read() parsed_json = json.loads(data) - return parsed_json.get('result', None) + result = parsed_json.get('result', None) + if params.get('cache', False) == True: + self.log(msg='Adding item to cache: (cache_id=' + url_values + ')') + self.kodi_helper.add_cached_item(cache_id=url_values, contents=result) + return result def open_settings(self, url): """Opens a foreign settings dialog""" diff --git a/resources/lib/NetflixHttpSubRessourceHandler.py b/resources/lib/NetflixHttpSubRessourceHandler.py index 4e7e1dd..3c6e7e4 100644 --- a/resources/lib/NetflixHttpSubRessourceHandler.py +++ b/resources/lib/NetflixHttpSubRessourceHandler.py @@ -3,6 +3,8 @@ # Module: NetflixHttpSubRessourceHandler # Created on: 07.03.2017 +from urllib2 import urlopen, URLError + class NetflixHttpSubRessourceHandler: """ Represents the callable internal server routes & translates/executes them to requests for Netflix""" @@ -22,19 +24,29 @@ class NetflixHttpSubRessourceHandler: self.kodi_helper = kodi_helper self.netflix_session = netflix_session self.credentials = self.kodi_helper.get_credentials() + self.profiles = [] + self.prefetch_login() 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 - if self.credentials['email'] != '' and self.credentials['password'] != '': - if self.netflix_session.is_logged_in(account=self.credentials): - self.netflix_session.refresh_session_data(account=self.credentials) + def prefetch_login (self): + """Check if we have stored credentials. + If so, do the login before the user requests it + If that is done, we cache the profiles + """ + if self._network_availble(): + if self.credentials['email'] != '' and self.credentials['password'] != '': + if self.netflix_session.is_logged_in(account=self.credentials): + self.netflix_session.refresh_session_data(account=self.credentials) + self.profiles = self.netflix_session.profiles + else: + self.netflix_session.login(account=self.credentials) + self.profiles = self.netflix_session.profiles else: - self.netflix_session.login(account=self.credentials) - self.profiles = self.netflix_session.profiles + self.profiles = [] else: - self.profiles = [] + sleep(1) + self.prefetch_login() def is_logged_in (self, params): """Existing login proxy function @@ -366,3 +378,16 @@ class NetflixHttpSubRessourceHandler: if 'error' in raw_search_contents: return raw_search_contents return self.netflix_session.parse_video_list(response_data=raw_search_contents) + + def _network_availble(self): + """Check if the network is available + Returns + ------- + bool + Network can be accessed + """ + try: + urlopen('http://216.58.192.142', timeout=1) + return True + except URLError as err: + return False diff --git a/resources/lib/NetflixSession.py b/resources/lib/NetflixSession.py index 6f28de1..7fcea38 100644 --- a/resources/lib/NetflixSession.py +++ b/resources/lib/NetflixSession.py @@ -150,12 +150,12 @@ class NetflixSession: List of all the serialized data pulled out of the pagws