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