diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index 282c5104..7a6ce0c6 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -2566,7 +2566,6 @@ class API(): if forceCheck is False: # Validate the path is correct with user intervention if self.askToValidate(path): - import state state.STOP_SYNC = True path = None window('plex_pathverified', value='true') diff --git a/resources/lib/PlexCompanion.py b/resources/lib/PlexCompanion.py index 48f6e831..af2971e8 100644 --- a/resources/lib/PlexCompanion.py +++ b/resources/lib/PlexCompanion.py @@ -7,14 +7,13 @@ from urllib import urlencode from xbmc import sleep, executebuiltin -from utils import settings, ThreadMethods +from utils import settings, thread_methods from plexbmchelper import listener, plexgdm, subscribers, functions, \ httppersist, plexsettings from PlexFunctions import ParseContainerKey, GetPlexMetadata from PlexAPI import API import player import variables as v -import state ############################################################################### @@ -23,7 +22,7 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_suspends=[state.PMS_STATUS]) +@thread_methods(add_suspends=['PMS_STATUS']) class PlexCompanion(Thread): """ """ diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index 4a6e352d..54e1d9a3 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -13,8 +13,7 @@ from xbmc import executeJSONRPC, sleep, translatePath from xbmcvfs import exists from utils import window, settings, language as lang, kodiSQL, tryEncode, \ - ThreadMethods, dialog, exists_dir -import state + thread_methods, dialog, exists_dir # Disable annoying requests warnings import requests.packages.urllib3 @@ -127,8 +126,8 @@ def double_urldecode(text): return unquote(unquote(text)) -@ThreadMethods(add_stops=[state.STOP_SYNC], - add_suspends=[state.SUSPEND_LIBRARY_THREAD, state.DB_SCAN]) +@thread_methods(add_stops=['STOP_SYNC'], + add_suspends=['SUSPEND_LIBRARY_THREAD', 'DB_SCAN']) class Image_Cache_Thread(Thread): xbmc_host = 'localhost' xbmc_port, xbmc_username, xbmc_password = setKodiWebServerDetails() diff --git a/resources/lib/command_pipeline.py b/resources/lib/command_pipeline.py index 9be330a6..2d6dcb35 100644 --- a/resources/lib/command_pipeline.py +++ b/resources/lib/command_pipeline.py @@ -6,7 +6,7 @@ from Queue import Queue from xbmc import sleep -from utils import window, ThreadMethods +from utils import window, thread_methods import state ############################################################################### @@ -15,7 +15,7 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods +@thread_methods class Monitor_Window(Thread): """ Monitors window('plex_command') for new entries that we need to take care diff --git a/resources/lib/library_sync/fanart.py b/resources/lib/library_sync/fanart.py index 483da89a..1fdcb4e7 100644 --- a/resources/lib/library_sync/fanart.py +++ b/resources/lib/library_sync/fanart.py @@ -5,11 +5,10 @@ from Queue import Empty from xbmc import sleep -from utils import ThreadMethods, window +from utils import thread_methods import plexdb_functions as plexdb import itemtypes import variables as v -import state ############################################################################### @@ -18,8 +17,8 @@ log = getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_suspends=[state.SUSPEND_LIBRARY_THREAD, state.DB_SCAN], - add_stops=[state.STOP_SYNC]) +@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD', 'DB_SCAN'], + add_stops=['STOP_SYNC']) class Process_Fanart_Thread(Thread): """ Threaded download of additional fanart in the background diff --git a/resources/lib/library_sync/get_metadata.py b/resources/lib/library_sync/get_metadata.py index 4aa44266..ed3e187e 100644 --- a/resources/lib/library_sync/get_metadata.py +++ b/resources/lib/library_sync/get_metadata.py @@ -5,10 +5,9 @@ from Queue import Empty from xbmc import sleep -from utils import ThreadMethods, window +from utils import thread_methods, window from PlexFunctions import GetPlexMetadata, GetAllPlexChildren import sync_info -import state ############################################################################### @@ -17,7 +16,7 @@ log = getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD]) +@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD']) class Threaded_Get_Metadata(Thread): """ Threaded download of Plex XML metadata for a certain library item. diff --git a/resources/lib/library_sync/process_metadata.py b/resources/lib/library_sync/process_metadata.py index 7b44ed33..c4c599a4 100644 --- a/resources/lib/library_sync/process_metadata.py +++ b/resources/lib/library_sync/process_metadata.py @@ -5,10 +5,9 @@ from Queue import Empty from xbmc import sleep -from utils import ThreadMethods +from utils import thread_methods import itemtypes import sync_info -import state ############################################################################### log = getLogger("PLEX."+__name__) @@ -16,7 +15,7 @@ log = getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD]) +@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD']) class Threaded_Process_Metadata(Thread): """ Not yet implemented for more than 1 thread - if ever. Only to be called by diff --git a/resources/lib/library_sync/sync_info.py b/resources/lib/library_sync/sync_info.py index 13caec52..b2dd98d8 100644 --- a/resources/lib/library_sync/sync_info.py +++ b/resources/lib/library_sync/sync_info.py @@ -4,8 +4,7 @@ from threading import Thread, Lock from xbmc import sleep -from utils import ThreadMethods, language as lang -import state +from utils import thread_methods, language as lang ############################################################################### @@ -19,7 +18,7 @@ LOCK = Lock() ############################################################################### -@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD]) +@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD']) class Threaded_Show_Sync_Info(Thread): """ Threaded class to show the Kodi statusbar of the metadata download. diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index c1362531..71fb096a 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -10,7 +10,7 @@ import xbmcgui from xbmcvfs import exists from utils import window, settings, getUnixTimestamp, sourcesXML,\ - ThreadMethods, create_actor_db_index, dialog, LogTime, getScreensaver,\ + thread_methods, create_actor_db_index, dialog, LogTime, getScreensaver,\ setScreensaver, playlistXSP, language as lang, DateToKodi, reset,\ advancedsettings_tweaks, tryDecode, deletePlaylists, deleteNodes import downloadutils @@ -38,8 +38,8 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_stops=[state.STOP_SYNC], - add_suspends=[state.SUSPEND_LIBRARY_THREAD]) +@thread_methods(add_stops=['STOP_SYNC'], + add_suspends=['SUSPEND_LIBRARY_THREAD']) class LibrarySync(Thread): """ """ diff --git a/resources/lib/playqueue.py b/resources/lib/playqueue.py index 7e716559..8c156482 100644 --- a/resources/lib/playqueue.py +++ b/resources/lib/playqueue.py @@ -5,13 +5,12 @@ from threading import RLock, Thread from xbmc import sleep, Player, PlayList, PLAYLIST_MUSIC, PLAYLIST_VIDEO -from utils import window, ThreadMethods +from utils import window, thread_methods import playlist_func as PL from PlexFunctions import ConvertPlexToKodiTime, GetAllPlexChildren from PlexAPI import API from playbackutils import PlaybackUtils import variables as v -import state ############################################################################### log = logging.getLogger("PLEX."+__name__) @@ -22,7 +21,7 @@ PLUGIN = 'plugin://%s' % v.ADDON_ID ############################################################################### -@ThreadMethods(add_suspends=[state.PMS_STATUS]) +@thread_methods(add_suspends=['PMS_STATUS']) class Playqueue(Thread): """ Monitors Kodi's playqueues for changes on the Kodi side diff --git a/resources/lib/state.py b/resources/lib/state.py index 6d9df0be..46bf020a 100644 --- a/resources/lib/state.py +++ b/resources/lib/state.py @@ -4,13 +4,14 @@ # Quit PKC STOP_PKC = False + # Usually triggered by another Python instance - will have to be set (by # polling window) through e.g. librarysync thread SUSPEND_LIBRARY_THREAD = False # Set if user decided to cancel sync STOP_SYNC = False -# Set if a Plex-Kodi DB sync is being done - along with window('plex_dbScan') -# set to 'true' +# Set if a Plex-Kodi DB sync is being done - along with +# window('plex_dbScan') set to 'true' DB_SCAN = False # Plex Media Server Status - along with window('plex_serverStatus') PMS_STATUS = False diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index 5757c702..e544dd3a 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -10,7 +10,7 @@ import xbmcaddon from xbmcvfs import exists -from utils import window, settings, language as lang, ThreadMethods +from utils import window, settings, language as lang, thread_methods import downloadutils import PlexAPI @@ -24,7 +24,7 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_suspends=[state.SUSPEND_USER_CLIENT]) +@thread_methods(add_suspends=['SUSPEND_USER_CLIENT']) class UserClient(threading.Thread): # Borg - multiple instances, shared state diff --git a/resources/lib/utils.py b/resources/lib/utils.py index f362a957..b767b25d 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -86,7 +86,7 @@ def plex_command(key, value): value: either 'True' or 'False' """ while window('plex_command'): - xbmc.sleep(1) + xbmc.sleep(5) window('plex_command', value='%s-%s' % (key, value)) @@ -920,7 +920,7 @@ def LogTime(func): return wrapper -def ThreadMethods(cls=None, add_stops=None, add_suspends=None): +def thread_methods(cls=None, add_stops=None, add_suspends=None): """ Decorator to add the following methods to a threading class: @@ -928,52 +928,69 @@ def ThreadMethods(cls=None, add_stops=None, add_suspends=None): resume_thread(): resumes the thread stop_thread(): stopps/kills the thread - thread_suspended(): returns True if thread is suspend_thread + thread_suspended(): returns True if thread is suspended thread_stopped(): returns True if thread is stopped (or should stop ;-)) - ALSO stops if PKC should exit + ALSO returns True if PKC should exit Also adds the following class attributes: - _thread_stopped - _thread_suspended + __thread_stopped + __thread_suspended + __stops + __suspends invoke with either - @NewThreadMethods + @Newthread_methods class MyClass(): or - @NewThreadMethods(add_stops=[state.SUSPEND_LIBRARY_TRHEAD], - add_suspends=[state.WHATEVER, state.WHATEVER2]) + @Newthread_methods(add_stops=['SUSPEND_LIBRARY_TRHEAD'], + add_suspends=['DB_SCAN', 'WHATEVER']) class MyClass(): """ + # So we don't need to invoke with () if cls is None: - return partial(ThreadMethods, + return partial(thread_methods, add_stops=add_stops, add_suspends=add_suspends) - # Make sure we have an iterable - add_stops = add_stops or [] - add_suspends = add_suspends or [] + # Because we need a reference, not a copy of the immutable objects in + # state, we need to look up state every time explicitly + cls.__stops = ['STOP_PKC'] + if add_stops is not None: + cls.__stops.extend(add_stops) + cls.__suspends = add_suspends or [] + # Attach new attributes to class - cls._thread_stopped = False - cls._thread_suspended = False + cls.__thread_stopped = False + cls.__thread_suspended = False # Define new class methods and attach them to class def stop_thread(self): - self._thread_stopped = True + self.__thread_stopped = True cls.stop_thread = stop_thread def suspend_thread(self): - self._thread_suspended = True + self.__thread_suspended = True cls.suspend_thread = suspend_thread def resume_thread(self): - self._thread_suspended = False + self.__thread_suspended = False cls.resume_thread = resume_thread def thread_suspended(self): - return self._thread_suspended or any(add_suspends) + if self.__thread_suspended is True: + return True + for suspend in self.__suspends: + if getattr(state, suspend): + return True + return False cls.thread_suspended = thread_suspended def thread_stopped(self): - return self._thread_stopped or state.STOP_PKC or any(add_stops) + if self.__thread_stopped is True: + return True + for stop in self.__stops: + if getattr(state, stop): + return True + return False cls.thread_stopped = thread_stopped # Return class to render this a decorator diff --git a/resources/lib/websocket_client.py b/resources/lib/websocket_client.py index e04a7f6e..3c9a0264 100644 --- a/resources/lib/websocket_client.py +++ b/resources/lib/websocket_client.py @@ -11,7 +11,7 @@ from ssl import CERT_NONE from xbmc import sleep -from utils import window, settings, ThreadMethods +from utils import window, settings, thread_methods from companion import process_command import state @@ -22,7 +22,7 @@ log = logging.getLogger("PLEX."+__name__) ############################################################################### -@ThreadMethods(add_suspends=[state.SUSPEND_LIBRARY_THREAD]) +@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD']) class WebSocket(Thread): opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY) @@ -140,10 +140,10 @@ class WebSocket(Thread): def stopThread(self): """ - Overwrite this method from ThreadMethods to close websockets + Overwrite this method from thread_methods to close websockets """ log.info("Stopping %s thread." % self.__class__.__name__) - self._threadStopped = True + self.__threadStopped = True try: self.ws.shutdown() except: @@ -209,6 +209,7 @@ class PMS_Websocket(WebSocket): window('plex_online', value='false') +@thread_methods(add_suspends=['RESTRICTED_USER', 'PLEX_TOKEN']) class Alexa_Websocket(WebSocket): """ Websocket connection to talk to Amazon Alexa @@ -247,11 +248,3 @@ class Alexa_Websocket(WebSocket): def IOError_response(self): pass - - def thread_suspended(self): - """ - Overwrite to ignore library sync stuff and allow to check for - RESTRICTED_USER and PLEX_TOKEN - """ - return self._thread_suspended or state.RESTRICTED_USER \ - or not state.PLEX_TOKEN