Esempio n. 1
0
 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()
Esempio n. 2
0
 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()
Esempio n. 4
0
    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()
Esempio n. 5
0
 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)
Esempio n. 6
0
    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()
Esempio n. 7
0
    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)
Esempio n. 10
0
 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)
Esempio n. 11
0
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)
Esempio n. 12
0
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()
Esempio n. 13
0
            '/'.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()
Esempio n. 14
0
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)
Esempio n. 15
0
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()