diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 503a3fff..5dff1bff 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -77,7 +77,7 @@ def chooseServer(): Lets user choose from list of PMS (signs out & signs in) """ string = xbmcaddon.Addon().getLocalizedString - utils.logMsg(title, "Choosing PMS server requested, starting", 0) + utils.logMsg(title, "Choosing PMS server requested, starting", 1) dialog = xbmcgui.Dialog() # Resetting, please wait dialog.notification( @@ -93,33 +93,24 @@ def chooseServer(): while utils.window('emby_dbScan') == 'true': if counter > 100: # Failed to reset PMS and plex.tv connects. Try to restart Kodi. - dialog.ok(addonName, - string(39208)) + dialog.ok(addonName, string(39208)) # Resuming threads, just in case utils.window('suspend_LibraryThread', clear=True) utils.logMsg(title, "Could not stop library sync, aborting", -1) return counter += 1 xbmc.sleep(50) - utils.logMsg(title, "Successfully stopped library sync", 0) - - # Reset connection details - utils.settings('plex_machineIdentifier', value="") - utils.settings('plex_servername', value="") - utils.settings('https', value="") - utils.settings('ipaddress', value="") - utils.settings('port', value="") + utils.logMsg(title, "Successfully stopped library sync", 1) # Log out currently signed in user: utils.window('emby_serverStatus', value="401") - # Above method needs to have run its course! Hence wait counter = 0 while utils.window('emby_serverStatus') == "401": if counter > 100: dialog.ok(addonName, string(39208)) - utils.logMsg(title, "Could not sign out, aborting", -1) + utils.logMsg(title, "Could not sign out, aborting PMS", -1) return counter += 1 xbmc.sleep(50) @@ -127,12 +118,22 @@ def chooseServer(): utils.window('suspend_Userclient', value='true') import initialsetup - initialsetup.InitialSetup().setup(chooseServer=True) + setup = initialsetup.InitialSetup() + server = setup.PickPMS() + if server is None: + utils.logMsg('We did not connect to a new PMS, aborting', -1) + utils.window('suspend_Userclient', clear=True) + utils.window('suspend_LibraryThread', clear=True) + return + + setup.WritePMStoSettings(server) # Request lib sync to get user view data (e.g. watched/unwatched) utils.window('plex_runLibScan', value='full') # Restart user client utils.window('suspend_Userclient', clear=True) utils.logMsg(title, "Choosing new PMS complete", 0) + # And do NOT clear suspend_LibraryThread flag, that needs to be done in + # service.py def reConnect(): diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index a4dae14e..f6638da5 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -21,150 +21,157 @@ from PlexFunctions import GetMachineIdentifier class InitialSetup(): def __init__(self): + self.logMsg('Entering initialsetup class', 1) self.clientInfo = clientinfo.ClientInfo() self.addonId = self.clientInfo.getAddonId() self.doUtils = downloadutils.DownloadUtils().downloadUrl self.userClient = userclient.UserClient() self.plx = PlexAPI.PlexAPI() + self.dialog = xbmcgui.Dialog() - def PlexTvSignIn(self): + self.string = xbmcaddon.Addon().getLocalizedString + + self.server = self.userClient.getServer() + self.serverid = utils.settings('plex_machineIdentifier') + # Get Plex credentials from settings file, if they exist + plexdict = self.plx.GetPlexLoginFromSettings() + self.myplexlogin = plexdict['myplexlogin'] == 'true' + self.plexLogin = plexdict['plexLogin'] + self.plexToken = plexdict['plexToken'] + self.plexid = plexdict['plexid'] + if self.plexToken: + self.logMsg('Found a plex.tv token in the settings', 1) + + def PlexTVSignIn(self): + """ + Signs (freshly) in to plex.tv (will be saved to file settings) + + Returns True if successful, or False if not + """ + result = self.plx.PlexTvSignInWithPin() + if result: + self.plexLogin = result['username'] + self.plexToken = result['token'] + self.plexid = result['plexid'] + return True + return False + + def CheckPlexTVSignIn(self): """ Checks existing connection to plex.tv. If not, triggers sign in """ - - def setup(self, forcePlexTV=False, chooseServer=False): - """ - Initial setup. Run once upon startup. - Check server, user, direct paths, music, direct stream if not direct - path. - """ - string = xbmcaddon.Addon().getLocalizedString - # SERVER INFO ##### - self.logMsg("Initial setup called.", 0) - server = self.userClient.getServer() - serverid = utils.settings('plex_machineIdentifier') - # Get Plex credentials from settings file, if they exist - plexdict = self.plx.GetPlexLoginFromSettings() - myplexlogin = plexdict['myplexlogin'] - plexLogin = plexdict['plexLogin'] - plexToken = plexdict['plexToken'] - plexid = plexdict['plexid'] - if plexToken: - self.logMsg('Found a plex.tv token in the settings', 0) - - dialog = xbmcgui.Dialog() - - # Optionally sign into plex.tv. Will not be called on very first run - # as plexToken will be '' - if (plexToken and myplexlogin == 'true' and forcePlexTV is False - and chooseServer is False): - chk = self.plx.CheckConnection('plex.tv', plexToken) - if chk in (401, 403): - # HTTP Error: unauthorized. Token is no longer valid - self.logMsg('plex.tv connection returned HTTP %s' % chk, 0) - # Delete token in the settings - utils.settings('plexToken', value='') - # Could not login, please try again - dialog.ok(self.addonName, - string(39009)) - result = self.plx.PlexTvSignInWithPin() - if result: - plexLogin = result['username'] - plexToken = result['token'] - plexid = result['plexid'] - elif chk is False or chk >= 400: - # Problems connecting to plex.tv. Network or internet issue? - self.logMsg('plex.tv connection returned HTTP %s' - % str(chk), 0) - dialog.ok(self.addonName, - string(39010)) + chk = self.plx.CheckConnection('plex.tv', self.plexToken) + if chk in (401, 403): + # HTTP Error: unauthorized. Token is no longer valid + self.logMsg('plex.tv connection returned HTTP %s' % chk, 1) + # Delete token in the settings + utils.settings('plexToken', value='') + # Could not login, please try again + self.dialog.ok(self.addonName, + self.string(39009)) + self.PlexTVSignIn() + elif chk is False or chk >= 400: + # Problems connecting to plex.tv. Network or internet issue? + self.logMsg('plex.tv connection returned HTTP %s' + % str(chk), 1) + self.dialog.ok(self.addonName, + self.string(39010)) + else: + self.logMsg('plex.tv connection with token successful', 1) + # Refresh the info from Plex.tv + xml = self.doUtils('https://plex.tv/users/account', + authenticate=False, + headerOptions={'X-Plex-Token': self.plexToken}) + try: + self.plexLogin = xml.attrib['title'] + except (AttributeError, KeyError): + self.logMsg('Failed to update Plex info from plex.tv', -1) else: - self.logMsg('plex.tv connection with token successful', 0) - # Refresh the info from Plex.tv - xml = self.doUtils('https://plex.tv/users/account', - authenticate=False, - headerOptions={'X-Plex-Token': plexToken}) - try: - plexLogin = xml.attrib['title'] - except (AttributeError, KeyError): - self.logMsg('Failed to update Plex info from plex.tv', -1) - else: - utils.settings('plexLogin', value=plexLogin) - home = 'true' if xml.attrib.get('home') == '1' else 'false' - utils.settings('plexhome', value=home) - utils.settings('plexAvatar', value=xml.attrib.get('thumb')) - utils.settings( - 'plexHomeSize', value=xml.attrib.get('homeSize', '1')) - self.logMsg('Updated Plex info from plex.tv', 0) + utils.settings('plexLogin', value=self.plexLogin) + home = 'true' if xml.attrib.get('home') == '1' else 'false' + utils.settings('plexhome', value=home) + utils.settings('plexAvatar', value=xml.attrib.get('thumb')) + utils.settings( + 'plexHomeSize', value=xml.attrib.get('homeSize', '1')) + self.logMsg('Updated Plex info from plex.tv', 1) - # If a Plex server IP has already been set - # return only if the right machine identifier is found - getNewPMS = False - if server and forcePlexTV is False and chooseServer is False: - self.logMsg("PMS is already set: %s. Checking now..." % server, 0) - chk = self.plx.CheckConnection(server, verifySSL=False) - if chk is False: - self.logMsg('Could not reach PMS %s' % server, -1) - getNewPMS = True - if getNewPMS is False and not serverid: - self.logMsg('No PMS machineIdentifier found for %s. Trying to ' - 'get the PMS unique ID' % server, 1) - serverid = GetMachineIdentifier(server) - if serverid is None: - self.logMsg('Could not retrieve machineIdentifier', -1) - getNewPMS = True - else: - utils.settings('plex_machineIdentifier', value=serverid) - elif getNewPMS is False: - tempServerid = GetMachineIdentifier(server) - if tempServerid != serverid: - self.logMsg('The current PMS %s was expected to have a ' - 'unique machineIdentifier of %s. But we got ' - '%s. Pick a new server to be sure' - % (server, serverid, tempServerid), 1) - getNewPMS = True - if getNewPMS is False: - self.logMsg("Using PMS %s with machineIdentifier %s" - % (server, serverid), 0) - return + def CheckPMS(self): + """ + Check the PMS that was set in file settings. + Will return False if we need to reconnect, because: + PMS could not be reached (no matter the authorization) + machineIdentifier did not match - # If not already retrieved myplex info, optionally let user sign in - # to plex.tv. This DOES get called on very first install run - if ((not plexToken and myplexlogin == 'true' and chooseServer is False) - or forcePlexTV): - result = self.plx.PlexTvSignInWithPin() - if result: - plexLogin = result['username'] - plexToken = result['token'] - plexid = result['plexid'] - # Get g_PMS list of servers (saved to plx.g_PMS) + Will also set the PMS machineIdentifier in the file settings if it was + not set before + """ + answer = True + chk = self.plx.CheckConnection(self.server, verifySSL=False) + if chk is False: + self.logMsg('Could not reach PMS %s' % self.server, -1) + answer = False + if answer is True and not self.serverid: + self.logMsg('No PMS machineIdentifier found for %s. Trying to ' + 'get the PMS unique ID' % self.server, 1) + self.serverid = GetMachineIdentifier(self.server) + if self.serverid is None: + self.logMsg('Could not retrieve machineIdentifier', -1) + answer = False + else: + utils.settings('plex_machineIdentifier', value=self.serverid) + elif answer is True: + tempServerid = GetMachineIdentifier(self.server) + if tempServerid != self.serverid: + self.logMsg('The current PMS %s was expected to have a ' + 'unique machineIdentifier of %s. But we got ' + '%s. Pick a new server to be sure' + % (self.server, self.serverid, tempServerid), 1) + answer = False + return answer + + def PickPMS(self): + """ + Searches for PMS and lets user pick one + + Returns the picked PMS' detail as a dict: + { + 'name': friendlyName, the Plex server's name + 'address': ip:port + 'ip': ip, without http/https + 'port': port + 'scheme': 'http'/'https', nice for checking for secure connections + 'local': '1'/'0', Is the server a local server? + 'owned': '1'/'0', Is the server owned by the user? + 'machineIdentifier': id, Plex server machine identifier + 'accesstoken': token Access token to this server + 'baseURL': baseURL scheme://ip:port + 'ownername' Plex username of PMS owner + } + + or None if unsuccessful + """ httpsUpdated = False while True: if httpsUpdated is False: # Populate g_PMS variable with the found Plex servers self.plx.discoverPMS(xbmc.getIPAddress(), - plexToken=plexToken) - isconnected = False - self.logMsg('g_PMS: %s' % self.plx.g_PMS, 1) + plexToken=self.plexToken) serverlist = self.plx.returnServerList(self.plx.g_PMS) self.logMsg('PMS serverlist: %s' % serverlist, 2) - # Let user pick server from a list - # Get a nicer list - dialoglist = [] # Exit if no servers found if len(serverlist) == 0: - dialog.ok( - self.addonName, - string(39011) - ) + self.dialog.ok(self.addonName, self.string(39011)) + server = None break + # Get a nicer list + dialoglist = [] for server in serverlist: if server['local'] == '1': # server is in the same network as client. Add "local" - msg = string(39022) + msg = self.string(39022) else: # Add 'remote' - msg = string(39054) + msg = self.string(39054) if server.get('ownername'): # Display username if its not our PMS dialoglist.append('%s (%s, %s)' @@ -173,29 +180,21 @@ class InitialSetup(): msg)) else: dialoglist.append('%s (%s)' - % (server['name'], - msg)) - resp = dialog.select(string(39012), dialoglist) + % (server['name'], msg)) + # Let user pick server from a list + resp = self.dialog.select(self.string(39012), dialoglist) server = serverlist[resp] - activeServer = server['machineIdentifier'] # Re-direct via plex if remote - will lead to the correct SSL # certificate if server['local'] == '1': - url = server['scheme'] + '://' + server['ip'] + ':' \ - + server['port'] + url = '%s://%s:%s' \ + % (server['scheme'], server['ip'], server['port']) else: url = server['baseURL'] # Deactive SSL verification if the server is local! - # Watch out - settings is cached by Kodi - use dedicated var! if server['local'] == '1': - utils.settings('sslverify', 'false') - self.logMsg("Setting SSL verify to false, because server is " - "local", 1) verifySSL = False else: - utils.settings('sslverify', 'true') - self.logMsg("Setting SSL verify to true, because server is " - "not local", 1) verifySSL = None chk = self.plx.CheckConnection(url, server['accesstoken'], @@ -209,66 +208,124 @@ class InitialSetup(): if chk == 401: # Not yet authorized for Plex server # Please sign in to plex.tv - dialog.ok(self.addonName, - string(39013) + server['name'], - string(39014)) - result = self.plx.PlexTvSignInWithPin() - if result: - plexLogin = result['username'] - plexToken = result['token'] - plexid = result['plexid'] - else: + self.dialog.ok(self.addonName, + self.string(39013) + server['name'], + self.string(39014)) + if self.PlexTVSignIn() is False: # Exit while loop if user cancels + server = None break # Problems connecting elif chk >= 400 or chk is False: # Problems connecting to server. Pick another server? - resp = dialog.yesno(self.addonName, - string(39015)) + answ = self.dialog.yesno(self.addonName, + self.string(39015)) # Exit while loop if user chooses No - if not resp: + if not answ: + server = None break # Otherwise: connection worked! else: - isconnected = True break - if not isconnected: - # Enter Kodi settings instead - xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) - return - # Write to Kodi settings file - utils.settings('plex_machineIdentifier', activeServer) + return server + + def WritePMStoSettings(self, server): + """ + Saves server to file settings. server is a dict of the form: + { + 'name': friendlyName, the Plex server's name + 'address': ip:port + 'ip': ip, without http/https + 'port': port + 'scheme': 'http'/'https', nice for checking for secure connections + 'local': '1'/'0', Is the server a local server? + 'owned': '1'/'0', Is the server owned by the user? + 'machineIdentifier': id, Plex server machine identifier + 'accesstoken': token Access token to this server + 'baseURL': baseURL scheme://ip:port + 'ownername' Plex username of PMS owner + } + """ + utils.settings('plex_machineIdentifier', server['machineIdentifier']) utils.settings('plex_servername', server['name']) utils.settings('plex_serverowned', 'true' if server['owned'] == '1' else 'false') + # Careful to distinguish local from remote PMS if server['local'] == '1': scheme = server['scheme'] utils.settings('ipaddress', server['ip']) utils.settings('port', server['port']) + self.logMsg("Setting SSL verify to false, because server is " + "local", 1) + utils.settings('sslverify', 'false') else: baseURL = server['baseURL'].split(':') scheme = baseURL[0] utils.settings('ipaddress', baseURL[1].replace('//', '')) utils.settings('port', baseURL[2]) + self.logMsg("Setting SSL verify to true, because server is not " + "local", 1) + utils.settings('sslverify', 'true') if scheme == 'https': utils.settings('https', 'true') else: utils.settings('https', 'false') + # And finally do some logging self.logMsg("Writing to Kodi user settings file", 0) self.logMsg("PMS machineIdentifier: %s, ip: %s, port: %s, https: %s " - % (activeServer, server['ip'], server['port'], - server['scheme']), 0) + % (server['machineIdentifier'], server['ip'], + server['port'], server['scheme']), 0) - if forcePlexTV is True or chooseServer is True: + def setup(self, forcePlexTV=False, chooseServer=False): + """ + Initial setup. Run once upon startup. + + Check server, user, direct paths, music, direct stream if not direct + path. + """ + self.logMsg("Initial setup called.", 0) + dialog = self.dialog + string = self.string + + # Optionally sign into plex.tv. Will not be called on very first run + # as plexToken will be '' + if self.plexToken and self.myplexlogin: + self.CheckPlexTVSignIn() + + # If a Plex server IP has already been set + # return only if the right machine identifier is found + getNewPMS = False + if self.server: + self.logMsg("PMS is already set: %s. Checking now..." + % self.server, 0) + getNewPMS = not self.CheckPMS() + if getNewPMS is False: + self.logMsg("Using PMS %s with machineIdentifier %s" + % (self.server, self.serverid), 0) + return + + # If not already retrieved myplex info, optionally let user sign in + # to plex.tv. This DOES get called on very first install run + if not self.plexToken and self.myplexlogin: + self.PlexTVSignIn() + + server = self.PickPMS() + if server is None: + # Enter Kodi settings instead + xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return + # Write our chosen server to Kodi settings file + self.WritePMStoSettings(server) + + # Additional settings where the user needs to choose goToSettings = False # Direct paths (\\NAS\mymovie.mkv) or addon (http)? - if dialog.yesno(heading=self.addonName, - line1=string(39027), - line2=string(39028), + if dialog.yesno(self.addonName, + string(39027), + string(39028), nolabel="Addon (Default)", yeslabel="Native (Direct Paths)"): self.logMsg("User opted to use direct paths.", 1)