def run(argv): # pylint: disable=broad-except,ungrouped-imports # Initialize globals right away to avoid stale values from the last addon invocation. # Otherwise Kodi's reuseLanguageInvoker will cause some really quirky behavior! # PR: https://github.com/xbmc/xbmc/pull/13814 g.init_globals(argv) reset_log_level_global_var() info('Started (Version {})'.format(g.VERSION_RAW)) info('URL is {}'.format(g.URL)) success = True window_cls = Window(10000) # Kodi home window # If you use multiple Kodi profiles you need to distinguish the property of current profile prop_nf_service_status = g.py2_encode('nf_service_status_' + get_current_kodi_profile_name()) is_external_call = _check_addon_external_call(window_cls, prop_nf_service_status) service_status = _get_service_status(window_cls, prop_nf_service_status) if service_status.get('status') != 'running': if not is_external_call: if service_status.get('status') == 'error': # The services are not started due to an error exception from resources.lib.kodi.ui import show_error_info show_error_info( get_local_string(30105), get_local_string(30240).format( service_status.get('message')), False, False) else: # The services are not started yet from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: try: if _check_valid_credentials(): if g.IS_ADDON_FIRSTRUN: if check_addon_upgrade(): from resources.lib.config_wizard import run_addon_configuration run_addon_configuration() route([part for part in g.PATH.split('/') if part]) else: success = False except BackendNotReady: from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False except Exception as exc: import traceback from resources.lib.kodi.ui import show_addon_error_info error(g.py2_decode(traceback.format_exc(), 'latin-1')) show_addon_error_info(exc) success = False if not success: _handle_endofdirectory() log_time_trace()
def _login(self, modal_error_message=False): """Perform account login""" # If exists get the current esn value before extract a new session data current_esn = g.get_esn() try: # First we get the authentication url without logging in, required for login API call react_context = website.extract_json(self._get('login'), 'reactContext') auth_url = website.extract_api_data(react_context)['auth_url'] common.debug('Logging in...') login_response = self._post( 'login', data=_login_payload(common.get_credentials(), auth_url)) try: website.extract_session_data(login_response, validate=True, update_profiles=True) common.info('Login successful') ui.show_notification(common.get_local_string(30109)) self.update_session_data(current_esn) return True except (LoginValidateError, LoginValidateErrorIncorrectPassword) as exc: self.session.cookies.clear() common.purge_credentials() if not modal_error_message: raise ui.show_ok_dialog(common.get_local_string(30008), unicode(exc)) except InvalidMembershipStatusError: ui.show_error_info(common.get_local_string(30008), common.get_local_string(30180), False, True) except Exception: # pylint: disable=broad-except import traceback common.error(g.py2_decode(traceback.format_exc(), 'latin-1')) self.session.cookies.clear() raise return False
def error_catching_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as exc: ui.show_error_info(common.get_local_string(30028), unicode(exc), unknown_error=not(unicode(exc)), netflix_error=isinstance(exc, MSLError)) raise
def search_query(row_id, perpetual_range_start, dir_update_listing): """Perform the research""" # Get item from database search_item = G.LOCAL_DB.get_search_item(row_id) if not search_item: ui.show_error_info('Search error', 'Item not found in the database.') return False # Update the last access data (move on top last used items) if not perpetual_range_start: G.LOCAL_DB.update_search_item_last_access(row_id) # Perform the path call menu_data = G.MAIN_MENU_ITEMS['search'] search_type = search_item['Type'] if search_type == 'text': call_args = { 'menu_data': menu_data, 'search_term': search_item['Value'], 'pathitems': ['search', 'search', row_id], 'perpetual_range_start': perpetual_range_start } list_data, extra_data = common.make_call('get_video_list_search', call_args) elif search_type == 'audio_lang': call_args = { 'menu_data': menu_data, 'pathitems': ['search', 'search', row_id], 'perpetual_range_start': perpetual_range_start, 'context_name': 'spokenAudio', 'context_id': common.convert_from_string(search_item['Parameters'], dict)['lang_code'] } list_data, extra_data = common.make_call('get_video_list_sorted_sp', call_args) elif search_type == 'subtitles_lang': call_args = { 'menu_data': menu_data, 'pathitems': ['search', 'search', row_id], 'perpetual_range_start': perpetual_range_start, 'context_name': 'subtitles', 'context_id': common.convert_from_string(search_item['Parameters'], dict)['lang_code'] } list_data, extra_data = common.make_call('get_video_list_sorted_sp', call_args) elif search_type == 'genre_id': call_args = { 'menu_data': menu_data, 'pathitems': ['search', 'search', row_id], 'perpetual_range_start': perpetual_range_start, 'context_name': 'genres', 'context_id': common.convert_from_string(search_item['Parameters'], dict)['genre_id'] } list_data, extra_data = common.make_call('get_video_list_sorted_sp', call_args) else: raise NotImplementedError('Search type {} not implemented'.format(search_type)) # Show the results if not list_data: ui.show_notification(common.get_local_string(30407)) return False _search_results_directory(search_item['Value'], menu_data, list_data, extra_data, dir_update_listing) return True
def error_catching_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as exc: message = f'{exc.__class__.__name__}: {exc}' ui.show_error_info(common.get_local_string(30028), message, unknown_error=not message, netflix_error=isinstance(exc, MSLError)) raise
def run(argv): # Initialize globals right away to avoid stale values from the last addon invocation. # Otherwise Kodi's reuseLanguageInvoker will cause some really quirky behavior! # PR: https://github.com/xbmc/xbmc/pull/13814 G.init_globals(argv) LOG.info('Started (Version {})'.format(G.VERSION_RAW)) LOG.info('URL is {}'.format(G.URL)) success = True window_cls = Window(10000) # Kodi home window # If you use multiple Kodi profiles you need to distinguish the property of current profile prop_nf_service_status = G.py2_encode('nf_service_status_' + get_current_kodi_profile_name()) is_external_call = _check_addon_external_call(window_cls, prop_nf_service_status) service_status = _get_service_status(window_cls, prop_nf_service_status) if service_status.get('status') != 'running': if not is_external_call: if service_status.get('status') == 'error': # The services are not started due to an error exception from resources.lib.kodi.ui import show_error_info show_error_info( get_local_string(30105), get_local_string(30240).format( service_status.get('message')), False, False) else: # The services are not started yet from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: cancel_playback = False pathitems = [part for part in G.REQUEST_PATH.split('/') if part] if G.IS_ADDON_FIRSTRUN: is_first_run_install, cancel_playback = check_addon_upgrade() if is_first_run_install: from resources.lib.config_wizard import run_addon_configuration run_addon_configuration() if cancel_playback and G.MODE_PLAY in pathitems[:1]: # Temporary for migration library STRM to new format. todo: to be removed in future releases # When a user do the add-on upgrade, the first time that the add-on will be opened will be executed # the library migration. But if a user instead to open the add-on, try to play a video from Kodi # library, Kodi will open the old STRM file because the migration is executed after. success = False else: success = route(pathitems) if not success: from xbmcplugin import endOfDirectory endOfDirectory(handle=G.PLUGIN_HANDLE, succeeded=False) LOG.log_time_trace()
def error_catching_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except Exception as exc: if isinstance(exc, MSLError): message = g.py2_decode(str(exc)) else: message = str(exc) ui.show_error_info(common.get_local_string(30028), message, unknown_error=not message, netflix_error=isinstance(exc, MSLError)) raise
def search_query(row_id, perpetual_range_start, dir_update_listing): """Perform the research""" # Get item from database search_item = G.LOCAL_DB.get_search_item(row_id) if not search_item: ui.show_error_info('Search error', 'Item not found in the database.') return False # Update the last access data (move on top last used items) if not perpetual_range_start: G.LOCAL_DB.update_search_item_last_access(row_id) return exec_query(row_id, search_item['Type'], search_item['Parameters'], search_item['Value'], perpetual_range_start, dir_update_listing)
def rate_thumb(videoid, rating, track_id_jaw): """Rate a video on Netflix""" common.debug('Thumb rating {} as {}', videoid.value, rating) event_uuid = common.get_random_uuid() response = common.make_call( 'post', {'component': 'set_thumb_rating', 'data': { 'eventUuid': event_uuid, 'titleId': int(videoid.value), 'trackId': track_id_jaw, 'rating': rating, }}) if response.get('status', '') == 'success': ui.show_notification(common.get_local_string(30045).split('|')[rating]) else: common.error('Rating thumb error, response detail: {}', response) ui.show_error_info('Rating error', 'Error type: {}' + response.get('status', '--'), True, True)
def wrapper(*args, **kwargs): # pylint: disable=broad-except, ungrouped-imports success = False try: func(*args, **kwargs) success = True except BackendNotReady as exc_bnr: from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready(G.py2_decode(str(exc_bnr), 'latin-1')) except InputStreamHelperError as exc: from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog('InputStream Helper Add-on error', ( 'The operation has been cancelled.\r\n' 'InputStream Helper has generated an internal error:\r\n{}\r\n\r\n' 'Please report it to InputStream Helper github.'.format(exc))) except ( HttpError401, HttpErrorTimeout ) as exc: # HTTP error 401 Client Error: Unauthorized for url ... # HttpError401: This is a generic error, can happen when the http request for some reason has failed. # Known causes: # - Possible change of data format or wrong data in the http request (also in headers/params) # - Some current nf session data are not more valid (authURL/cookies/...) # HttpErrorTimeout: This error is raised by Requests ReadTimeout error, unknown causes from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog( get_local_string(30105), ('There was a communication problem with Netflix.[CR]' 'You can try the operation again or exit.[CR]' '(Error code: {})').format(exc.__class__.__name__)) except (MbrStatusNeverMemberError, MbrStatusFormerMemberError): from resources.lib.kodi.ui import show_error_info show_error_info(get_local_string(30008), get_local_string(30180), False, True) except Exception as exc: import traceback from resources.lib.kodi.ui import show_addon_error_info LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) show_addon_error_info(exc) finally: if not success: from xbmcplugin import endOfDirectory endOfDirectory(handle=G.PLUGIN_HANDLE, succeeded=False)
def run(argv): # Initialize globals right away to avoid stale values from the last addon invocation. # Otherwise Kodi's reuseLanguageInvoker will cause some really quirky behavior! # PR: https://github.com/xbmc/xbmc/pull/13814 G.init_globals(argv) LOG.info('Started (Version {})', G.VERSION_RAW) LOG.info('URL is {}', G.URL) success = True is_external_call = _check_addon_external_call() service_status = _get_service_status() if service_status.get('status') != 'running': if not is_external_call: if service_status.get('status') == 'error': # The services are not started due to an error exception from resources.lib.kodi.ui import show_error_info show_error_info(get_local_string(30105), get_local_string(30240).format(service_status.get('message')), False, False) else: # The services are not started yet from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: pathitems = [part for part in G.REQUEST_PATH.split('/') if part] if G.IS_ADDON_FIRSTRUN: is_first_run_install = check_addon_upgrade() if is_first_run_install: from resources.lib.config_wizard import run_addon_configuration run_addon_configuration() success = route(pathitems) if not success: from xbmcplugin import endOfDirectory endOfDirectory(handle=G.PLUGIN_HANDLE, succeeded=False) LOG.log_time_trace()
def login(self, modal_error_message=True): """Perform account login""" try: # First we get the authentication url without logging in, required for login API call react_context = website.extract_json(self.get('login'), 'reactContext') auth_url = website.extract_api_data(react_context)['auth_url'] LOG.debug('Logging in...') login_response = self.post('login', data=_login_payload( common.get_credentials(), auth_url)) try: website.extract_session_data(login_response, validate=True, update_profiles=True) LOG.info('Login successful') ui.show_notification(common.get_local_string(30109)) cookies.save(self.account_hash, self.session.cookies) return True except LoginValidateError as exc: self.session.cookies.clear() common.purge_credentials() if not modal_error_message: raise ui.show_ok_dialog(common.get_local_string(30008), unicode(exc)) except (MbrStatusNeverMemberError, MbrStatusFormerMemberError): if not modal_error_message: raise ui.show_error_info(common.get_local_string(30008), common.get_local_string(30180), False, True) except Exception: # pylint: disable=broad-except import traceback LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) self.session.cookies.clear() raise return False
def run(argv): # pylint: disable=broad-except,ungrouped-imports,too-many-branches # Initialize globals right away to avoid stale values from the last addon invocation. # Otherwise Kodi's reuseLanguageInvoker will cause some really quirky behavior! # PR: https://github.com/xbmc/xbmc/pull/13814 g.init_globals(argv) reset_log_level_global_var() info('Started (Version {})'.format(g.VERSION_RAW)) info('URL is {}'.format(g.URL)) success = True window_cls = Window(10000) # Kodi home window # If you use multiple Kodi profiles you need to distinguish the property of current profile prop_nf_service_status = g.py2_encode('nf_service_status_' + get_current_kodi_profile_name()) is_external_call = _check_addon_external_call(window_cls, prop_nf_service_status) service_status = _get_service_status(window_cls, prop_nf_service_status) if service_status.get('status') != 'running': if not is_external_call: if service_status.get('status') == 'error': # The services are not started due to an error exception from resources.lib.kodi.ui import show_error_info show_error_info( get_local_string(30105), get_local_string(30240).format( service_status.get('message')), False, False) else: # The services are not started yet from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: try: if _check_valid_credentials(): if g.IS_ADDON_FIRSTRUN: if check_addon_upgrade(): from resources.lib.config_wizard import run_addon_configuration run_addon_configuration() route([part for part in g.PATH.split('/') if part]) else: success = False except BackendNotReady: from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False except InputStreamHelperError as exc: from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog('InputStream Helper Add-on error', ( 'The operation has been cancelled.\r\n' 'InputStream Helper has generated an internal error:\r\n{}\r\n\r\n' 'Please report it to InputStream Helper github.'.format(exc))) success = False except HttpError401: # Http error 401 Client Error: Unauthorized for url ... issue (see _request in nfsession_requests.py) from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog(get_local_string(30105), ( 'There was a communication problem with Netflix.\r\n' 'This is a known and unresolvable issue, do not submit reports.\r\n' 'You can try the operation again or exit.')) success = False except Exception as exc: import traceback from resources.lib.kodi.ui import show_addon_error_info error(g.py2_decode(traceback.format_exc(), 'latin-1')) show_addon_error_info(exc) success = False if not success: _handle_endofdirectory() log_time_trace()
def run(argv): # pylint: disable=broad-except,ungrouped-imports,too-many-branches # Initialize globals right away to avoid stale values from the last addon invocation. # Otherwise Kodi's reuseLanguageInvoker will cause some really quirky behavior! # PR: https://github.com/xbmc/xbmc/pull/13814 G.init_globals(argv) reset_log_level_global_var() info('Started (Version {})'.format(G.VERSION_RAW)) info('URL is {}'.format(G.URL)) success = True window_cls = Window(10000) # Kodi home window # If you use multiple Kodi profiles you need to distinguish the property of current profile prop_nf_service_status = G.py2_encode('nf_service_status_' + get_current_kodi_profile_name()) is_external_call = _check_addon_external_call(window_cls, prop_nf_service_status) service_status = _get_service_status(window_cls, prop_nf_service_status) if service_status.get('status') != 'running': if not is_external_call: if service_status.get('status') == 'error': # The services are not started due to an error exception from resources.lib.kodi.ui import show_error_info show_error_info( get_local_string(30105), get_local_string(30240).format( service_status.get('message')), False, False) else: # The services are not started yet from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: try: cancel_playback = False pathitems = [part for part in G.REQUEST_PATH.split('/') if part] if G.IS_ADDON_FIRSTRUN: is_first_run_install, cancel_playback = check_addon_upgrade() if is_first_run_install: from resources.lib.config_wizard import run_addon_configuration run_addon_configuration() if cancel_playback and G.MODE_PLAY in pathitems[:1]: # Temporary for migration library STRM to new format. todo: to be removed in future releases # When a user do the add-on upgrade, the first time that the add-on will be opened will be executed # the library migration. But if a user instead to open the add-on, try to play a video from Kodi # library, Kodi will open the old STRM file because the migration is executed after. success = False else: success = route(pathitems) except BackendNotReady as exc_bnr: from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready(G.py2_decode(str(exc_bnr), 'latin-1')) success = False except InputStreamHelperError as exc: from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog('InputStream Helper Add-on error', ( 'The operation has been cancelled.\r\n' 'InputStream Helper has generated an internal error:\r\n{}\r\n\r\n' 'Please report it to InputStream Helper github.'.format(exc))) success = False except HttpError401: # HTTP error 401 Client Error: Unauthorized for url ... # This is a generic error, can happen when the http request for some reason has failed. # Known causes: # - Possible change of data format or wrong data in the http request (also in headers/params) # - Some current nf session data are not more valid (authURL/cookies/...) from resources.lib.kodi.ui import show_ok_dialog show_ok_dialog( get_local_string(30105), ('There was a communication problem with Netflix.\r\n' 'You can try the operation again or exit.')) success = False except (MbrStatusNeverMemberError, MbrStatusFormerMemberError): from resources.lib.kodi.ui import show_error_info show_error_info(get_local_string(30008), get_local_string(30180), False, True) success = False except Exception as exc: import traceback from resources.lib.kodi.ui import show_addon_error_info error(G.py2_decode(traceback.format_exc(), 'latin-1')) show_addon_error_info(exc) success = False if not success: from xbmcplugin import endOfDirectory endOfDirectory(handle=G.PLUGIN_HANDLE, succeeded=False) log_time_trace()