def _skin_widget_call(window_cls): """ Workaround to intercept calls made by the Skin Widgets currently in use. Currently, the Skin widgets associated with add-ons are executed at Kodi startup immediately without respecting any services needed by the add-ons. This is causing different kinds of problems like widgets not loaded, add-on warning message, etc... this loop freeze the add-on instance until the service is ready. """ # Note to "Window.IsMedia": # All widgets will be either on Home or in a Custom Window, so "Window.IsMedia" will be false # When the user is browsing the plugin, Window.IsMedia will be true because video add-ons open # in MyVideoNav.xml (which is a Media window) # This is not a safe solution, because DEPENDS ON WHICH WINDOW IS OPEN, # for example it can fail if you open add-on video browser while widget is still loading. # Needed a proper solution by script.skinshortcuts / script.skin.helper.service, and forks limit_sec = 10 if not getCondVisibility("Window.IsMedia"): monitor = Monitor() sec_elapsed = 0 while not window_cls.getProperty('nf_service_status') == 'running': if sec_elapsed >= limit_sec or monitor.abortRequested() or monitor.waitForAbort(0.5): break sec_elapsed += 0.5 debug('Skin widget workaround enabled - time elapsed: {}', sec_elapsed) return True return False
def generate_pairing_code(): monitor = Monitor() progress = DialogProgress() progress.create(get_string(32000), get_string(32001)) chromecast = YoutubeCastV1() pairing_code = chromecast.pair() i = 0 if PY3: progress.update(i, message="{} {}".format(get_string(32002), pairing_code)) else: progress.update(i, get_string(32002), pairing_code) start_time = time.time() while not monitor.abortRequested( ) and not chromecast.has_client and not progress.iscanceled() and not ( time.time() - start_time) > (60 * 1): i += 10 if i > 100: i = 0 if PY3: progress.update(i, message="{} {}".format(get_string(32002), pairing_code)) else: progress.update(i, get_string(32002), pairing_code) monitor.waitForAbort(2) progress.close()
def autostart(): """ Starts the cleaning service. """ cleaner = Cleaner() monitor = Monitor() service_sleep = 4 # Lower than 4 causes too much stress on resource limited systems such as RPi ticker = 0 delayed_completed = False while not monitor.abortRequested(): if get_setting(service_enabled): scan_interval_ticker = get_setting(scan_interval) * 60 / service_sleep delayed_start_ticker = get_setting(delayed_start) * 60 / service_sleep if delayed_completed and ticker >= scan_interval_ticker: results = cleaner.clean_all() if results: notify(results) ticker = 0 elif not delayed_completed and ticker >= delayed_start_ticker: delayed_completed = True results = cleaner.clean_all() if results: notify(results) ticker = 0 xbmc.sleep(service_sleep * 1000) ticker += 1 else: xbmc.sleep(service_sleep * 1000) print("Abort requested. Terminating.") return
def run(self): debug('START player bg service') m = Monitor() while not m.abortRequested(): sleep(1000) try: self.periodical_check() except: debug('player bg service ERR {}'.format( traceback.format_exc())) debug('END player bg service')
def test_popup(window): popup = TestPopup(window, addon_path(), 'default', '1080i') popup.show() step = 0 wait = 100 timeout = 10000 monitor = Monitor() while popup and step < timeout and not monitor.abortRequested(): if popup.pause: continue sleep(wait) popup.update_progress_control(timeout, wait) step += wait
def _check_addon_external_call(window_cls, prop_nf_service_status): """Check system to verify if the calls to the add-on are originated externally""" # The calls that are made from outside do not respect and do not check whether the services required # for the add-on are actually working and operational, causing problems with the execution of the frontend. # A clear example are the Skin widgets, that are executed at Kodi startup immediately and this is cause of different # kinds of problems like widgets not loaded, add-on warning message, etc... # Cases where it can happen: # - Calls made by the Skin Widgets, Scripts, Kodi library # - Calls made by others Kodi windows (like file browser) # - Calls made by other add-ons # To try to solve the problem, when the service is not ready a loop will be started to freeze the add-on instance # until the service will be ready. is_other_plugin_name = getInfoLabel( 'Container.PluginName') != g.ADDON.getAddonInfo('id') limit_sec = 10 # Note to Kodi boolean condition "Window.IsMedia": # All widgets will be either on Home or in a Custom Window, so "Window.IsMedia" will be false # When the user is browsing the plugin, Window.IsMedia will be true because video add-ons open # in MyVideoNav.xml (which is a Media window) # This is not a safe solution, because DEPENDS ON WHICH WINDOW IS OPEN, # for example it can fail if you open add-on video browser while widget is still loading. # Needed a proper solution by script.skinshortcuts / script.skin.helper.service, and forks if is_other_plugin_name or not getCondVisibility("Window.IsMedia"): monitor = Monitor() sec_elapsed = 0 while not _get_service_status( window_cls, prop_nf_service_status).get('status') == 'running': if sec_elapsed >= limit_sec or monitor.abortRequested( ) or monitor.waitForAbort(0.5): break sec_elapsed += 0.5 debug( 'Add-on was initiated by an external call - workaround enabled time elapsed {}s', sec_elapsed) g.IS_ADDON_EXTERNAL_CALL = True return True return False
except IOError as ioe: log("removing unresponsive light %s" % light.label, level=LOGWARNING) unresponsive.append(light) for light in unresponsive: del self.lights[light] def log(msg, level=LOGNOTICE): xbmc.log("lifxbmc - %s" % msg.replace("\0", ""), level=level) # strings returned from lights sometimes have null chars if __name__ == '__main__': monitor = Monitor() player = LifxPlayer() log("inited") while not monitor.abortRequested(): if monitor.waitForAbort(10): break try: lifx = LifxLAN() for light, color in lifx.get_color_all_lights(): if len(addon.getSetting("group_filter")) > 0: pass if light not in player: log("discovered new light %s" % light.get_label()) player.add_light(light, color) except Exception as e: log("Exception while discovering lights: %s" % e, level=LOGERROR)
if __name__ == '__main__': monitor = Monitor() # start thread for MLS servie msl_thread = threading.Thread(target=msl_server.serve_forever) msl_thread.daemon = True msl_thread.start() # start thread for Netflix HTTP service nd_thread = threading.Thread(target=nd_server.serve_forever) nd_thread.daemon = True nd_thread.start() # kill the services if kodi monitor tells us to while not monitor.abortRequested(): if monitor.waitForAbort(5): msl_server.shutdown() nd_server.shutdown() break # MSL service shutdown sequence msl_server.server_close() msl_server.socket.close() msl_server.shutdown() kodi_helper.log(msg='Stopped MSL Service') # Netflix service shutdown sequence nd_server.server_close() nd_server.socket.close() nd_server.shutdown()
class Service(): server_online = True warn_auth = True user = None ws = None library = None plexCompanion = None user_running = False ws_running = False alexa_running = False library_running = False plexCompanion_running = False kodimonitor_running = False playback_starter_running = False image_cache_thread_running = False def __init__(self): # Initial logging LOG.info("======== START %s ========", v.ADDON_NAME) LOG.info("Platform: %s", v.PLATFORM) LOG.info("KODI Version: %s", v.KODILONGVERSION) LOG.info("%s Version: %s", v.ADDON_NAME, v.ADDON_VERSION) LOG.info("PKC Direct Paths: %s", settings('useDirectPaths') == "true") LOG.info("Number of sync threads: %s", settings('syncThreadNumber')) LOG.info("Full sys.argv received: %s", argv) self.monitor = Monitor() # Load/Reset PKC entirely - important for user/Kodi profile switch initialsetup.reload_pkc() def __stop_PKC(self): """ Kodi's abortRequested is really unreliable :-( """ return self.monitor.abortRequested() or state.STOP_PKC def ServiceEntryPoint(self): # Important: Threads depending on abortRequest will not trigger # if profile switch happens more than once. __stop_PKC = self.__stop_PKC monitor = self.monitor kodiProfile = v.KODI_PROFILE # Server auto-detect initialsetup.InitialSetup().setup() # Detect playback start early on self.command_pipeline = Monitor_Window() self.command_pipeline.start() # Initialize important threads, handing over self for callback purposes self.user = UserClient() self.ws = PMS_Websocket() self.alexa = Alexa_Websocket() self.library = LibrarySync() self.plexCompanion = PlexCompanion() self.specialMonitor = SpecialMonitor() self.playback_starter = Playback_Starter() self.playqueue = PlayqueueMonitor() if settings('enableTextureCache') == "true": self.image_cache_thread = Image_Cache_Thread() welcome_msg = True counter = 0 while not __stop_PKC(): if window('plex_kodiProfile') != kodiProfile: # Profile change happened, terminate this thread and others LOG.info( "Kodi profile was: %s and changed to: %s. " "Terminating old PlexKodiConnect thread.", kodiProfile, window('plex_kodiProfile')) break # Before proceeding, need to make sure: # 1. Server is online # 2. User is set # 3. User has access to the server if window('plex_online') == "true": # Plex server is online # Verify if user is set and has access to the server if (self.user.currUser is not None) and self.user.HasAccess: if not self.kodimonitor_running: # Start up events self.warn_auth = True if welcome_msg is True: # Reset authentication warnings welcome_msg = False dialog('notification', lang(29999), "%s %s" % (lang(33000), self.user.currUser), icon='{plex}', time=2000, sound=False) # Start monitoring kodi events self.kodimonitor_running = KodiMonitor() self.specialMonitor.start() # Start the Websocket Client if not self.ws_running: self.ws_running = True self.ws.start() # Start the Alexa thread if (not self.alexa_running and settings('enable_alexa') == 'true'): self.alexa_running = True self.alexa.start() # Start the syncing thread if not self.library_running: self.library_running = True self.library.start() # Start the Plex Companion thread if not self.plexCompanion_running: self.plexCompanion_running = True self.plexCompanion.start() if not self.playback_starter_running: self.playback_starter_running = True self.playback_starter.start() self.playqueue.start() if (not self.image_cache_thread_running and settings('enableTextureCache') == "true"): self.image_cache_thread_running = True self.image_cache_thread.start() else: if (self.user.currUser is None) and self.warn_auth: # Alert user is not authenticated and suppress future # warning self.warn_auth = False LOG.warn("Not authenticated yet.") # User access is restricted. # Keep verifying until access is granted # unless server goes offline or Kodi is shut down. while self.user.HasAccess is False: # Verify access with an API call self.user.hasAccess() if window('plex_online') != "true": # Server went offline break if monitor.waitForAbort(3): # Abort was requested while waiting. We should exit break else: # Wait until Plex server is online # or Kodi is shut down. while not self.__stop_PKC(): server = self.user.getServer() if server is False: # No server info set in add-on settings pass elif check_connection(server, verifySSL=True) is False: # Server is offline or cannot be reached # Alert the user and suppress future warning if self.server_online: self.server_online = False window('plex_online', value="false") # Suspend threads state.SUSPEND_LIBRARY_THREAD = True LOG.error("Plex Media Server went offline") if settings('show_pms_offline') == 'true': dialog('notification', lang(33001), "%s %s" % (lang(29999), lang(33002)), icon='{plex}', sound=False) counter += 1 # Periodically check if the IP changed, e.g. per minute if counter > 20: counter = 0 setup = initialsetup.InitialSetup() tmp = setup.pick_pms() if tmp is not None: setup.write_pms_to_settings(tmp) else: # Server is online counter = 0 if not self.server_online: # Server was offline when Kodi started. # Wait for server to be fully established. if monitor.waitForAbort(5): # Abort was requested while waiting. break self.server_online = True # Alert the user that server is online. if (welcome_msg is False and settings('show_pms_offline') == 'true'): dialog('notification', lang(29999), lang(33003), icon='{plex}', time=5000, sound=False) LOG.info("Server %s is online and ready.", server) window('plex_online', value="true") if state.AUTHENTICATED: # Server got offline when we were authenticated. # Hence resume threads state.SUSPEND_LIBRARY_THREAD = False # Start the userclient thread if not self.user_running: self.user_running = True self.user.start() break if monitor.waitForAbort(3): # Abort was requested while waiting. break if monitor.waitForAbort(0.05): # Abort was requested while waiting. We should exit break # Terminating PlexKodiConnect # Tell all threads to terminate (e.g. several lib sync threads) state.STOP_PKC = True window('plex_service_started', clear=True) LOG.info("======== STOP %s ========", v.ADDON_NAME)
class Service(): server_online = True warn_auth = True user = None ws = None library = None plexCompanion = None user_running = False ws_running = False alexa_running = False library_running = False plexCompanion_running = False kodimonitor_running = False playback_starter_running = False image_cache_thread_running = False def __init__(self): # Initial logging LOG.info("======== START %s ========", v.ADDON_NAME) LOG.info("Platform: %s", v.PLATFORM) LOG.info("KODI Version: %s", v.KODILONGVERSION) LOG.info("%s Version: %s", v.ADDON_NAME, v.ADDON_VERSION) LOG.info("PKC Direct Paths: %s", settings('useDirectPaths') == "true") LOG.info("Number of sync threads: %s", settings('syncThreadNumber')) LOG.info("Full sys.argv received: %s", argv) # Reset window props for profile switch properties = [ "plex_online", "plex_serverStatus", "plex_onWake", "plex_kodiScan", "plex_shouldStop", "plex_dbScan", "plex_initialScan", "plex_customplayqueue", "plex_playbackProps", "pms_token", "plex_token", "pms_server", "plex_machineIdentifier", "plex_servername", "plex_authenticated", "PlexUserImage", "useDirectPaths", "countError", "countUnauthorized", "plex_restricteduser", "plex_allows_mediaDeletion", "plex_command", "plex_result", "plex_force_transcode_pix" ] for prop in properties: window(prop, clear=True) # Clear video nodes properties videonodes.VideoNodes().clearProperties() # Init some stuff state.VERIFY_SSL_CERT = settings('sslverify') == 'true' state.SSL_CERT_PATH = settings('sslcert') \ if settings('sslcert') != 'None' else None state.FULL_SYNC_INTERVALL = int(settings('fullSyncInterval')) * 60 state.SYNC_THREAD_NUMBER = int(settings('syncThreadNumber')) state.SYNC_DIALOG = settings('dbSyncIndicator') == 'true' state.ENABLE_MUSIC = settings('enableMusic') == 'true' state.BACKGROUND_SYNC = settings( 'enableBackgroundSync') == 'true' state.BACKGROUNDSYNC_SAFTYMARGIN = int( settings('backgroundsync_saftyMargin')) state.REPLACE_SMB_PATH = settings('replaceSMB') == 'true' state.REMAP_PATH = settings('remapSMB') == 'true' set_replace_paths() state.KODI_PLEX_TIME_OFFSET = float(settings('kodiplextimeoffset')) window('plex_minDBVersion', value="2.0.0") set_webserver() self.monitor = Monitor() window('plex_kodiProfile', value=tryDecode(translatePath("special://profile"))) window('fetch_pms_item_number', value=settings('fetch_pms_item_number')) clientinfo.getDeviceId() def __stop_PKC(self): """ Kodi's abortRequested is really unreliable :-( """ return self.monitor.abortRequested() or state.STOP_PKC def ServiceEntryPoint(self): # Important: Threads depending on abortRequest will not trigger # if profile switch happens more than once. __stop_PKC = self.__stop_PKC monitor = self.monitor kodiProfile = v.KODI_PROFILE # Server auto-detect initialsetup.InitialSetup().setup() # Detect playback start early on self.command_pipeline = Monitor_Window() self.command_pipeline.start() # Initialize important threads, handing over self for callback purposes self.user = UserClient() self.ws = PMS_Websocket() self.alexa = Alexa_Websocket() self.library = LibrarySync() self.plexCompanion = PlexCompanion() self.specialMonitor = SpecialMonitor() self.playback_starter = Playback_Starter() self.playqueue = PlayqueueMonitor() if settings('enableTextureCache') == "true": self.image_cache_thread = Image_Cache_Thread() plx = PlexAPI.PlexAPI() welcome_msg = True counter = 0 while not __stop_PKC(): if window('plex_kodiProfile') != kodiProfile: # Profile change happened, terminate this thread and others LOG.info("Kodi profile was: %s and changed to: %s. " "Terminating old PlexKodiConnect thread." % (kodiProfile, window('plex_kodiProfile'))) break # Before proceeding, need to make sure: # 1. Server is online # 2. User is set # 3. User has access to the server if window('plex_online') == "true": # Plex server is online # Verify if user is set and has access to the server if (self.user.currUser is not None) and self.user.HasAccess: if not self.kodimonitor_running: # Start up events self.warn_auth = True if welcome_msg is True: # Reset authentication warnings welcome_msg = False dialog('notification', lang(29999), "%s %s" % (lang(33000), self.user.currUser), icon='{plex}', time=2000, sound=False) # Start monitoring kodi events self.kodimonitor_running = KodiMonitor() self.specialMonitor.start() # Start the Websocket Client if not self.ws_running: self.ws_running = True self.ws.start() # Start the Alexa thread if (not self.alexa_running and settings('enable_alexa') == 'true'): self.alexa_running = True self.alexa.start() # Start the syncing thread if not self.library_running: self.library_running = True self.library.start() # Start the Plex Companion thread if not self.plexCompanion_running: self.plexCompanion_running = True self.plexCompanion.start() if not self.playback_starter_running: self.playback_starter_running = True self.playback_starter.start() self.playqueue.start() if (not self.image_cache_thread_running and settings('enableTextureCache') == "true"): self.image_cache_thread_running = True self.image_cache_thread.start() else: if (self.user.currUser is None) and self.warn_auth: # Alert user is not authenticated and suppress future # warning self.warn_auth = False LOG.warn("Not authenticated yet.") # User access is restricted. # Keep verifying until access is granted # unless server goes offline or Kodi is shut down. while self.user.HasAccess is False: # Verify access with an API call self.user.hasAccess() if window('plex_online') != "true": # Server went offline break if monitor.waitForAbort(3): # Abort was requested while waiting. We should exit break else: # Wait until Plex server is online # or Kodi is shut down. while not self.__stop_PKC(): server = self.user.getServer() if server is False: # No server info set in add-on settings pass elif plx.CheckConnection(server, verifySSL=True) is False: # Server is offline or cannot be reached # Alert the user and suppress future warning if self.server_online: self.server_online = False window('plex_online', value="false") # Suspend threads state.SUSPEND_LIBRARY_THREAD = True LOG.error("Plex Media Server went offline") if settings('show_pms_offline') == 'true': dialog('notification', lang(33001), "%s %s" % (lang(29999), lang(33002)), icon='{plex}', sound=False) counter += 1 # Periodically check if the IP changed, e.g. per minute if counter > 20: counter = 0 setup = initialsetup.InitialSetup() tmp = setup.PickPMS() if tmp is not None: setup.WritePMStoSettings(tmp) else: # Server is online counter = 0 if not self.server_online: # Server was offline when Kodi started. # Wait for server to be fully established. if monitor.waitForAbort(5): # Abort was requested while waiting. break self.server_online = True # Alert the user that server is online. if (welcome_msg is False and settings('show_pms_offline') == 'true'): dialog('notification', lang(29999), lang(33003), icon='{plex}', time=5000, sound=False) LOG.info("Server %s is online and ready." % server) window('plex_online', value="true") if state.AUTHENTICATED: # Server got offline when we were authenticated. # Hence resume threads state.SUSPEND_LIBRARY_THREAD = False # Start the userclient thread if not self.user_running: self.user_running = True self.user.start() break if monitor.waitForAbort(3): # Abort was requested while waiting. break if monitor.waitForAbort(0.05): # Abort was requested while waiting. We should exit break # Terminating PlexKodiConnect # Tell all threads to terminate (e.g. several lib sync threads) state.STOP_PKC = True try: downloadutils.DownloadUtils().stopSession() except: pass window('plex_service_started', clear=True) LOG.info("======== STOP %s ========" % v.ADDON_NAME)
thumb_req_port = select_unused_port() ADDON.setSetting('thumbmail_port', str(thumb_req_port)) thumb_req_server = TCPServer(('127.0.0.1', thumb_req_port), ThumbRequestHandler) thumb_req_server.server_activate() thumb_req_server.timeout = 1 utils.log('Started 7Plus Thumbnail HTTP server on port {0}' .format(thumb_req_port)) if __name__ == '__main__': mon = Monitor() # start thread for thumbnail HTTP service thumb_req_thread = threading.Thread(target=thumb_req_server.serve_forever) thumb_req_thread.daemon = True thumb_req_thread.start() # kill the services if kodi monitor tells us to while not mon.abortRequested(): if mon.waitForAbort(5): thumb_req_server.shutdown() break # Netflix service shutdown sequence thumb_req_server.server_close() thumb_req_server.socket.close() thumb_req_server.shutdown() utils.log('Stopped 7Plus Thumbnail HTTP server')
if __name__ == '__main__': MONITOR = Monitor() # start thread for MLS servie MSL_THREAD = threading.Thread(target=MSL_SERVER.serve_forever) MSL_THREAD.daemon = True MSL_THREAD.start() # start thread for Netflix HTTP service NS_THREAD = threading.Thread(target=NS_SERVER.serve_forever) NS_THREAD.daemon = True NS_THREAD.start() # kill the services if kodi monitor tells us to while not MONITOR.abortRequested(): if MONITOR.waitForAbort(5): MSL_SERVER.shutdown() NS_SERVER.shutdown() break # MSL service shutdown sequence MSL_SERVER.server_close() MSL_SERVER.socket.close() MSL_SERVER.shutdown() KODI_HELPER.log(msg='Stopped MSL Service') # Netflix service shutdown sequence NS_SERVER.server_close() NS_SERVER.socket.close() NS_SERVER.shutdown()