Rewire PKC startup and authentication mechanism
This commit is contained in:
parent
6d450b2be9
commit
6dc436da91
18 changed files with 243 additions and 232 deletions
17
default.py
17
default.py
|
@ -101,17 +101,12 @@ class Main():
|
||||||
entrypoint.switch_plex_user()
|
entrypoint.switch_plex_user()
|
||||||
|
|
||||||
elif mode in ('manualsync', 'repair'):
|
elif mode in ('manualsync', 'repair'):
|
||||||
if pickler.pickl_window('plex_online') != 'true':
|
if mode == 'repair':
|
||||||
# Server is not online, do not run the sync
|
log.info('Requesting repair lib sync')
|
||||||
utils.messageDialog(utils.lang(29999), utils.lang(39205))
|
utils.plex_command('repair-scan')
|
||||||
log.error('Not connected to a PMS.')
|
elif mode == 'manualsync':
|
||||||
else:
|
log.info('Requesting full library scan')
|
||||||
if mode == 'repair':
|
utils.plex_command('full-scan')
|
||||||
log.info('Requesting repair lib sync')
|
|
||||||
utils.plex_command('repair-scan')
|
|
||||||
elif mode == 'manualsync':
|
|
||||||
log.info('Requesting full library scan')
|
|
||||||
utils.plex_command('full-scan')
|
|
||||||
|
|
||||||
elif mode == 'texturecache':
|
elif mode == 'texturecache':
|
||||||
log.info('Requesting texture caching of all textures')
|
log.info('Requesting texture caching of all textures')
|
||||||
|
|
|
@ -619,7 +619,7 @@ msgid "Invalid username or password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "#33010"
|
msgctxt "#33010"
|
||||||
msgid "Your Plex token is no longer valid. Logging-out of plex.tv"
|
msgid "User is unauthorized for server {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "#33011"
|
msgctxt "#33011"
|
||||||
|
|
|
@ -30,6 +30,9 @@ class Account(object):
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
LOG.debug('Loading account settings')
|
LOG.debug('Loading account settings')
|
||||||
|
# User name we used to sign in to plex.tv
|
||||||
|
self.plex_login = utils.settings('plexLogin') or None
|
||||||
|
self.plex_login_id = utils.settings('plexid') or None
|
||||||
# plex.tv username
|
# plex.tv username
|
||||||
self.plex_username = utils.settings('username') or None
|
self.plex_username = utils.settings('username') or None
|
||||||
# Plex ID of that user (e.g. for plex.tv) as a STRING
|
# Plex ID of that user (e.g. for plex.tv) as a STRING
|
||||||
|
@ -62,13 +65,17 @@ class Account(object):
|
||||||
LOG.debug('User is restricted Home user: %s', self.restricted_user)
|
LOG.debug('User is restricted Home user: %s', self.restricted_user)
|
||||||
|
|
||||||
def log_out(self):
|
def log_out(self):
|
||||||
LOG.debug('Logging-out user')
|
LOG.debug('Logging-out user %s', self.plex_username)
|
||||||
self.plex_username = None
|
self.plex_username = None
|
||||||
self.plex_user_id = None
|
self.plex_user_id = None
|
||||||
self.pms_token = None
|
self.pms_token = None
|
||||||
self.avatar = None
|
self.avatar = None
|
||||||
self.restricted_user = None
|
self.restricted_user = None
|
||||||
self.authenticated = False
|
self.authenticated = False
|
||||||
|
try:
|
||||||
|
self._session.close()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
self._session = None
|
self._session = None
|
||||||
|
|
||||||
utils.settings('username', value='')
|
utils.settings('username', value='')
|
||||||
|
@ -91,6 +98,12 @@ class Account(object):
|
||||||
self.avatar = None
|
self.avatar = None
|
||||||
self.restricted_user = None
|
self.restricted_user = None
|
||||||
self.authenticated = False
|
self.authenticated = False
|
||||||
|
self.plex_login = None
|
||||||
|
self.plex_login_id = None
|
||||||
|
try:
|
||||||
|
self._session.close()
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
self._session = None
|
self._session = None
|
||||||
|
|
||||||
utils.settings('username', value='')
|
utils.settings('username', value='')
|
||||||
|
@ -99,6 +112,8 @@ class Account(object):
|
||||||
utils.settings('plexToken', value='')
|
utils.settings('plexToken', value='')
|
||||||
utils.settings('accessToken', value='')
|
utils.settings('accessToken', value='')
|
||||||
utils.settings('plexAvatar', value='')
|
utils.settings('plexAvatar', value='')
|
||||||
|
utils.settings('plexLogin', value='')
|
||||||
|
utils.settings('plexid', value='')
|
||||||
|
|
||||||
utils.window('plex_restricteduser', clear=True)
|
utils.window('plex_restricteduser', clear=True)
|
||||||
utils.window('plex_token', clear=True)
|
utils.window('plex_token', clear=True)
|
||||||
|
|
|
@ -17,7 +17,10 @@ class App(object):
|
||||||
return
|
return
|
||||||
# Quit PKC?
|
# Quit PKC?
|
||||||
self.stop_pkc = False
|
self.stop_pkc = False
|
||||||
|
# Shall we completely suspend PKC and our threads?
|
||||||
|
self.suspend = False
|
||||||
|
# Shall we only suspend threads?
|
||||||
|
self._suspend_threads = False
|
||||||
# Need to lock all methods and functions messing with Plex Companion subscribers
|
# Need to lock all methods and functions messing with Plex Companion subscribers
|
||||||
self.lock_subscriber = RLock()
|
self.lock_subscriber = RLock()
|
||||||
# Need to lock everything messing with Kodi/PKC playqueues
|
# Need to lock everything messing with Kodi/PKC playqueues
|
||||||
|
@ -43,3 +46,11 @@ class App(object):
|
||||||
# Hack to force Kodi widget for "in progress" to show up if it was empty
|
# Hack to force Kodi widget for "in progress" to show up if it was empty
|
||||||
# before
|
# before
|
||||||
self.force_reload_skin = utils.settings('forceReloadSkinOnPlaybackStop') == 'true'
|
self.force_reload_skin = utils.settings('forceReloadSkinOnPlaybackStop') == 'true'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def suspend_threads(self):
|
||||||
|
return self._suspend_threads or self.suspend
|
||||||
|
|
||||||
|
@suspend_threads.setter
|
||||||
|
def suspend_threads(self, value):
|
||||||
|
self._suspend_threads = value
|
||||||
|
|
|
@ -16,12 +16,6 @@ class Connection(object):
|
||||||
return
|
return
|
||||||
# TODO: Delete
|
# TODO: Delete
|
||||||
self.pms_server = None
|
self.pms_server = None
|
||||||
# Plex Media Server Status - along with window('plex_serverStatus')
|
|
||||||
# Values:
|
|
||||||
# 'Stop': set if e.g.
|
|
||||||
# '401': Token has been revoked - PKC yet to delete tokens
|
|
||||||
# 'Auth':
|
|
||||||
self.pms_status = False
|
|
||||||
# Token passed along, e.g. if playback initiated by Plex Companion. Might be
|
# Token passed along, e.g. if playback initiated by Plex Companion. Might be
|
||||||
# another user playing something! Token identifies user
|
# another user playing something! Token identifies user
|
||||||
self.plex_transient_token = None
|
self.plex_transient_token = None
|
||||||
|
@ -61,6 +55,7 @@ class Connection(object):
|
||||||
else:
|
else:
|
||||||
self.server = 'http://%s:%s' % (self.host, self.port)
|
self.server = 'http://%s:%s' % (self.host, self.port)
|
||||||
utils.window('pms_server', value=self.server)
|
utils.window('pms_server', value=self.server)
|
||||||
|
self.online = False
|
||||||
LOG.debug('Set server %s (%s) to %s',
|
LOG.debug('Set server %s (%s) to %s',
|
||||||
self.server_name, self.machine_identifier, self.server)
|
self.server_name, self.machine_identifier, self.server)
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,6 @@ class Sync(object):
|
||||||
return
|
return
|
||||||
# Do we need to run a special library scan?
|
# Do we need to run a special library scan?
|
||||||
self.run_lib_scan = None
|
self.run_lib_scan = None
|
||||||
# Usually triggered by another Python instance - will have to be set (by
|
|
||||||
# polling window) through e.g. librarysync thread
|
|
||||||
self.suspend_library_thread = False
|
|
||||||
# Set if user decided to cancel sync
|
# Set if user decided to cancel sync
|
||||||
self.stop_sync = False
|
self.stop_sync = False
|
||||||
# Set during media playback if PKC should not do any syncs. Will NOT
|
# Set during media playback if PKC should not do any syncs. Will NOT
|
||||||
|
|
|
@ -160,15 +160,18 @@ class Task(object):
|
||||||
return not self.finished and not self._canceled
|
return not self.finished and not self._canceled
|
||||||
|
|
||||||
|
|
||||||
def FunctionAsTask(Task):
|
class FunctionAsTask(Task):
|
||||||
def __init__(self, function, *args, **kwargs):
|
def __init__(self, function, callback, *args, **kwargs):
|
||||||
self.function = function
|
self._function = function
|
||||||
|
self._callback = callback
|
||||||
self._args = args
|
self._args = args
|
||||||
self._kwargs = kwargs
|
self._kwargs = kwargs
|
||||||
super(FunctionAsTask, self).__init__()
|
super(FunctionAsTask, self).__init__()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.function(*self._args, **self._kwargs)
|
result = self._function(*self._args, **self._kwargs)
|
||||||
|
if self._callback:
|
||||||
|
self._callback(result)
|
||||||
|
|
||||||
|
|
||||||
class MutablePriorityQueue(Queue.PriorityQueue):
|
class MutablePriorityQueue(Queue.PriorityQueue):
|
||||||
|
|
|
@ -28,9 +28,11 @@ class DownloadUtils():
|
||||||
_shared_state = {}
|
_shared_state = {}
|
||||||
|
|
||||||
# How many failed attempts before declaring PMS dead?
|
# How many failed attempts before declaring PMS dead?
|
||||||
connectionAttempts = 1
|
connection_attempts = 1
|
||||||
|
count_error = 0
|
||||||
# How many 401 returns before declaring unauthorized?
|
# How many 401 returns before declaring unauthorized?
|
||||||
unauthorizedAttempts = 2
|
unauthorized_attempts = 2
|
||||||
|
count_unauthorized = 0
|
||||||
# How long should we wait for an answer from the
|
# How long should we wait for an answer from the
|
||||||
timeout = 30.0
|
timeout = 30.0
|
||||||
|
|
||||||
|
@ -69,11 +71,9 @@ class DownloadUtils():
|
||||||
self.setSSL()
|
self.setSSL()
|
||||||
|
|
||||||
# Counters to declare PMS dead or unauthorized
|
# Counters to declare PMS dead or unauthorized
|
||||||
# Use window variables because start of movies will be called with a
|
|
||||||
# new plugin instance - it's impossible to share data otherwise
|
|
||||||
if reset is True:
|
if reset is True:
|
||||||
utils.window('countUnauthorized', value='0')
|
self.count_error = 0
|
||||||
utils.window('countError', value='0')
|
self.count_unauthorized = 0
|
||||||
|
|
||||||
# Retry connections to the server
|
# Retry connections to the server
|
||||||
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||||
|
@ -210,9 +210,9 @@ class DownloadUtils():
|
||||||
else:
|
else:
|
||||||
# We COULD contact the PMS, hence it ain't dead
|
# We COULD contact the PMS, hence it ain't dead
|
||||||
if authenticate is True:
|
if authenticate is True:
|
||||||
utils.window('countError', value='0')
|
self.count_error = 0
|
||||||
if r.status_code != 401:
|
if r.status_code != 401:
|
||||||
utils.window('countUnauthorized', value='0')
|
self.count_unauthorized = 0
|
||||||
|
|
||||||
if r.status_code == 204:
|
if r.status_code == 204:
|
||||||
# No body in the response
|
# No body in the response
|
||||||
|
@ -230,22 +230,16 @@ class DownloadUtils():
|
||||||
LOG.info(r.text)
|
LOG.info(r.text)
|
||||||
if '401 Unauthorized' in r.text:
|
if '401 Unauthorized' in r.text:
|
||||||
# Truly unauthorized
|
# Truly unauthorized
|
||||||
utils.window(
|
self.count_unauthorized += 1
|
||||||
'countUnauthorized',
|
if self.count_unauthorized >= self.unauthorized_attempts:
|
||||||
value=str(int(utils.window('countUnauthorized')) + 1))
|
|
||||||
if (int(utils.window('countUnauthorized')) >=
|
|
||||||
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 app.CONN.pms_status not in ('401', 'Auth'):
|
# Unauthorized access, user no longer has access
|
||||||
# Tell others token has been revoked.
|
app.ACCOUNT.log_out()
|
||||||
LOG.debug('Setting PMS server status to '
|
utils.dialog('notification',
|
||||||
'unauthorized')
|
utils.lang(29999),
|
||||||
app.CONN.pms_status = '401'
|
utils.lang(30017),
|
||||||
utils.dialog('notification',
|
icon='{error}')
|
||||||
utils.lang(29999),
|
|
||||||
utils.lang(30017),
|
|
||||||
icon='{error}')
|
|
||||||
else:
|
else:
|
||||||
# there might be other 401 where e.g. PMS under strain
|
# there might be other 401 where e.g. PMS under strain
|
||||||
LOG.info('PMS might only be under strain')
|
LOG.info('PMS might only be under strain')
|
||||||
|
@ -284,7 +278,7 @@ class DownloadUtils():
|
||||||
elif r.status_code == 403:
|
elif r.status_code == 403:
|
||||||
# E.g. deleting a PMS item
|
# E.g. deleting a PMS item
|
||||||
LOG.warn('PMS sent 403: Forbidden error for url %s', url)
|
LOG.warn('PMS sent 403: Forbidden error for url %s', url)
|
||||||
return None
|
return
|
||||||
else:
|
else:
|
||||||
r.encoding = 'utf-8'
|
r.encoding = 'utf-8'
|
||||||
LOG.warn('Unknown answer from PMS %s with status code %s. ',
|
LOG.warn('Unknown answer from PMS %s with status code %s. ',
|
||||||
|
@ -294,14 +288,9 @@ class DownloadUtils():
|
||||||
# And now deal with the consequences of the exceptions
|
# And now deal with the consequences of the exceptions
|
||||||
if authenticate is True:
|
if authenticate is True:
|
||||||
# Make the addon aware of status
|
# Make the addon aware of status
|
||||||
try:
|
self.count_error += 1
|
||||||
utils.window('countError',
|
if self.count_error >= self.connection_attempts:
|
||||||
value=str(int(utils.window('countError')) + 1))
|
LOG.warn('Failed to connect to %s too many times. '
|
||||||
if int(utils.window('countError')) >= self.connectionAttempts:
|
'Declare PMS dead', url)
|
||||||
LOG.warn('Failed to connect to %s too many times. '
|
app.CONN.online = False
|
||||||
'Declare PMS dead', url)
|
return
|
||||||
utils.window('plex_online', value="false")
|
|
||||||
except ValueError:
|
|
||||||
# 'countError' not yet set
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ class InitialSetup(object):
|
||||||
# Get Plex credentials from settings file, if they exist
|
# Get Plex credentials from settings file, if they exist
|
||||||
plexdict = PF.GetPlexLoginFromSettings()
|
plexdict = PF.GetPlexLoginFromSettings()
|
||||||
self.plex_login = plexdict['plexLogin']
|
self.plex_login = plexdict['plexLogin']
|
||||||
|
self.plex_login_id = plexdict['plexid']
|
||||||
self.plex_token = plexdict['plexToken']
|
self.plex_token = plexdict['plexToken']
|
||||||
self.plexid = plexdict['plexid']
|
|
||||||
# Token for the PMS, not plex.tv
|
# Token for the PMS, not plex.tv
|
||||||
self.pms_token = utils.settings('accessToken')
|
self.pms_token = utils.settings('accessToken')
|
||||||
if self.plex_token:
|
if self.plex_token:
|
||||||
|
@ -66,7 +66,7 @@ class InitialSetup(object):
|
||||||
Writes Plex username, token to plex.tv and Plex id to PKC settings
|
Writes Plex username, token to plex.tv and Plex id to PKC settings
|
||||||
"""
|
"""
|
||||||
utils.settings('username', value=self.plex_login or '')
|
utils.settings('username', value=self.plex_login or '')
|
||||||
utils.settings('userid', value=self.plexid or '')
|
utils.settings('userid', value=self.plex_login_id or '')
|
||||||
utils.settings('plexToken', value=self.plex_token or '')
|
utils.settings('plexToken', value=self.plex_token or '')
|
||||||
|
|
||||||
def enter_new_pms_address(self):
|
def enter_new_pms_address(self):
|
||||||
|
@ -117,14 +117,11 @@ class InitialSetup(object):
|
||||||
|
|
||||||
Returns True if successful, or False if not
|
Returns True if successful, or False if not
|
||||||
"""
|
"""
|
||||||
try:
|
user = plex_tv.sign_in_with_pin()
|
||||||
user = plex_tv.sign_in_with_pin()
|
|
||||||
except:
|
|
||||||
utils.ERROR()
|
|
||||||
if user:
|
if user:
|
||||||
self.plex_login = user.username
|
self.plex_login = user.username
|
||||||
self.plex_token = user.authToken
|
self.plex_token = user.authToken
|
||||||
self.plexid = user.id
|
self.plex_login_id = user.id
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -600,7 +597,7 @@ class InitialSetup(object):
|
||||||
goto_settings = utils.yesno_dialog(utils.lang(29999),
|
goto_settings = utils.yesno_dialog(utils.lang(29999),
|
||||||
utils.lang(39017))
|
utils.lang(39017))
|
||||||
if goto_settings:
|
if goto_settings:
|
||||||
state.PMS_STATUS = 'Stop'
|
app.APP.suspend = True
|
||||||
executebuiltin(
|
executebuiltin(
|
||||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||||
elif reboot is True:
|
elif reboot is True:
|
||||||
|
|
|
@ -54,6 +54,8 @@ class KodiMonitor(xbmc.Monitor):
|
||||||
Monitor the PKC settings for changes made by the user
|
Monitor the PKC settings for changes made by the user
|
||||||
"""
|
"""
|
||||||
LOG.debug('PKC settings change detected')
|
LOG.debug('PKC settings change detected')
|
||||||
|
# Assume that the user changed something so we can try to reconnect
|
||||||
|
app.APP.suspend = False
|
||||||
|
|
||||||
def onNotification(self, sender, method, data):
|
def onNotification(self, sender, method, data):
|
||||||
"""
|
"""
|
||||||
|
@ -129,11 +131,10 @@ class KodiMonitor(xbmc.Monitor):
|
||||||
elif method == "System.OnSleep":
|
elif method == "System.OnSleep":
|
||||||
# Connection is going to sleep
|
# Connection is going to sleep
|
||||||
LOG.info("Marking the server as offline. SystemOnSleep activated.")
|
LOG.info("Marking the server as offline. SystemOnSleep activated.")
|
||||||
utils.window('plex_online', value="sleep")
|
|
||||||
elif method == "System.OnWake":
|
elif method == "System.OnWake":
|
||||||
# Allow network to wake up
|
# Allow network to wake up
|
||||||
self.waitForAbort(10)
|
self.waitForAbort(10)
|
||||||
utils.window('plex_online', value="false")
|
app.CONN.online = False
|
||||||
elif method == "GUI.OnScreensaverDeactivated":
|
elif method == "GUI.OnScreensaverDeactivated":
|
||||||
if utils.settings('dbSyncScreensaver') == "true":
|
if utils.settings('dbSyncScreensaver') == "true":
|
||||||
self.waitForAbort(5)
|
self.waitForAbort(5)
|
||||||
|
@ -511,7 +512,7 @@ def _record_playstate(status, ended):
|
||||||
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
|
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
|
||||||
LOG.debug('Refreshing skin to update widgets')
|
LOG.debug('Refreshing skin to update widgets')
|
||||||
xbmc.executebuiltin('ReloadSkin()')
|
xbmc.executebuiltin('ReloadSkin()')
|
||||||
task = backgroundthread.FunctionAsTask(_clean_file_table)
|
task = backgroundthread.FunctionAsTask(function=_clean_file_table)
|
||||||
backgroundthread.BGThreader.addTasksToFront(task)
|
backgroundthread.BGThreader.addTasksToFront(task)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from .. import app
|
||||||
class libsync_mixin(object):
|
class libsync_mixin(object):
|
||||||
def isCanceled(self):
|
def isCanceled(self):
|
||||||
return (self._canceled or app.APP.stop_pkc or app.SYNC.stop_sync or
|
return (self._canceled or app.APP.stop_pkc or app.SYNC.stop_sync or
|
||||||
app.SYNC.suspend_library_thread or app.SYNC.suspend_sync)
|
app.APP.suspend_threads or app.SYNC.suspend_sync)
|
||||||
|
|
||||||
|
|
||||||
def update_kodi_library(video=True, music=True):
|
def update_kodi_library(video=True, music=True):
|
||||||
|
|
|
@ -18,7 +18,7 @@ PREFER_KODI_COLLECTION_ART = utils.settings('PreferKodiCollectionArt') == 'false
|
||||||
|
|
||||||
|
|
||||||
def suspends():
|
def suspends():
|
||||||
return (app.SYNC.suspend_library_thread or
|
return (app.APP.suspend_threads or
|
||||||
app.SYNC.stop_sync or
|
app.SYNC.stop_sync or
|
||||||
app.SYNC.db_scan or
|
app.SYNC.db_scan or
|
||||||
app.SYNC.suspend_sync)
|
app.SYNC.suspend_sync)
|
||||||
|
|
|
@ -22,7 +22,7 @@ PLAYSTATE_SESSIONS = {}
|
||||||
|
|
||||||
|
|
||||||
def interrupt_processing():
|
def interrupt_processing():
|
||||||
return app.APP.stop_pkc or app.SYNC.suspend_library_thread or app.SYNC.stop_sync
|
return app.APP.stop_pkc or app.APP.suspend_threads or app.SYNC.stop_sync
|
||||||
|
|
||||||
|
|
||||||
def multi_delete(input_list, delete_list):
|
def multi_delete(input_list, delete_list):
|
||||||
|
|
|
@ -101,7 +101,7 @@ class PlayqueueMonitor(backgroundthread.KillableThread):
|
||||||
"""
|
"""
|
||||||
Returns True if the thread is suspended
|
Returns True if the thread is suspended
|
||||||
"""
|
"""
|
||||||
return self._suspended or app.CONN.pms_status
|
return self._suspended or app.APP.suspend_threads
|
||||||
|
|
||||||
def _compare_playqueues(self, playqueue, new):
|
def _compare_playqueues(self, playqueue, new):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -84,7 +84,7 @@ class PlexCompanion(backgroundthread.KillableThread):
|
||||||
"""
|
"""
|
||||||
Returns True if the thread is suspended
|
Returns True if the thread is suspended
|
||||||
"""
|
"""
|
||||||
return self._suspended or app.CONN.pms_status
|
return self._suspended or app.APP.suspend
|
||||||
|
|
||||||
def _process_alexa(self, data):
|
def _process_alexa(self, data):
|
||||||
xml = PF.GetPlexMetadata(data['key'])
|
xml = PF.GetPlexMetadata(data['key'])
|
||||||
|
|
|
@ -17,6 +17,7 @@ from . import playqueue
|
||||||
from . import variables as v
|
from . import variables as v
|
||||||
from . import app
|
from . import app
|
||||||
from . import loghandler
|
from . import loghandler
|
||||||
|
from . import backgroundthread
|
||||||
from .windows import userselect
|
from .windows import userselect
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -25,11 +26,11 @@ LOG = logging.getLogger("PLEX.service")
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
WINDOW_PROPERTIES = (
|
WINDOW_PROPERTIES = (
|
||||||
"plex_online", "plex_command_processed", "plex_shouldStop", "plex_dbScan",
|
"plex_command_processed", "plex_shouldStop", "plex_dbScan",
|
||||||
"plex_customplayqueue", "plex_playbackProps",
|
"plex_customplayqueue", "plex_playbackProps",
|
||||||
"pms_token", "plex_token", "pms_server", "plex_machineIdentifier",
|
"pms_token", "plex_token", "pms_server", "plex_machineIdentifier",
|
||||||
"plex_servername", "plex_authenticated", "PlexUserImage", "useDirectPaths",
|
"plex_servername", "plex_authenticated", "PlexUserImage", "useDirectPaths",
|
||||||
"countError", "countUnauthorized", "plex_restricteduser",
|
"plex_restricteduser",
|
||||||
"plex_allows_mediaDeletion", "plex_command", "plex_result",
|
"plex_allows_mediaDeletion", "plex_command", "plex_result",
|
||||||
"plex_force_transcode_pix"
|
"plex_force_transcode_pix"
|
||||||
)
|
)
|
||||||
|
@ -40,13 +41,6 @@ class Service():
|
||||||
sync = None
|
sync = None
|
||||||
plexcompanion = None
|
plexcompanion = None
|
||||||
|
|
||||||
ws_running = False
|
|
||||||
alexa_running = False
|
|
||||||
sync_running = False
|
|
||||||
plexcompanion_running = False
|
|
||||||
kodimonitor_running = False
|
|
||||||
playback_starter_running = False
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Initial logging
|
# Initial logging
|
||||||
LOG.info("======== START %s ========", v.ADDON_NAME)
|
LOG.info("======== START %s ========", v.ADDON_NAME)
|
||||||
|
@ -87,15 +81,71 @@ class Service():
|
||||||
# Init time-offset between Kodi and Plex
|
# Init time-offset between Kodi and Plex
|
||||||
timing.KODI_PLEX_TIME_OFFSET = float(utils.settings('kodiplextimeoffset') or 0.0)
|
timing.KODI_PLEX_TIME_OFFSET = float(utils.settings('kodiplextimeoffset') or 0.0)
|
||||||
|
|
||||||
def isCanceled(self):
|
self.startup_completed = False
|
||||||
return xbmc.abortRequested
|
self.server_has_been_online = True
|
||||||
|
self.welcome_msg = True
|
||||||
|
self.connection_check_counter = 0
|
||||||
|
# Flags for other threads
|
||||||
|
self.connection_check_running = False
|
||||||
|
self.auth_running = False
|
||||||
|
|
||||||
|
def on_connection_check(self, result):
|
||||||
|
"""
|
||||||
|
Call this method after PF.check_connection()
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if result is False:
|
||||||
|
# Server is offline or cannot be reached
|
||||||
|
# Alert the user and suppress future warning
|
||||||
|
if app.CONN.online:
|
||||||
|
# PMS was online before
|
||||||
|
app.CONN.online = False
|
||||||
|
app.APP.suspend_threads = True
|
||||||
|
LOG.warn("Plex Media Server went offline")
|
||||||
|
if utils.settings('show_pms_offline') == 'true':
|
||||||
|
utils.dialog('notification',
|
||||||
|
utils.lang(33001),
|
||||||
|
"%s %s" % (utils.lang(29999),
|
||||||
|
utils.lang(33002)),
|
||||||
|
icon='{plex}',
|
||||||
|
sound=False)
|
||||||
|
self.connection_check_counter += 1
|
||||||
|
# Periodically check if the IP changed every 15 seconds
|
||||||
|
if self.connection_check_counter > 150:
|
||||||
|
self.connection_check_counter = 0
|
||||||
|
server = self.setup.pick_pms()
|
||||||
|
if server:
|
||||||
|
self.setup.write_pms_to_settings(server)
|
||||||
|
app.CONN.load()
|
||||||
|
else:
|
||||||
|
# Server is online
|
||||||
|
self.connection_check_counter = 0
|
||||||
|
if not app.CONN.online:
|
||||||
|
# Server was offline before
|
||||||
|
if (self.welcome_msg is False and
|
||||||
|
utils.settings('show_pms_offline') == 'true'):
|
||||||
|
# Alert the user that server is online
|
||||||
|
utils.dialog('notification',
|
||||||
|
utils.lang(29999),
|
||||||
|
utils.lang(33003),
|
||||||
|
icon='{plex}',
|
||||||
|
time=5000,
|
||||||
|
sound=False)
|
||||||
|
LOG.info("Server is online and ready")
|
||||||
|
if app.ACCOUNT.authenticated:
|
||||||
|
# Server got offline when we were authenticated.
|
||||||
|
# Hence resume threads
|
||||||
|
app.APP.suspend_threads = False
|
||||||
|
app.CONN.online = True
|
||||||
|
finally:
|
||||||
|
self.connection_check_running = False
|
||||||
|
|
||||||
def log_out(self):
|
def log_out(self):
|
||||||
"""
|
"""
|
||||||
Ensures that lib sync threads are suspended; signs out user
|
Ensures that lib sync threads are suspended; signs out user
|
||||||
"""
|
"""
|
||||||
LOG.info('Log-out requested')
|
LOG.info('Log-out requested')
|
||||||
app.SYNC.suspend_library_thread = True
|
app.APP.suspend_threads = True
|
||||||
i = 0
|
i = 0
|
||||||
while app.SYNC.db_scan:
|
while app.SYNC.db_scan:
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -105,7 +155,7 @@ class Service():
|
||||||
# Failed to reset PMS and plex.tv connects. Try to restart Kodi
|
# Failed to reset PMS and plex.tv connects. Try to restart Kodi
|
||||||
utils.messageDialog(utils.lang(29999), utils.lang(39208))
|
utils.messageDialog(utils.lang(29999), utils.lang(39208))
|
||||||
# Resuming threads, just in case
|
# Resuming threads, just in case
|
||||||
app.SYNC.suspend_library_thread = False
|
app.APP.suspend_threads = False
|
||||||
return False
|
return False
|
||||||
LOG.info('Successfully stopped library sync')
|
LOG.info('Successfully stopped library sync')
|
||||||
app.ACCOUNT.log_out()
|
app.ACCOUNT.log_out()
|
||||||
|
@ -132,6 +182,9 @@ class Service():
|
||||||
# Wipe Kodi and Plex database as well as playlists and video nodes
|
# Wipe Kodi and Plex database as well as playlists and video nodes
|
||||||
utils.wipe_database()
|
utils.wipe_database()
|
||||||
app.CONN.load()
|
app.CONN.load()
|
||||||
|
app.ACCOUNT.set_unauthenticated()
|
||||||
|
self.server_has_been_online = False
|
||||||
|
self.welcome_msg = False
|
||||||
LOG.info("Choosing new PMS complete")
|
LOG.info("Choosing new PMS complete")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -142,16 +195,19 @@ class Service():
|
||||||
utils.delete_playlists()
|
utils.delete_playlists()
|
||||||
# Remove video nodes
|
# Remove video nodes
|
||||||
utils.delete_nodes()
|
utils.delete_nodes()
|
||||||
|
app.ACCOUNT.set_unauthenticated()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def toggle_plex_tv(self):
|
def toggle_plex_tv(self):
|
||||||
if utils.settings('plexToken'):
|
if app.ACCOUNT.plex_token:
|
||||||
LOG.info('Reseting plex.tv credentials in settings')
|
LOG.info('Resetting plex.tv credentials in settings')
|
||||||
|
self.log_out()
|
||||||
app.ACCOUNT.clear()
|
app.ACCOUNT.clear()
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
LOG.info('Login to plex.tv')
|
LOG.info('Login to plex.tv')
|
||||||
return self.setup.plex_tv_sign_in()
|
if self.setup.plex_tv_sign_in():
|
||||||
|
self.setup.write_credentials_to_settings()
|
||||||
|
app.ACCOUNT.load()
|
||||||
|
|
||||||
def authenticate(self):
|
def authenticate(self):
|
||||||
"""
|
"""
|
||||||
|
@ -160,9 +216,30 @@ class Service():
|
||||||
Returns True if successful, False if not. 'aborted' if user chose to
|
Returns True if successful, False if not. 'aborted' if user chose to
|
||||||
abort
|
abort
|
||||||
"""
|
"""
|
||||||
|
if self._do_auth():
|
||||||
|
if self.welcome_msg is True:
|
||||||
|
# Reset authentication warnings
|
||||||
|
self.welcome_msg = False
|
||||||
|
utils.dialog('notification',
|
||||||
|
utils.lang(29999),
|
||||||
|
"%s %s" % (utils.lang(33000),
|
||||||
|
app.ACCOUNT.plex_username),
|
||||||
|
icon='{plex}',
|
||||||
|
time=2000,
|
||||||
|
sound=False)
|
||||||
|
app.APP.suspend_threads = False
|
||||||
|
self.auth_running = False
|
||||||
|
|
||||||
|
def enter_new_pms_address(self):
|
||||||
|
if self.setup.enter_new_pms_address():
|
||||||
|
app.CONN.load()
|
||||||
|
app.ACCOUNT.set_unauthenticated()
|
||||||
|
self.server_has_been_online = False
|
||||||
|
self.welcome_msg = False
|
||||||
|
|
||||||
|
def _do_auth(self):
|
||||||
LOG.info('Authenticating user')
|
LOG.info('Authenticating user')
|
||||||
if app.ACCOUNT.plex_username and not app.ACCOUNT.force_login:
|
if app.ACCOUNT.plex_username and not app.ACCOUNT.force_login: # Found a user in the settings, try to authenticate
|
||||||
# Found a user in the settings, try to authenticate
|
|
||||||
LOG.info('Trying to authenticate with old settings')
|
LOG.info('Trying to authenticate with old settings')
|
||||||
res = PF.check_connection(app.CONN.server,
|
res = PF.check_connection(app.CONN.server,
|
||||||
token=app.ACCOUNT.pms_token,
|
token=app.ACCOUNT.pms_token,
|
||||||
|
@ -171,8 +248,9 @@ class Service():
|
||||||
LOG.error('Something went wrong while checking connection')
|
LOG.error('Something went wrong while checking connection')
|
||||||
return False
|
return False
|
||||||
elif res == 401:
|
elif res == 401:
|
||||||
LOG.error('User token no longer valid. Sign user out')
|
LOG.error('User %s no longer has access - signing user out',
|
||||||
app.ACCOUNT.clear()
|
app.ACCOUNT.plex_username)
|
||||||
|
self.log_out()
|
||||||
return False
|
return False
|
||||||
elif res >= 400:
|
elif res >= 400:
|
||||||
LOG.error('Answer from PMS is not as expected')
|
LOG.error('Answer from PMS is not as expected')
|
||||||
|
@ -188,7 +266,7 @@ class Service():
|
||||||
user, _ = userselect.start()
|
user, _ = userselect.start()
|
||||||
if not user:
|
if not user:
|
||||||
LOG.info('No user received')
|
LOG.info('No user received')
|
||||||
app.CONN.pms_status = 'Stop'
|
app.APP.suspend = True
|
||||||
return False
|
return False
|
||||||
username = user.title
|
username = user.title
|
||||||
user_id = user.id
|
user_id = user.id
|
||||||
|
@ -206,10 +284,12 @@ class Service():
|
||||||
return False
|
return False
|
||||||
elif res == 401:
|
elif res == 401:
|
||||||
if app.ACCOUNT.plex_token:
|
if app.ACCOUNT.plex_token:
|
||||||
LOG.error('Token no longer valid')
|
LOG.error('User %s does not have access to PMS %s on %s',
|
||||||
# "Your Plex token is no longer valid. Logging-out of plex.tv"
|
username, app.CONN.server_name, app.CONN.server)
|
||||||
utils.messageDialog(utils.lang(29999), utils.lang(33010))
|
# "User is unauthorized for server {0}"
|
||||||
app.ACCOUNT.clear()
|
utils.messageDialog(utils.lang(29999),
|
||||||
|
utils.lang(33010).format(app.CONN.server_name))
|
||||||
|
self.log_out()
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# "Failed to authenticate. Did you login to plex.tv?"
|
# "Failed to authenticate. Did you login to plex.tv?"
|
||||||
|
@ -219,6 +299,7 @@ class Service():
|
||||||
app.ACCOUNT.load()
|
app.ACCOUNT.load()
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
app.APP.suspend = True
|
||||||
return False
|
return False
|
||||||
elif res >= 400:
|
elif res >= 400:
|
||||||
LOG.error('Answer from PMS is not as expected')
|
LOG.error('Answer from PMS is not as expected')
|
||||||
|
@ -235,12 +316,12 @@ class Service():
|
||||||
def ServiceEntryPoint(self):
|
def ServiceEntryPoint(self):
|
||||||
# Important: Threads depending on abortRequest will not trigger
|
# Important: Threads depending on abortRequest will not trigger
|
||||||
# if profile switch happens more than once.
|
# if profile switch happens more than once.
|
||||||
app.init()
|
|
||||||
# Some plumbing
|
# Some plumbing
|
||||||
|
app.init()
|
||||||
app.APP.monitor = kodimonitor.KodiMonitor()
|
app.APP.monitor = kodimonitor.KodiMonitor()
|
||||||
app.APP.player = xbmc.Player()
|
app.APP.player = xbmc.Player()
|
||||||
artwork.IMAGE_CACHING_SUSPENDS = [
|
artwork.IMAGE_CACHING_SUSPENDS = [
|
||||||
app.SYNC.suspend_library_thread,
|
app.APP.suspend_threads,
|
||||||
app.SYNC.stop_sync,
|
app.SYNC.stop_sync,
|
||||||
app.SYNC.db_scan
|
app.SYNC.db_scan
|
||||||
]
|
]
|
||||||
|
@ -262,11 +343,9 @@ class Service():
|
||||||
self.playback_starter = playback_starter.PlaybackStarter()
|
self.playback_starter = playback_starter.PlaybackStarter()
|
||||||
self.playqueue = playqueue.PlayqueueMonitor()
|
self.playqueue = playqueue.PlayqueueMonitor()
|
||||||
|
|
||||||
server_online = True
|
# Main PKC program loop
|
||||||
welcome_msg = True
|
while not xbmc.abortRequested:
|
||||||
counter = 0
|
# Check for Kodi profile change
|
||||||
while not self.isCanceled():
|
|
||||||
|
|
||||||
if utils.window('plex_kodiProfile') != v.KODI_PROFILE:
|
if utils.window('plex_kodiProfile') != v.KODI_PROFILE:
|
||||||
# Profile change happened, terminate this thread and others
|
# Profile change happened, terminate this thread and others
|
||||||
LOG.info("Kodi profile was: %s and changed to: %s. "
|
LOG.info("Kodi profile was: %s and changed to: %s. "
|
||||||
|
@ -274,6 +353,7 @@ class Service():
|
||||||
v.KODI_PROFILE, utils.window('plex_kodiProfile'))
|
v.KODI_PROFILE, utils.window('plex_kodiProfile'))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Check for PKC commands from other Python instances
|
||||||
plex_command = utils.window('plex_command')
|
plex_command = utils.window('plex_command')
|
||||||
if plex_command:
|
if plex_command:
|
||||||
# Commands/user interaction received from other PKC Python
|
# Commands/user interaction received from other PKC Python
|
||||||
|
@ -291,24 +371,21 @@ class Service():
|
||||||
'dummy?mode=context_menu&%s'
|
'dummy?mode=context_menu&%s'
|
||||||
% plex_command.replace('CONTEXT_menu?', ''))
|
% plex_command.replace('CONTEXT_menu?', ''))
|
||||||
elif plex_command == 'choose_pms_server':
|
elif plex_command == 'choose_pms_server':
|
||||||
if self.choose_pms_server():
|
task = backgroundthread.FunctionAsTask(
|
||||||
utils.window('plex_online', clear=True)
|
self.choose_pms_server, None)
|
||||||
app.ACCOUNT.set_unauthenticated()
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
server_online = False
|
|
||||||
welcome_msg = False
|
|
||||||
elif plex_command == 'switch_plex_user':
|
elif plex_command == 'switch_plex_user':
|
||||||
if self.switch_plex_user():
|
task = backgroundthread.FunctionAsTask(
|
||||||
app.ACCOUNT.set_unauthenticated()
|
self.switch_plex_user, None)
|
||||||
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
elif plex_command == 'enter_new_pms_address':
|
elif plex_command == 'enter_new_pms_address':
|
||||||
if self.setup.enter_new_pms_address():
|
task = backgroundthread.FunctionAsTask(
|
||||||
if self.log_out():
|
self.enter_new_pms_address, None)
|
||||||
utils.window('plex_online', clear=True)
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
app.ACCOUNT.set_unauthenticated()
|
|
||||||
server_online = False
|
|
||||||
welcome_msg = False
|
|
||||||
elif plex_command == 'toggle_plex_tv_sign_in':
|
elif plex_command == 'toggle_plex_tv_sign_in':
|
||||||
if self.toggle_plex_tv():
|
task = backgroundthread.FunctionAsTask(
|
||||||
app.ACCOUNT.set_unauthenticated()
|
self.toggle_plex_tv, None)
|
||||||
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
elif plex_command == 'repair-scan':
|
elif plex_command == 'repair-scan':
|
||||||
app.SYNC.run_lib_scan = 'repair'
|
app.SYNC.run_lib_scan = 'repair'
|
||||||
elif plex_command == 'full-scan':
|
elif plex_command == 'full-scan':
|
||||||
|
@ -319,120 +396,51 @@ class Service():
|
||||||
app.SYNC.run_lib_scan = 'textures'
|
app.SYNC.run_lib_scan = 'textures'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if app.APP.suspend:
|
||||||
|
app.APP.monitor.waitForAbort(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
# Before proceeding, need to make sure:
|
# Before proceeding, need to make sure:
|
||||||
# 1. Server is online
|
# 1. Server is online
|
||||||
# 2. User is set
|
# 2. User is set
|
||||||
# 3. User has access to the server
|
# 3. User has access to the server
|
||||||
if utils.window('plex_online') == "true":
|
if not app.CONN.online:
|
||||||
# Plex server is online
|
# Not online
|
||||||
if app.CONN.pms_status == 'Stop':
|
|
||||||
app.APP.monitor.waitForAbort(0.05)
|
|
||||||
continue
|
|
||||||
elif app.CONN.pms_status == '401':
|
|
||||||
# Unauthorized access, revoke token
|
|
||||||
LOG.info('401 received - revoking token')
|
|
||||||
app.ACCOUNT.clear()
|
|
||||||
app.CONN.pms_status = 'Auth'
|
|
||||||
utils.window('plex_serverStatus', value='Auth')
|
|
||||||
continue
|
|
||||||
if not app.ACCOUNT.authenticated:
|
|
||||||
LOG.info('Not yet authenticated')
|
|
||||||
# Do authentication
|
|
||||||
if not self.authenticate():
|
|
||||||
continue
|
|
||||||
# Start up events
|
|
||||||
if welcome_msg is True:
|
|
||||||
# Reset authentication warnings
|
|
||||||
welcome_msg = False
|
|
||||||
utils.dialog('notification',
|
|
||||||
utils.lang(29999),
|
|
||||||
"%s %s" % (utils.lang(33000),
|
|
||||||
app.ACCOUNT.plex_username),
|
|
||||||
icon='{plex}',
|
|
||||||
time=2000,
|
|
||||||
sound=False)
|
|
||||||
# Start monitoring kodi events
|
|
||||||
if not self.kodimonitor_running:
|
|
||||||
self.kodimonitor_running = True
|
|
||||||
self.specialmonitor.start()
|
|
||||||
# Start the Websocket Client
|
|
||||||
if not self.ws_running:
|
|
||||||
self.ws_running = True
|
|
||||||
self.ws.start()
|
|
||||||
# Start the Alexa thread
|
|
||||||
if (not self.alexa_running and
|
|
||||||
utils.settings('enable_alexa') == 'true'):
|
|
||||||
self.alexa_running = True
|
|
||||||
self.alexa.start()
|
|
||||||
# Start the syncing thread
|
|
||||||
if not self.sync_running:
|
|
||||||
self.sync_running = True
|
|
||||||
self.sync.start()
|
|
||||||
# Start the Plex Companion thread
|
|
||||||
if not self.plexcompanion_running:
|
|
||||||
self.plexcompanion_running = True
|
|
||||||
self.plexcompanion.start()
|
|
||||||
if not self.playback_starter_running:
|
|
||||||
self.playback_starter_running = True
|
|
||||||
self.playback_starter.start()
|
|
||||||
self.playqueue.start()
|
|
||||||
else:
|
|
||||||
# Wait until Plex server is online
|
|
||||||
# or Kodi is shut down.
|
|
||||||
server = app.CONN.server
|
server = app.CONN.server
|
||||||
if not server:
|
if not server:
|
||||||
# No server info set in add-on settings
|
# No server info set in add-on settings
|
||||||
pass
|
pass
|
||||||
elif PF.check_connection(server, verifySSL=True) is False:
|
elif not self.connection_check_running:
|
||||||
# Server is offline or cannot be reached
|
self.connection_check_running = True
|
||||||
# Alert the user and suppress future warning
|
task = backgroundthread.FunctionAsTask(
|
||||||
if server_online:
|
PF.check_connection,
|
||||||
server_online = False
|
self.on_connection_check,
|
||||||
utils.window('plex_online', value="false")
|
server,
|
||||||
# Suspend threads
|
verifySSL=True)
|
||||||
app.SYNC.suspend_library_thread = True
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
LOG.warn("Plex Media Server went offline")
|
continue
|
||||||
if utils.settings('show_pms_offline') == 'true':
|
elif not app.ACCOUNT.authenticated:
|
||||||
utils.dialog('notification',
|
# Plex server is online, but we're not yet authenticated
|
||||||
utils.lang(33001),
|
if not self.auth_running:
|
||||||
"%s %s" % (utils.lang(29999),
|
self.auth_running = True
|
||||||
utils.lang(33002)),
|
task = backgroundthread.FunctionAsTask(
|
||||||
icon='{plex}',
|
self.authenticate, None)
|
||||||
sound=False)
|
backgroundthread.BGThreader.addTasksToFront([task])
|
||||||
counter += 1
|
continue
|
||||||
# Periodically check if the IP changed, e.g. per minute
|
elif not self.startup_completed:
|
||||||
if counter > 20:
|
self.startup_completed = True
|
||||||
counter = 0
|
self.specialmonitor.start()
|
||||||
setup = initialsetup.InitialSetup()
|
self.ws.start()
|
||||||
tmp = setup.pick_pms()
|
self.sync.start()
|
||||||
if tmp:
|
self.plexcompanion.start()
|
||||||
setup.write_pms_to_settings(tmp)
|
self.playback_starter.start()
|
||||||
app.CONN.load()
|
self.playqueue.start()
|
||||||
else:
|
if utils.settings('enable_alexa') == 'true':
|
||||||
# Server is online
|
self.alexa.start()
|
||||||
counter = 0
|
|
||||||
if not server_online:
|
|
||||||
# Server was offline when Kodi started.
|
|
||||||
server_online = True
|
|
||||||
# Alert the user that server is online.
|
|
||||||
if (welcome_msg is False and
|
|
||||||
utils.settings('show_pms_offline') == 'true'):
|
|
||||||
utils.dialog('notification',
|
|
||||||
utils.lang(29999),
|
|
||||||
utils.lang(33003),
|
|
||||||
icon='{plex}',
|
|
||||||
time=5000,
|
|
||||||
sound=False)
|
|
||||||
LOG.info("Server %s is online and ready.", server)
|
|
||||||
utils.window('plex_online', value="true")
|
|
||||||
if app.ACCOUNT.authenticated:
|
|
||||||
# Server got offline when we were authenticated.
|
|
||||||
# Hence resume threads
|
|
||||||
app.SYNC.suspend_library_thread = False
|
|
||||||
|
|
||||||
if app.APP.monitor.waitForAbort(0.05):
|
app.APP.monitor.waitForAbort(0.1)
|
||||||
# Abort was requested while waiting. We should exit
|
|
||||||
break
|
# EXITING PKC
|
||||||
# Tell all threads to terminate (e.g. several lib sync threads)
|
# Tell all threads to terminate (e.g. several lib sync threads)
|
||||||
app.APP.stop_pkc = True
|
app.APP.stop_pkc = True
|
||||||
utils.window('plex_service_started', clear=True)
|
utils.window('plex_service_started', clear=True)
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Sync(backgroundthread.KillableThread):
|
||||||
super(Sync, self).__init__()
|
super(Sync, self).__init__()
|
||||||
|
|
||||||
def isSuspended(self):
|
def isSuspended(self):
|
||||||
return self._suspended or app.SYNC.suspend_library_thread
|
return self._suspended or app.APP.suspend_threads
|
||||||
|
|
||||||
def show_kodi_note(self, message, icon="plex", force=False):
|
def show_kodi_note(self, message, icon="plex", force=False):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -137,7 +137,7 @@ class PMS_Websocket(WebSocket):
|
||||||
Returns True if the thread is suspended
|
Returns True if the thread is suspended
|
||||||
"""
|
"""
|
||||||
return (self._suspended or
|
return (self._suspended or
|
||||||
app.SYNC.suspend_library_thread or
|
app.APP.suspend_threads or
|
||||||
app.SYNC.background_sync_disabled)
|
app.SYNC.background_sync_disabled)
|
||||||
|
|
||||||
def getUri(self):
|
def getUri(self):
|
||||||
|
|
Loading…
Reference in a new issue