From fdc8f531311526dca22768d106a2c87b990e3948 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 08:43:12 +0100 Subject: [PATCH 01/16] Sleep for a while in loops - drastically reduces CPU load --- resources/lib/PlexCompanion.py | 2 ++ resources/lib/userclient.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/resources/lib/PlexCompanion.py b/resources/lib/PlexCompanion.py index 5af8def4..c79cb5bc 100644 --- a/resources/lib/PlexCompanion.py +++ b/resources/lib/PlexCompanion.py @@ -87,9 +87,11 @@ class PlexCompanion(threading.Thread): subscribers.subMgr.notify() settings['serverList'] = self.client.getServerList() + xbmc.sleep(50) except: self.logMsg("Error in loop, continuing anyway", 1) self.logMsg(traceback.print_exc(), 1) + xbmc.sleep(50) self.client.stop_all() try: diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index c5a073ef..df22a7f5 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -455,5 +455,8 @@ class UserClient(threading.Thread): log("Server found: %s" % server, 2) self.auth = True + # Minimize CPU load + xbmc.sleep(500) + self.doUtils.stopSession() log("##===---- UserClient Stopped ----===##", 0) From 8e9b355473a23c8781cd6d0af033226a8e0913ce Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 09:20:06 +0100 Subject: [PATCH 02/16] New Setting to reset all PMS and the plex.tv connection --- default.py | 2 +- resources/language/English/strings.xml | 4 ++- resources/language/German/strings.xml | 6 +++- resources/lib/entrypoint.py | 38 +++++++++++++++++++++++--- resources/settings.xml | 2 +- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/default.py b/default.py index 0cc69761..6864431c 100644 --- a/default.py +++ b/default.py @@ -66,7 +66,7 @@ class Main: 'companion': entrypoint.plexCompanion, 'switchuser': entrypoint.switchPlexUser, 'deviceid': entrypoint.resetDeviceId, - 'doPlexTvLogin': entrypoint.doPlexTvLogin + 'reConnect': entrypoint.reConnect } if "/extrafanart" in sys.argv[0]: diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 51e5c48c..8fa4b09c 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -362,7 +362,7 @@ [COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR] (local) Failed to authenticate. Did you login to plex.tv? - [COLOR yellow]Log into plex.tv[/COLOR] + [COLOR yellow]Reset PMS and plex.tv connections to re-login[/COLOR] Automatically log into plex.tv on startup Enable constant background sync (restart Kodi!) @@ -375,6 +375,8 @@ Perform manual library sync Unable to run the sync, the add-on is not connected to a Plex server. Plex might lock your account if you fail to log in too many times. Proceed anyway? + Reseting PMS connections, please wait. Test: עޥ + Failed to reset PMS and plex.tv connects. Try to restart Kodi. diff --git a/resources/language/German/strings.xml b/resources/language/German/strings.xml index d42cb99a..a1f6eb53 100644 --- a/resources/language/German/strings.xml +++ b/resources/language/German/strings.xml @@ -293,7 +293,7 @@ [COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR] (lokal) Plex Media Server Authentifizierung fehlgeschlagen. Haben Sie sich bei plex.tv eingeloggt? - [COLOR yellow]Bei plex.tv einloggen[/COLOR] + [COLOR yellow]PMS und plex.tv Verbindungen zurücksetzen für erneuten Login[/COLOR] Automatisch beim Starten bei plex.tv einloggen Laufende Synchronisierung im Hintergrund aktivieren (Neustart!) @@ -305,6 +305,10 @@ Manuellen Scan der Plex Bibliotheken starten Plex Bibliothek kann nicht gescannt werden, da keine Verbindung mit einem Plex Server besteht. Plex könnte möglicherweise Ihren Account sperren, wenn Sie zu oft versuchen, sich erfolglos anzumelden. Trotzdem fortfahren? + PMS Verbindungen werden zurückgesetzt + PMS und plex.tv Verbindungen konnten nicht zurückgesetzt werden. Bitte versuchen Sie, Kodi neu zu starten, um das Problem zu beheben. + + Alle Plex Bilder in Kodi zwischenzuspeichern kann sehr lange dauern. Möchten Sie wirklich fortfahren? diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 5080bccd..8f0c6703 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -72,18 +72,48 @@ def plexCompanion(fullurl, params): title, "Not knowing what to do for now - no playQueue sent", -1) -def doPlexTvLogin(): +def reConnect(): """ - Triggers login to plex.tv + Triggers login to plex.tv and re-authorization """ + string = xbmcaddon.Addon().getLocalizedString + utils.logMsg("entrypoint reConnect", + "Connection resets requested", 0) + # Pause library sync thread - user needs to be auth in order to sync + utils.window('suspend_LibraryThread', value='true') # Suspend the user client during procedure utils.window('suspend_Userclient', value='true') + dialog = xbmcgui.Dialog() + dialog.notification( + heading=addonName, + message=string(39207), + icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", + sound=False) + + # Wait max for 20 seconds for all lib scans to finish + counter = 0 + while utils.window('emby_dbScan') == 'true': + xbmc.sleep(1000) + counter += 1 + if counter > 20: + dialog.ok( + heading=addonName, + message=string(39208).encode('utf-8'), + ) + # Resuming threads, just in case + utils.window('suspend_LibraryThread', clear=True) + utils.window('suspend_Userclient', clear=True) + # Abort reConnection + return + import initialsetup initialsetup.InitialSetup().setup(forcePlexTV=True) - utils.logMsg("PLEX", "Reset login attempts.", 1) - utils.window('emby_serverStatus', value="Auth") + # Log out currently signed in user: + utils.window('emby_serverStatus', value="401") # Restart user client utils.window('suspend_Userclient', clear=True) + # Request lib sync to get user view data (e.g. watched/unwatched) + utils.window('plex_runLibScan', value='full') def PassPlaylist(xml, resume=None): diff --git a/resources/settings.xml b/resources/settings.xml index 517ec5f9..0de69e97 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -21,12 +21,12 @@ + - From b7fbb8fa4dd64c21e4e25ae6e5839630e7e65739 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 11:04:58 +0100 Subject: [PATCH 03/16] Re-add setting to log-in to plex.tv --- resources/language/English/strings.xml | 1 + resources/language/German/strings.xml | 1 + resources/settings.xml | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 8fa4b09c..fc9f4bf0 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -377,6 +377,7 @@ Plex might lock your account if you fail to log in too many times. Proceed anyway? Reseting PMS connections, please wait. Test: עޥ Failed to reset PMS and plex.tv connects. Try to restart Kodi. + [COLOR yellow]Log-in to plex.tv[/COLOR] diff --git a/resources/language/German/strings.xml b/resources/language/German/strings.xml index a1f6eb53..e1aa564e 100644 --- a/resources/language/German/strings.xml +++ b/resources/language/German/strings.xml @@ -307,6 +307,7 @@ Plex könnte möglicherweise Ihren Account sperren, wenn Sie zu oft versuchen, sich erfolglos anzumelden. Trotzdem fortfahren? PMS Verbindungen werden zurückgesetzt PMS und plex.tv Verbindungen konnten nicht zurückgesetzt werden. Bitte versuchen Sie, Kodi neu zu starten, um das Problem zu beheben. + [COLOR yellow]Bei plex.tv einloggen[/COLOR] diff --git a/resources/settings.xml b/resources/settings.xml index 0de69e97..a521b967 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -21,12 +21,13 @@ - + + From 333b93b481d08da3fb2533e90e5479f959357070 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 11:05:50 +0100 Subject: [PATCH 04/16] Get rid of a test string --- resources/language/English/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index fc9f4bf0..79a17d17 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -375,7 +375,7 @@ Perform manual library sync Unable to run the sync, the add-on is not connected to a Plex server. Plex might lock your account if you fail to log in too many times. Proceed anyway? - Reseting PMS connections, please wait. Test: עޥ + Reseting PMS connections, please wait Failed to reset PMS and plex.tv connects. Try to restart Kodi. [COLOR yellow]Log-in to plex.tv[/COLOR] From 0b4736b01b28b28cf2443c62db8d9feb2e346713 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 11:20:11 +0100 Subject: [PATCH 05/16] Clean-up library sync loop --- resources/lib/librarysync.py | 67 +++++++++++++++++++----------------- resources/lib/userclient.py | 2 +- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 2382f26c..0ad027ea 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -243,16 +243,6 @@ class LibrarySync(Thread): icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", sound=False) - def startSync(self): - utils.window('emby_dbScan', value="true") - completed = self.fastSync() - if not completed: - # Fast sync failed or server plugin is not found - self.logMsg("Something went wrong, starting full sync", -1) - completed = self.fullSync(manualrun=True) - utils.window('emby_dbScan', clear=True) - return completed - def fastSync(self): """ Fast incremential lib sync @@ -1129,29 +1119,37 @@ class LibrarySync(Thread): raise def run_internal(self): + # Re-assign handles to have faster calls window = utils.window settings = utils.settings log = self.logMsg + threadStopped = self.threadStopped + threadSuspended = self.threadSuspended + installSyncDone = self.installSyncDone + enableBackgroundSync = self.enableBackgroundSync + fullSync = self.fullSync + fastSync = self.fastSync + + dialog = xbmcgui.Dialog() startupComplete = False self.views = [] count = 0 errorcount = 0 - self.logMsg("---===### Starting LibrarySync ###===---", 0) - while not self.threadStopped(): + log("---===### Starting LibrarySync ###===---", 0) + while not threadStopped(): # In the event the server goes offline, or an item is playing - while self.threadSuspended(): + while threadSuspended(): # Set in service.py - if self.threadStopped(): + if threadStopped(): # Abort was requested while waiting. We should exit log("###===--- LibrarySync Stopped ---===###", 0) return xbmc.sleep(1000) - if (window('emby_dbCheck') != "true" and - self.installSyncDone): + if (window('emby_dbCheck') != "true" and installSyncDone): # Verify the validity of the database currentVersion = settings('dbCreatedWithVersion') minVersion = window('emby_minDBVersion') @@ -1160,14 +1158,14 @@ class LibrarySync(Thread): if not uptoDate: log("Db version out of date: %s minimum version required: " "%s" % (currentVersion, minVersion), 0) - resp = xbmcgui.Dialog().yesno( + resp = dialog.yesno( heading="Db Version", line1=("Detected the database needs to be recreated " "for this version of " + self.addonName + "Proceed?")) if not resp: log("Db version out of date! USER IGNORED!", 0) - xbmcgui.Dialog().ok( + dialog.ok( heading=self.addonName, line1=(self.addonName + " may not work correctly " "until the database is reset.")) @@ -1185,7 +1183,7 @@ class LibrarySync(Thread): # Database does not exists log("The current Kodi version is incompatible " "to know which Kodi versions are supported.", 0) - xbmcgui.Dialog().ok( + dialog.ok( heading=self.addonName, line1=("Cancelling the database syncing process. " "Current Kodi version: %s is unsupported. " @@ -1197,7 +1195,7 @@ class LibrarySync(Thread): window('emby_dbScan', value="true") log("Db version: %s" % settings('dbCreatedWithVersion'), 0) log("Initial start-up full sync starting", 0) - librarySync = self.fullSync(manualrun=True) + librarySync = fullSync(manualrun=True) window('emby_dbScan', clear=True) if librarySync: log("Initial start-up full sync successful", 0) @@ -1205,13 +1203,13 @@ class LibrarySync(Thread): settings('SyncInstallRunDone', value="true") settings("dbCreatedWithVersion", self.clientInfo.getVersion()) - self.installSyncDone = True + installSyncDone = True else: log("Initial start-up full sync unsuccessful", -1) errorcount += 1 if errorcount > 2: log("Startup full sync failed. Stopping sync", -1) - xbmcgui.Dialog().ok( + dialog.ok( heading=self.addonName, line1=("Startup syncing process failed repeatedly." " Try restarting Kodi. Stopping Sync for " @@ -1225,7 +1223,7 @@ class LibrarySync(Thread): log('Full library scan requested, starting', 0) window('emby_dbScan', value="true") window('plex_runLibScan', clear=True) - self.fullSync(manualrun=True) + fullSync(manualrun=True) window('emby_dbScan', clear=True) count = 0 # Reset views was requested from somewhere else @@ -1239,8 +1237,8 @@ class LibrarySync(Thread): # Remove video nodes utils.deleteNodes() # Kick off refresh - dialog = xbmcgui.Dialog() if self.maintainViews(): + # Ran successfully dialog.notification( heading=self.addonName, message="Plex playlists/nodes refreshed", @@ -1248,7 +1246,8 @@ class LibrarySync(Thread): time=3000, sound=True) else: - self.logMsg("Refresh playlists/nodes failed", -1) + # Failed + log("Refresh playlists/nodes failed", -1) dialog.notification( heading=self.addonName, message="Plex playlists/nodes refresh failed", @@ -1256,19 +1255,25 @@ class LibrarySync(Thread): time=3000, sound=True) window('emby_dbScan', clear=True) - elif self.enableBackgroundSync: + elif enableBackgroundSync: # Run full lib scan approx every 30min if count >= 1800: count = 0 window('emby_dbScan', value="true") - log('Running automatic full lib scan', 0) - self.fullSync(manualrun=True) + log('Running background full lib scan', 0) + fullSync(manualrun=True) window('emby_dbScan', clear=True) - # Run fast sync otherwise (ever 2 seconds or so) + # Run fast sync otherwise (ever second or so) else: - self.startSync() + window('emby_dbScan', value="true") + if not fastSync(): + # Fast sync failed or server plugin is not found + self.logMsg( + "Something went wrong, starting full sync", -1) + fullSync(manualrun=True) + window('emby_dbScan', clear=True) - xbmc.sleep(2000) + xbmc.sleep(1000) count += 1 log("###===--- LibrarySync Stopped ---===###", 0) diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index df22a7f5..bc671acd 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -423,7 +423,7 @@ class UserClient(threading.Thread): while self.threadSuspended(): if self.threadStopped(): break - xbmc.sleep(3000) + xbmc.sleep(1000) status = window('emby_serverStatus') if status: From 8ab99b50362726a3c8bc49e4fe37c47770bdbce9 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 11:47:46 +0100 Subject: [PATCH 06/16] Language strings for library sync --- resources/language/English/strings.xml | 9 +++++ resources/language/German/strings.xml | 9 +++++ resources/lib/librarysync.py | 56 +++++++++++++------------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 79a17d17..2f2ab15e 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -396,4 +396,13 @@ Could not log in user Please try again. + + Library sync thread has crashed. You should restart Kodi now. Please report this on the forum + Detected Kodi database needs to be recreated for this version. This might take a while. Proceed? + may not work correctly until the database is reset. + Cancelling the database syncing process. Current Kodi version is unsupported. Please verify your logs for more info. + Startup syncing process failed repeatedly. Try restarting Kodi. Stopping Sync for now. + Plex playlists/nodes refreshed + Plex playlists/nodes refresh failed + diff --git a/resources/language/German/strings.xml b/resources/language/German/strings.xml index e1aa564e..f3e70b34 100644 --- a/resources/language/German/strings.xml +++ b/resources/language/German/strings.xml @@ -327,4 +327,13 @@ Anmeldung fehlgeschlagen für Benutzer Bitte erneut versuchen. + + Die Synchronisierung der Plex Bibliotheken ist abgestürzt. Bitte Kodi neu starten. Danke, wenn Sie sich die Zeit nehmen und im Plex Forum vom Absturz berichten. + Die Kodi Datenbank muss neu kreiert werden für diese Version. Das kann eine Weile dauern. Fortfahren? + funktioniert möglicherweise nicht richtig, bis die Kodi Datenbank zurückgesetzt worden ist. + Synchronisierung der Plex Bibliotheken wird abgebrochen. Die momentane Kodi Version wird nicht unterstützt. Für weitere Informationen bitte das Kodi Log konsultieren. + Der Startup Synchronisations-Prozess der Plex Bibliotheken ist mehrmals fehlgeschlagen. Bitte Kodi neu starten. Synch wird jetzt gestoppt. + Plex Playlisten/Nodes aktualisiert + Plex Playlisten/Nodes Aktualisierung fehlgeschlagen + diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 0ad027ea..a630aab3 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -8,6 +8,7 @@ import Queue import xbmc import xbmcgui import xbmcvfs +import xbmcaddon import utils import clientinfo @@ -213,6 +214,8 @@ class LibrarySync(Thread): self.__dict__ = self._shared_state + self.__language__ = xbmcaddon.Addon().getLocalizedString + self.clientInfo = clientinfo.ClientInfo() self.user = userclient.UserClient() self.emby = embyserver.Read_EmbyServer() @@ -1111,11 +1114,10 @@ class LibrarySync(Thread): self.run_internal() except Exception as e: utils.window('emby_dbScan', clear=True) + # Library sync thread has crashed xbmcgui.Dialog().ok( heading=self.addonName, - line1=("Library sync thread has crashed. " - "You should restart Kodi now. " - "Please report this on the forum.")) + line1=self.__language__(39400)) raise def run_internal(self): @@ -1129,6 +1131,7 @@ class LibrarySync(Thread): enableBackgroundSync = self.enableBackgroundSync fullSync = self.fullSync fastSync = self.fastSync + string = self.__language__ dialog = xbmcgui.Dialog() @@ -1158,17 +1161,14 @@ class LibrarySync(Thread): if not uptoDate: log("Db version out of date: %s minimum version required: " "%s" % (currentVersion, minVersion), 0) - resp = dialog.yesno( - heading="Db Version", - line1=("Detected the database needs to be recreated " - "for this version of " + self.addonName + - "Proceed?")) + # DB out of date. Proceed to recreate? + resp = dialog.yesno(heading=self.addonName, + line1=string(39401)) if not resp: log("Db version out of date! USER IGNORED!", 0) - dialog.ok( - heading=self.addonName, - line1=(self.addonName + " may not work correctly " - "until the database is reset.")) + # PKC may not work correctly until reset + dialog.ok(heading=self.addonName, + line1=(self.addonName + string(39402))) else: utils.reset() break @@ -1182,13 +1182,12 @@ class LibrarySync(Thread): if not xbmcvfs.exists(videoDb): # Database does not exists log("The current Kodi version is incompatible " - "to know which Kodi versions are supported.", 0) - dialog.ok( - heading=self.addonName, - line1=("Cancelling the database syncing process. " - "Current Kodi version: %s is unsupported. " - "Please verify your logs for more info." - % xbmc.getInfoLabel('System.BuildVersion'))) + "to know which Kodi versions are supported.", -1) + log('Current Kodi version: %s' % xbmc.getInfoLabel( + 'System.BuildVersion').decode('utf-8')) + # "Current Kodi version is unsupported, cancel lib sync" + dialog.ok(heading=self.addonName, + line1=string(39403)) break # Run start up sync @@ -1209,11 +1208,10 @@ class LibrarySync(Thread): errorcount += 1 if errorcount > 2: log("Startup full sync failed. Stopping sync", -1) - dialog.ok( - heading=self.addonName, - line1=("Startup syncing process failed repeatedly." - " Try restarting Kodi. Stopping Sync for " - "now.")) + # "Startup syncing process failed repeatedly" + # "Please restart" + dialog.ok(heading=self.addonName, + line1=string(39404)) break # Currently no db scan, so we can start a new scan @@ -1239,18 +1237,21 @@ class LibrarySync(Thread): # Kick off refresh if self.maintainViews(): # Ran successfully + log("Refresh playlists/nodes completed", 0) + # "Plex playlists/nodes refreshed" dialog.notification( heading=self.addonName, - message="Plex playlists/nodes refreshed", + message=string(39405), icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", time=3000, sound=True) else: # Failed log("Refresh playlists/nodes failed", -1) + # "Plex playlists/nodes refresh failed" dialog.notification( heading=self.addonName, - message="Plex playlists/nodes refresh failed", + message=string(39406), icon=xbmcgui.NOTIFICATION_ERROR, time=3000, sound=True) @@ -1268,8 +1269,7 @@ class LibrarySync(Thread): window('emby_dbScan', value="true") if not fastSync(): # Fast sync failed or server plugin is not found - self.logMsg( - "Something went wrong, starting full sync", -1) + log("Something went wrong, starting full sync", -1) fullSync(manualrun=True) window('emby_dbScan', clear=True) From b05ec9746ac883607799590629397957fabe5360 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 11:58:14 +0100 Subject: [PATCH 07/16] Remove obsolete check for method in processing metadata --- resources/lib/librarysync.py | 11 +++-------- resources/lib/utils.py | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index a630aab3..e2b77bac 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -124,14 +124,9 @@ class ThreadedProcessMetadata(Thread): with lock: # Get the one child entry in the xml and process for child in plexitem: - if method == 'add_updateAlbum': - item.add_updateAlbum(child, - viewtag=viewName, - viewid=viewId) - else: - itemSubFkt(child, - viewtag=viewName, - viewid=viewId) + itemSubFkt(child, + viewtag=viewName, + viewid=viewId) # Keep track of where we are at processMetadataCount += 1 processingViewName = title diff --git a/resources/lib/utils.py b/resources/lib/utils.py index d2db3fdf..f2859c1b 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -443,7 +443,7 @@ def reset(): logMsg("PLEX", "Deleting: settings.xml", 1) dialog.ok( - heading="Emby for Kodi", + heading=addonName, line1="Database reset has completed, Kodi will now restart to apply the changes.") xbmc.executebuiltin('RestartApp') From d5aae4934bb47f834772486a21705d42e0c5fd7a Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 12:13:47 +0100 Subject: [PATCH 08/16] Clean out library sync --- resources/lib/librarysync.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index e2b77bac..89567852 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -160,10 +160,10 @@ class ThreadedShowSyncInfo(Thread): threadStopped = self.threadStopped downloadLock = self.locks[0] processLock = self.locks[1] - dialog.create(("%s: Sync %s: %s items" + dialog.create("%s: Sync %s: %s items" % (self.addonName, self.itemType, - str(total))).encode('utf-8'), + str(total)), "Starting") global getMetadataCount global processMetadataCount @@ -181,15 +181,11 @@ class ThreadedShowSyncInfo(Thread): percentage = int(float(totalProgress) / float(total)*100.0) except ZeroDivisionError: percentage = 0 - try: - dialog.update( - percentage, - message=("Downloaded: %s. Processed: %s: %s" - % (getMetadataProgress, processMetadataProgress, - viewName))).encode('utf-8') - except: - # Wierd formating of the string viewName?!? - pass + dialog.update(percentage, + message="Downloaded: %s. Processed: %s: %s" + % (getMetadataProgress, + processMetadataProgress, + viewName)) # Sleep for x milliseconds xbmc.sleep(500) dialog.close() @@ -224,20 +220,20 @@ class LibrarySync(Thread): self.enableMusic = True if utils.settings('enableMusic') == "true" \ else False self.enableBackgroundSync = True if utils.settings( - 'enableBackgroundSync') == "true" \ - else False + 'enableBackgroundSync') == "true" else False Thread.__init__(self) def showKodiNote(self, message, forced=False): """ - Shows a Kodi popup, if user selected to do so + Shows a Kodi popup, if user selected to do so. Pass message in unicode + or string """ if not (self.showDbSync or forced): return xbmcgui.Dialog().notification( heading=self.addonName, - message=message.encode('utf-8'), + message=message, icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", sound=False) @@ -279,8 +275,8 @@ class LibrarySync(Thread): if self.threadStopped(): return True # Get items per view - items = PlexFunctions.GetAllPlexLeaves( - view['id'], updatedAt=lastSync) + items = PlexFunctions.GetAllPlexLeaves(view['id'], + updatedAt=lastSync) # Just skip item if something went wrong if not items: continue @@ -444,7 +440,7 @@ class LibrarySync(Thread): "Found viewid: %s" % folderid, "viewname: %s" % current_viewname, "viewtype: %s" % current_viewtype, - "tagid: %s" % current_tagid)), 2) + "tagid: %s" % current_tagid)), 1) # Remove views that are still valid to delete rest later try: From 56af183288e2723f44f86bf0fe0a6e70058baa3a Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 13:00:03 +0100 Subject: [PATCH 09/16] Correct encoding Kodi dialogs take unicode --- resources/lib/PlexAPI.py | 34 +++++++++++-------------- resources/lib/entrypoint.py | 10 ++++---- resources/lib/initialsetup.py | 47 ++++++++++++++++------------------- resources/lib/player.py | 4 +-- resources/lib/playutils.py | 7 ++++-- resources/lib/userclient.py | 25 +++++++------------ resources/lib/utils.py | 23 ++++++++++------- resources/lib/videonodes.py | 1 - 8 files changed, 70 insertions(+), 81 deletions(-) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index a3d68ea8..719e10cb 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -131,17 +131,14 @@ class PlexAPI(): dialog = xbmcgui.Dialog() while retrievedPlexLogin == '' and plexLogin != '': # Enter plex.tv username. Or nothing to cancel. - plexLogin = dialog.input( - self.addonName.encode('utf-8') + string(39300).encode('utf-8'), - type=xbmcgui.INPUT_ALPHANUM, - ) + plexLogin = dialog.input(self.addonName + string(39300), + type=xbmcgui.INPUT_ALPHANUM) if plexLogin != "": # Enter password for plex.tv user plexPassword = dialog.input( - string(39301).encode('utf-8') + plexLogin.encode('utf-8'), + string(39301) + plexLogin, type=xbmcgui.INPUT_ALPHANUM, - option=xbmcgui.ALPHANUM_HIDE_INPUT - ) + option=xbmcgui.ALPHANUM_HIDE_INPUT) retrievedPlexLogin, authtoken = self.MyPlexSignIn( plexLogin, plexPassword, @@ -151,8 +148,7 @@ class PlexAPI(): if plexLogin == '': # Could not sign in user dialog.ok(self.addonName, - string(39302).encode('utf-8') - + plexLogin.encode('utf-8')) + string(39302) + plexLogin) # Write to Kodi settings file utils.settings('plexLogin', value=retrievedPlexLogin) utils.settings('plexToken', value=authtoken) @@ -177,12 +173,12 @@ class PlexAPI(): dialog = xbmcgui.Dialog() if not code: # Problems trying to contact plex.tv. Try again later - dialog.ok(self.addonName, string(39303).encode('utf-8')) + dialog.ok(self.addonName, string(39303)) return False # Go to https://plex.tv/pin and enter the code: answer = dialog.yesno(self.addonName, - (string(39304) + "\n\n").encode('utf-8'), - code.encode('utf-8')) + string(39304) + "\n\n", + code) if not answer: return False count = 0 @@ -196,7 +192,7 @@ class PlexAPI(): count += 1 if not xml: # Could not sign in to plex.tv Try again later - dialog.ok(self.addonName, string(39305).encode('utf-8')) + dialog.ok(self.addonName, string(39305)) return False # Parse xml userid = xml.attrib.get('id') @@ -1089,7 +1085,7 @@ class PlexAPI(): if usernumber > 1: # Select user user_select = dialog.select( - (self.addonName + string(39306)).encode('utf-8'), + self.addonName + string(39306), userlistCoded) if user_select == -1: self.logMsg("No user selected.", 1) @@ -1108,7 +1104,7 @@ class PlexAPI(): # Please enter pin for user self.logMsg('Asking for users PIN', 1) pin = dialog.input( - (string(39307) + selected_user).encode('utf-8'), + string(39307) + selected_user, type=xbmcgui.INPUT_NUMERIC, option=xbmcgui.ALPHANUM_HIDE_INPUT) # User chose to cancel @@ -1129,11 +1125,9 @@ class PlexAPI(): # Couldn't get user auth if not username: # Could not login user, please try again - if not dialog.yesno( - self.addonName, - (string(39308) + selected_user).encode('utf-8'), - string(39309).encode('utf-8') - ): + if not dialog.yesno(self.addonName, + string(39308) + selected_user, + string(39309)): # User chose to cancel break # Successfully retrieved: break out of while loop diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 8f0c6703..901b8def 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -98,7 +98,7 @@ def reConnect(): if counter > 20: dialog.ok( heading=addonName, - message=string(39208).encode('utf-8'), + message=string(39208), ) # Resuming threads, just in case utils.window('suspend_LibraryThread', clear=True) @@ -185,7 +185,7 @@ def resetAuth(): string = xbmcaddon.Addon().getLocalizedString resp = xbmcgui.Dialog().yesno( heading="Warning", - line1=string(39206).encode('utf-8')) + line1=string(39206)) if resp == 1: utils.logMsg("PLEX", "Reset login attempts.", 1) utils.window('emby_serverStatus', value="Auth") @@ -255,14 +255,14 @@ def resetDeviceId(): "Failed to generate a new device Id: %s" % e, 1) dialog.ok( heading=addonName, - line1=language(33032).encode('utf-8')) + line1=language(33032)) else: utils.logMsg(addonName, "Successfully removed old deviceId: %s New deviceId: %s" % (deviceId_old, deviceId), 1) dialog.ok( heading=addonName, - line1=language(33033).encode('utf-8')) + line1=language(33033)) xbmc.executebuiltin('RestartApp') ##### ADD ADDITIONAL USERS ##### @@ -1189,6 +1189,6 @@ def RunLibScan(mode): # Server is not online, do not run the sync string = xbmcaddon.Addon().getLocalizedString xbmcgui.Dialog().ok(heading=addonName, - line1=string(39205).encode('utf-8')) + line1=string(39205)) else: utils.window('plex_runLibScan', value='full') diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index 1853695c..5d69464ce 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -57,10 +57,8 @@ class InitialSetup(): # Delete token in the settings utils.settings('plexToken', value='') # Could not login, please try again - dialog.ok( - self.addonName, - string(39009).encode('utf-8') - ) + dialog.ok(self.addonName, + string(39009)) result = self.plx.PlexTvSignInWithPin() if result: plexLogin = result['username'] @@ -68,10 +66,8 @@ class InitialSetup(): plexid = result['plexid'] elif chk is False or chk >= 400: # Problems connecting to plex.tv. Network or internet issue? - dialog.ok( - self.addonName, - string(39010).encode('utf-8') - ) + dialog.ok(self.addonName, + string(39010)) # If a Plex server IP has already been set, return. if server and forcePlexTV is False: self.logMsg("Server is already set.", 0) @@ -100,8 +96,8 @@ class InitialSetup(): self.logMsg("Result of setting g_PMS variable: %s" % self.plx.g_PMS, 1) isconnected = False - serverlist = self.plx.returnServerList( - clientId, self.plx.g_PMS) + serverlist = self.plx.returnServerList(clientId, + self.plx.g_PMS) self.logMsg('PMS serverlist: %s' % serverlist) # Let user pick server from a list # Get a nicer list @@ -110,18 +106,18 @@ class InitialSetup(): if len(serverlist) == 0: dialog.ok( self.addonName, - string(39011).encode('utf-8') + string(39011) ) break for server in serverlist: if server['local'] == '1': # server is in the same network as client. Add "local" dialoglist.append( - server['name'].encode('utf-8') - + string(39022).encode('utf-8')) + server['name'] + + string(39022)) else: - dialoglist.append(server['name'].encode('utf-8')) - resp = dialog.select(string(39012).encode('utf-8'), dialoglist) + dialoglist.append(server['name']) + resp = dialog.select(string(39012), dialoglist) server = serverlist[resp] activeServer = server['machineIdentifier'] url = server['scheme'] + '://' + server['ip'] + ':' + \ @@ -146,9 +142,8 @@ class InitialSetup(): # Not yet authorized for Plex server # Please sign in to plex.tv dialog.ok(self.addonName, - string(39013).encode('utf-8') - + server['name'].encode('utf-8'), - string(39014).encode('utf-8')) + string(39013) + server['name'], + string(39014)) result = self.plx.PlexTvSignInWithPin() if result: plexLogin = result['username'] @@ -161,7 +156,7 @@ class InitialSetup(): elif chk >= 400 or chk is False: # Problems connecting to server. Pick another server? resp = dialog.yesno(self.addonName, - string(39015).encode('utf-8')) + string(39015)) # Exit while loop if user chooses No if not resp: break @@ -173,7 +168,7 @@ class InitialSetup(): # Enter Kodi settings instead if dialog.yesno( heading=self.addonName, - line1=string(39016).encode('utf-8')): + line1=string(39016)): self.logMsg("User opted to disable Plex music library.", 1) utils.settings('enableMusic', value="false") xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) @@ -207,14 +202,14 @@ class InitialSetup(): if forcePlexTV: return - if dialog.yesno( - heading=self.addonName, - line1=string(39016).encode('utf-8')): + # Disable Plex music? + if dialog.yesno(heading=self.addonName, + line1=string(39016)): self.logMsg("User opted to disable Plex music library.", 1) utils.settings('enableMusic', value="false") - if dialog.yesno( - heading=self.addonName, - line1=string(39017).encode('utf-8')): + # Open Settings page now? + if dialog.yesno(heading=self.addonName, + line1=string(39017)): xbmc.executebuiltin( 'Addon.OpenSettings(plugin.video.plexkodiconnect)') diff --git a/resources/lib/player.py b/resources/lib/player.py index 24a5a037..a29ab512 100644 --- a/resources/lib/player.py +++ b/resources/lib/player.py @@ -524,8 +524,8 @@ class Player(xbmc.Player): offerDelete = False if percentComplete >= markPlayedAt and offerDelete: resp = xbmcgui.Dialog().yesno( - lang(30091).encode('utf-8'), - lang(33015).encode('utf-8'), + lang(30091), + lang(33015), autoclose=120000) if not resp: log("User skipped deletion.", 1) diff --git a/resources/lib/playutils.py b/resources/lib/playutils.py index 8a382f1a..019d7614 100644 --- a/resources/lib/playutils.py +++ b/resources/lib/playutils.py @@ -34,6 +34,8 @@ class PlayUtils(): """ Returns the playurl for the part with number partNumber (movie might consist of several files) + + playurl is utf-8 encoded! """ log = self.logMsg window = utils.window @@ -64,6 +66,7 @@ class PlayUtils(): } playurl = self.API.getTranscodeVideoPath('Transcode', quality=quality) + playurl = playurl.encode('utf-8') # Set playmethod property window('emby_%s.playmethod' % playurl, value="Transcode") @@ -371,7 +374,7 @@ class PlayUtils(): subNum += 1 if audioNum > 1: - resp = dialog.select(lang(33013).encode('utf-8'), audioStreams) + resp = dialog.select(lang(33013), audioStreams) if resp > -1: # User selected audio playurlprefs['audioStreamID'] = audioStreamsList[resp] @@ -384,7 +387,7 @@ class PlayUtils(): playurlprefs['audioBoost'] = utils.settings('audioBoost') if subNum > 1: - resp = dialog.select(lang(33014).encode('utf-8'), subtitleStreams) + resp = dialog.select(lang(33014), subtitleStreams) if resp == 0: # User selected no subtitles playurlprefs["skipSubtitles"] = 1 diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index bc671acd..4246654e 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -46,23 +46,16 @@ class UserClient(threading.Thread): threading.Thread.__init__(self) - def getAdditionalUsers(self): - - additionalUsers = utils.settings('additionalUsers') - - if additionalUsers: - self.AdditionalUser = additionalUsers.split(',') - def getUsername(self): """ Returns username as unicode """ - username = utils.settings('username').decode('utf-8') + username = utils.settings('username') if not username: self.logMsg("No username saved, trying to get Plex username", 0) - username = utils.settings('plexLogin').decode('utf-8') + username = utils.settings('plexLogin') if not username: self.logMsg("Also no Plex username found", 0) return "" @@ -245,9 +238,8 @@ class UserClient(threading.Thread): log("Access is granted.", 1) self.HasAccess = True window('emby_serverStatus', clear=True) - xbmcgui.Dialog().notification( - self.addonName, - utils.language(33007).encode('utf-8')) + xbmcgui.Dialog().notification(self.addonName, + utils.language(33007)) def loadCurrUser(self, authenticated=False): self.logMsg('Loading current user', 0) @@ -318,7 +310,8 @@ class UserClient(threading.Thread): dialog = xbmcgui.Dialog() # Get /profile/addon_data - addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8') + addondir = xbmc.translatePath( + self.addon.getAddonInfo('profile')).decode('utf-8') hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) # If there's no settings.xml @@ -373,7 +366,7 @@ class UserClient(threading.Thread): if username: dialog.notification( heading=self.addonName, - message=("Welcome " + username).encode('utf-8'), + message="Welcome " + username, icon="special://home/addons/plugin.video.plexkodiconnect/icon.png") else: dialog.notification( @@ -391,8 +384,8 @@ class UserClient(threading.Thread): if self.retry >= 5: log("Too many retries.", 1) window('emby_serverStatus', value="Stop") - dialog.ok(lang(33001).encode('utf-8'), - lang(39023).encode('utf-8')) + dialog.ok(lang(33001), + lang(39023)) xbmc.executebuiltin( 'Addon.OpenSettings(plugin.video.plexkodiconnect)') diff --git a/resources/lib/utils.py b/resources/lib/utils.py index f2859c1b..1a636a12 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -217,7 +217,13 @@ def logMsg(title, msg, level=1): def window(property, value=None, clear=False, windowid=10000): - # Get or set window property + """ + Get or set window property - thread safe! + + Returns unicode. + + Property needs to be string; value may be string or unicode + """ WINDOW = xbmcgui.Window(windowid) #setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues @@ -228,14 +234,13 @@ def window(property, value=None, clear=False, windowid=10000): if clear: WINDOW.clearProperty(property) elif value is not None: - # Takes unicode or string by default! - WINDOW.setProperty(property, value) - else: #getproperty returns string so convert to unicode - return WINDOW.getProperty(property) + WINDOW.setProperty(property, value.encode('utf-8')) + else: + return WINDOW.getProperty(property).decode('utf-8') def settings(setting, value=None): """ - Get or add addon setting. + Get or add addon setting. Returns unicode Settings needs to be string Value can either be unicode or string @@ -244,10 +249,10 @@ def settings(setting, value=None): if value is not None: # Takes string or unicode by default! - addon.setSetting(setting, value) + addon.setSetting(setting, value.encode('utf-8')) else: - # Returns unicode by default! - return addon.getSetting(setting) + # Should return unicode by default, but just in case + return addon.getSetting(setting).decode('utf-8') def language(stringid): # Central string retrieval diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py index 12768ad1..6e99f3bd 100644 --- a/resources/lib/videonodes.py +++ b/resources/lib/videonodes.py @@ -4,7 +4,6 @@ import shutil import xml.etree.ElementTree as etree -from os import path as ospath import xbmc import xbmcvfs From 15f934f77ae23495f8b76ccd6dde0d27998e779c Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 13:09:15 +0100 Subject: [PATCH 10/16] Fix encoding in service.py --- service.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/service.py b/service.py index c0663461..2d47e1fa 100644 --- a/service.py +++ b/service.py @@ -171,8 +171,7 @@ class Service(): self.welcome_msg = False xbmcgui.Dialog().notification( heading=self.addonName, - message=("%s %s" % (lang(33000), user.currUser) - ).encode('utf-8'), + message="%s %s" % (lang(33000), user.currUser), icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", time=2000, sound=False) @@ -225,8 +224,9 @@ class Service(): window('emby_online', value="false") xbmcgui.Dialog().notification( - heading=lang(33001).encode('utf-8'), - message=("%s %s" % (self.addonName, lang(33002))).encode('utf-8'), + heading=lang(33001), + message="%s %s" + % (self.addonName, lang(33002)), icon="special://home/addons/plugin.video." "plexkodiconnect/icon.png", sound=False) @@ -244,7 +244,7 @@ class Service(): # Alert the user that server is online. xbmcgui.Dialog().notification( heading=self.addonName, - message=lang(33003).encode('utf-8'), + message=lang(33003), icon="special://home/addons/plugin.video." "plexkodiconnect/icon.png", time=2000, From 0cefee6cfec4983daecd714c17f48b6ad032fa8f Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 13:52:17 +0100 Subject: [PATCH 11/16] Reduce number of unsuccesful retries to 3 before telling user --- resources/lib/userclient.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index 4246654e..ffc7d1e3 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -381,8 +381,8 @@ class UserClient(threading.Thread): settings('userId', value="") # Give attempts at entering password / selecting user - if self.retry >= 5: - log("Too many retries.", 1) + if self.retry >= 3: + log("Too many retries to login.", -1) window('emby_serverStatus', value="Stop") dialog.ok(lang(33001), lang(39023)) From 1ab657cd0bbe87cd60df133212742998d2559ebb Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 14:02:01 +0100 Subject: [PATCH 12/16] Change logging to show "Error" category --- resources/lib/utils.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 1a636a12..84642439 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -192,28 +192,37 @@ def logMsg(title, msg, level=1): logLevel = int(window('emby_logLevel')) except ValueError: logLevel = 0 - + kodiLevel = { + -1: xbmc.LOGERROR, + 0: xbmc.LOGNOTICE, + 1: xbmc.LOGNOTICE, + 2: xbmc.LOGNOTICE + } if logLevel >= level: - if logLevel == 2: # inspect is expensive func = inspect.currentframe().f_back.f_back.f_code try: xbmc.log("%s -> %s : %s" % ( - title, func.co_name, msg)) + title, func.co_name, msg), level=kodiLevel[level]) except UnicodeEncodeError: try: xbmc.log("%s -> %s : %s" % ( - title, func.co_name, msg.encode('utf-8'))) + title, func.co_name, msg.encode('utf-8')), + level=kodiLevel[level]) except: - xbmc.log("%s -> %s : %s" % (title, func.co_name, 'COULDNT LOG')) + xbmc.log("%s -> %s : %s" % ( + title, func.co_name, 'COULDNT LOG'), + level=kodiLevel[level]) else: try: - xbmc.log("%s -> %s" % (title, msg)) + xbmc.log("%s -> %s" % (title, msg), level=kodiLevel[level]) except UnicodeEncodeError: try: - xbmc.log("%s -> %s" % (title, msg.encode('utf-8'))) + xbmc.log("%s -> %s" % (title, msg.encode('utf-8')), + level=kodiLevel[level]) except: - xbmc.log("%s -> %s " % (title, 'COULDNT LOG')) + xbmc.log("%s -> %s " % (title, 'COULDNT LOG'), + level=kodiLevel[level]) def window(property, value=None, clear=False, windowid=10000): From 100421ce2de51c0d66ad58a58f4847ec5c6b3024 Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 14:50:43 +0100 Subject: [PATCH 13/16] Connect to remote PMS --- resources/lib/PlexAPI.py | 10 +++++----- resources/lib/downloadutils.py | 2 +- resources/lib/initialsetup.py | 30 +++++++++++++++++++----------- resources/lib/userclient.py | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index 719e10cb..a68c6014 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -295,13 +295,13 @@ class PlexAPI(): verify=verify, timeout=timeout) except requests.exceptions.ConnectionError as e: - self.logMsg("Server is offline or cannot be reached. Url: %s." - "Header: %s. Error message: %s" - % (url, header, e), -1) + self.logMsg("Server is offline or cannot be reached. Url: %s. " + "Error message: %s" + % (url, e), -1) return False except requests.exceptions.ReadTimeout: - self.logMsg("Server timeout reached for Url %s with header %s" - % (url, header), -1) + self.logMsg("Server timeout reached for Url %s" + % url, -1) return False # We received an answer from the server, but not as expected. if answer.status_code >= 400: diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index e7826709..c53c0664 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -359,7 +359,7 @@ class DownloadUtils(): except requests.exceptions.ConnectionError as e: # Make the addon aware of status if utils.window('emby_online') != "false": - self.logMsg("Server unreachable at: %s" % url, 0) + self.logMsg("Server unreachable at: %s" % url, -1) self.logMsg(e, 2) utils.window('emby_online', value="false") diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index 5d69464ce..8fa55c92 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -44,7 +44,7 @@ class InitialSetup(): plexLogin = plexdict['plexLogin'] plexToken = plexdict['plexToken'] plexid = plexdict['plexid'] - self.logMsg('Plex info retrieved from settings: %s' % plexdict, 1) + self.logMsg('Plex info retrieved from settings', 1) dialog = xbmcgui.Dialog() @@ -120,8 +120,13 @@ class InitialSetup(): resp = dialog.select(string(39012), dialoglist) server = serverlist[resp] activeServer = server['machineIdentifier'] - url = server['scheme'] + '://' + server['ip'] + ':' + \ - server['port'] + # Re-direct via plex if remote - will lead to the correct SSL + # certificate + if server['local'] == '1': + url = server['scheme'] + '://' + server['ip'] + ':' \ + + server['port'] + else: + url = server['baseURL'] # Deactive SSL verification if the server is local! if server['local'] == '1': utils.settings('sslverify', 'false') @@ -166,18 +171,21 @@ class InitialSetup(): break if not isconnected: # Enter Kodi settings instead - if dialog.yesno( - heading=self.addonName, - line1=string(39016)): - self.logMsg("User opted to disable Plex music library.", 1) - utils.settings('enableMusic', value="false") xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return # Write to Kodi settings file utils.settings('plex_machineIdentifier', activeServer) - utils.settings('ipaddress', server['ip']) - utils.settings('port', server['port']) - if server['scheme'] == 'https': + if server['local'] == '1': + scheme = server['scheme'] + utils.settings('ipaddress', server['ip']) + utils.settings('port', server['port']) + else: + baseURL = server['baseURL'].split(':') + scheme = baseURL[0] + utils.settings('ipaddress', baseURL[1].replace('//', '')) + utils.settings('port', baseURL[2]) + + if scheme == 'https': utils.settings('https', 'true') else: utils.settings('https', 'false') diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index ffc7d1e3..3d67ba7a 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -381,7 +381,7 @@ class UserClient(threading.Thread): settings('userId', value="") # Give attempts at entering password / selecting user - if self.retry >= 3: + if self.retry >= 2: log("Too many retries to login.", -1) window('emby_serverStatus', value="Stop") dialog.ok(lang(33001), From e5e6f2208e5b9576b37b203b6a8e911564cfb35b Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 15:28:59 +0100 Subject: [PATCH 14/16] Much shorter download timeouts This should hopefully solve the stuck library sync --- resources/lib/downloadutils.py | 2 +- resources/lib/image_cache_thread.py | 2 +- resources/lib/librarysync.py | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index c53c0664..1a1a9984 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -37,7 +37,7 @@ class DownloadUtils(): # Requests session s = None - timeout = 30 + timeout = 3 def __init__(self): diff --git a/resources/lib/image_cache_thread.py b/resources/lib/image_cache_thread.py index 71ebe574..a9a76962 100644 --- a/resources/lib/image_cache_thread.py +++ b/resources/lib/image_cache_thread.py @@ -40,7 +40,7 @@ class image_cache_thread(threading.Thread): "http://%s:%s/image/image://%s" % (self.xbmc_host, self.xbmc_port, self.urlToProcess)), auth=(self.xbmc_username, self.xbmc_password), - timeout=(35.1, 35.1)) + timeout=(0.1, 0.1)) # We don't need the result except: pass diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 89567852..f7a56908 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -25,6 +25,7 @@ import PlexFunctions ############################################################################### +@utils.logging @utils.ThreadMethodsAdditionalStop('emby_shouldStop') @utils.ThreadMethods class ThreadedGetMetadata(Thread): @@ -64,6 +65,10 @@ class ThreadedGetMetadata(Thread): plexXML = PlexFunctions.GetPlexMetadata(updateItem['itemId']) if plexXML is None: # Did not receive a valid XML - skip that item for now + self.logMsg("Could not get metadata for %s. " + "Skipping that item for now", -1) + with lock: + getMetadataCount += 1 queue.task_done() continue @@ -1105,6 +1110,7 @@ class LibrarySync(Thread): self.run_internal() except Exception as e: utils.window('emby_dbScan', clear=True) + self.logMsg('LibrarySync thread crashed', -1) # Library sync thread has crashed xbmcgui.Dialog().ok( heading=self.addonName, From e635f43845a4a0eff0ebfb4441188833577605ca Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 17:41:07 +0100 Subject: [PATCH 15/16] Improve sync resiliance and GDM discovery Improve sync resiliance to bad connections (e.g. behind a firewall) --- resources/lib/PlexAPI.py | 8 +++++++- resources/lib/PlexFunctions.py | 21 +++++++++++++++++++ resources/lib/librarysync.py | 28 +++++++++++++++++--------- resources/lib/plexbmchelper/plexgdm.py | 27 +++++++++++++++++++------ 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index a68c6014..ba72c46b 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -55,7 +55,7 @@ import re import json from urllib import urlencode, quote_plus -from PlexFunctions import PlexToKodiTimefactor +from PlexFunctions import PlexToKodiTimefactor, PMSHttpsEnabled try: import xml.etree.cElementTree as etree @@ -630,6 +630,12 @@ class PlexAPI(): self.getPMSListFromMyPlex(ATV_udid, authtoken) # all servers - update enableGzip for uuid_id in self.g_PMS.get(ATV_udid, {}): + # Ping to check whether we need HTTPs or HTTP + url = (self.getPMSProperty(ATV_udid, uuid_id, 'ip') + ':' + + self.getPMSProperty(ATV_udid, uuid_id, 'port')) + if PMSHttpsEnabled(url): + self.logMsg('PMS %s talks HTTPS' % uuid_id, 1) + self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'https') # enable Gzip if not on same host, local&remote PMS depending # on setting enableGzip = (not self.getPMSProperty(ATV_udid, uuid_id, 'ip') == IP_self) \ diff --git a/resources/lib/PlexFunctions.py b/resources/lib/PlexFunctions.py index c371ac2c..6fc744f4 100644 --- a/resources/lib/PlexFunctions.py +++ b/resources/lib/PlexFunctions.py @@ -347,3 +347,24 @@ def getPlexRepeat(kodiRepeat): 'all': '2' # does this work?!? } return plexRepeat.get(kodiRepeat) + + +def PMSHttpsEnabled(url): + """ + Returns True if the PMS wants to talk https, False otherwise + + With with e.g. url=192.168.0.1:32400 (NO http/https) + + This is done by GET /identity (returns an error if https is enabled and we + are trying to use http) + """ + xml = downloadutils.DownloadUtils().downloadUrl('http://%s/identity' % url) + try: + # received a valid XML - http connection is possible + xml.attrib + logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTP' % url, 1) + return False + except: + # couldn't get an xml - switch to https traffic + logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTPS' % url, 1) + return True diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index f7a56908..828f0ac5 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -40,10 +40,11 @@ class ThreadedGetMetadata(Thread): the downloaded metadata XMLs as etree objects lock Lock(), used for counting where we are """ - def __init__(self, queue, out_queue, lock): + def __init__(self, queue, out_queue, lock, processlock): self.queue = queue self.out_queue = out_queue self.lock = lock + self.processlock = processlock Thread.__init__(self) def run(self): @@ -51,8 +52,10 @@ class ThreadedGetMetadata(Thread): queue = self.queue out_queue = self.out_queue lock = self.lock + processlock = self.processlock threadStopped = self.threadStopped global getMetadataCount + global processMetadataCount while threadStopped() is False: # grabs Plex item from queue try: @@ -66,9 +69,13 @@ class ThreadedGetMetadata(Thread): if plexXML is None: # Did not receive a valid XML - skip that item for now self.logMsg("Could not get metadata for %s. " - "Skipping that item for now", -1) + "Skipping that item for now" + % updateItem['itemId'], -1) + # Increase BOTH counters - since metadata won't be processed with lock: getMetadataCount += 1 + with processlock: + processMetadataCount += 1 queue.task_done() continue @@ -119,20 +126,20 @@ class ThreadedProcessMetadata(Thread): except Queue.Empty: xbmc.sleep(100) continue - # Do the work; lock to be sure we've only got 1 Thread + # Do the work plexitem = updateItem['XML'] method = updateItem['method'] viewName = updateItem['viewName'] viewId = updateItem['viewId'] title = updateItem['title'] itemSubFkt = getattr(item, method) + # Get the one child entry in the xml and process + for child in plexitem: + itemSubFkt(child, + viewtag=viewName, + viewid=viewId) + # Keep track of where we are at with lock: - # Get the one child entry in the xml and process - for child in plexitem: - itemSubFkt(child, - viewtag=viewName, - viewid=viewId) - # Keep track of where we are at processMetadataCount += 1 processingViewName = title # signals to queue job is done @@ -728,7 +735,8 @@ class LibrarySync(Thread): for i in range(min(self.syncThreadNumber, itemNumber)): thread = ThreadedGetMetadata(getMetadataQueue, processMetadataQueue, - getMetadataLock) + getMetadataLock, + processMetadataLock) thread.setDaemon(True) thread.start() threads.append(thread) diff --git a/resources/lib/plexbmchelper/plexgdm.py b/resources/lib/plexbmchelper/plexgdm.py index 06544f94..597eedc3 100644 --- a/resources/lib/plexbmchelper/plexgdm.py +++ b/resources/lib/plexbmchelper/plexgdm.py @@ -31,7 +31,10 @@ import re import threading import time import urllib2 + import downloadutils +from PlexFunctions import PMSHttpsEnabled + class plexgdm: @@ -56,6 +59,7 @@ class plexgdm: self.discovery_complete = False self.client_registered = False self.debug = debug + self.download = downloadutils.DownloadUtils().downloadUrl def __printDebug(self, message, level=1): if self.debug: @@ -139,13 +143,19 @@ class plexgdm: try: media_server=self.server_list[0]['server'] media_port=self.server_list[0]['port'] + scheme = self.server_list[0]['protocol'] self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2) - client_result = downloadutils.DownloadUtils().downloadUrl( - 'http://%s:%s/clients' % (media_server, media_port)) + client_result = self.download( + '%s://%s:%s/clients' % (scheme, media_server, media_port)) # f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port)) # client_result = f.read() - if self.client_id in str(client_result): + registered = False + for client in client_result: + if (client.attrib.get('machineIdentifier') == + self.client_id): + registered = True + if registered: self.__printDebug("Client registration successful",1) self.__printDebug("Client data is: %s" % client_result, 3) return True @@ -208,7 +218,6 @@ class plexgdm: if "200 OK" in response.get('data'): for each in response.get('data').split('\r\n'): - update['discovery'] = "auto" update['owned']='1' update['master']= 1 @@ -230,7 +239,13 @@ class plexgdm: elif "Server-Class:" in each: update['class'] = each.split(':')[1].strip() - discovered_servers.append(update) + # Quickly test if we need https + if PMSHttpsEnabled( + '%s:%s' % (update['server'], update['port'])): + update['protocol'] = 'https' + else: + update['protocol'] = 'http' + discovered_servers.append(update) self.server_list = discovered_servers @@ -239,7 +254,7 @@ class plexgdm: else: self.__printDebug("Number of servers Discovered: %s" % len(self.server_list),1) for items in self.server_list: - self.__printDebug("Server Discovered: %s" % items['serverName'] ,2) + self.__printDebug("Server Discovered: %s" % items, 2) def setInterval(self, interval): From 63df69dee9dd4a4dc5fdf9eeac799073ed999c4c Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Tue, 8 Mar 2016 18:35:36 +0100 Subject: [PATCH 16/16] Version bump --- addon.xml | 2 +- changelog.txt | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/addon.xml b/addon.xml index 8506f0de..1c919d4e 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/changelog.txt b/changelog.txt index b13a874f..138db97a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,14 @@ +version 1.0.4 +- Sleep for a while in loops - drastically reduces CPU load +- Connect to remote PMS! +- New Setting to reset all PMS and the plex.tv connection +- Correct encoding +- Much shorter download timeouts +- Improve sync resiliance and GDM discovery +- Reduce number of unsuccesful retries to 3 before telling user +- Clean-up library sync loop +- Language strings for library sync + version 1.0.3 - Hotfix database minimum version = 1.0.2