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()
|
||||
|
||||
elif mode in ('manualsync', 'repair'):
|
||||
if pickler.pickl_window('plex_online') != 'true':
|
||||
# Server is not online, do not run the sync
|
||||
utils.messageDialog(utils.lang(29999), utils.lang(39205))
|
||||
log.error('Not connected to a PMS.')
|
||||
else:
|
||||
if mode == 'repair':
|
||||
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')
|
||||
if mode == 'repair':
|
||||
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':
|
||||
log.info('Requesting texture caching of all textures')
|
||||
|
|
|
@ -619,7 +619,7 @@ msgid "Invalid username or password"
|
|||
msgstr ""
|
||||
|
||||
msgctxt "#33010"
|
||||
msgid "Your Plex token is no longer valid. Logging-out of plex.tv"
|
||||
msgid "User is unauthorized for server {0}"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#33011"
|
||||
|
|
|
@ -30,6 +30,9 @@ class Account(object):
|
|||
|
||||
def load(self):
|
||||
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
|
||||
self.plex_username = utils.settings('username') or None
|
||||
# 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)
|
||||
|
||||
def log_out(self):
|
||||
LOG.debug('Logging-out user')
|
||||
LOG.debug('Logging-out user %s', self.plex_username)
|
||||
self.plex_username = None
|
||||
self.plex_user_id = None
|
||||
self.pms_token = None
|
||||
self.avatar = None
|
||||
self.restricted_user = None
|
||||
self.authenticated = False
|
||||
try:
|
||||
self._session.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
self._session = None
|
||||
|
||||
utils.settings('username', value='')
|
||||
|
@ -91,6 +98,12 @@ class Account(object):
|
|||
self.avatar = None
|
||||
self.restricted_user = None
|
||||
self.authenticated = False
|
||||
self.plex_login = None
|
||||
self.plex_login_id = None
|
||||
try:
|
||||
self._session.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
self._session = None
|
||||
|
||||
utils.settings('username', value='')
|
||||
|
@ -99,6 +112,8 @@ class Account(object):
|
|||
utils.settings('plexToken', value='')
|
||||
utils.settings('accessToken', value='')
|
||||
utils.settings('plexAvatar', value='')
|
||||
utils.settings('plexLogin', value='')
|
||||
utils.settings('plexid', value='')
|
||||
|
||||
utils.window('plex_restricteduser', clear=True)
|
||||
utils.window('plex_token', clear=True)
|
||||
|
|
|
@ -17,7 +17,10 @@ class App(object):
|
|||
return
|
||||
# Quit PKC?
|
||||
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
|
||||
self.lock_subscriber = RLock()
|
||||
# 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
|
||||
# before
|
||||
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
|
||||
# TODO: Delete
|
||||
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
|
||||
# another user playing something! Token identifies user
|
||||
self.plex_transient_token = None
|
||||
|
@ -61,6 +55,7 @@ class Connection(object):
|
|||
else:
|
||||
self.server = 'http://%s:%s' % (self.host, self.port)
|
||||
utils.window('pms_server', value=self.server)
|
||||
self.online = False
|
||||
LOG.debug('Set server %s (%s) to %s',
|
||||
self.server_name, self.machine_identifier, self.server)
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ class Sync(object):
|
|||
return
|
||||
# Do we need to run a special library scan?
|
||||
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
|
||||
self.stop_sync = False
|
||||
# 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
|
||||
|
||||
|
||||
def FunctionAsTask(Task):
|
||||
def __init__(self, function, *args, **kwargs):
|
||||
self.function = function
|
||||
class FunctionAsTask(Task):
|
||||
def __init__(self, function, callback, *args, **kwargs):
|
||||
self._function = function
|
||||
self._callback = callback
|
||||
self._args = args
|
||||
self._kwargs = kwargs
|
||||
super(FunctionAsTask, self).__init__()
|
||||
|
||||
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):
|
||||
|
|
|
@ -28,9 +28,11 @@ class DownloadUtils():
|
|||
_shared_state = {}
|
||||
|
||||
# How many failed attempts before declaring PMS dead?
|
||||
connectionAttempts = 1
|
||||
connection_attempts = 1
|
||||
count_error = 0
|
||||
# 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
|
||||
timeout = 30.0
|
||||
|
||||
|
@ -69,11 +71,9 @@ class DownloadUtils():
|
|||
self.setSSL()
|
||||
|
||||
# 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:
|
||||
utils.window('countUnauthorized', value='0')
|
||||
utils.window('countError', value='0')
|
||||
self.count_error = 0
|
||||
self.count_unauthorized = 0
|
||||
|
||||
# Retry connections to the server
|
||||
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||
|
@ -210,9 +210,9 @@ class DownloadUtils():
|
|||
else:
|
||||
# We COULD contact the PMS, hence it ain't dead
|
||||
if authenticate is True:
|
||||
utils.window('countError', value='0')
|
||||
self.count_error = 0
|
||||
if r.status_code != 401:
|
||||
utils.window('countUnauthorized', value='0')
|
||||
self.count_unauthorized = 0
|
||||
|
||||
if r.status_code == 204:
|
||||
# No body in the response
|
||||
|
@ -230,22 +230,16 @@ class DownloadUtils():
|
|||
LOG.info(r.text)
|
||||
if '401 Unauthorized' in r.text:
|
||||
# Truly unauthorized
|
||||
utils.window(
|
||||
'countUnauthorized',
|
||||
value=str(int(utils.window('countUnauthorized')) + 1))
|
||||
if (int(utils.window('countUnauthorized')) >=
|
||||
self.unauthorizedAttempts):
|
||||
self.count_unauthorized += 1
|
||||
if self.count_unauthorized >= self.unauthorized_attempts:
|
||||
LOG.warn('We seem to be truly unauthorized for PMS'
|
||||
' %s ', url)
|
||||
if app.CONN.pms_status not in ('401', 'Auth'):
|
||||
# Tell others token has been revoked.
|
||||
LOG.debug('Setting PMS server status to '
|
||||
'unauthorized')
|
||||
app.CONN.pms_status = '401'
|
||||
utils.dialog('notification',
|
||||
utils.lang(29999),
|
||||
utils.lang(30017),
|
||||
icon='{error}')
|
||||
# Unauthorized access, user no longer has access
|
||||
app.ACCOUNT.log_out()
|
||||
utils.dialog('notification',
|
||||
utils.lang(29999),
|
||||
utils.lang(30017),
|
||||
icon='{error}')
|
||||
else:
|
||||
# there might be other 401 where e.g. PMS under strain
|
||||
LOG.info('PMS might only be under strain')
|
||||
|
@ -284,7 +278,7 @@ class DownloadUtils():
|
|||
elif r.status_code == 403:
|
||||
# E.g. deleting a PMS item
|
||||
LOG.warn('PMS sent 403: Forbidden error for url %s', url)
|
||||
return None
|
||||
return
|
||||
else:
|
||||
r.encoding = 'utf-8'
|
||||
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
|
||||
if authenticate is True:
|
||||
# Make the addon aware of status
|
||||
try:
|
||||
utils.window('countError',
|
||||
value=str(int(utils.window('countError')) + 1))
|
||||
if int(utils.window('countError')) >= self.connectionAttempts:
|
||||
LOG.warn('Failed to connect to %s too many times. '
|
||||
'Declare PMS dead', url)
|
||||
utils.window('plex_online', value="false")
|
||||
except ValueError:
|
||||
# 'countError' not yet set
|
||||
pass
|
||||
return None
|
||||
self.count_error += 1
|
||||
if self.count_error >= self.connection_attempts:
|
||||
LOG.warn('Failed to connect to %s too many times. '
|
||||
'Declare PMS dead', url)
|
||||
app.CONN.online = False
|
||||
return
|
||||
|
|
|
@ -54,8 +54,8 @@ class InitialSetup(object):
|
|||
# Get Plex credentials from settings file, if they exist
|
||||
plexdict = PF.GetPlexLoginFromSettings()
|
||||
self.plex_login = plexdict['plexLogin']
|
||||
self.plex_login_id = plexdict['plexid']
|
||||
self.plex_token = plexdict['plexToken']
|
||||
self.plexid = plexdict['plexid']
|
||||
# Token for the PMS, not plex.tv
|
||||
self.pms_token = utils.settings('accessToken')
|
||||
if self.plex_token:
|
||||
|
@ -66,7 +66,7 @@ class InitialSetup(object):
|
|||
Writes Plex username, token to plex.tv and Plex id to PKC settings
|
||||
"""
|
||||
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 '')
|
||||
|
||||
def enter_new_pms_address(self):
|
||||
|
@ -117,14 +117,11 @@ class InitialSetup(object):
|
|||
|
||||
Returns True if successful, or False if not
|
||||
"""
|
||||
try:
|
||||
user = plex_tv.sign_in_with_pin()
|
||||
except:
|
||||
utils.ERROR()
|
||||
user = plex_tv.sign_in_with_pin()
|
||||
if user:
|
||||
self.plex_login = user.username
|
||||
self.plex_token = user.authToken
|
||||
self.plexid = user.id
|
||||
self.plex_login_id = user.id
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -600,7 +597,7 @@ class InitialSetup(object):
|
|||
goto_settings = utils.yesno_dialog(utils.lang(29999),
|
||||
utils.lang(39017))
|
||||
if goto_settings:
|
||||
state.PMS_STATUS = 'Stop'
|
||||
app.APP.suspend = True
|
||||
executebuiltin(
|
||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
elif reboot is True:
|
||||
|
|
|
@ -54,6 +54,8 @@ class KodiMonitor(xbmc.Monitor):
|
|||
Monitor the PKC settings for changes made by the user
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
|
@ -129,11 +131,10 @@ class KodiMonitor(xbmc.Monitor):
|
|||
elif method == "System.OnSleep":
|
||||
# Connection is going to sleep
|
||||
LOG.info("Marking the server as offline. SystemOnSleep activated.")
|
||||
utils.window('plex_online', value="sleep")
|
||||
elif method == "System.OnWake":
|
||||
# Allow network to wake up
|
||||
self.waitForAbort(10)
|
||||
utils.window('plex_online', value="false")
|
||||
app.CONN.online = False
|
||||
elif method == "GUI.OnScreensaverDeactivated":
|
||||
if utils.settings('dbSyncScreensaver') == "true":
|
||||
self.waitForAbort(5)
|
||||
|
@ -511,7 +512,7 @@ def _record_playstate(status, ended):
|
|||
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
|
||||
LOG.debug('Refreshing skin to update widgets')
|
||||
xbmc.executebuiltin('ReloadSkin()')
|
||||
task = backgroundthread.FunctionAsTask(_clean_file_table)
|
||||
task = backgroundthread.FunctionAsTask(function=_clean_file_table)
|
||||
backgroundthread.BGThreader.addTasksToFront(task)
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ from .. import app
|
|||
class libsync_mixin(object):
|
||||
def isCanceled(self):
|
||||
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):
|
||||
|
|
|
@ -18,7 +18,7 @@ PREFER_KODI_COLLECTION_ART = utils.settings('PreferKodiCollectionArt') == 'false
|
|||
|
||||
|
||||
def suspends():
|
||||
return (app.SYNC.suspend_library_thread or
|
||||
return (app.APP.suspend_threads or
|
||||
app.SYNC.stop_sync or
|
||||
app.SYNC.db_scan or
|
||||
app.SYNC.suspend_sync)
|
||||
|
|
|
@ -22,7 +22,7 @@ PLAYSTATE_SESSIONS = {}
|
|||
|
||||
|
||||
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):
|
||||
|
|
|
@ -101,7 +101,7 @@ class PlayqueueMonitor(backgroundthread.KillableThread):
|
|||
"""
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -84,7 +84,7 @@ class PlexCompanion(backgroundthread.KillableThread):
|
|||
"""
|
||||
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):
|
||||
xml = PF.GetPlexMetadata(data['key'])
|
||||
|
|
|
@ -17,6 +17,7 @@ from . import playqueue
|
|||
from . import variables as v
|
||||
from . import app
|
||||
from . import loghandler
|
||||
from . import backgroundthread
|
||||
from .windows import userselect
|
||||
|
||||
###############################################################################
|
||||
|
@ -25,11 +26,11 @@ LOG = logging.getLogger("PLEX.service")
|
|||
###############################################################################
|
||||
|
||||
WINDOW_PROPERTIES = (
|
||||
"plex_online", "plex_command_processed", "plex_shouldStop", "plex_dbScan",
|
||||
"plex_command_processed", "plex_shouldStop", "plex_dbScan",
|
||||
"plex_customplayqueue", "plex_playbackProps",
|
||||
"pms_token", "plex_token", "pms_server", "plex_machineIdentifier",
|
||||
"plex_servername", "plex_authenticated", "PlexUserImage", "useDirectPaths",
|
||||
"countError", "countUnauthorized", "plex_restricteduser",
|
||||
"plex_restricteduser",
|
||||
"plex_allows_mediaDeletion", "plex_command", "plex_result",
|
||||
"plex_force_transcode_pix"
|
||||
)
|
||||
|
@ -40,13 +41,6 @@ class Service():
|
|||
sync = 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):
|
||||
# Initial logging
|
||||
LOG.info("======== START %s ========", v.ADDON_NAME)
|
||||
|
@ -87,15 +81,71 @@ class Service():
|
|||
# Init time-offset between Kodi and Plex
|
||||
timing.KODI_PLEX_TIME_OFFSET = float(utils.settings('kodiplextimeoffset') or 0.0)
|
||||
|
||||
def isCanceled(self):
|
||||
return xbmc.abortRequested
|
||||
self.startup_completed = False
|
||||
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):
|
||||
"""
|
||||
Ensures that lib sync threads are suspended; signs out user
|
||||
"""
|
||||
LOG.info('Log-out requested')
|
||||
app.SYNC.suspend_library_thread = True
|
||||
app.APP.suspend_threads = True
|
||||
i = 0
|
||||
while app.SYNC.db_scan:
|
||||
i += 1
|
||||
|
@ -105,7 +155,7 @@ class Service():
|
|||
# Failed to reset PMS and plex.tv connects. Try to restart Kodi
|
||||
utils.messageDialog(utils.lang(29999), utils.lang(39208))
|
||||
# Resuming threads, just in case
|
||||
app.SYNC.suspend_library_thread = False
|
||||
app.APP.suspend_threads = False
|
||||
return False
|
||||
LOG.info('Successfully stopped library sync')
|
||||
app.ACCOUNT.log_out()
|
||||
|
@ -132,6 +182,9 @@ class Service():
|
|||
# Wipe Kodi and Plex database as well as playlists and video nodes
|
||||
utils.wipe_database()
|
||||
app.CONN.load()
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
self.server_has_been_online = False
|
||||
self.welcome_msg = False
|
||||
LOG.info("Choosing new PMS complete")
|
||||
return True
|
||||
|
||||
|
@ -142,16 +195,19 @@ class Service():
|
|||
utils.delete_playlists()
|
||||
# Remove video nodes
|
||||
utils.delete_nodes()
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
return True
|
||||
|
||||
def toggle_plex_tv(self):
|
||||
if utils.settings('plexToken'):
|
||||
LOG.info('Reseting plex.tv credentials in settings')
|
||||
if app.ACCOUNT.plex_token:
|
||||
LOG.info('Resetting plex.tv credentials in settings')
|
||||
self.log_out()
|
||||
app.ACCOUNT.clear()
|
||||
return True
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
|
@ -160,9 +216,30 @@ class Service():
|
|||
Returns True if successful, False if not. 'aborted' if user chose to
|
||||
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')
|
||||
if app.ACCOUNT.plex_username and not app.ACCOUNT.force_login:
|
||||
# Found a user in the settings, try to authenticate
|
||||
if app.ACCOUNT.plex_username and not app.ACCOUNT.force_login: # Found a user in the settings, try to authenticate
|
||||
LOG.info('Trying to authenticate with old settings')
|
||||
res = PF.check_connection(app.CONN.server,
|
||||
token=app.ACCOUNT.pms_token,
|
||||
|
@ -171,8 +248,9 @@ class Service():
|
|||
LOG.error('Something went wrong while checking connection')
|
||||
return False
|
||||
elif res == 401:
|
||||
LOG.error('User token no longer valid. Sign user out')
|
||||
app.ACCOUNT.clear()
|
||||
LOG.error('User %s no longer has access - signing user out',
|
||||
app.ACCOUNT.plex_username)
|
||||
self.log_out()
|
||||
return False
|
||||
elif res >= 400:
|
||||
LOG.error('Answer from PMS is not as expected')
|
||||
|
@ -188,7 +266,7 @@ class Service():
|
|||
user, _ = userselect.start()
|
||||
if not user:
|
||||
LOG.info('No user received')
|
||||
app.CONN.pms_status = 'Stop'
|
||||
app.APP.suspend = True
|
||||
return False
|
||||
username = user.title
|
||||
user_id = user.id
|
||||
|
@ -206,10 +284,12 @@ class Service():
|
|||
return False
|
||||
elif res == 401:
|
||||
if app.ACCOUNT.plex_token:
|
||||
LOG.error('Token no longer valid')
|
||||
# "Your Plex token is no longer valid. Logging-out of plex.tv"
|
||||
utils.messageDialog(utils.lang(29999), utils.lang(33010))
|
||||
app.ACCOUNT.clear()
|
||||
LOG.error('User %s does not have access to PMS %s on %s',
|
||||
username, app.CONN.server_name, app.CONN.server)
|
||||
# "User is unauthorized for server {0}"
|
||||
utils.messageDialog(utils.lang(29999),
|
||||
utils.lang(33010).format(app.CONN.server_name))
|
||||
self.log_out()
|
||||
return False
|
||||
else:
|
||||
# "Failed to authenticate. Did you login to plex.tv?"
|
||||
|
@ -219,6 +299,7 @@ class Service():
|
|||
app.ACCOUNT.load()
|
||||
continue
|
||||
else:
|
||||
app.APP.suspend = True
|
||||
return False
|
||||
elif res >= 400:
|
||||
LOG.error('Answer from PMS is not as expected')
|
||||
|
@ -235,12 +316,12 @@ class Service():
|
|||
def ServiceEntryPoint(self):
|
||||
# Important: Threads depending on abortRequest will not trigger
|
||||
# if profile switch happens more than once.
|
||||
app.init()
|
||||
# Some plumbing
|
||||
app.init()
|
||||
app.APP.monitor = kodimonitor.KodiMonitor()
|
||||
app.APP.player = xbmc.Player()
|
||||
artwork.IMAGE_CACHING_SUSPENDS = [
|
||||
app.SYNC.suspend_library_thread,
|
||||
app.APP.suspend_threads,
|
||||
app.SYNC.stop_sync,
|
||||
app.SYNC.db_scan
|
||||
]
|
||||
|
@ -262,11 +343,9 @@ class Service():
|
|||
self.playback_starter = playback_starter.PlaybackStarter()
|
||||
self.playqueue = playqueue.PlayqueueMonitor()
|
||||
|
||||
server_online = True
|
||||
welcome_msg = True
|
||||
counter = 0
|
||||
while not self.isCanceled():
|
||||
|
||||
# Main PKC program loop
|
||||
while not xbmc.abortRequested:
|
||||
# Check for Kodi profile change
|
||||
if utils.window('plex_kodiProfile') != v.KODI_PROFILE:
|
||||
# Profile change happened, terminate this thread and others
|
||||
LOG.info("Kodi profile was: %s and changed to: %s. "
|
||||
|
@ -274,6 +353,7 @@ class Service():
|
|||
v.KODI_PROFILE, utils.window('plex_kodiProfile'))
|
||||
break
|
||||
|
||||
# Check for PKC commands from other Python instances
|
||||
plex_command = utils.window('plex_command')
|
||||
if plex_command:
|
||||
# Commands/user interaction received from other PKC Python
|
||||
|
@ -291,24 +371,21 @@ class Service():
|
|||
'dummy?mode=context_menu&%s'
|
||||
% plex_command.replace('CONTEXT_menu?', ''))
|
||||
elif plex_command == 'choose_pms_server':
|
||||
if self.choose_pms_server():
|
||||
utils.window('plex_online', clear=True)
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
server_online = False
|
||||
welcome_msg = False
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
self.choose_pms_server, None)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
elif plex_command == 'switch_plex_user':
|
||||
if self.switch_plex_user():
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
self.switch_plex_user, None)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
elif plex_command == 'enter_new_pms_address':
|
||||
if self.setup.enter_new_pms_address():
|
||||
if self.log_out():
|
||||
utils.window('plex_online', clear=True)
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
server_online = False
|
||||
welcome_msg = False
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
self.enter_new_pms_address, None)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
elif plex_command == 'toggle_plex_tv_sign_in':
|
||||
if self.toggle_plex_tv():
|
||||
app.ACCOUNT.set_unauthenticated()
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
self.toggle_plex_tv, None)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
elif plex_command == 'repair-scan':
|
||||
app.SYNC.run_lib_scan = 'repair'
|
||||
elif plex_command == 'full-scan':
|
||||
|
@ -319,120 +396,51 @@ class Service():
|
|||
app.SYNC.run_lib_scan = 'textures'
|
||||
continue
|
||||
|
||||
if app.APP.suspend:
|
||||
app.APP.monitor.waitForAbort(0.1)
|
||||
continue
|
||||
|
||||
# Before proceeding, need to make sure:
|
||||
# 1. Server is online
|
||||
# 2. User is set
|
||||
# 3. User has access to the server
|
||||
if utils.window('plex_online') == "true":
|
||||
# Plex server is 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.
|
||||
if not app.CONN.online:
|
||||
# Not online
|
||||
server = app.CONN.server
|
||||
if not server:
|
||||
# No server info set in add-on settings
|
||||
pass
|
||||
elif PF.check_connection(server, verifySSL=True) is False:
|
||||
# Server is offline or cannot be reached
|
||||
# Alert the user and suppress future warning
|
||||
if server_online:
|
||||
server_online = False
|
||||
utils.window('plex_online', value="false")
|
||||
# Suspend threads
|
||||
app.SYNC.suspend_library_thread = 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)
|
||||
counter += 1
|
||||
# Periodically check if the IP changed, e.g. per minute
|
||||
if counter > 20:
|
||||
counter = 0
|
||||
setup = initialsetup.InitialSetup()
|
||||
tmp = setup.pick_pms()
|
||||
if tmp:
|
||||
setup.write_pms_to_settings(tmp)
|
||||
app.CONN.load()
|
||||
else:
|
||||
# Server is online
|
||||
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
|
||||
elif not self.connection_check_running:
|
||||
self.connection_check_running = True
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
PF.check_connection,
|
||||
self.on_connection_check,
|
||||
server,
|
||||
verifySSL=True)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
continue
|
||||
elif not app.ACCOUNT.authenticated:
|
||||
# Plex server is online, but we're not yet authenticated
|
||||
if not self.auth_running:
|
||||
self.auth_running = True
|
||||
task = backgroundthread.FunctionAsTask(
|
||||
self.authenticate, None)
|
||||
backgroundthread.BGThreader.addTasksToFront([task])
|
||||
continue
|
||||
elif not self.startup_completed:
|
||||
self.startup_completed = True
|
||||
self.specialmonitor.start()
|
||||
self.ws.start()
|
||||
self.sync.start()
|
||||
self.plexcompanion.start()
|
||||
self.playback_starter.start()
|
||||
self.playqueue.start()
|
||||
if utils.settings('enable_alexa') == 'true':
|
||||
self.alexa.start()
|
||||
|
||||
if app.APP.monitor.waitForAbort(0.05):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
app.APP.monitor.waitForAbort(0.1)
|
||||
|
||||
# EXITING PKC
|
||||
# Tell all threads to terminate (e.g. several lib sync threads)
|
||||
app.APP.stop_pkc = True
|
||||
utils.window('plex_service_started', clear=True)
|
||||
|
|
|
@ -41,7 +41,7 @@ class Sync(backgroundthread.KillableThread):
|
|||
super(Sync, self).__init__()
|
||||
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -137,7 +137,7 @@ class PMS_Websocket(WebSocket):
|
|||
Returns True if the thread is suspended
|
||||
"""
|
||||
return (self._suspended or
|
||||
app.SYNC.suspend_library_thread or
|
||||
app.APP.suspend_threads or
|
||||
app.SYNC.background_sync_disabled)
|
||||
|
||||
def getUri(self):
|
||||
|
|
Loading…
Reference in a new issue