Code refactoring: avoid window vars in loops
This commit is contained in:
parent
85e59e3207
commit
6629fb41e3
21 changed files with 327 additions and 311 deletions
|
@ -170,10 +170,10 @@ class Main():
|
|||
Start up playback_starter in main Python thread
|
||||
"""
|
||||
# Put the request into the 'queue'
|
||||
while window('plex_play_new_item'):
|
||||
while window('plex_command'):
|
||||
sleep(50)
|
||||
window('plex_play_new_item',
|
||||
value='%s%s' % ('play', argv[2]))
|
||||
window('plex_command',
|
||||
value='play_%s' % argv[2])
|
||||
# Wait for the result
|
||||
while not pickl_window('plex_result'):
|
||||
sleep(50)
|
||||
|
|
|
@ -53,6 +53,7 @@ from utils import window, settings, language as lang, tryDecode, tryEncode, \
|
|||
from PlexFunctions import PMSHttpsEnabled
|
||||
import plexdb_functions as plexdb
|
||||
import variables as v
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -879,6 +880,8 @@ class PlexAPI():
|
|||
settings('plex_restricteduser',
|
||||
'true' if answer.attrib.get('restricted', '0') == '1'
|
||||
else 'false')
|
||||
state.RESTRICTED_USER = True if \
|
||||
answer.attrib.get('restricted', '0') == '1' else False
|
||||
|
||||
# Get final token to the PMS we've chosen
|
||||
url = 'https://plex.tv/api/resources?includeHttps=1'
|
||||
|
@ -2563,7 +2566,8 @@ class API():
|
|||
if forceCheck is False:
|
||||
# Validate the path is correct with user intervention
|
||||
if self.askToValidate(path):
|
||||
window('plex_shouldStop', value="true")
|
||||
import state
|
||||
state.STOP_SYNC = True
|
||||
path = None
|
||||
window('plex_pathverified', value='true')
|
||||
else:
|
||||
|
|
|
@ -7,13 +7,14 @@ from urllib import urlencode
|
|||
|
||||
from xbmc import sleep, executebuiltin
|
||||
|
||||
from utils import settings, ThreadMethodsAdditionalSuspend, ThreadMethods
|
||||
from utils import settings, ThreadMethods
|
||||
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
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -22,8 +23,7 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('plex_serverStatus')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_suspends=[state.PMS_STATUS])
|
||||
class PlexCompanion(Thread):
|
||||
"""
|
||||
"""
|
||||
|
@ -164,8 +164,8 @@ class PlexCompanion(Thread):
|
|||
httpd = self.httpd
|
||||
# Cache for quicker while loops
|
||||
client = self.client
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
|
||||
# Start up instances
|
||||
requestMgr = httppersist.RequestMgr()
|
||||
|
@ -213,12 +213,12 @@ class PlexCompanion(Thread):
|
|||
if httpd:
|
||||
t = Thread(target=httpd.handle_request)
|
||||
|
||||
while not threadStopped():
|
||||
while not thread_stopped():
|
||||
# If we are not authorized, sleep
|
||||
# Otherwise, we trigger a download which leads to a
|
||||
# re-authorizations
|
||||
while threadSuspended():
|
||||
if threadStopped():
|
||||
while thread_suspended():
|
||||
if thread_stopped():
|
||||
break
|
||||
sleep(1000)
|
||||
try:
|
||||
|
|
|
@ -13,7 +13,8 @@ from xbmc import executeJSONRPC, sleep, translatePath
|
|||
from xbmcvfs import exists
|
||||
|
||||
from utils import window, settings, language as lang, kodiSQL, tryEncode, \
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, dialog, exists_dir
|
||||
ThreadMethods, dialog, exists_dir
|
||||
import state
|
||||
|
||||
# Disable annoying requests warnings
|
||||
import requests.packages.urllib3
|
||||
|
@ -126,8 +127,8 @@ def double_urldecode(text):
|
|||
return unquote(unquote(text))
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalStop('plex_shouldStop')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_stops=[state.STOP_SYNC],
|
||||
add_suspends=[state.SUSPEND_LIBRARY_THREAD, state.DB_SCAN])
|
||||
class Image_Cache_Thread(Thread):
|
||||
xbmc_host = 'localhost'
|
||||
xbmc_port, xbmc_username, xbmc_password = setKodiWebServerDetails()
|
||||
|
@ -140,22 +141,16 @@ class Image_Cache_Thread(Thread):
|
|||
self.queue = ARTWORK_QUEUE
|
||||
Thread.__init__(self)
|
||||
|
||||
def threadSuspended(self):
|
||||
# Overwrite method to add TWO additional suspends
|
||||
return (self._threadSuspended or
|
||||
window('suspend_LibraryThread') or
|
||||
window('plex_dbScan'))
|
||||
|
||||
def run(self):
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
queue = self.queue
|
||||
sleep_between = self.sleep_between
|
||||
while not threadStopped():
|
||||
while not thread_stopped():
|
||||
# In the event the server goes offline
|
||||
while threadSuspended():
|
||||
while thread_suspended():
|
||||
# Set in service.py
|
||||
if threadStopped():
|
||||
if thread_stopped():
|
||||
# Abort was requested while waiting. We should exit
|
||||
log.info("---===### Stopped Image_Cache_Thread ###===---")
|
||||
return
|
||||
|
@ -178,7 +173,7 @@ class Image_Cache_Thread(Thread):
|
|||
# download. All is well
|
||||
break
|
||||
except requests.ConnectionError:
|
||||
if threadStopped():
|
||||
if thread_stopped():
|
||||
# Kodi terminated
|
||||
break
|
||||
# Server thinks its a DOS attack, ('error 10053')
|
||||
|
|
68
resources/lib/command_pipeline.py
Normal file
68
resources/lib/command_pipeline.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###############################################################################
|
||||
import logging
|
||||
from threading import Thread
|
||||
from Queue import Queue
|
||||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import window, ThreadMethods
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethods
|
||||
class Monitor_Window(Thread):
|
||||
"""
|
||||
Monitors window('plex_command') for new entries that we need to take care
|
||||
of, e.g. for new plays initiated on the Kodi side with addon paths.
|
||||
|
||||
Possible values of window('plex_command'):
|
||||
'play_....': to start playback using playback_starter
|
||||
|
||||
Adjusts state.py accordingly
|
||||
"""
|
||||
# Borg - multiple instances, shared state
|
||||
def __init__(self, callback=None):
|
||||
self.mgr = callback
|
||||
self.playback_queue = Queue()
|
||||
Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
thread_stopped = self.thread_stopped
|
||||
queue = self.playback_queue
|
||||
log.info("----===## Starting Kodi_Play_Client ##===----")
|
||||
while not thread_stopped():
|
||||
if window('plex_command'):
|
||||
value = window('plex_command')
|
||||
window('plex_command', clear=True)
|
||||
if value.startswith('play_'):
|
||||
queue.put(value)
|
||||
|
||||
elif value == 'SUSPEND_LIBRARY_THREAD-True':
|
||||
state.SUSPEND_LIBRARY_THREAD = True
|
||||
elif value == 'SUSPEND_LIBRARY_THREAD-False':
|
||||
state.SUSPEND_LIBRARY_THREAD = False
|
||||
elif value == 'STOP_SYNC-True':
|
||||
state.STOP_SYNC = True
|
||||
elif value == 'STOP_SYNC-False':
|
||||
state.STOP_SYNC = False
|
||||
elif value == 'PMS_STATUS-Auth':
|
||||
state.PMS_STATUS = 'Auth'
|
||||
elif value == 'PMS_STATUS-401':
|
||||
state.PMS_STATUS = '401'
|
||||
elif value == 'SUSPEND_USER_CLIENT-True':
|
||||
state.SUSPEND_USER_CLIENT = True
|
||||
elif value == 'SUSPEND_USER_CLIENT-False':
|
||||
state.SUSPEND_USER_CLIENT = False
|
||||
elif value.startswith('PLEX_TOKEN-'):
|
||||
state.PLEX_TOKEN = value.replace('PLEX_TOKEN-', '') or None
|
||||
else:
|
||||
sleep(50)
|
||||
# Put one last item into the queue to let playback_starter end
|
||||
queue.put(None)
|
||||
log.info("----===## Kodi_Play_Client stopped ##===----")
|
|
@ -9,6 +9,8 @@ import xml.etree.ElementTree as etree
|
|||
from utils import settings, window, language as lang, dialog
|
||||
import clientinfo as client
|
||||
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Disable annoying requests warnings
|
||||
|
@ -274,10 +276,11 @@ class DownloadUtils():
|
|||
self.unauthorizedAttempts):
|
||||
log.warn('We seem to be truly unauthorized for PMS'
|
||||
' %s ' % url)
|
||||
if window('plex_serverStatus') not in ('401', 'Auth'):
|
||||
if state.PMS_STATUS not in ('401', 'Auth'):
|
||||
# Tell userclient token has been revoked.
|
||||
log.debug('Setting PMS server status to '
|
||||
'unauthorized')
|
||||
state.PMS_STATUS = '401'
|
||||
window('plex_serverStatus', value="401")
|
||||
dialog('notification',
|
||||
lang(29999),
|
||||
|
|
|
@ -12,7 +12,7 @@ from xbmc import sleep, executebuiltin, translatePath
|
|||
from xbmcgui import ListItem
|
||||
|
||||
from utils import window, settings, language as lang, dialog, tryEncode, \
|
||||
CatchExceptions, JSONRPC, exists_dir
|
||||
CatchExceptions, JSONRPC, exists_dir, plex_command
|
||||
import downloadutils
|
||||
|
||||
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
|
||||
|
@ -42,8 +42,8 @@ def chooseServer():
|
|||
server = setup.PickPMS(showDialog=True)
|
||||
if server is None:
|
||||
log.error('We did not connect to a new PMS, aborting')
|
||||
window('suspend_Userclient', clear=True)
|
||||
window('suspend_LibraryThread', clear=True)
|
||||
plex_command('SUSPEND_USER_CLIENT', 'False')
|
||||
plex_command('SUSPEND_LIBRARY_THREAD', 'False')
|
||||
return
|
||||
|
||||
log.info("User chose server %s" % server['name'])
|
||||
|
@ -81,6 +81,7 @@ def togglePlexTV():
|
|||
settings('plex_status', value="Not logged in to plex.tv")
|
||||
|
||||
window('plex_token', clear=True)
|
||||
plex_command('PLEX_TOKEN', '')
|
||||
window('plex_username', clear=True)
|
||||
else:
|
||||
log.info('Login to plex.tv')
|
||||
|
@ -100,7 +101,7 @@ def resetAuth():
|
|||
resp = dialog('yesno', heading="{plex}", line1=lang(39206))
|
||||
if resp == 1:
|
||||
log.info("Reset login attempts.")
|
||||
window('plex_serverStatus', value="Auth")
|
||||
plex_command('PMS_STATUS', 'Auth')
|
||||
else:
|
||||
executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
|
||||
|
@ -964,22 +965,19 @@ def enterPMS():
|
|||
|
||||
def __LogIn():
|
||||
"""
|
||||
Resets (clears) window properties to enable (re-)login:
|
||||
suspend_Userclient
|
||||
plex_runLibScan: set to 'full' to trigger lib sync
|
||||
Resets (clears) window properties to enable (re-)login
|
||||
|
||||
suspend_LibraryThread is cleared in service.py if user was signed out!
|
||||
SUSPEND_LIBRARY_THREAD is set to False in service.py if user was signed
|
||||
out!
|
||||
"""
|
||||
window('plex_runLibScan', value='full')
|
||||
# Restart user client
|
||||
window('suspend_Userclient', clear=True)
|
||||
plex_command('SUSPEND_USER_CLIENT', 'False')
|
||||
|
||||
|
||||
def __LogOut():
|
||||
"""
|
||||
Finishes lib scans, logs out user. The following window attributes are set:
|
||||
suspend_LibraryThread: 'true'
|
||||
suspend_Userclient: 'true'
|
||||
Finishes lib scans, logs out user.
|
||||
|
||||
Returns True if successfully signed out, False otherwise
|
||||
"""
|
||||
|
@ -991,7 +989,7 @@ def __LogOut():
|
|||
time=3000,
|
||||
sound=False)
|
||||
# Pause library sync thread
|
||||
window('suspend_LibraryThread', value='true')
|
||||
plex_command('SUSPEND_LIBRARY_THREAD', 'True')
|
||||
# Wait max for 10 seconds for all lib scans to shutdown
|
||||
counter = 0
|
||||
while window('plex_dbScan') == 'true':
|
||||
|
@ -999,17 +997,18 @@ def __LogOut():
|
|||
# Failed to reset PMS and plex.tv connects. Try to restart Kodi.
|
||||
dialog('ok', lang(29999), lang(39208))
|
||||
# Resuming threads, just in case
|
||||
window('suspend_LibraryThread', clear=True)
|
||||
plex_command('SUSPEND_LIBRARY_THREAD', 'False')
|
||||
log.error("Could not stop library sync, aborting")
|
||||
return False
|
||||
counter += 1
|
||||
sleep(50)
|
||||
log.debug("Successfully stopped library sync")
|
||||
|
||||
# Log out currently signed in user:
|
||||
window('plex_serverStatus', value="401")
|
||||
# Above method needs to have run its course! Hence wait
|
||||
counter = 0
|
||||
# Log out currently signed in user:
|
||||
window('plex_serverStatus', value='401')
|
||||
plex_command('PMS_STATUS', '401')
|
||||
# Above method needs to have run its course! Hence wait
|
||||
while window('plex_serverStatus') == "401":
|
||||
if counter > 100:
|
||||
# 'Failed to reset PKC. Try to restart Kodi.'
|
||||
|
@ -1019,5 +1018,5 @@ def __LogOut():
|
|||
counter += 1
|
||||
sleep(50)
|
||||
# Suspend the user client during procedure
|
||||
window('suspend_Userclient', value='true')
|
||||
plex_command('SUSPEND_USER_CLIENT', 'True')
|
||||
return True
|
||||
|
|
|
@ -13,6 +13,7 @@ from userclient import UserClient
|
|||
|
||||
from PlexAPI import PlexAPI
|
||||
from PlexFunctions import GetMachineIdentifier, get_PMS_settings
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -496,7 +497,7 @@ class InitialSetup():
|
|||
# Open Settings page now? You will need to restart!
|
||||
goToSettings = dialog.yesno(heading=lang(29999), line1=lang(39017))
|
||||
if goToSettings:
|
||||
window('plex_serverStatus', value="Stop")
|
||||
state.PMS_STATUS = 'Stop'
|
||||
xbmc.executebuiltin(
|
||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
else:
|
||||
|
|
|
@ -5,11 +5,11 @@ from Queue import Empty
|
|||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import ThreadMethodsAdditionalStop, ThreadMethods, window, \
|
||||
ThreadMethodsAdditionalSuspend
|
||||
from utils import ThreadMethods, window
|
||||
import plexdb_functions as plexdb
|
||||
import itemtypes
|
||||
import variables as v
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -18,9 +18,8 @@ log = getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('suspend_LibraryThread')
|
||||
@ThreadMethodsAdditionalStop('plex_shouldStop')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_suspends=[state.SUSPEND_LIBRARY_THREAD, state.DB_SCAN],
|
||||
add_stops=[state.STOP_SYNC])
|
||||
class Process_Fanart_Thread(Thread):
|
||||
"""
|
||||
Threaded download of additional fanart in the background
|
||||
|
@ -55,14 +54,14 @@ class Process_Fanart_Thread(Thread):
|
|||
Do the work
|
||||
"""
|
||||
log.debug("---===### Starting FanartSync ###===---")
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
queue = self.queue
|
||||
while not threadStopped():
|
||||
while not thread_stopped():
|
||||
# In the event the server goes offline
|
||||
while threadSuspended() or window('plex_dbScan'):
|
||||
while thread_suspended():
|
||||
# Set in service.py
|
||||
if threadStopped():
|
||||
if thread_stopped():
|
||||
# Abort was requested while waiting. We should exit
|
||||
log.info("---===### Stopped FanartSync ###===---")
|
||||
return
|
||||
|
|
|
@ -5,9 +5,10 @@ from Queue import Empty
|
|||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import ThreadMethodsAdditionalStop, ThreadMethods, window
|
||||
from utils import ThreadMethods, window
|
||||
from PlexFunctions import GetPlexMetadata, GetAllPlexChildren
|
||||
import sync_info
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -16,8 +17,7 @@ log = getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalStop('suspend_LibraryThread')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD])
|
||||
class Threaded_Get_Metadata(Thread):
|
||||
"""
|
||||
Threaded download of Plex XML metadata for a certain library item.
|
||||
|
@ -48,7 +48,7 @@ class Threaded_Get_Metadata(Thread):
|
|||
continue
|
||||
else:
|
||||
self.queue.task_done()
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
# Shutdown from outside requested; purge out_queue as well
|
||||
while not self.out_queue.empty():
|
||||
# Still try because remaining item might have been taken
|
||||
|
@ -79,8 +79,8 @@ class Threaded_Get_Metadata(Thread):
|
|||
# cache local variables because it's faster
|
||||
queue = self.queue
|
||||
out_queue = self.out_queue
|
||||
threadStopped = self.threadStopped
|
||||
while threadStopped() is False:
|
||||
thread_stopped = self.thread_stopped
|
||||
while thread_stopped() is False:
|
||||
# grabs Plex item from queue
|
||||
try:
|
||||
item = queue.get(block=False)
|
||||
|
|
|
@ -5,19 +5,18 @@ from Queue import Empty
|
|||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import ThreadMethodsAdditionalStop, ThreadMethods
|
||||
from utils import ThreadMethods
|
||||
import itemtypes
|
||||
import sync_info
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
log = getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalStop('suspend_LibraryThread')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD])
|
||||
class Threaded_Process_Metadata(Thread):
|
||||
"""
|
||||
Not yet implemented for more than 1 thread - if ever. Only to be called by
|
||||
|
@ -70,9 +69,9 @@ class Threaded_Process_Metadata(Thread):
|
|||
item_fct = getattr(itemtypes, self.item_type)
|
||||
# cache local variables because it's faster
|
||||
queue = self.queue
|
||||
threadStopped = self.threadStopped
|
||||
thread_stopped = self.thread_stopped
|
||||
with item_fct() as item_class:
|
||||
while threadStopped() is False:
|
||||
while thread_stopped() is False:
|
||||
# grabs item from queue
|
||||
try:
|
||||
item = queue.get(block=False)
|
||||
|
|
|
@ -4,7 +4,8 @@ from threading import Thread, Lock
|
|||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import ThreadMethodsAdditionalStop, ThreadMethods, language as lang
|
||||
from utils import ThreadMethods, language as lang
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -18,8 +19,7 @@ LOCK = Lock()
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalStop('suspend_LibraryThread')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_stops=[state.SUSPEND_LIBRARY_THREAD])
|
||||
class Threaded_Show_Sync_Info(Thread):
|
||||
"""
|
||||
Threaded class to show the Kodi statusbar of the metadata download.
|
||||
|
@ -53,13 +53,13 @@ class Threaded_Show_Sync_Info(Thread):
|
|||
# cache local variables because it's faster
|
||||
total = self.total
|
||||
dialog = self.dialog
|
||||
threadStopped = self.threadStopped
|
||||
thread_stopped = self.thread_stopped
|
||||
dialog.create("%s %s: %s %s"
|
||||
% (lang(39714), self.item_type, str(total), lang(39715)))
|
||||
|
||||
total = 2 * total
|
||||
totalProgress = 0
|
||||
while threadStopped() is False:
|
||||
while thread_stopped() is False:
|
||||
with LOCK:
|
||||
get_progress = GET_METADATA_COUNT
|
||||
process_progress = PROCESS_METADATA_COUNT
|
||||
|
|
|
@ -10,10 +10,9 @@ import xbmcgui
|
|||
from xbmcvfs import exists
|
||||
|
||||
from utils import window, settings, getUnixTimestamp, sourcesXML,\
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, LogTime, getScreensaver,\
|
||||
ThreadMethods, create_actor_db_index, dialog, LogTime, getScreensaver,\
|
||||
setScreensaver, playlistXSP, language as lang, DateToKodi, reset,\
|
||||
advancedsettings_tweaks, tryDecode, deletePlaylists, deleteNodes, \
|
||||
ThreadMethodsAdditionalSuspend, create_actor_db_index, dialog
|
||||
advancedsettings_tweaks, tryDecode, deletePlaylists, deleteNodes
|
||||
import downloadutils
|
||||
import itemtypes
|
||||
import plexdb_functions as plexdb
|
||||
|
@ -30,6 +29,7 @@ from library_sync.process_metadata import Threaded_Process_Metadata
|
|||
import library_sync.sync_info as sync_info
|
||||
from library_sync.fanart import Process_Fanart_Thread
|
||||
import music
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -38,9 +38,8 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('suspend_LibraryThread')
|
||||
@ThreadMethodsAdditionalStop('plex_shouldStop')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_stops=[state.STOP_SYNC],
|
||||
add_suspends=[state.SUSPEND_LIBRARY_THREAD])
|
||||
class LibrarySync(Thread):
|
||||
"""
|
||||
"""
|
||||
|
@ -300,7 +299,7 @@ class LibrarySync(Thread):
|
|||
|
||||
# Do the processing
|
||||
for itemtype in process:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
xbmc.executebuiltin('InhibitIdleShutdown(false)')
|
||||
setScreensaver(value=screensaver)
|
||||
return False
|
||||
|
@ -323,7 +322,7 @@ class LibrarySync(Thread):
|
|||
window('plex_scancrashed', clear=True)
|
||||
elif window('plex_scancrashed') == '401':
|
||||
window('plex_scancrashed', clear=True)
|
||||
if window('plex_serverStatus') not in ('401', 'Auth'):
|
||||
if state.PMS_STATUS not in ('401', 'Auth'):
|
||||
# Plex server had too much and returned ERROR
|
||||
self.dialog.ok(lang(29999), lang(39409))
|
||||
|
||||
|
@ -759,8 +758,8 @@ class LibrarySync(Thread):
|
|||
for thread in threads:
|
||||
# Threads might already have quit by themselves (e.g. Kodi exit)
|
||||
try:
|
||||
thread.stopThread()
|
||||
except:
|
||||
thread.stop_thread()
|
||||
except AttributeError:
|
||||
pass
|
||||
log.debug("Stop sent to all threads")
|
||||
# Wait till threads are indeed dead
|
||||
|
@ -805,7 +804,7 @@ class LibrarySync(Thread):
|
|||
# PROCESS MOVIES #####
|
||||
self.updatelist = []
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
# Get items per view
|
||||
viewId = view['id']
|
||||
|
@ -826,7 +825,7 @@ class LibrarySync(Thread):
|
|||
log.info("Processed view")
|
||||
# Update viewstate for EVERY item
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
self.PlexUpdateWatched(view['id'], itemType)
|
||||
|
||||
|
@ -898,7 +897,7 @@ class LibrarySync(Thread):
|
|||
# PROCESS TV Shows #####
|
||||
self.updatelist = []
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
# Get items per view
|
||||
viewId = view['id']
|
||||
|
@ -927,7 +926,7 @@ class LibrarySync(Thread):
|
|||
# PROCESS TV Seasons #####
|
||||
# Cycle through tv shows
|
||||
for tvShowId in allPlexTvShowsId:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
# Grab all seasons to tvshow from PMS
|
||||
seasons = GetAllPlexChildren(tvShowId)
|
||||
|
@ -952,7 +951,7 @@ class LibrarySync(Thread):
|
|||
# PROCESS TV Episodes #####
|
||||
# Cycle through tv shows
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
# Grab all episodes to tvshow from PMS
|
||||
episodes = GetAllPlexLeaves(view['id'])
|
||||
|
@ -987,7 +986,7 @@ class LibrarySync(Thread):
|
|||
|
||||
# Update viewstate:
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
self.PlexUpdateWatched(view['id'], itemType)
|
||||
|
||||
|
@ -1024,7 +1023,7 @@ class LibrarySync(Thread):
|
|||
for kind in (v.PLEX_TYPE_ARTIST,
|
||||
v.PLEX_TYPE_ALBUM,
|
||||
v.PLEX_TYPE_SONG):
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
log.debug("Start processing music %s" % kind)
|
||||
self.allKodiElementsId = {}
|
||||
|
@ -1041,7 +1040,7 @@ class LibrarySync(Thread):
|
|||
|
||||
# Update viewstate for EVERY item
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
self.PlexUpdateWatched(view['id'], itemType)
|
||||
|
||||
|
@ -1066,7 +1065,7 @@ class LibrarySync(Thread):
|
|||
except ValueError:
|
||||
pass
|
||||
for view in views:
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
return False
|
||||
# Get items per view
|
||||
itemsXML = GetPlexSectionResults(view['id'], args=urlArgs)
|
||||
|
@ -1172,7 +1171,7 @@ class LibrarySync(Thread):
|
|||
now = getUnixTimestamp()
|
||||
deleteListe = []
|
||||
for i, item in enumerate(self.itemsToProcess):
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
# Chances are that Kodi gets shut down
|
||||
break
|
||||
if item['state'] == 9:
|
||||
|
@ -1277,8 +1276,8 @@ class LibrarySync(Thread):
|
|||
# movie or episode)
|
||||
continue
|
||||
typus = int(item.get('type', 0))
|
||||
state = int(item.get('state', 0))
|
||||
if state == 9 or (typus in (1, 4, 10) and state == 5):
|
||||
status = int(item.get('state', 0))
|
||||
if status == 9 or (typus in (1, 4, 10) and status == 5):
|
||||
# Only process deleted items OR movies, episodes, tracks/songs
|
||||
plex_id = str(item.get('itemID', '0'))
|
||||
if plex_id == '0':
|
||||
|
@ -1286,7 +1285,7 @@ class LibrarySync(Thread):
|
|||
continue
|
||||
try:
|
||||
if (now - self.just_processed[plex_id] <
|
||||
self.ignore_just_processed and state != 9):
|
||||
self.ignore_just_processed and status != 9):
|
||||
log.debug('We just processed %s: ignoring' % plex_id)
|
||||
continue
|
||||
except KeyError:
|
||||
|
@ -1299,7 +1298,7 @@ class LibrarySync(Thread):
|
|||
else:
|
||||
# Haven't added this element to the queue yet
|
||||
self.itemsToProcess.append({
|
||||
'state': state,
|
||||
'state': status,
|
||||
'type': typus,
|
||||
'ratingKey': plex_id,
|
||||
'timestamp': getUnixTimestamp(),
|
||||
|
@ -1315,8 +1314,8 @@ class LibrarySync(Thread):
|
|||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
for item in data:
|
||||
# Drop buffering messages immediately
|
||||
state = item.get('state')
|
||||
if state == 'buffering':
|
||||
status = item.get('state')
|
||||
if status == 'buffering':
|
||||
continue
|
||||
ratingKey = item.get('ratingKey')
|
||||
kodiInfo = plex_db.getItem_byId(ratingKey)
|
||||
|
@ -1335,8 +1334,7 @@ class LibrarySync(Thread):
|
|||
}
|
||||
else:
|
||||
# PMS is ours - get all current sessions
|
||||
self.sessionKeys = GetPMSStatus(
|
||||
window('plex_token'))
|
||||
self.sessionKeys = GetPMSStatus(state.PLEX_TOKEN)
|
||||
log.debug('Updated current sessions. They are: %s'
|
||||
% self.sessionKeys)
|
||||
if sessionKey not in self.sessionKeys:
|
||||
|
@ -1349,8 +1347,7 @@ class LibrarySync(Thread):
|
|||
# Identify the user - same one as signed on with PKC? Skip
|
||||
# update if neither session's username nor userid match
|
||||
# (Owner sometime's returns id '1', not always)
|
||||
if (window('plex_token') == '' and
|
||||
currSess['userId'] == '1'):
|
||||
if (not state.PLEX_TOKEN and currSess['userId'] == '1'):
|
||||
# PKC not signed in to plex.tv. Plus owner of PMS is
|
||||
# playing (the '1').
|
||||
# Hence must be us (since several users require plex.tv
|
||||
|
@ -1394,7 +1391,7 @@ class LibrarySync(Thread):
|
|||
'file_id': kodiInfo[1],
|
||||
'kodi_type': kodiInfo[4],
|
||||
'viewOffset': resume,
|
||||
'state': state,
|
||||
'state': status,
|
||||
'duration': currSess['duration'],
|
||||
'viewCount': currSess['viewCount'],
|
||||
'lastViewedAt': DateToKodi(getUnixTimestamp())
|
||||
|
@ -1433,6 +1430,7 @@ class LibrarySync(Thread):
|
|||
try:
|
||||
self.run_internal()
|
||||
except Exception as e:
|
||||
state.DB_SCAN = False
|
||||
window('plex_dbScan', clear=True)
|
||||
log.error('LibrarySync thread crashed. Error message: %s' % e)
|
||||
import traceback
|
||||
|
@ -1443,8 +1441,8 @@ class LibrarySync(Thread):
|
|||
|
||||
def run_internal(self):
|
||||
# Re-assign handles to have faster calls
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
installSyncDone = self.installSyncDone
|
||||
enableBackgroundSync = self.enableBackgroundSync
|
||||
fullSync = self.fullSync
|
||||
|
@ -1476,12 +1474,12 @@ class LibrarySync(Thread):
|
|||
if settings('FanartTV') == 'true':
|
||||
self.fanartthread.start()
|
||||
|
||||
while not threadStopped():
|
||||
while not thread_stopped():
|
||||
|
||||
# In the event the server goes offline
|
||||
while threadSuspended():
|
||||
while thread_suspended():
|
||||
# Set in service.py
|
||||
if threadStopped():
|
||||
if thread_stopped():
|
||||
# Abort was requested while waiting. We should exit
|
||||
log.info("###===--- LibrarySync Stopped ---===###")
|
||||
return
|
||||
|
@ -1523,6 +1521,7 @@ class LibrarySync(Thread):
|
|||
self.dialog.ok(heading=lang(29999), line1=lang(39403))
|
||||
break
|
||||
# Run start up sync
|
||||
state.DB_SCAN = True
|
||||
window('plex_dbScan', value="true")
|
||||
log.info("Db version: %s" % settings('dbCreatedWithVersion'))
|
||||
lastTimeSync = getUnixTimestamp()
|
||||
|
@ -1547,6 +1546,7 @@ class LibrarySync(Thread):
|
|||
log.info("Initial start-up full sync starting")
|
||||
librarySync = fullSync()
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
if librarySync:
|
||||
log.info("Initial start-up full sync successful")
|
||||
startupComplete = True
|
||||
|
@ -1565,23 +1565,26 @@ class LibrarySync(Thread):
|
|||
break
|
||||
|
||||
# Currently no db scan, so we can start a new scan
|
||||
elif window('plex_dbScan') != "true":
|
||||
elif state.DB_SCAN is False:
|
||||
# Full scan was requested from somewhere else, e.g. userclient
|
||||
if window('plex_runLibScan') in ("full", "repair"):
|
||||
log.info('Full library scan requested, starting')
|
||||
window('plex_dbScan', value="true")
|
||||
state.DB_SCAN = True
|
||||
if window('plex_runLibScan') == "full":
|
||||
fullSync()
|
||||
elif window('plex_runLibScan') == "repair":
|
||||
fullSync(repair=True)
|
||||
window('plex_runLibScan', clear=True)
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
# Full library sync finished
|
||||
self.showKodiNote(lang(39407), forced=False)
|
||||
# Reset views was requested from somewhere else
|
||||
elif window('plex_runLibScan') == "views":
|
||||
log.info('Refresh playlist and nodes requested, starting')
|
||||
window('plex_dbScan', value="true")
|
||||
state.DB_SCAN = True
|
||||
window('plex_runLibScan', clear=True)
|
||||
|
||||
# First remove playlists
|
||||
|
@ -1602,6 +1605,7 @@ class LibrarySync(Thread):
|
|||
forced=True,
|
||||
icon="error")
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
elif window('plex_runLibScan') == 'fanart':
|
||||
window('plex_runLibScan', clear=True)
|
||||
# Only look for missing fanart (No)
|
||||
|
@ -1613,31 +1617,37 @@ class LibrarySync(Thread):
|
|||
yeslabel=lang(39225)))
|
||||
elif window('plex_runLibScan') == 'del_textures':
|
||||
window('plex_runLibScan', clear=True)
|
||||
state.DB_SCAN = True
|
||||
window('plex_dbScan', value="true")
|
||||
import artwork
|
||||
artwork.Artwork().fullTextureCacheSync()
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
else:
|
||||
now = getUnixTimestamp()
|
||||
if (now - lastSync > fullSyncInterval and
|
||||
not xbmcplayer.isPlaying()):
|
||||
lastSync = now
|
||||
log.info('Doing scheduled full library scan')
|
||||
state.DB_SCAN = True
|
||||
window('plex_dbScan', value="true")
|
||||
if fullSync() is False and not threadStopped():
|
||||
if fullSync() is False and not thread_stopped():
|
||||
log.error('Could not finish scheduled full sync')
|
||||
self.showKodiNote(lang(39410),
|
||||
forced=True,
|
||||
icon='error')
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
# Full library sync finished
|
||||
self.showKodiNote(lang(39407), forced=False)
|
||||
elif now - lastTimeSync > oneDay:
|
||||
lastTimeSync = now
|
||||
log.info('Starting daily time sync')
|
||||
state.DB_SCAN = True
|
||||
window('plex_dbScan', value="true")
|
||||
self.syncPMStime()
|
||||
window('plex_dbScan', clear=True)
|
||||
state.DB_SCAN = False
|
||||
elif enableBackgroundSync:
|
||||
# Check back whether we should process something
|
||||
# Only do this once every while (otherwise, potentially
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###############################################################################
|
||||
import logging
|
||||
from threading import Thread
|
||||
from Queue import Queue
|
||||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import window, ThreadMethods
|
||||
|
||||
###############################################################################
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethods
|
||||
class Monitor_Kodi_Play(Thread):
|
||||
"""
|
||||
Monitors for new plays initiated on the Kodi side with addon paths.
|
||||
Immediately throws them into a queue to be processed by playback_starter
|
||||
"""
|
||||
# Borg - multiple instances, shared state
|
||||
def __init__(self, callback=None):
|
||||
self.mgr = callback
|
||||
self.playback_queue = Queue()
|
||||
Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
threadStopped = self.threadStopped
|
||||
queue = self.playback_queue
|
||||
log.info("----===## Starting Kodi_Play_Client ##===----")
|
||||
while not threadStopped():
|
||||
if window('plex_play_new_item'):
|
||||
queue.put(window('plex_play_new_item'))
|
||||
window('plex_play_new_item', clear=True)
|
||||
else:
|
||||
sleep(50)
|
||||
# Put one last item into the queue to let playback_starter end
|
||||
queue.put(None)
|
||||
log.info("----===## Kodi_Play_Client stopped ##===----")
|
|
@ -152,12 +152,12 @@ class Playback_Starter(Thread):
|
|||
pickle_me(result)
|
||||
|
||||
def run(self):
|
||||
queue = self.mgr.monitor_kodi_play.playback_queue
|
||||
queue = self.mgr.command_pipeline.playback_queue
|
||||
log.info("----===## Starting Playback_Starter ##===----")
|
||||
while True:
|
||||
item = queue.get()
|
||||
if item is None:
|
||||
# Need to shutdown - initiated by monitor_kodi_play
|
||||
# Need to shutdown - initiated by command_pipeline
|
||||
break
|
||||
else:
|
||||
self.triage(item)
|
||||
|
|
|
@ -5,12 +5,13 @@ from threading import RLock, Thread
|
|||
|
||||
from xbmc import sleep, Player, PlayList, PLAYLIST_MUSIC, PLAYLIST_VIDEO
|
||||
|
||||
from utils import window, ThreadMethods, ThreadMethodsAdditionalSuspend
|
||||
from utils import window, ThreadMethods
|
||||
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__)
|
||||
|
@ -21,8 +22,7 @@ PLUGIN = 'plugin://%s' % v.ADDON_ID
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('plex_serverStatus')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_suspends=[state.PMS_STATUS])
|
||||
class Playqueue(Thread):
|
||||
"""
|
||||
Monitors Kodi's playqueues for changes on the Kodi side
|
||||
|
@ -153,7 +153,7 @@ class Playqueue(Thread):
|
|||
# Ignore new media added by other addons
|
||||
continue
|
||||
for j, old_item in enumerate(old):
|
||||
if self.threadStopped():
|
||||
if self.thread_stopped():
|
||||
# Chances are that we got an empty Kodi playlist due to
|
||||
# Kodi exit
|
||||
return
|
||||
|
@ -193,8 +193,8 @@ class Playqueue(Thread):
|
|||
log.debug('Done comparing playqueues')
|
||||
|
||||
def run(self):
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
log.info("----===## Starting PlayQueue client ##===----")
|
||||
# Initialize the playqueues, if Kodi already got items in them
|
||||
for playqueue in self.playqueues:
|
||||
|
@ -203,9 +203,9 @@ class Playqueue(Thread):
|
|||
PL.init_Plex_playlist(playqueue, kodi_item=item)
|
||||
else:
|
||||
PL.add_item_to_PMS_playlist(playqueue, i, kodi_item=item)
|
||||
while not threadStopped():
|
||||
while threadSuspended():
|
||||
if threadStopped():
|
||||
while not thread_stopped():
|
||||
while thread_suspended():
|
||||
if thread_stopped():
|
||||
break
|
||||
sleep(1000)
|
||||
with lock:
|
||||
|
|
22
resources/lib/state.py
Normal file
22
resources/lib/state.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# THREAD SAFE
|
||||
|
||||
# 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'
|
||||
DB_SCAN = False
|
||||
# Plex Media Server Status - along with window('plex_serverStatus')
|
||||
PMS_STATUS = False
|
||||
# When the userclient needs to wait
|
||||
SUSPEND_USER_CLIENT = False
|
||||
# Plex home user? Then "False". Along with window('plex_restricteduser')
|
||||
RESTRICTED_USER = False
|
||||
|
||||
PLEX_TOKEN = None
|
|
@ -10,12 +10,12 @@ import xbmcaddon
|
|||
from xbmcvfs import exists
|
||||
|
||||
|
||||
from utils import window, settings, language as lang, ThreadMethods, \
|
||||
ThreadMethodsAdditionalSuspend
|
||||
from utils import window, settings, language as lang, ThreadMethods
|
||||
import downloadutils
|
||||
|
||||
import PlexAPI
|
||||
from PlexFunctions import GetMachineIdentifier
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -24,8 +24,7 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('suspend_Userclient')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_suspends=[state.SUSPEND_USER_CLIENT])
|
||||
class UserClient(threading.Thread):
|
||||
|
||||
# Borg - multiple instances, shared state
|
||||
|
@ -118,25 +117,6 @@ class UserClient(threading.Thread):
|
|||
def hasAccess(self):
|
||||
# Plex: always return True for now
|
||||
return True
|
||||
# hasAccess is verified in service.py
|
||||
url = "{server}/emby/Users?format=json"
|
||||
result = self.doUtils.downloadUrl(url)
|
||||
|
||||
if result is False:
|
||||
# Access is restricted, set in downloadutils.py via exception
|
||||
log.info("Access is restricted.")
|
||||
self.HasAccess = False
|
||||
|
||||
elif window('plex_online') != "true":
|
||||
# Server connection failed
|
||||
pass
|
||||
|
||||
elif window('plex_serverStatus') == "restricted":
|
||||
log.info("Access is granted.")
|
||||
self.HasAccess = True
|
||||
window('plex_serverStatus', clear=True)
|
||||
xbmcgui.Dialog().notification(lang(29999),
|
||||
lang(33007))
|
||||
|
||||
def loadCurrUser(self, username, userId, usertoken, authenticated=False):
|
||||
log.debug('Loading current user')
|
||||
|
@ -171,7 +151,10 @@ class UserClient(threading.Thread):
|
|||
# This is the token for plex.tv for the current user
|
||||
# Is only '' if user is not signed in to plex.tv
|
||||
window('plex_token', value=settings('plexToken'))
|
||||
state.PLEX_TOKEN = settings('plexToken') or None
|
||||
window('plex_restricteduser', value=settings('plex_restricteduser'))
|
||||
state.RESTRICTED_USER = True \
|
||||
if settings('plex_restricteduser') == 'true' else False
|
||||
window('pms_server', value=self.currServer)
|
||||
window('plex_machineIdentifier', value=self.machineIdentifier)
|
||||
window('plex_servername', value=self.servername)
|
||||
|
@ -202,7 +185,7 @@ class UserClient(threading.Thread):
|
|||
# Give attempts at entering password / selecting user
|
||||
if self.retry >= 2:
|
||||
log.error("Too many retries to login.")
|
||||
window('plex_serverStatus', value="Stop")
|
||||
state.PMS_STATUS = 'Stop'
|
||||
dialog.ok(lang(33001),
|
||||
lang(39023))
|
||||
xbmc.executebuiltin(
|
||||
|
@ -284,6 +267,7 @@ class UserClient(threading.Thread):
|
|||
|
||||
window('plex_authenticated', clear=True)
|
||||
window('pms_token', clear=True)
|
||||
state.PLEX_TOKEN = None
|
||||
window('plex_token', clear=True)
|
||||
window('pms_server', clear=True)
|
||||
window('plex_machineIdentifier', clear=True)
|
||||
|
@ -291,6 +275,7 @@ class UserClient(threading.Thread):
|
|||
window('currUserId', clear=True)
|
||||
window('plex_username', clear=True)
|
||||
window('plex_restricteduser', clear=True)
|
||||
state.RESTRICTED_USER = False
|
||||
|
||||
settings('username', value='')
|
||||
settings('userid', value='')
|
||||
|
@ -310,32 +295,32 @@ class UserClient(threading.Thread):
|
|||
|
||||
def run(self):
|
||||
log.info("----===## Starting UserClient ##===----")
|
||||
while not self.threadStopped():
|
||||
while self.threadSuspended():
|
||||
if self.threadStopped():
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
while not thread_stopped():
|
||||
while thread_suspended():
|
||||
if thread_stopped():
|
||||
break
|
||||
xbmc.sleep(1000)
|
||||
|
||||
status = window('plex_serverStatus')
|
||||
|
||||
if status == "Stop":
|
||||
if state.PMS_STATUS == "Stop":
|
||||
xbmc.sleep(500)
|
||||
continue
|
||||
|
||||
# Verify the connection status to server
|
||||
elif status == "restricted":
|
||||
elif state.PMS_STATUS == "restricted":
|
||||
# Parental control is restricting access
|
||||
self.HasAccess = False
|
||||
|
||||
elif status == "401":
|
||||
elif state.PMS_STATUS == "401":
|
||||
# Unauthorized access, revoke token
|
||||
window('plex_serverStatus', value="Auth")
|
||||
state.PMS_STATUS = 'Auth'
|
||||
self.resetClient()
|
||||
xbmc.sleep(2000)
|
||||
|
||||
if self.auth and (self.currUser is None):
|
||||
# Try to authenticate user
|
||||
if not status or status == "Auth":
|
||||
if not state.PMS_STATUS or state.PMS_STATUS == "Auth":
|
||||
# Set auth flag because we no longer need
|
||||
# to authenticate the user
|
||||
self.auth = False
|
||||
|
@ -345,8 +330,9 @@ class UserClient(threading.Thread):
|
|||
log.info("Current user: %s" % self.currUser)
|
||||
log.info("Current userId: %s" % self.currUserId)
|
||||
self.retry = 0
|
||||
window('suspend_LibraryThread', clear=True)
|
||||
state.SUSPEND_LIBRARY_THREAD = False
|
||||
window('plex_serverStatus', clear=True)
|
||||
state.PMS_STATUS = False
|
||||
|
||||
if not self.auth and (self.currUser is None):
|
||||
# Loop if no server found
|
||||
|
@ -354,7 +340,7 @@ class UserClient(threading.Thread):
|
|||
|
||||
# The status Stop is for when user cancelled password dialog.
|
||||
# Or retried too many times
|
||||
if server and status != "Stop":
|
||||
if server and state.PMS_STATUS != "Stop":
|
||||
# Only if there's information found to login
|
||||
log.debug("Server found: %s" % server)
|
||||
self.auth = True
|
||||
|
@ -362,5 +348,4 @@ class UserClient(threading.Thread):
|
|||
# Minimize CPU load
|
||||
xbmc.sleep(100)
|
||||
|
||||
self.doUtils.stopSession()
|
||||
log.info("##===---- UserClient Stopped ----===##")
|
||||
|
|
|
@ -11,7 +11,7 @@ from StringIO import StringIO
|
|||
from time import localtime, strftime, strptime
|
||||
from unicodedata import normalize
|
||||
import xml.etree.ElementTree as etree
|
||||
from functools import wraps
|
||||
from functools import wraps, partial
|
||||
from calendar import timegm
|
||||
from os.path import join
|
||||
from os import remove, walk, makedirs
|
||||
|
@ -25,6 +25,7 @@ from xbmcvfs import exists, delete
|
|||
|
||||
from variables import DB_VIDEO_PATH, DB_MUSIC_PATH, DB_TEXTURE_PATH, \
|
||||
DB_PLEX_PATH, KODI_PROFILE, KODIVERSION
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -76,6 +77,19 @@ def pickl_window(property, value=None, clear=False, windowid=10000):
|
|||
return win.getProperty(property)
|
||||
|
||||
|
||||
def plex_command(key, value):
|
||||
"""
|
||||
Used to funnel states between different Python instances. NOT really thread
|
||||
safe - let's hope the Kodi user can't click fast enough
|
||||
|
||||
key: state.py variable
|
||||
value: either 'True' or 'False'
|
||||
"""
|
||||
while window('plex_command'):
|
||||
xbmc.sleep(1)
|
||||
window('plex_command', value='%s-%s' % (key, value))
|
||||
|
||||
|
||||
def settings(setting, value=None):
|
||||
"""
|
||||
Get or add addon setting. Returns unicode
|
||||
|
@ -319,7 +333,7 @@ def reset():
|
|||
return
|
||||
|
||||
# first stop any db sync
|
||||
window('plex_shouldStop', value="true")
|
||||
plex_command('STOP_SYNC', 'True')
|
||||
count = 10
|
||||
while window('plex_dbScan') == "true":
|
||||
log.debug("Sync is running, will retry: %s..." % count)
|
||||
|
@ -906,78 +920,61 @@ def LogTime(func):
|
|||
return wrapper
|
||||
|
||||
|
||||
def ThreadMethodsAdditionalStop(windowAttribute):
|
||||
"""
|
||||
Decorator to replace stopThread method to include the Kodi windowAttribute
|
||||
|
||||
Use with any sync threads. @ThreadMethods still required FIRST
|
||||
"""
|
||||
def wrapper(cls):
|
||||
def threadStopped(self):
|
||||
return (self._threadStopped or
|
||||
(window('plex_terminateNow') == "true") or
|
||||
window(windowAttribute) == "true")
|
||||
cls.threadStopped = threadStopped
|
||||
return cls
|
||||
return wrapper
|
||||
|
||||
|
||||
def ThreadMethodsAdditionalSuspend(windowAttribute):
|
||||
"""
|
||||
Decorator to replace threadSuspended(): thread now also suspends if a
|
||||
Kodi windowAttribute is set to 'true', e.g. 'suspend_LibraryThread'
|
||||
|
||||
Use with any library sync threads. @ThreadMethods still required FIRST
|
||||
"""
|
||||
def wrapper(cls):
|
||||
def threadSuspended(self):
|
||||
return (self._threadSuspended or
|
||||
window(windowAttribute) == 'true')
|
||||
cls.threadSuspended = threadSuspended
|
||||
return cls
|
||||
return wrapper
|
||||
|
||||
|
||||
def ThreadMethods(cls):
|
||||
def ThreadMethods(cls=None, add_stops=None, add_suspends=None):
|
||||
"""
|
||||
Decorator to add the following methods to a threading class:
|
||||
|
||||
suspendThread(): pauses the thread
|
||||
resumeThread(): resumes the thread
|
||||
stopThread(): stopps/kills the thread
|
||||
suspend_thread(): pauses the thread
|
||||
resume_thread(): resumes the thread
|
||||
stop_thread(): stopps/kills the thread
|
||||
|
||||
threadSuspended(): returns True if thread is suspend_thread
|
||||
threadStopped(): returns True if thread is stopped (or should stop ;-))
|
||||
ALSO stops if Kodi is exited
|
||||
thread_suspended(): returns True if thread is suspend_thread
|
||||
thread_stopped(): returns True if thread is stopped (or should stop ;-))
|
||||
ALSO stops if PKC should exit
|
||||
|
||||
Also adds the following class attributes:
|
||||
_threadStopped
|
||||
_threadSuspended
|
||||
_thread_stopped
|
||||
_thread_suspended
|
||||
|
||||
invoke with either
|
||||
@NewThreadMethods
|
||||
class MyClass():
|
||||
or
|
||||
@NewThreadMethods(add_stops=[state.SUSPEND_LIBRARY_TRHEAD],
|
||||
add_suspends=[state.WHATEVER, state.WHATEVER2])
|
||||
class MyClass():
|
||||
"""
|
||||
if cls is None:
|
||||
return partial(ThreadMethods,
|
||||
add_stops=add_stops,
|
||||
add_suspends=add_suspends)
|
||||
# Make sure we have an iterable
|
||||
add_stops = add_stops or []
|
||||
add_suspends = add_suspends or []
|
||||
# Attach new attributes to class
|
||||
cls._threadStopped = False
|
||||
cls._threadSuspended = False
|
||||
cls._thread_stopped = False
|
||||
cls._thread_suspended = False
|
||||
|
||||
# Define new class methods and attach them to class
|
||||
def stopThread(self):
|
||||
self._threadStopped = True
|
||||
cls.stopThread = stopThread
|
||||
def stop_thread(self):
|
||||
self._thread_stopped = True
|
||||
cls.stop_thread = stop_thread
|
||||
|
||||
def suspendThread(self):
|
||||
self._threadSuspended = True
|
||||
cls.suspendThread = suspendThread
|
||||
def suspend_thread(self):
|
||||
self._thread_suspended = True
|
||||
cls.suspend_thread = suspend_thread
|
||||
|
||||
def resumeThread(self):
|
||||
self._threadSuspended = False
|
||||
cls.resumeThread = resumeThread
|
||||
def resume_thread(self):
|
||||
self._thread_suspended = False
|
||||
cls.resume_thread = resume_thread
|
||||
|
||||
def threadSuspended(self):
|
||||
return self._threadSuspended
|
||||
cls.threadSuspended = threadSuspended
|
||||
def thread_suspended(self):
|
||||
return self._thread_suspended or any(add_suspends)
|
||||
cls.thread_suspended = thread_suspended
|
||||
|
||||
def threadStopped(self):
|
||||
return self._threadStopped or (window('plex_terminateNow') == 'true')
|
||||
cls.threadStopped = threadStopped
|
||||
def thread_stopped(self):
|
||||
return self._thread_stopped or state.STOP_PKC or any(add_stops)
|
||||
cls.thread_stopped = thread_stopped
|
||||
|
||||
# Return class to render this a decorator
|
||||
return cls
|
||||
|
|
|
@ -11,9 +11,9 @@ from ssl import CERT_NONE
|
|||
|
||||
from xbmc import sleep
|
||||
|
||||
from utils import window, settings, ThreadMethodsAdditionalSuspend, \
|
||||
ThreadMethods
|
||||
from utils import window, settings, ThreadMethods
|
||||
from companion import process_command
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -22,8 +22,7 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
###############################################################################
|
||||
|
||||
|
||||
@ThreadMethodsAdditionalSuspend('suspend_LibraryThread')
|
||||
@ThreadMethods
|
||||
@ThreadMethods(add_suspends=[state.SUSPEND_LIBRARY_THREAD])
|
||||
class WebSocket(Thread):
|
||||
opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)
|
||||
|
||||
|
@ -62,11 +61,11 @@ class WebSocket(Thread):
|
|||
|
||||
counter = 0
|
||||
handshake_counter = 0
|
||||
threadStopped = self.threadStopped
|
||||
threadSuspended = self.threadSuspended
|
||||
while not threadStopped():
|
||||
thread_stopped = self.thread_stopped
|
||||
thread_suspended = self.thread_suspended
|
||||
while not thread_stopped():
|
||||
# In the event the server goes offline
|
||||
while threadSuspended():
|
||||
while thread_suspended():
|
||||
# Set in service.py
|
||||
if self.ws is not None:
|
||||
try:
|
||||
|
@ -74,7 +73,7 @@ class WebSocket(Thread):
|
|||
except:
|
||||
pass
|
||||
self.ws = None
|
||||
if threadStopped():
|
||||
if thread_stopped():
|
||||
# Abort was requested while waiting. We should exit
|
||||
log.info("##===---- %s Stopped ----===##"
|
||||
% self.__class__.__name__)
|
||||
|
@ -160,16 +159,15 @@ class PMS_Websocket(WebSocket):
|
|||
|
||||
def getUri(self):
|
||||
server = window('pms_server')
|
||||
# Need to use plex.tv token, if any. NOT user token
|
||||
token = window('plex_token')
|
||||
# Get the appropriate prefix for the websocket
|
||||
if server.startswith('https'):
|
||||
server = "wss%s" % server[5:]
|
||||
else:
|
||||
server = "ws%s" % server[4:]
|
||||
uri = "%s/:/websockets/notifications" % server
|
||||
if token:
|
||||
uri += '?X-Plex-Token=%s' % token
|
||||
# Need to use plex.tv token, if any. NOT user token
|
||||
if state.PLEX_TOKEN:
|
||||
uri += '?X-Plex-Token=%s' % state.PLEX_TOKEN
|
||||
sslopt = {}
|
||||
if settings('sslverify') == "false":
|
||||
sslopt["cert_reqs"] = CERT_NONE
|
||||
|
@ -218,9 +216,7 @@ class Alexa_Websocket(WebSocket):
|
|||
def getUri(self):
|
||||
self.plex_client_Id = window('plex_client_Id')
|
||||
uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s'
|
||||
% (window('currUserId'),
|
||||
self.plex_client_Id,
|
||||
window('plex_token')))
|
||||
% (window('currUserId'), self.plex_client_Id, state.PLEX_TOKEN))
|
||||
sslopt = {}
|
||||
log.debug("Uri: %s, sslopt: %s" % (uri, sslopt))
|
||||
return uri, sslopt
|
||||
|
@ -252,11 +248,10 @@ class Alexa_Websocket(WebSocket):
|
|||
def IOError_response(self):
|
||||
pass
|
||||
|
||||
def threadSuspended(self):
|
||||
def thread_suspended(self):
|
||||
"""
|
||||
Overwrite to ignore library sync stuff and allow to check for
|
||||
plex_restricteduser
|
||||
RESTRICTED_USER and PLEX_TOKEN
|
||||
"""
|
||||
return (self._threadSuspended or
|
||||
window('plex_restricteduser') == 'true' or
|
||||
not window('plex_token'))
|
||||
return self._thread_suspended or state.RESTRICTED_USER \
|
||||
or not state.PLEX_TOKEN
|
||||
|
|
38
service.py
38
service.py
|
@ -42,10 +42,11 @@ from playqueue import Playqueue
|
|||
|
||||
import PlexAPI
|
||||
from PlexCompanion import PlexCompanion
|
||||
from monitor_kodi_play import Monitor_Kodi_Play
|
||||
from command_pipeline import Monitor_Window
|
||||
from playback_starter import Playback_Starter
|
||||
from artwork import Image_Cache_Thread
|
||||
import variables as v
|
||||
import state
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -105,7 +106,6 @@ class Service():
|
|||
|
||||
# Reset window props for profile switch
|
||||
properties = [
|
||||
|
||||
"plex_online", "plex_serverStatus", "plex_onWake",
|
||||
"plex_dbCheck", "plex_kodiScan",
|
||||
"plex_shouldStop", "currUserId", "plex_dbScan",
|
||||
|
@ -113,10 +113,9 @@ class Service():
|
|||
"plex_runLibScan", "plex_username", "pms_token", "plex_token",
|
||||
"pms_server", "plex_machineIdentifier", "plex_servername",
|
||||
"plex_authenticated", "PlexUserImage", "useDirectPaths",
|
||||
"suspend_LibraryThread", "plex_terminateNow",
|
||||
"kodiplextimeoffset", "countError", "countUnauthorized",
|
||||
"plex_restricteduser", "plex_allows_mediaDeletion",
|
||||
"plex_play_new_item", "plex_result", "plex_force_transcode_pix"
|
||||
"plex_command", "plex_result", "plex_force_transcode_pix"
|
||||
]
|
||||
for prop in properties:
|
||||
window(prop, clear=True)
|
||||
|
@ -141,8 +140,8 @@ class Service():
|
|||
kodiProfile = v.KODI_PROFILE
|
||||
|
||||
# Detect playback start early on
|
||||
self.monitor_kodi_play = Monitor_Kodi_Play(self)
|
||||
self.monitor_kodi_play.start()
|
||||
self.command_pipeline = Monitor_Window(self)
|
||||
self.command_pipeline.start()
|
||||
|
||||
# Server auto-detect
|
||||
initialsetup.InitialSetup().setup()
|
||||
|
@ -261,7 +260,7 @@ class Service():
|
|||
self.server_online = False
|
||||
window('plex_online', value="false")
|
||||
# Suspend threads
|
||||
window('suspend_LibraryThread', value='true')
|
||||
state.SUSPEND_LIBRARY_THREAD = True
|
||||
log.error("Plex Media Server went offline")
|
||||
if settings('show_pms_offline') == 'true':
|
||||
dialog('notification',
|
||||
|
@ -301,7 +300,7 @@ class Service():
|
|||
if window('plex_authenticated') == 'true':
|
||||
# Server got offline when we were authenticated.
|
||||
# Hence resume threads
|
||||
window('suspend_LibraryThread', clear=True)
|
||||
state.SUSPEND_LIBRARY_THREAD = False
|
||||
|
||||
# Start the userclient thread
|
||||
if not self.user_running:
|
||||
|
@ -321,27 +320,7 @@ class Service():
|
|||
# Terminating PlexKodiConnect
|
||||
|
||||
# Tell all threads to terminate (e.g. several lib sync threads)
|
||||
window('plex_terminateNow', value='true')
|
||||
try:
|
||||
self.plexCompanion.stopThread()
|
||||
except:
|
||||
log.warn('plexCompanion already shut down')
|
||||
try:
|
||||
self.library.stopThread()
|
||||
except:
|
||||
log.warn('Library sync already shut down')
|
||||
try:
|
||||
self.ws.stopThread()
|
||||
except:
|
||||
log.warn('Websocket client already shut down')
|
||||
try:
|
||||
self.alexa.stopThread()
|
||||
except:
|
||||
log.warn('Websocket client already shut down')
|
||||
try:
|
||||
self.user.stopThread()
|
||||
except:
|
||||
log.warn('User client already shut down')
|
||||
state.STOP_PKC = True
|
||||
try:
|
||||
downloadutils.DownloadUtils().stopSession()
|
||||
except:
|
||||
|
@ -349,6 +328,7 @@ class Service():
|
|||
window('plex_service_started', clear=True)
|
||||
log.warn("======== STOP %s ========" % v.ADDON_NAME)
|
||||
|
||||
|
||||
# Safety net - Kody starts PKC twice upon first installation!
|
||||
if window('plex_service_started') == 'true':
|
||||
exit = True
|
||||
|
|
Loading…
Reference in a new issue