def _init_database(self, initialize): # Initialize local database if initialize: import resources.lib.database.db_local as db_local self.LOCAL_DB = db_local.NFLocalDatabase() # Initialize shared database use_mysql = G.ADDON.getSettingBool('use_mysql') if initialize or use_mysql: import resources.lib.database.db_shared as db_shared from resources.lib.common.exceptions import DBMySQLConnectionError, DBMySQLError try: shared_db_class = db_shared.get_shareddb_class(use_mysql=use_mysql) self.SHARED_DB = shared_db_class() except (DBMySQLConnectionError, DBMySQLError) as exc: import resources.lib.kodi.ui as ui if isinstance(exc, DBMySQLError): # There is a problem with the database ui.show_addon_error_info(exc) # The MySQL database cannot be reached, fallback to local SQLite database # When this code is called from addon, is needed apply the change also in the # service, so disabling it run the SettingsMonitor self.ADDON.setSettingBool('use_mysql', False) ui.show_notification(self.ADDON.getLocalizedString(30206), time=10000) shared_db_class = db_shared.get_shareddb_class() self.SHARED_DB = shared_db_class()
def callback_event_video_queue(self, data=None): """Callback to add a video event""" try: self.add_event_to_queue(data['event_type'], data['event_data'], data['player_state']) except Exception as exc: # pylint: disable=broad-except import traceback from resources.lib.kodi.ui import show_addon_error_info LOG.error(traceback.format_exc()) show_addon_error_info(exc)
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)) 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) if window_cls.getProperty(prop_nf_service_status) != 'running': if not is_external_call: 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() if not is_external_call: update_cache_videoid_runtime(window_cls) 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(traceback.format_exc()) show_addon_error_info(exc) success = False if not success: _handle_endofdirectory() g.CACHE.commit() log_time_trace()
def run(self): """Main loop. Runs until xbmc.Monitor requests abort""" # pylint: disable=broad-except try: self.start_services() except Exception as exc: ui.show_addon_error_info(exc) return while not self.controller.abortRequested(): if self._tick_and_wait_for_abort(): break self.shutdown()
def parental_control(self, pathitems=None): # pylint: disable=unused-argument """Open parental control settings dialog""" password = ui.ask_for_password() if not password: return try: parental_control_data = api.get_parental_control_data(password) ui.show_modal_dialog(False, ui.xmldialogs.ParentalControl, 'plugin-video-netflix-ParentalControl.xml', g.ADDON.getAddonInfo('path'), **parental_control_data) except MissingCredentialsError: ui.show_ok_dialog('Netflix', common.get_local_string(30009)) except WebsiteParsingError as exc: ui.show_addon_error_info(exc)
def run(self): """Main loop. Runs until xbmc.Monitor requests abort""" try: self.start_services() except Exception as exc: # pylint: disable=broad-except self._set_service_status('stopped') 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) return while not self.controller.abortRequested(): if self._tick_and_wait_for_abort(): break self.shutdown()
def run(self): """Main loop. Runs until xbmc.Monitor requests abort""" # pylint: disable=broad-except try: self.start_services() except Exception as exc: self.window_cls.setProperty(self.prop_nf_service_status, 'stopped') import traceback from resources.lib.kodi.ui import show_addon_error_info error(traceback.format_exc()) show_addon_error_info(exc) return while not self.controller.abortRequested(): if self._tick_and_wait_for_abort(): break self.shutdown()
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)) info('URL is {}'.format(g.URL)) success = True window_cls = Window(10000) is_widget_skin_call = _skin_widget_call(window_cls) if window_cls.getProperty('nf_service_status') != 'running': if not is_widget_skin_call: from resources.lib.kodi.ui import show_backend_not_ready show_backend_not_ready() success = False if success: try: if _check_valid_credentials(): check_addon_upgrade() g.initial_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(traceback.format_exc()) show_addon_error_info(exc) success = False if not success: _handle_endofdirectory() g.CACHE.commit() log_time_trace()
def remove_item(self, job_data, library_home=None): # pylint: disable=unused-argument """Remove an item from the Kodi library, delete it from disk, remove add-on database references""" videoid = job_data['videoid'] LOG.debug('Removing {} ({}) from add-on library', videoid, job_data['title']) try: # Remove the STRM file exported exported_file_path = G.py2_decode( xbmc.translatePath(job_data['file_path'])) common.delete_file_safe(exported_file_path) parent_folder = G.py2_decode( xbmc.translatePath(os.path.dirname(exported_file_path))) # Remove the NFO file of the related STRM file nfo_file = os.path.splitext(exported_file_path)[0] + '.nfo' common.delete_file_safe(nfo_file) dirs, files = common.list_dir(parent_folder) # Remove the tvshow NFO file (only when it is the last file in the folder) tvshow_nfo_file = common.join_folders_paths( parent_folder, 'tvshow.nfo') # (users have the option of removing even single seasons) if xbmcvfs.exists(tvshow_nfo_file) and not dirs and len( files) == 1: xbmcvfs.delete(tvshow_nfo_file) # Delete parent folder xbmcvfs.rmdir(parent_folder) # Delete parent folder when empty if not dirs and not files: xbmcvfs.rmdir(parent_folder) # Remove videoid records from add-on database remove_videoid_from_db(videoid) except ItemNotFound: LOG.warn( 'The videoid {} not exists in the add-on library database', videoid) except Exception as exc: # pylint: disable=broad-except import traceback LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) ui.show_addon_error_info(exc)
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 remove_item(item_task, library_home=None): """Remove an item from the library and delete if from disk""" # pylint: disable=unused-argument, broad-except common.info('Removing {} from library', item_task['title']) exported_filename = xbmc.translatePath(item_task['filepath']) videoid = item_task['videoid'] common.debug('VideoId: {}', videoid) try: parent_folder = xbmc.translatePath(os.path.dirname(exported_filename)) if xbmcvfs.exists(exported_filename): xbmcvfs.delete(exported_filename) else: common.warn('Cannot delete {}, file does not exist', g.py2_decode(exported_filename)) # Remove the NFO files if exists nfo_file = os.path.splitext( g.py2_decode(exported_filename))[0] + '.nfo' if xbmcvfs.exists(nfo_file): xbmcvfs.delete(nfo_file) dirs, files = xbmcvfs.listdir(parent_folder) tvshow_nfo_file = xbmc.makeLegalFilename('/'.join( [g.py2_decode(parent_folder), 'tvshow.nfo'])) # Remove tvshow_nfo_file only when is the last file # (users have the option of removing even single seasons) if xbmcvfs.exists(tvshow_nfo_file) and not dirs and len(files) == 1: xbmcvfs.delete(tvshow_nfo_file) # Delete parent folder xbmcvfs.rmdir(parent_folder) # Delete parent folder when empty if not dirs and not files: xbmcvfs.rmdir(parent_folder) _remove_videoid_from_db(videoid) except ItemNotFound: common.warn('The video with id {} not exists in the database', videoid) except Exception as exc: import traceback common.error(traceback.format_exc()) ui.show_addon_error_info(exc)
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()
'/'.join(pathitems))) else: nav.execute(NAV_HANDLERS[root_handler], pathitems[1:], g.REQUEST_PARAMS) if __name__ == '__main__': # pylint: disable=broad-except # Initialize variables in common module scope # (necessary when reusing language invoker) common.info('Started (Version {})'.format(g.VERSION)) common.info('URL is {}'.format(g.URL)) success = False try: g.initial_addon_configuration() route(filter(None, g.PATH.split('/'))) success = True except common.BackendNotReady: ui.show_backend_not_ready() except Exception as exc: import traceback common.error(traceback.format_exc()) ui.show_addon_error_info(exc) if not success: xbmcplugin.endOfDirectory(g.PLUGIN_HANDLE, succeeded=success) g.CACHE.commit() common.log_time_trace()
def export_all_new_episodes(): """ Update the local Kodi library with new episodes of every exported shows """ from resources.lib.cache import CACHE_COMMON from resources.lib.database.db_exceptions import ProfilesMissing if _export_all_new_episodes_running(): return common.log('Starting to export new episodes for all tv shows') g.SHARED_DB.set_value('library_export_new_episodes_running', True) g.SHARED_DB.set_value('library_export_new_episode_start_time', datetime.now()) # Get the list of the tvshows exported to kodi library exported_videoids_values = g.SHARED_DB.get_tvshows_id_list() # Get the list of the tvshows exported but to exclude from updates excluded_videoids_values = g.SHARED_DB.get_tvshows_id_list( VidLibProp.exclude_update, True) # Before start to get updated mylist items, you have to select the owner account # TODO: in the future you can also add the possibility to synchronize from a chosen profile try: guid_owner_profile = g.LOCAL_DB.get_guid_owner_profile() except ProfilesMissing as exc: import traceback common.error(traceback.format_exc()) ui.show_addon_error_info(exc) return if guid_owner_profile != g.LOCAL_DB.get_active_profile_guid(): common.debug('Switching to owner account profile') api.activate_profile(guid_owner_profile) # Retrieve updated items from "my list" # Invalidate my-list cached data to force to obtain new data g.CACHE.invalidate_entry(CACHE_COMMON, 'my_list_items') mylist_videoids = api.mylist_items() # Check if any tvshow have been removed from the mylist for videoid_value in exported_videoids_values: if any(videoid.value == unicode(videoid_value) for videoid in mylist_videoids): continue # Tvshow no more exist in mylist so remove it from library videoid = common.VideoId.from_path( [common.VideoId.SHOW, videoid_value]) execute_library_tasks_silently(videoid, [remove_item], sync_mylist=False) # Update or add tvshow in kodi library for videoid in mylist_videoids: # Only tvshows require be updated if videoid.mediatype != common.VideoId.SHOW: continue if videoid.value in excluded_videoids_values: continue if videoid.value in exported_videoids_values: # It is possible that the user has chosen not to export nfo for a tvshow nfo_export = g.SHARED_DB.get_tvshow_property( videoid.value, VidLibProp.nfo_export, False) nfo_settings = nfo.NFOSettings(nfo_export) else: nfo_settings = nfo.NFOSettings() export_new_episodes(videoid, True, nfo_settings) # add some randomness between show analysis to limit servers load and ban risks xbmc.sleep(random.randint(1000, 5001)) g.SHARED_DB.set_value('library_export_new_episodes_running', False) if not g.ADDON.getSettingBool('disable_library_sync_notification'): ui.show_notification(common.get_local_string(30220), time=5000) common.debug('Notify service to update the library') common.send_signal(common.Signals.LIBRARY_UPDATE_REQUESTED)
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()