From d2768f28d6d68efa7c2d1f5cfad0d1b1eed5628e Mon Sep 17 00:00:00 2001 From: asciidisco Date: Tue, 10 Oct 2017 19:50:27 +0200 Subject: [PATCH] feat(video): Add ability to turn on the adult pin verification --- resources/language/English/strings.po | 4 ++ resources/language/German/strings.po | 4 ++ resources/lib/KodiHelper.py | 40 ++++++++++++++++++- resources/lib/Navigation.py | 30 ++++++++++++++ .../lib/NetflixHttpSubRessourceHandler.py | 16 ++++++++ resources/lib/NetflixSession.py | 19 +++++---- resources/settings.xml | 2 + 7 files changed, 103 insertions(+), 12 deletions(-) diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po index 169e35a1b..289200779 100644 --- a/resources/language/English/strings.po +++ b/resources/language/English/strings.po @@ -264,3 +264,7 @@ msgstr "" msgctxt "#30061" msgid "Update inside library" msgstr "" + +msgctxt "#30062" +msgid "Enable/disable adult pin. Active:" +msgstr "" \ No newline at end of file diff --git a/resources/language/German/strings.po b/resources/language/German/strings.po index f7e018251..35d64b1ab 100644 --- a/resources/language/German/strings.po +++ b/resources/language/German/strings.po @@ -252,3 +252,7 @@ msgstr "Aktiviere HEVC profile (z.b. für 4k in Android)" msgctxt "#30061" msgid "Update inside library" msgstr "In Bibliothek aktualisieren" + +msgctxt "#30062" +msgid "Enable/disable adult pin. Active:" +msgstr "Kindersicherungs PIN Abfrage ein-/ausschalten. Aktiv:" \ No newline at end of file diff --git a/resources/lib/KodiHelper.py b/resources/lib/KodiHelper.py index 6b6b38b7f..eed80f1fa 100644 --- a/resources/lib/KodiHelper.py +++ b/resources/lib/KodiHelper.py @@ -106,6 +106,29 @@ def show_rating_dialog (self): dlg = xbmcgui.Dialog() return dlg.numeric(heading=self.get_local_string(string_id=30019) + ' ' + self.get_local_string(string_id=30022), type=0) + def show_adult_pin_dialog (self): + """Asks the user for the adult pin + + Returns + ------- + :obj:`int` + 4 digit adult pin needed for adult movies + """ + dlg = xbmcgui.Dialog() + return dlg.input(self.get_local_string(string_id=30002), type=xbmcgui.INPUT_NUMERIC) + + def show_wrong_adult_pin_notification (self): + """Shows notification that a wrong adult pin was given + + Returns + ------- + bool + Dialog shown + """ + dialog = xbmcgui.Dialog() + dialog.notification(self.get_local_string(string_id=30006), self.get_local_string(string_id=30007), xbmcgui.NOTIFICATION_ERROR, 5000) + return True + def show_search_term_dialog (self): """Asks the user for a term to query the netflix search for @@ -301,6 +324,17 @@ def get_setting (self, key): """ return self.get_addon().getSetting(key) + def toggle_adult_pin(self): + """Toggles the adult pin setting""" + addon = self.get_addon() + adultpin_enabled = False + raw_adultpin_enabled = addon.getSetting('adultpin_enable') + if raw_adultpin_enabled == 'true' or raw_adultpin_enabled == 'True': + adultpin_enabled = True + if adultpin_enabled is False: + return addon.setSetting('adultpin_enable', 'True') + return addon.setSetting('adultpin_enable', 'False') + def get_credentials (self): """Returns the users stored credentials @@ -707,14 +741,16 @@ def build_video_listing (self, video_list, actions, type, build_url, has_more=Fa li = self._generate_context_menu_items(entry=video, li=li) # lists can be mixed with shows & movies, therefor we need to check if its a movie, so play it right away if video_list[video_list_id]['type'] == 'movie': - # it´s a movie, so we need no subfolder & a route to play it + # it´s a movie, so we need no subfolder & a route to play it isFolder = False - url = build_url({'action': 'play_video', 'video_id': video_list_id, 'infoLabels': infos}) + needs_pin = (True, False)[int(video['maturity']['level']) >= 1000] + url = build_url({'action': 'play_video', 'video_id': video_list_id, 'infoLabels': infos, 'pin': needs_pin}) view = VIEW_MOVIE else: # it´s a show, so we need a subfolder & route (for seasons) isFolder = True params = {'action': actions[video['type']], 'show_id': video_list_id} + params['pin'] = (True, False)[int(video['maturity']['level']) >= 1000] if 'tvshowtitle' in infos: params['tvshowtitle'] = base64.urlsafe_b64encode(infos.get('tvshowtitle', '').encode('utf-8')) url = build_url(params) diff --git a/resources/lib/Navigation.py b/resources/lib/Navigation.py index 2e4a8bb4c..38571d929 100644 --- a/resources/lib/Navigation.py +++ b/resources/lib/Navigation.py @@ -68,6 +68,13 @@ def router(self, paramstring): if self.establish_session(account=account) != True: return self.kodi_helper.show_login_failed_notification() + # switch user account + if 'action' in params.keys() and params['action'] == 'toggle_adult_pin': + adult_pin = self.kodi_helper.show_adult_pin_dialog() + if self._check_response(self.call_netflix_service({'method': 'send_adult_pin', 'pin': adult_pin})) != True: + return self.kodi_helper.show_wrong_adult_pin_notification() + return self.kodi_helper.toggle_adult_pin() + # check if we need to execute any actions before the actual routing # gives back a dict of options routes might need options = self.before_routing_action(params=params) @@ -145,6 +152,14 @@ def router(self, paramstring): # display the lists (recommendations, genres, etc.) return self.show_user_list(type=params['type']) elif params['action'] == 'play_video': + # play a video, check for adult pin if needed + adult_pin = None + ask_for_adult_pin = self.kodi_helper.get_setting('adultpin_enable').lower() == 'true' + if ask_for_adult_pin is True: + if self.check_for_adult_pin(params=params): + adult_pin = self.kodi_helper.show_adult_pin_dialog() + if self._check_response(self.call_netflix_service({'method': 'send_adult_pin', 'pin': adult_pin})) != True: + return self.kodi_helper.show_wrong_adult_pin_notification() self.play_video(video_id=params['video_id'], start_offset=params.get('start_offset', -1), infoLabels=params.get('infoLabels', {})) elif params['action'] == 'user-items' and params['type'] == 'search': # if the user requested a search, ask for the term @@ -472,6 +487,21 @@ def switch_account(self): return self.kodi_helper.show_login_failed_notification() return True + def check_for_adult_pin (self, params): + """Checks if an adult pin is given in the query params + + Parameters + ---------- + params : :obj:`dict` of :obj:`str` + Url query params + + Returns + ------- + bool + Adult pin parameter exists or not + """ + return (True, False)[params.get('pin') == 'True'] + @log def before_routing_action(self, params): """Executes actions before the actual routing takes place: diff --git a/resources/lib/NetflixHttpSubRessourceHandler.py b/resources/lib/NetflixHttpSubRessourceHandler.py index 3a91483b7..51a267012 100644 --- a/resources/lib/NetflixHttpSubRessourceHandler.py +++ b/resources/lib/NetflixHttpSubRessourceHandler.py @@ -281,6 +281,22 @@ def fetch_metadata (self, params): video_id = params.get('video_id', [''])[0] return self.netflix_session.fetch_metadata(id=video_id) + def send_adult_pin(self, params): + """Checks the adult pin + + Parameters + ---------- + params : :obj:`dict` of :obj:`str` + Request params + + Returns + ------- + :obj:`Requests.Response` + Response of the remote call + """ + pin = params.get('pin', [''])[0] + return self.netflix_session.send_adult_pin(pin=pin) + def switch_profile (self, params): """Switch profile proxy function diff --git a/resources/lib/NetflixSession.py b/resources/lib/NetflixSession.py index da973cc02..19bbf0285 100644 --- a/resources/lib/NetflixSession.py +++ b/resources/lib/NetflixSession.py @@ -289,7 +289,7 @@ def switch_profile (self, profile_id, account): self.user_data['guid'] = profile_id; return self._save_data(filename=self.data_path + '_' + account_hash) - def send_adult_pin (self, pin): + def send_adult_pin(self, pin): """Send the adult pin to Netflix in case an adult rated video requests it Note: Once entered, it should last for the complete session (Not so sure about this) @@ -309,16 +309,15 @@ def send_adult_pin (self, pin): """ payload = { 'pin': pin, - 'authURL': self.user_data['authURL'] + 'authURL': self.user_data.get('authURL', '') } - response = self._session_get(component='adult_pin', params=payload) + response = self._session_post(component='adult_pin', type='api', data=payload) pin_response = self._process_response(response=response, component=self._get_api_url_for(component='adult_pin')) - keys = pin_response.keys() - if 'success' in keys: - return True - if 'error' in keys: - return pin_response - return False + if 'error' in pin_response.keys(): + self.log(msg='Pin error') + self.log(msg=str(pin_response)) + return False + return pin_response.get('success', False) def add_to_list (self, video_id): """Adds a video to "my list" on Netflix @@ -1964,7 +1963,7 @@ def _session_post (self, component, type='document', data={}, headers={}, params :obj:`str` Contents of the field to match """ - url = self._get_document_url_for(component=component) if type == 'document' else self._get_api_url_for(component=component) + url = self._get_document_url_for(component=component) if type == 'document' else self._get_api_url_for(component=component) start = time() try: response = self.session.post(url=url, data=data, params=params, headers=headers, verify=self.verify_ssl) diff --git a/resources/settings.xml b/resources/settings.xml index d8e172ddc..db7c0201a 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -5,6 +5,8 @@ + +