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 c91478c9c..a7af9d36c 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
@@ -1965,7 +1964,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 @@
+
+