def make_http_call_cache(callname, params, data): """Make an IPC call via HTTP and wait for it to return. The contents of data will be expanded to kwargs and passed into the target function.""" try: # Python 3 from urllib.request import build_opener, install_opener, ProxyHandler, HTTPError, URLError, Request, urlopen except ImportError: # Python 2 from urllib2 import build_opener, install_opener, ProxyHandler, HTTPError, URLError, Request, urlopen import json # debug('Handling HTTP IPC call to {}'.format(callname)) # Note: On python 3, using 'localhost' slowdown the call (Windows OS is affected) not sure if it is an urllib issue url = 'http://127.0.0.1:{}/{}'.format(G.LOCAL_DB.get_value('cache_service_port', 8002), callname) install_opener(build_opener(ProxyHandler({}))) # don't use proxy for localhost r = Request(url=url, data=data, headers={'Params': json.dumps(params)}) try: result = urlopen(r, timeout=IPC_TIMEOUT_SECS).read() except HTTPError as exc: if exc.reason in exceptions.__dict__: raise_from(exceptions.__dict__[exc.reason], exc) raise_from(Exception('The service has returned: {}'.format(exc.reason)), exc) except URLError as exc: # On PY2 the exception message have to be decoded with latin-1 for system with symbolic characters err_msg = G.py2_decode(str(exc), 'latin-1') if '10049' in err_msg: err_msg += '\r\nPossible cause is wrong localhost settings in your operative system.' LOG.error(err_msg) raise_from(exceptions.BackendNotReady(G.py2_encode(err_msg, encoding='latin-1')), exc) return result
def _log(msg, level, *args, **kwargs): """Log a message to the Kodi logfile.""" if args or kwargs: msg = msg.format(*args, **kwargs) xbmc.log( G.py2_encode('[{identifier} ({handle})] {msg}'.format( identifier=G.ADDON_ID, handle=G.PLUGIN_HANDLE, msg=msg)), level)
def make_http_call(callname, data): """Make an IPC call via HTTP and wait for it to return. The contents of data will be expanded to kwargs and passed into the target function.""" from collections import OrderedDict try: # Python 3 from urllib.request import build_opener, install_opener, ProxyHandler, HTTPError, URLError, urlopen except ImportError: # Python 2 from urllib2 import build_opener, install_opener, ProxyHandler, HTTPError, URLError, urlopen import json LOG.debug('Handling HTTP IPC call to {}'.format(callname)) # Note: On python 3, using 'localhost' slowdown the call (Windows OS is affected) not sure if it is an urllib issue url = 'http://127.0.0.1:{}/{}'.format(G.LOCAL_DB.get_value('ns_service_port', 8001), callname) install_opener(build_opener(ProxyHandler({}))) # don't use proxy for localhost try: result = json.loads( urlopen(url=url, data=json.dumps(data).encode('utf-8'), timeout=IPC_TIMEOUT_SECS).read(), object_pairs_hook=OrderedDict) except HTTPError as exc: result = json.loads(exc.reason) except URLError as exc: # On PY2 the exception message have to be decoded with latin-1 for system with symbolic characters err_msg = G.py2_decode(str(exc), 'latin-1') if '10049' in err_msg: err_msg += '\r\nPossible cause is wrong localhost settings in your operative system.' LOG.error(err_msg) raise_from(exceptions.BackendNotReady(G.py2_encode(err_msg, encoding='latin-1')), exc) _raise_for_error(result) return result
def _get_error_details(decoded_response): err_message = 'Unhandled error check log.' err_number = None # Catch a chunk error if 'errordata' in decoded_response: err_data = json.loads( base64.standard_b64decode(decoded_response['errordata'])) err_message = err_data['errormsg'] err_number = err_data['internalcode'] # Catch a manifest error elif 'error' in decoded_response: if decoded_response['error'].get('errorDisplayMessage'): err_message = decoded_response['error']['errorDisplayMessage'] err_number = decoded_response['error'].get('bladeRunnerCode') # Catch a license error elif 'result' in decoded_response and isinstance( decoded_response.get('result'), list): if 'error' in decoded_response['result'][0]: if decoded_response['result'][0]['error'].get( 'errorDisplayMessage'): err_message = decoded_response['result'][0]['error'][ 'errorDisplayMessage'] err_number = decoded_response['result'][0]['error'].get( 'bladeRunnerCode') return G.py2_encode(err_message), err_number
def __getitem__(self, key): try: # If you use multiple Kodi profiles you need to distinguish the property of current profile return G.WND_KODI_HOME.getProperty( G.py2_encode('netflix_{}_{}'.format( get_current_kodi_profile_name(), key))) except Exception: # pylint: disable=broad-except return ''
def __init__(self): self.window_cls = Window(10000) # Kodi home window # If you use multiple Kodi profiles you need to distinguish the property of current profile self.prop_nf_service_status = G.py2_encode( 'nf_service_status_' + get_current_kodi_profile_name()) self.controller = None self.library_updater = None self.settings_monitor = None
def _get_error_details(decoded_response): # Catch a chunk error if 'errordata' in decoded_response: return G.py2_encode( json.loads(base64.standard_b64decode( decoded_response['errordata']))['errormsg']) # Catch a manifest error if 'error' in decoded_response: if decoded_response['error'].get('errorDisplayMessage'): return G.py2_encode( decoded_response['error']['errorDisplayMessage']) # Catch a license error if 'result' in decoded_response and isinstance( decoded_response.get('result'), list): if 'error' in decoded_response['result'][0]: if decoded_response['result'][0]['error'].get( 'errorDisplayMessage'): return G.py2_encode(decoded_response['result'][0]['error'] ['errorDisplayMessage']) return G.py2_encode('Unhandled error check log.')
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 convert_language_iso(from_value, iso_format=xbmc.ISO_639_1, use_fallback=True): """ Convert language code from an English name or three letter code (ISO 639-2) to two letter code (ISO 639-1) :param iso_format: specify the iso format (ISO_639_1 or ISO_639_2) :param use_fallback: if True when the conversion fails, is returned the current Kodi active language """ converted_lang = xbmc.convertLanguage(G.py2_encode(from_value), iso_format) if not use_fallback: return converted_lang converted_lang = converted_lang if converted_lang else xbmc.getLanguage(iso_format, False) # Get lang. active return converted_lang if converted_lang else 'en' if iso_format == xbmc.ISO_639_1 else 'eng'
def _convert_season(value): if isinstance(value, int): return str(value) # isdigit is needed to filter out non numeric characters from 'shortName' key return ''.join([n for n in G.py2_encode(value) if n.isdigit()])
def show_notification(msg, title='Netflix', time=3000): """Show a notification""" xbmc.executebuiltin( G.py2_encode('Notification({}, {}, {}, {})'.format( title, msg, time, G.ICON)))
def __setitem__(self, key, newvalue): # If you use multiple Kodi profiles you need to distinguish the property of current profile G.WND_KODI_HOME.setProperty( G.py2_encode('netflix_{}_{}'.format( get_current_kodi_profile_name(), key)), newvalue)
def play_media(media): """Play a media in Kodi""" xbmc.executebuiltin(G.py2_encode('PlayMedia({})'.format(media)))
def convert_language_iso(from_value, iso_format=xbmc.ISO_639_1): """ Convert given value (English name or two/three letter code) to the specified format :param iso_format: specify the iso format (two letter code ISO_639_1 or three letter code ISO_639_2) """ return xbmc.convertLanguage(G.py2_encode(from_value), iso_format)
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()