class NetflixService:
    """Netflix addon service"""
    HOST_ADDRESS = '127.0.0.1'

    def __init__(self):
        self.library_updater = None
        self.nf_server_instance = None
        self.nf_server_thread = None

    def init_servers(self):
        """Initialize the HTTP server"""
        try:
            # Import modules here to intercept possible missing libraries on linux systems
            from resources.lib.services.http_server import NFThreadedTCPServer
            self.nf_server_instance = NFThreadedTCPServer(
                (self.HOST_ADDRESS, select_port('NF_SERVER')))
            self.nf_server_instance.allow_reuse_address = True
            self.nf_server_thread = threading.Thread(
                target=self.nf_server_instance.serve_forever)
            return True
        except Exception as exc:  # pylint: disable=broad-except
            LOG.error(
                'Background services do not start due to the following error')
            import traceback
            LOG.error(traceback.format_exc())
            if isinstance(exc, gaierror):
                message = (
                    'Something is wrong in your network localhost configuration.\r\n'
                    f'It is possible that the hostname {self.HOST_ADDRESS} can not be resolved.'
                )
            elif isinstance(exc, ImportError):
                message = (
                    'In your system is missing some required library to run Netflix.\r\n'
                    'Read how to install the add-on in the GitHub Readme.\r\n'
                    f'Error details: {exc}')
            else:
                message = str(exc)
            self._set_service_status('error', message)
        return False

    def start_services(self):
        """Start the background services"""
        from resources.lib.services.library_updater import LibraryUpdateService

        self.nf_server_instance.server_activate()
        self.nf_server_thread.start()
        LOG.info('[NF_SERVER] Thread started')

        self.library_updater = LibraryUpdateService()
        # We reset the value in case of any eventuality (add-on disabled, update, etc)
        WndHomeProps[WndHomeProps.CURRENT_DIRECTORY] = None
        # Mark the service as active
        self._set_service_status('running')
        if not G.ADDON.getSettingBool('disable_startup_notification'):
            from resources.lib.kodi.ui import show_notification
            show_notification(get_local_string(30110))

    def shutdown(self):
        """Stop the background services"""
        self._set_service_status('stopped')
        self.nf_server_instance.shutdown()
        self.nf_server_instance.server_close()
        self.nf_server_instance = None
        self.nf_server_thread.join()
        self.nf_server_thread = None
        LOG.info('Stopped MSL Service')

    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
            LOG.error(traceback.format_exc())
            show_addon_error_info(exc)
            return

        while not G.SETTINGS_MONITOR.abortRequested():
            if self._tick_and_wait_for_abort():
                break
        self.shutdown()

    def _tick_and_wait_for_abort(self):
        try:
            self.library_updater.on_service_tick()
            G.CACHE_MANAGEMENT.on_service_tick()
        except Exception as exc:  # pylint: disable=broad-except
            import traceback
            from resources.lib.kodi.ui import show_notification
            LOG.error(traceback.format_exc())
            show_notification(': '.join((exc.__class__.__name__, str(exc))))
        return G.SETTINGS_MONITOR.waitForAbort(1)

    def _set_service_status(self, status, message=None):
        """Save the service status to a Kodi property"""
        from json import dumps
        status = {'status': status, 'message': message}
        WndHomeProps[WndHomeProps.SERVICE_STATUS] = dumps(status)
