diff --git a/default.py b/default.py index e308fdcd..36f3d041 100644 --- a/default.py +++ b/default.py @@ -64,7 +64,8 @@ class Main: 'inprogressepisodes': entrypoint.getInProgressEpisodes, 'recentepisodes': entrypoint.getRecentEpisodes, 'refreshplaylist': entrypoint.refreshPlaylist, - 'companion': entrypoint.plexCompanion + 'companion': entrypoint.plexCompanion, + 'switchuser': entrypoint.switchPlexUser } if "extrafanart" in sys.argv[0]: @@ -98,9 +99,6 @@ class Main: # Other functions if mode == "settings": xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)') - if mode == "switchuser": - xbmc.log('Requesting user switch') - utils.window('emby_serverStatus', value="401") elif mode in ("manualsync", "repair"): if utils.window('emby_dbScan') != "true": import librarysync diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index fd894fd2..74508e10 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -161,7 +161,7 @@ class PlexAPI(): """ Prompts user to sign in by visiting https://plex.tv/pin - Writes username and token to Kodi settings file. Returns: + Writes plexhome, username and token to Kodi settings file. Returns: { 'plexhome': 'true' if Plex Home, 'false' otherwise 'username': diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 87e3b39d..06669e27 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -119,6 +119,12 @@ def doMainListing(): elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"): addDirectoryItem(label, path) + # Plex user switch, if Plex home is in use + if utils.settings('plexhome') == 'true': + addDirectoryItem("Switch Plex Home User", + "plugin://plugin.video.plexkodiconnect/" + "?mode=switchuser") + #experimental live tv nodes addDirectoryItem("Live Tv Channels (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=tvchannels&folderid=root") addDirectoryItem("Live Tv Recordings (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=recordings&folderid=root") @@ -257,6 +263,27 @@ def addUser(): utils.window('EmbyAdditionalUserPosition.%s' % userid, value=str(count)) count +=1 + +def switchPlexUser(): + """ + Signs out currently logged in user (if applicable). Triggers sign-in of a + new user + """ + # Guess these user avatars are a future feature. Skipping for now + # Delete any userimages. Since there's always only 1 user: position = 0 + # position = 0 + # utils.window('EmbyAdditionalUserImage.%s' % position, clear=True) + utils.logMsg("PLEX", "Plex home user switch requested", 0) + # Pause library sync thread - user needs to be auth in order to sync + lib = librarysync.LibrarySync() + lib.suspendThread() + # Log out currently signed in user: + utils.window('emby_serverStatus', value="401") + # Request lib sync to get user view data (e.g. watched/unwatched) + utils.window('plex_runLibScan', value='true') + # Reset Plex userdata: resume points, watched/unwatched status + + ##### THEME MUSIC/VIDEOS ##### def getThemeMedia(): diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index a045ee62..f0bdb5d5 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -14,6 +14,7 @@ import clientinfo import downloadutils import PlexAPI +import librarysync ################################################################################################## @@ -21,7 +22,7 @@ import PlexAPI class UserClient(threading.Thread): # Borg - multiple instances, shared state - _shared_state = {} + __shared_state = {} stopClient = False auth = True @@ -39,7 +40,7 @@ class UserClient(threading.Thread): def __init__(self): - self.__dict__ = self._shared_state + self.__dict__ = self.__shared_state self.addon = xbmcaddon.Addon() self.addonName = clientinfo.ClientInfo().getAddonName() @@ -267,6 +268,7 @@ class UserClient(threading.Thread): def authenticate(self): # Get /profile/addon_data plx = PlexAPI.PlexAPI() + lib = librarysync.LibrarySync() addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8') hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) @@ -294,6 +296,7 @@ class UserClient(threading.Thread): self.logMsg("Current user: %s" % self.currUser, 1) self.logMsg("Current userId: %s" % self.currUserId, 1) self.logMsg("Current accessToken: xxxx", 1) + lib.resumeThread() return ##### AUTHENTICATE USER ##### @@ -310,11 +313,17 @@ class UserClient(threading.Thread): # Check connection if plx.CheckConnection(server, accessToken) == 200: self.currUser = username + dialog = xbmcgui.Dialog() if username: - xbmcgui.Dialog().notification(self.addonName, "Welcome %s" - % username) + dialog.notification(self.addonName, + "Welcome %s" % username, + "special://home/addons/plugin.video." + "plexkodiconnect/icon.png") else: - xbmcgui.Dialog().notification(self.addonName, "Welcome") + dialog.notification(self.addonName, + "Welcome", + "special://home/addons/plugin.video." + "plexkodiconnect/icon.png") utils.settings('accessToken', value=accessToken) utils.settings('userId%s' % username, value=userId) self.logMsg("User authenticated with an access token", 1) @@ -322,8 +331,10 @@ class UserClient(threading.Thread): utils.window('emby_serverStatus', clear=True) # Write plex_machineIdentifier to window plex_machineIdentifier = utils.settings('plex_machineIdentifier') - utils.windows('plex_machineIdentifier', plex_machineIdentifier) + utils.window('plex_machineIdentifier', plex_machineIdentifier) self.retry = 0 + # Make sure that lib sync thread is not paused + lib.resumeThread() else: self.logMsg("Error: user authentication failed.", -1) utils.settings('accessToken', value="") diff --git a/resources/lib/utils.py b/resources/lib/utils.py index e5955929..8e0b9c81 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -20,6 +20,20 @@ import clientinfo ################################################################################################# +def borg(cls): + """ + Dekorator to turn a class into a borg class with an added "@utils.borg" + """ + cls._state = {} + orig_init = cls.__init__ + + def new_init(self, *args, **kwargs): + self.__dict__ = cls._state + orig_init(self, *args, **kwargs) + cls.__init__ = new_init + return cls + + class logDecor(object): """ A decorator adding logging capabilities. @@ -402,7 +416,7 @@ def passwordsXML(): settings('networkCreds', value="") xbmcgui.Dialog().notification( - heading="Emby for Kodi", + heading='PlexKodiConnect', message="%s removed from passwords.xml" % credentials, icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", time=1000, @@ -419,7 +433,7 @@ def passwordsXML(): dialog.ok( heading="Network credentials", line1= ( - "Input the server name or IP address as indicated in your emby library paths. " + "Input the server name or IP address as indicated in your plex library paths. " 'For example, the server name: \\\\SERVER-PC\\path\\ is "SERVER-PC".')) server = dialog.input("Enter the server name or IP address") if not server: @@ -461,7 +475,7 @@ def passwordsXML(): etree.ElementTree(root).write(xmlpath) dialog.notification( - heading="Emby for Kodi", + heading="PlexKodiConnect", message="%s added to passwords.xml" % server, icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", time=1000, diff --git a/service.py b/service.py index 7e348f61..05d15573 100644 --- a/service.py +++ b/service.py @@ -61,6 +61,8 @@ class Service(): utils.window('emby_kodiProfile', value=xbmc.translatePath("special://profile")) utils.window('emby_pluginpath', value=utils.settings('useDirectPaths')) + self.runPlexCompanion = utils.settings('plexCompanion') + # Initial logging self.logMsg("======== START %s ========" % self.addonName, 0) self.logMsg("Platform: %s" % (self.clientInfo.getPlatform()), 0) @@ -75,7 +77,8 @@ class Service(): "emby_online", "emby_serverStatus", "emby_onWake", "emby_syncRunning", "emby_dbCheck", "emby_kodiScan", "emby_shouldStop", "emby_currUser", "emby_dbScan", "emby_sessionId", - "emby_initialScan", "emby_customplaylist", "emby_playbackProps" + "emby_initialScan", "emby_customplaylist", "emby_playbackProps", + "plex_runLibScan" ] for prop in properties: utils.window(prop, clear=True) @@ -108,7 +111,7 @@ class Service(): kplayer = player.Player() plx = PlexAPI.PlexAPI() plexCompanion = PlexCompanion.PlexCompanion() - plexCompanionDesired = utils.settings('plexCompanion') + # Sync and progress report lastProgressUpdate = datetime.today() @@ -273,7 +276,7 @@ class Service(): # Start the Plex Companion thread if not self.plexCompanion_running and \ - plexCompanionDesired == "true": + self.runPlexCompanion == "true": self.plexCompanion_running = True plexCompanion.start()