Exemple #2
0
class NetflixService(object):
    """
    Netflix addon service
    """
    SERVERS = []
    HOST_ADDRESS = '127.0.0.1'

    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 init_servers(self):
        """Initialize the http servers"""
        try:
            # Import modules here to intercept possible missing libraries on linux systems
            from resources.lib.services.msl.http_server import MSLTCPServer
            from resources.lib.services.nfsession.http_server import NetflixTCPServer
            from resources.lib.services.cache.http_server import CacheTCPServer
            # Do not change the init order of the servers,
            # MSLTCPServer must always be initialized first to get the DRM info
            self.SERVERS = [{
                'name': 'MSL',
                'class': MSLTCPServer,
                'instance': None,
                'thread': None
            }, {
                'name': 'NS',
                'class': NetflixTCPServer,
                'instance': None,
                'thread': None
            }, {
                'name': 'CACHE',
                'class': CacheTCPServer,
                'instance': None,
                'thread': None
            }]

            for server in self.SERVERS:
                self._init_server(server)
            return True
        except Exception as exc:  # pylint: disable=broad-except
            error(
                'Background services do not start due to the following error')
            import traceback
            error(g.py2_decode(traceback.format_exc(), 'latin-1'))
            if isinstance(exc, gaierror):
                message = (
                    'Something is wrong in your network localhost configuration.\r\n'
                    'It is possible that the hostname {} can not be resolved.'
                ).format(self.HOST_ADDRESS)
            elif ImportError(exc, ImportError):
                message = (
                    'In your system is missing some required library to run Netflix.\r\n'
                    'Read how to install the add-on in the GitHub Readme.\r\n'
                    'Error details: {}'.format(exc))
            else:
                message = unicode(exc)
            self._set_service_status('error', message)
        return False

    def _init_server(self, server):
        server['class'].allow_reuse_address = True
        server['instance'] = server['class'](
            (self.HOST_ADDRESS, select_port(server['name'])))
        server['thread'] = threading.Thread(
            target=server['instance'].serve_forever)

    def start_services(self):
        """
        Start the background services
        """
        from resources.lib.services.playback.action_controller import ActionController
        from resources.lib.services.library_updater import LibraryUpdateService
        from resources.lib.services.settings_monitor import SettingsMonitor
        for server in self.SERVERS:
            server['instance'].server_activate()
            server['instance'].timeout = 1
            server['thread'].start()
            info('[{}] Thread started'.format(server['name']))
        self.controller = ActionController()
        self.library_updater = LibraryUpdateService()
        self.settings_monitor = SettingsMonitor()
        # Mark the service as active
        self._set_service_status('running')
        if not g.ADDON.getSettingBool('disable_startup_notification'):
            from resources.lib.kodi.ui import show_notification
            show_notification(get_local_string(30110))

    def shutdown(self):
        """
        Stop the background services
        """
        self._set_service_status('stopped')
        for server in self.SERVERS:
            server['instance'].shutdown()
            server['instance'].server_close()
            server['instance'] = None
            server['thread'].join()
            server['thread'] = None
        info('Stopped MSL Service')

    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 _tick_and_wait_for_abort(self):
        try:
            self.controller.on_service_tick()
            self.library_updater.on_service_tick()
            g.CACHE_MANAGEMENT.on_service_tick()
        except Exception as exc:  # pylint: disable=broad-except
            import traceback
            from resources.lib.kodi.ui import show_notification
            error(g.py2_decode(traceback.format_exc(), 'latin-1'))
            show_notification(': '.join(
                (exc.__class__.__name__, unicode(exc))))
        return self.controller.waitForAbort(1)

    def _set_service_status(self, status, message=None):
        """Save the service status to a Kodi property"""
        from json import dumps
        status = {'status': status, 'message': message}
        self.window_cls.setProperty(self.prop_nf_service_status, dumps(status))
class NetflixService(object):
    """
    Netflix addon service
    """
    from resources.lib.services.msl.http_server import MSLTCPServer
    from resources.lib.services.nfsession.http_server import NetflixTCPServer
    from resources.lib.services.cache.http_server import CacheTCPServer
    # Do not change the init order of the servers,
    # MSLTCPServer must always be initialized first to get the DRM info
    SERVERS = [{
        'name': 'MSL',
        'class': MSLTCPServer,
        'instance': None,
        'thread': None
    }, {
        'name': 'NS',
        'class': NetflixTCPServer,
        'instance': None,
        'thread': None
    }, {
        'name': 'CACHE',
        'class': CacheTCPServer,
        'instance': None,
        'thread': None
    }]

    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())
        for server in self.SERVERS:
            self.init_server(server)
        self.controller = None
        self.library_updater = None
        self.settings_monitor = None

    def init_server(self, server):
        server['class'].allow_reuse_address = True
        server['instance'] = server['class'](
            ('127.0.0.1', select_port(server['name'])))
        server['thread'] = threading.Thread(
            target=server['instance'].serve_forever)

    def start_services(self):
        """
        Start the background services
        """
        from resources.lib.services.playback.controller import PlaybackController
        from resources.lib.services.library_updater import LibraryUpdateService
        from resources.lib.services.settings_monitor import SettingsMonitor
        for server in self.SERVERS:
            server['instance'].server_activate()
            server['instance'].timeout = 1
            server['thread'].start()
            info('[{}] Thread started'.format(server['name']))
        self.controller = PlaybackController()
        self.library_updater = LibraryUpdateService()
        self.settings_monitor = SettingsMonitor()
        # Mark the service as active
        self.window_cls.setProperty(self.prop_nf_service_status, 'running')
        if not g.ADDON.getSettingBool('disable_startup_notification'):
            from resources.lib.kodi.ui import show_notification
            show_notification(get_local_string(30110))

    def shutdown(self):
        """
        Stop the background services
        """
        self.window_cls.setProperty(self.prop_nf_service_status, 'stopped')
        for server in self.SERVERS:
            server['instance'].shutdown()
            server['instance'].server_close()
            server['instance'] = None
            server['thread'].join()
            server['thread'] = None
        info('Stopped MSL Service')

    def run(self):
        """Main loop. Runs until xbmc.Monitor requests abort"""
        try:
            self.start_services()
        except Exception as exc:  # pylint: disable=broad-except
            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 _tick_and_wait_for_abort(self):
        try:
            self.controller.on_service_tick()
            self.library_updater.on_service_tick()
            g.CACHE_MANAGEMENT.on_service_tick()
        except Exception as exc:  # pylint: disable=broad-except
            import traceback
            from resources.lib.kodi.ui import show_notification
            error(traceback.format_exc())
            show_notification(': '.join(
                (exc.__class__.__name__, unicode(exc))))
        return self.controller.waitForAbort(1)