From a4a1be97f592deb383c099f54ba886d181ebd121 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 15:30:12 -0600 Subject: [PATCH 1/8] Remove encode for playutils Since we encode in utils now. --- resources/lib/playutils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/lib/playutils.py b/resources/lib/playutils.py index 8b5474aa..6e0301bb 100644 --- a/resources/lib/playutils.py +++ b/resources/lib/playutils.py @@ -52,7 +52,6 @@ class PlayUtils(): self.logMsg("File is direct playing.", 1) playurl = self.directPlay() - playurl = playurl.encode('utf-8') # Set playmethod property utils.window('emby_%s.playmethod' % playurl, value="DirectPlay") From 395140262dbe2a01080adf6a82e96b7c2c09696b Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 15:59:31 -0600 Subject: [PATCH 2/8] Revert "Remove encode for playutils" This reverts commit a4a1be97f592deb383c099f54ba886d181ebd121. --- resources/lib/playutils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lib/playutils.py b/resources/lib/playutils.py index 6e0301bb..8b5474aa 100644 --- a/resources/lib/playutils.py +++ b/resources/lib/playutils.py @@ -52,6 +52,7 @@ class PlayUtils(): self.logMsg("File is direct playing.", 1) playurl = self.directPlay() + playurl = playurl.encode('utf-8') # Set playmethod property utils.window('emby_%s.playmethod' % playurl, value="DirectPlay") From 04d7ac2f012f6c8b9fdb015eea1503fcc536871b Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 16:49:59 -0600 Subject: [PATCH 3/8] Missing reference to rating Was it moved by accident? --- resources/lib/itemtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index e2ad16c4..7c85db54 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -1948,6 +1948,7 @@ class Music(Items): track = disc*2**16 + tracknumber year = item.get('ProductionYear') duration = API.getRuntime() + rating = userdata['UserRating'] #if enabled, try to get the rating from file and/or emby if not self.directstream: @@ -1955,7 +1956,6 @@ class Music(Items): else: hasEmbeddedCover = False comment = API.getOverview() - rating = userdata['UserRating'] ##### GET THE FILE AND PATH ##### From 55d841b0b33aef5c163bc5266a673a8ea5ebb4d8 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 16:51:48 -0600 Subject: [PATCH 4/8] Temp removal of encoding in window prop Causing errors in report back, etc. Will have a look after the new version is released. --- resources/lib/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 11a059b3..7d9bc236 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -44,17 +44,17 @@ def window(property, value=None, clear=False, windowid=10000): 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 - if isinstance(property, unicode): + '''if isinstance(property, unicode): property = property.encode("utf-8") if isinstance(value, unicode): - value = value.encode("utf-8") + value = value.encode("utf-8")''' if clear: WINDOW.clearProperty(property) elif value is not None: WINDOW.setProperty(property, value) else: #getproperty returns string so convert to unicode - return WINDOW.getProperty(property).decode("utf-8") + return WINDOW.getProperty(property)#.decode("utf-8") def settings(setting, value=None): # Get or add addon setting From 1d6556fb44266de55a36e4aae26df2b1601b01a3 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 17:12:23 -0600 Subject: [PATCH 5/8] Add refresh for videonodes To fix home video nodes. --- resources/lib/entrypoint.py | 11 +++++++---- resources/lib/utils.py | 25 +++++++++++++++---------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 58053e1f..8654d36d 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -85,7 +85,7 @@ def doMainListing(): addDirectoryItem("Network credentials", "plugin://plugin.video.emby/?mode=passwords") addDirectoryItem("Settings", "plugin://plugin.video.emby/?mode=settings") addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser") - addDirectoryItem("Refresh Emby playlists", "plugin://plugin.video.emby/?mode=refreshplaylist") + addDirectoryItem("Refresh Emby playlists/nodes", "plugin://plugin.video.emby/?mode=refreshplaylist") addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync") addDirectoryItem("Repair local database (force update all content)", "plugin://plugin.video.emby/?mode=repair") addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset") @@ -382,19 +382,22 @@ def refreshPlaylist(): try: # First remove playlists utils.deletePlaylists() + # Remove video nodes + utils.deleteNodes() # Refresh views lib.refreshViews() dialog.notification( heading="Emby for Kodi", - message="Emby playlist refreshed", + message="Emby playlists/nodes refreshed", icon="special://home/addons/plugin.video.emby/icon.png", time=1000, sound=False) + except Exception as e: - utils.logMsg("EMBY", "Refresh playlist failed: %s" % e, 1) + utils.logMsg("EMBY", "Refresh playlists/nodes failed: %s" % e, 1) dialog.notification( heading="Emby for Kodi", - message="Emby playlist refresh failed", + message="Emby playlists/nodes refresh failed", icon=xbmcgui.NOTIFICATION_ERROR, time=1000, sound=False) diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 7d9bc236..7431c4a2 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -140,15 +140,7 @@ def reset(): deletePlaylists() # Clean up the video nodes - import shutil - path = xbmc.translatePath("special://profile/library/video/").decode('utf-8') - dirs, files = xbmcvfs.listdir(path) - for dir in dirs: - if dir.decode('utf-8').startswith('Emby'): - shutil.rmtree("%s%s" % (path, dir.decode('utf-8'))) - for file in files: - if file.decode('utf-8').startswith('emby'): - xbmcvfs.delete("%s%s" % (path, file.decode('utf-8'))) + deleteNodes() # Wipe the kodi databases logMsg("EMBY", "Resetting the Kodi video database.") @@ -502,4 +494,17 @@ def deletePlaylists(): dirs, files = xbmcvfs.listdir(path) for file in files: if file.decode('utf-8').startswith('Emby'): - xbmcvfs.delete("%s%s" % (path, file)) \ No newline at end of file + xbmcvfs.delete("%s%s" % (path, file)) + +def deleteNodes(): + + # Clean up video nodes + import shutil + path = xbmc.translatePath("special://profile/library/video/").decode('utf-8') + dirs, files = xbmcvfs.listdir(path) + for dir in dirs: + if dir.decode('utf-8').startswith('Emby'): + shutil.rmtree("%s%s" % (path, dir.decode('utf-8'))) + for file in files: + if file.decode('utf-8').startswith('emby'): + xbmcvfs.delete("%s%s" % (path, file.decode('utf-8'))) \ No newline at end of file From 7fd8a686b83cb4aaa5a33993f367b6395bd30d35 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Fri, 22 Jan 2016 17:13:45 -0600 Subject: [PATCH 6/8] Version bump 1.1.80 --- addon.xml | 2 +- changelog.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addon.xml b/addon.xml index 4948d7ab..b64d9107 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/changelog.txt b/changelog.txt index b8a87643..57c565c2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,8 @@ +version 1.1.80 +- Add refresh for video nodes +- Fix for home videos (being unable to back out of the menu). Running refresh playlists/nodes will fix this. +- Fix to music, causing sync to crash + version 1.1.76 - Add music rating system - Add home videos as a dynamic plugin entry (requires a reset) From 6653b1a929462056cdf231fef9d7fe39a926f952 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 23 Jan 2016 02:29:30 -0600 Subject: [PATCH 7/8] Move manual sync to own class It's better to separate the code to gain more control over the manual sync rather than working around the full sync and doing "if compare" all over the place. --- default.py | 2 +- resources/lib/librarysync.py | 856 +++++++++++++++++++++-------------- 2 files changed, 505 insertions(+), 353 deletions(-) diff --git a/default.py b/default.py index a3c461e7..9932d758 100644 --- a/default.py +++ b/default.py @@ -99,7 +99,7 @@ class Main: import librarysync lib = librarysync.LibrarySync() if mode == "manualsync": - lib.fullSync(manualrun=True) + librarysync.ManualSync() else: lib.fullSync(repair=True) else: diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index babe1985..b538016c 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -234,7 +234,7 @@ class LibrarySync(threading.Thread): } for itemtype in process: startTime = datetime.now() - completed = process[itemtype](embycursor, kodicursor, pDialog, compare=manualrun) + completed = process[itemtype](embycursor, kodicursor, pDialog) if not completed: utils.window('emby_dbScan', clear=True) @@ -262,7 +262,7 @@ class LibrarySync(threading.Thread): musiccursor = musicconn.cursor() startTime = datetime.now() - completed = self.music(embycursor, musiccursor, pDialog, compare=manualrun) + completed = self.music(embycursor, musiccursor, pDialog) if not completed: utils.window('emby_dbScan', clear=True) @@ -448,7 +448,7 @@ class LibrarySync(threading.Thread): # Save total utils.window('Emby.nodes.total', str(totalnodes)) - def movies(self, embycursor, kodicursor, pdialog, compare=False): + def movies(self, embycursor, kodicursor, pdialog): # Get movies from emby emby = self.emby emby_db = embydb.Embydb_Functions(embycursor) @@ -458,22 +458,6 @@ class LibrarySync(threading.Thread): views += emby_db.getView_byType('mixed') self.logMsg("Media folders: %s" % views, 1) - if compare: - # Pull the list of movies and boxsets in Kodi - try: - all_kodimovies = dict(emby_db.getChecksum('Movie')) - except ValueError: - all_kodimovies = {} - - try: - all_kodisets = dict(emby_db.getChecksum('BoxSet')) - except ValueError: - all_kodisets = {} - - all_embymoviesIds = set() - all_embyboxsetsIds = set() - updatelist = [] - ##### PROCESS MOVIES ##### for view in views: @@ -489,38 +473,10 @@ class LibrarySync(threading.Thread): heading="Emby for Kodi", message="Gathering movies from view: %s..." % viewName) - if compare: - # Manual sync - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing movies from view: %s..." % viewName) - - all_embymovies = emby.getMovies(viewId, basic=True, dialog=pdialog) - for embymovie in all_embymovies['Items']: - - if self.shouldStop(): - return False - - API = api.API(embymovie) - itemid = embymovie['Id'] - all_embymoviesIds.add(itemid) - - - if all_kodimovies.get(itemid) != API.getChecksum(): - # Only update if movie is not in Kodi or checksum is different - updatelist.append(itemid) - - self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1) - embymovies = emby.getFullItems(updatelist) - total = len(updatelist) - del updatelist[:] - else: - # Initial or repair sync - all_embymovies = emby.getMovies(viewId, dialog=pdialog) - total = all_embymovies['TotalRecordCount'] - embymovies = all_embymovies['Items'] - + # Initial or repair sync + all_embymovies = emby.getMovies(viewId, dialog=pdialog) + total = all_embymovies['TotalRecordCount'] + embymovies = all_embymovies['Items'] if pdialog: pdialog.update(heading="Processing %s / %s items" % (viewName, total)) @@ -546,38 +502,9 @@ class LibrarySync(threading.Thread): pdialog.update(heading="Emby for Kodi", message="Gathering boxsets from server...") boxsets = emby.getBoxset(dialog=pdialog) - - if compare: - # Manual sync - embyboxsets = [] - - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing boxsets...") - - for boxset in boxsets['Items']: - - if self.shouldStop(): - return False - - # Boxset has no real userdata, so using etag to compare - checksum = boxset['Etag'] - itemid = boxset['Id'] - all_embyboxsetsIds.add(itemid) - - if all_kodisets.get(itemid) != checksum: - # Only update if boxset is not in Kodi or checksum is different - updatelist.append(itemid) - embyboxsets.append(boxset) - - self.logMsg("Boxsets to update: %s" % updatelist, 1) - total = len(updatelist) - else: - total = boxsets['TotalRecordCount'] - embyboxsets = boxsets['Items'] + total = boxsets['TotalRecordCount'] + embyboxsets = boxsets['Items'] - if pdialog: pdialog.update(heading="Processing Boxsets / %s items" % total) @@ -596,25 +523,9 @@ class LibrarySync(threading.Thread): else: self.logMsg("Boxsets finished.", 2) - - ##### PROCESS DELETES ##### - if compare: - # Manual sync, process deletes - for kodimovie in all_kodimovies: - if kodimovie not in all_embymoviesIds: - movies.remove(kodimovie) - else: - self.logMsg("Movies compare finished.", 1) - - for boxset in all_kodisets: - if boxset not in all_embyboxsetsIds: - movies.remove(boxset) - else: - self.logMsg("Boxsets compare finished.", 1) - return True - def musicvideos(self, embycursor, kodicursor, pdialog, compare=False): + def musicvideos(self, embycursor, kodicursor, pdialog): # Get musicvideos from emby emby = self.emby emby_db = embydb.Embydb_Functions(embycursor) @@ -623,16 +534,6 @@ class LibrarySync(threading.Thread): views = emby_db.getView_byType('musicvideos') self.logMsg("Media folders: %s" % views, 1) - if compare: - # Pull the list of musicvideos in Kodi - try: - all_kodimvideos = dict(emby_db.getChecksum('MusicVideo')) - except ValueError: - all_kodimvideos = {} - - all_embymvideosIds = set() - updatelist = [] - for view in views: if self.shouldStop(): @@ -647,38 +548,10 @@ class LibrarySync(threading.Thread): heading="Emby for Kodi", message="Gathering musicvideos from view: %s..." % viewName) - if compare: - # Manual sync - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing musicvideos from view: %s..." % viewName) - - all_embymvideos = emby.getMusicVideos(viewId, basic=True, dialog=pdialog) - for embymvideo in all_embymvideos['Items']: - - if self.shouldStop(): - return False - - API = api.API(embymvideo) - itemid = embymvideo['Id'] - all_embymvideosIds.add(itemid) - - - if all_kodimvideos.get(itemid) != API.getChecksum(): - # Only update if musicvideo is not in Kodi or checksum is different - updatelist.append(itemid) - - self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1) - embymvideos = emby.getFullItems(updatelist) - total = len(updatelist) - del updatelist[:] - else: - # Initial or repair sync - all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog) - total = all_embymvideos['TotalRecordCount'] - embymvideos = all_embymvideos['Items'] - + # Initial or repair sync + all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog) + total = all_embymvideos['TotalRecordCount'] + embymvideos = all_embymvideos['Items'] if pdialog: pdialog.update(heading="Processing %s / %s items" % (viewName, total)) @@ -697,19 +570,10 @@ class LibrarySync(threading.Thread): mvideos.add_update(embymvideo, viewName, viewId) else: self.logMsg("MusicVideos finished.", 2) - - ##### PROCESS DELETES ##### - if compare: - # Manual sync, process deletes - for kodimvideo in all_kodimvideos: - if kodimvideo not in all_embymvideosIds: - mvideos.remove(kodimvideo) - else: - self.logMsg("MusicVideos compare finished.", 1) return True - def tvshows(self, embycursor, kodicursor, pdialog, compare=False): + def tvshows(self, embycursor, kodicursor, pdialog): # Get shows from emby emby = self.emby emby_db = embydb.Embydb_Functions(embycursor) @@ -719,23 +583,6 @@ class LibrarySync(threading.Thread): views += emby_db.getView_byType('mixed') self.logMsg("Media folders: %s" % views, 1) - if compare: - # Pull the list of movies and boxsets in Kodi - try: - all_koditvshows = dict(emby_db.getChecksum('Series')) - except ValueError: - all_koditvshows = {} - - try: - all_kodiepisodes = dict(emby_db.getChecksum('Episode')) - except ValueError: - all_kodiepisodes = {} - - all_embytvshowsIds = set() - all_embyepisodesIds = set() - updatelist = [] - - for view in views: if self.shouldStop(): @@ -750,37 +597,9 @@ class LibrarySync(threading.Thread): heading="Emby for Kodi", message="Gathering tvshows from view: %s..." % viewName) - if compare: - # Manual sync - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing tvshows from view: %s..." % viewName) - - all_embytvshows = emby.getShows(viewId, basic=True, dialog=pdialog) - for embytvshow in all_embytvshows['Items']: - - if self.shouldStop(): - return False - - API = api.API(embytvshow) - itemid = embytvshow['Id'] - all_embytvshowsIds.add(itemid) - - - if all_koditvshows.get(itemid) != API.getChecksum(): - # Only update if movie is not in Kodi or checksum is different - updatelist.append(itemid) - - self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1) - embytvshows = emby.getFullItems(updatelist) - total = len(updatelist) - del updatelist[:] - else: - all_embytvshows = emby.getShows(viewId, dialog=pdialog) - total = all_embytvshows['TotalRecordCount'] - embytvshows = all_embytvshows['Items'] - + all_embytvshows = emby.getShows(viewId, dialog=pdialog) + total = all_embytvshows['TotalRecordCount'] + embytvshows = all_embytvshows['Items'] if pdialog: pdialog.update(heading="Processing %s / %s items" % (viewName, total)) @@ -799,108 +618,29 @@ class LibrarySync(threading.Thread): count += 1 tvshows.add_update(embytvshow, viewName, viewId) - if not compare: - # Process episodes - all_episodes = emby.getEpisodesbyShow(itemid) - for episode in all_episodes['Items']: + # Process episodes + all_episodes = emby.getEpisodesbyShow(itemid) + for episode in all_episodes['Items']: - # Process individual show - if self.shouldStop(): - return False + # Process individual show + if self.shouldStop(): + return False - episodetitle = episode['Name'] - if pdialog: - pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) - tvshows.add_updateEpisode(episode) - else: - if compare: - # Get all episodes in view + episodetitle = episode['Name'] if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing episodes from view: %s..." % viewName) - - all_embyepisodes = emby.getEpisodes(viewId, basic=True, dialog=pdialog) - for embyepisode in all_embyepisodes['Items']: - - if self.shouldStop(): - return False - - API = api.API(embyepisode) - itemid = embyepisode['Id'] - all_embyepisodesIds.add(itemid) - - if all_kodiepisodes.get(itemid) != API.getChecksum(): - # Only update if movie is not in Kodi or checksum is different - updatelist.append(itemid) - - self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1) - embyepisodes = emby.getFullItems(updatelist) - total = len(updatelist) - del updatelist[:] - - count = 0 - for episode in embyepisodes: - - # Process individual episode - if self.shouldStop(): - return False - - title = episode['SeriesName'] - episodetitle = episode['Name'] - if pdialog: - percentage = int((float(count) / float(total))*100) - pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) - count += 1 - tvshows.add_updateEpisode(episode) + pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) + tvshows.add_updateEpisode(episode) else: self.logMsg("TVShows finished.", 2) - - ##### PROCESS DELETES ##### - if compare: - # Manual sync, process deletes - for koditvshow in all_koditvshows: - if koditvshow not in all_embytvshowsIds: - tvshows.remove(koditvshow) - else: - self.logMsg("TVShows compare finished.", 1) - - for kodiepisode in all_kodiepisodes: - if kodiepisode not in all_embyepisodesIds: - tvshows.remove(kodiepisode) - else: - self.logMsg("Episodes compare finished.", 1) return True - def music(self, embycursor, kodicursor, pdialog, compare=False): + def music(self, embycursor, kodicursor, pdialog): # Get music from emby emby = self.emby emby_db = embydb.Embydb_Functions(embycursor) music = itemtypes.Music(embycursor, kodicursor) - if compare: - # Pull the list of movies and boxsets in Kodi - try: - all_kodiartists = dict(emby_db.getChecksum('MusicArtist')) - except ValueError: - all_kodiartists = {} - - try: - all_kodialbums = dict(emby_db.getChecksum('MusicAlbum')) - except ValueError: - all_kodialbums = {} - - try: - all_kodisongs = dict(emby_db.getChecksum('Audio')) - except ValueError: - all_kodisongs = {} - - all_embyartistsIds = set() - all_embyalbumsIds = set() - all_embysongsIds = set() - updatelist = [] - process = { 'artists': [emby.getArtists, music.add_updateArtist], @@ -915,48 +655,9 @@ class LibrarySync(threading.Thread): heading="Emby for Kodi", message="Gathering %s..." % type) - if compare: - # Manual Sync - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Comparing %s..." % type) - - if type != "artists": - all_embyitems = process[type][0](basic=True, dialog=pdialog) - else: - all_embyitems = process[type][0](dialog=pdialog) - for embyitem in all_embyitems['Items']: - - if self.shouldStop(): - return False - - API = api.API(embyitem) - itemid = embyitem['Id'] - if type == "artists": - all_embyartistsIds.add(itemid) - if all_kodiartists.get(itemid) != API.getChecksum(): - # Only update if artist is not in Kodi or checksum is different - updatelist.append(itemid) - elif type == "albums": - all_embyalbumsIds.add(itemid) - if all_kodialbums.get(itemid) != API.getChecksum(): - # Only update if album is not in Kodi or checksum is different - updatelist.append(itemid) - else: - all_embysongsIds.add(itemid) - if all_kodisongs.get(itemid) != API.getChecksum(): - # Only update if songs is not in Kodi or checksum is different - updatelist.append(itemid) - - self.logMsg("%s to update: %s" % (type, updatelist), 1) - embyitems = emby.getFullItems(updatelist) - total = len(updatelist) - del updatelist[:] - else: - all_embyitems = process[type][0](dialog=pdialog) - total = all_embyitems['TotalRecordCount'] - embyitems = all_embyitems['Items'] + all_embyitems = process[type][0](dialog=pdialog) + total = all_embyitems['TotalRecordCount'] + embyitems = all_embyitems['Items'] if pdialog: pdialog.update(heading="Processing %s / %s items" % (type, total)) @@ -977,27 +678,6 @@ class LibrarySync(threading.Thread): else: self.logMsg("%s finished." % type, 2) - ##### PROCESS DELETES ##### - if compare: - # Manual sync, process deletes - for kodiartist in all_kodiartists: - if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None: - music.remove(kodiartist) - else: - self.logMsg("Artist compare finished.", 1) - - for kodialbum in all_kodialbums: - if kodialbum not in all_embyalbumsIds: - music.remove(kodialbum) - else: - self.logMsg("Albums compare finished.", 1) - - for kodisong in all_kodisongs: - if kodisong not in all_embysongsIds: - music.remove(kodisong) - else: - self.logMsg("Songs compare finished.", 1) - return True # Reserved for websocket_client.py and fast start @@ -1246,4 +926,476 @@ class LibrarySync(threading.Thread): def resumeThread(self): self.suspend_thread = False - self.logMsg("Resuming thread...", 0) \ No newline at end of file + self.logMsg("Resuming thread...", 0) + + +class ManualSync(LibrarySync): + + + def __init__(self): + + LibrarySync.__init__(self) + self.fullSync(manualrun=True) + + + def movies(self, embycursor, kodicursor, pdialog): + # Get movies from emby + emby = self.emby + emby_db = embydb.Embydb_Functions(embycursor) + movies = itemtypes.Movies(embycursor, kodicursor) + + views = emby_db.getView_byType('movies') + views += emby_db.getView_byType('mixed') + self.logMsg("Media folders: %s" % views, 1) + + # Pull the list of movies and boxsets in Kodi + try: + all_kodimovies = dict(emby_db.getChecksum('Movie')) + except ValueError: + all_kodimovies = {} + + try: + all_kodisets = dict(emby_db.getChecksum('BoxSet')) + except ValueError: + all_kodisets = {} + + all_embymoviesIds = set() + all_embyboxsetsIds = set() + updatelist = [] + + ##### PROCESS MOVIES ##### + for view in views: + + if self.shouldStop(): + return False + + # Get items per view + viewId = view['id'] + viewName = view['name'] + + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing movies from view: %s..." % viewName) + + all_embymovies = emby.getMovies(viewId, basic=True, dialog=pdialog) + for embymovie in all_embymovies['Items']: + + if self.shouldStop(): + return False + + API = api.API(embymovie) + itemid = embymovie['Id'] + all_embymoviesIds.add(itemid) + + + if all_kodimovies.get(itemid) != API.getChecksum(): + # Only update if movie is not in Kodi or checksum is different + updatelist.append(itemid) + + self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1) + embymovies = emby.getFullItems(updatelist) + total = len(updatelist) + del updatelist[:] + + if pdialog: + pdialog.update(heading="Processing %s / %s items" % (viewName, total)) + + count = 0 + for embymovie in embymovies: + # Process individual movies + if self.shouldStop(): + return False + + title = embymovie['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message=title) + count += 1 + movies.add_update(embymovie, viewName, viewId) + + ##### PROCESS BOXSETS ##### + + boxsets = emby.getBoxset(dialog=pdialog) + embyboxsets = [] + + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing boxsets...") + + for boxset in boxsets['Items']: + + if self.shouldStop(): + return False + + # Boxset has no real userdata, so using etag to compare + checksum = boxset['Etag'] + itemid = boxset['Id'] + all_embyboxsetsIds.add(itemid) + + if all_kodisets.get(itemid) != checksum: + # Only update if boxset is not in Kodi or checksum is different + updatelist.append(itemid) + embyboxsets.append(boxset) + + self.logMsg("Boxsets to update: %s" % updatelist, 1) + total = len(updatelist) + + if pdialog: + pdialog.update(heading="Processing Boxsets / %s items" % total) + + count = 0 + for boxset in embyboxsets: + # Process individual boxset + if self.shouldStop(): + return False + + title = boxset['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message=title) + count += 1 + movies.add_updateBoxset(boxset) + + ##### PROCESS DELETES ##### + + for kodimovie in all_kodimovies: + if kodimovie not in all_embymoviesIds: + movies.remove(kodimovie) + else: + self.logMsg("Movies compare finished.", 1) + + for boxset in all_kodisets: + if boxset not in all_embyboxsetsIds: + movies.remove(boxset) + else: + self.logMsg("Boxsets compare finished.", 1) + + return True + + def musicvideos(self, embycursor, kodicursor, pdialog): + # Get musicvideos from emby + emby = self.emby + emby_db = embydb.Embydb_Functions(embycursor) + mvideos = itemtypes.MusicVideos(embycursor, kodicursor) + + views = emby_db.getView_byType('musicvideos') + self.logMsg("Media folders: %s" % views, 1) + + # Pull the list of musicvideos in Kodi + try: + all_kodimvideos = dict(emby_db.getChecksum('MusicVideo')) + except ValueError: + all_kodimvideos = {} + + all_embymvideosIds = set() + updatelist = [] + + for view in views: + + if self.shouldStop(): + return False + + # Get items per view + viewId = view['id'] + viewName = view['name'] + + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing musicvideos from view: %s..." % viewName) + + all_embymvideos = emby.getMusicVideos(viewId, basic=True, dialog=pdialog) + for embymvideo in all_embymvideos['Items']: + + if self.shouldStop(): + return False + + API = api.API(embymvideo) + itemid = embymvideo['Id'] + all_embymvideosIds.add(itemid) + + + if all_kodimvideos.get(itemid) != API.getChecksum(): + # Only update if musicvideo is not in Kodi or checksum is different + updatelist.append(itemid) + + self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1) + embymvideos = emby.getFullItems(updatelist) + total = len(updatelist) + del updatelist[:] + + + if pdialog: + pdialog.update(heading="Processing %s / %s items" % (viewName, total)) + + count = 0 + for embymvideo in embymvideos: + # Process individual musicvideo + if self.shouldStop(): + return False + + title = embymvideo['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message=title) + count += 1 + mvideos.add_update(embymvideo, viewName, viewId) + + ##### PROCESS DELETES ##### + + for kodimvideo in all_kodimvideos: + if kodimvideo not in all_embymvideosIds: + mvideos.remove(kodimvideo) + else: + self.logMsg("MusicVideos compare finished.", 1) + + return True + + def tvshows(self, embycursor, kodicursor, pdialog): + # Get shows from emby + emby = self.emby + emby_db = embydb.Embydb_Functions(embycursor) + tvshows = itemtypes.TVShows(embycursor, kodicursor) + + views = emby_db.getView_byType('tvshows') + views += emby_db.getView_byType('mixed') + self.logMsg("Media folders: %s" % views, 1) + + # Pull the list of tvshows and episodes in Kodi + try: + all_koditvshows = dict(emby_db.getChecksum('Series')) + except ValueError: + all_koditvshows = {} + + try: + all_kodiepisodes = dict(emby_db.getChecksum('Episode')) + except ValueError: + all_kodiepisodes = {} + + all_embytvshowsIds = set() + all_embyepisodesIds = set() + updatelist = [] + + + for view in views: + + if self.shouldStop(): + return False + + # Get items per view + viewId = view['id'] + viewName = view['name'] + + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing tvshows from view: %s..." % viewName) + + all_embytvshows = emby.getShows(viewId, basic=True, dialog=pdialog) + for embytvshow in all_embytvshows['Items']: + + if self.shouldStop(): + return False + + API = api.API(embytvshow) + itemid = embytvshow['Id'] + all_embytvshowsIds.add(itemid) + + + if all_koditvshows.get(itemid) != API.getChecksum(): + # Only update if movie is not in Kodi or checksum is different + updatelist.append(itemid) + + self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1) + embytvshows = emby.getFullItems(updatelist) + total = len(updatelist) + del updatelist[:] + + + if pdialog: + pdialog.update(heading="Processing %s / %s items" % (viewName, total)) + + count = 0 + for embytvshow in embytvshows: + # Process individual show + if self.shouldStop(): + return False + + itemid = embytvshow['Id'] + title = embytvshow['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message=title) + count += 1 + tvshows.add_update(embytvshow, viewName, viewId) + + else: + # Get all episodes in view + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing episodes from view: %s..." % viewName) + + all_embyepisodes = emby.getEpisodes(viewId, basic=True, dialog=pdialog) + for embyepisode in all_embyepisodes['Items']: + + if self.shouldStop(): + return False + + API = api.API(embyepisode) + itemid = embyepisode['Id'] + all_embyepisodesIds.add(itemid) + + if all_kodiepisodes.get(itemid) != API.getChecksum(): + # Only update if movie is not in Kodi or checksum is different + updatelist.append(itemid) + + self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1) + embyepisodes = emby.getFullItems(updatelist) + total = len(updatelist) + del updatelist[:] + + count = 0 + for episode in embyepisodes: + + # Process individual episode + if self.shouldStop(): + return False + + title = episode['SeriesName'] + episodetitle = episode['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) + count += 1 + tvshows.add_updateEpisode(episode) + + ##### PROCESS DELETES ##### + + for koditvshow in all_koditvshows: + if koditvshow not in all_embytvshowsIds: + tvshows.remove(koditvshow) + else: + self.logMsg("TVShows compare finished.", 1) + + for kodiepisode in all_kodiepisodes: + if kodiepisode not in all_embyepisodesIds: + tvshows.remove(kodiepisode) + else: + self.logMsg("Episodes compare finished.", 1) + + return True + + def music(self, embycursor, kodicursor, pdialog): + # Get music from emby + emby = self.emby + emby_db = embydb.Embydb_Functions(embycursor) + music = itemtypes.Music(embycursor, kodicursor) + + # Pull the list of artists, albums, songs + try: + all_kodiartists = dict(emby_db.getChecksum('MusicArtist')) + except ValueError: + all_kodiartists = {} + + try: + all_kodialbums = dict(emby_db.getChecksum('MusicAlbum')) + except ValueError: + all_kodialbums = {} + + try: + all_kodisongs = dict(emby_db.getChecksum('Audio')) + except ValueError: + all_kodisongs = {} + + all_embyartistsIds = set() + all_embyalbumsIds = set() + all_embysongsIds = set() + updatelist = [] + + process = { + + 'artists': [emby.getArtists, music.add_updateArtist], + 'albums': [emby.getAlbums, music.add_updateAlbum], + 'songs': [emby.getSongs, music.add_updateSong] + } + types = ['artists', 'albums', 'songs'] + for type in types: + + if pdialog: + pdialog.update( + heading="Emby for Kodi", + message="Comparing %s..." % type) + + if type != "artists": + all_embyitems = process[type][0](basic=True, dialog=pdialog) + else: + all_embyitems = process[type][0](dialog=pdialog) + for embyitem in all_embyitems['Items']: + + if self.shouldStop(): + return False + + API = api.API(embyitem) + itemid = embyitem['Id'] + if type == "artists": + all_embyartistsIds.add(itemid) + if all_kodiartists.get(itemid) != API.getChecksum(): + # Only update if artist is not in Kodi or checksum is different + updatelist.append(itemid) + elif type == "albums": + all_embyalbumsIds.add(itemid) + if all_kodialbums.get(itemid) != API.getChecksum(): + # Only update if album is not in Kodi or checksum is different + updatelist.append(itemid) + else: + all_embysongsIds.add(itemid) + if all_kodisongs.get(itemid) != API.getChecksum(): + # Only update if songs is not in Kodi or checksum is different + updatelist.append(itemid) + + self.logMsg("%s to update: %s" % (type, updatelist), 1) + embyitems = emby.getFullItems(updatelist) + total = len(updatelist) + del updatelist[:] + + if pdialog: + pdialog.update(heading="Processing %s / %s items" % (type, total)) + + count = 0 + for embyitem in embyitems: + # Process individual item + if self.shouldStop(): + return False + + title = embyitem['Name'] + if pdialog: + percentage = int((float(count) / float(total))*100) + pdialog.update(percentage, message=title) + count += 1 + + process[type][1](embyitem) + + ##### PROCESS DELETES ##### + + for kodiartist in all_kodiartists: + if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None: + music.remove(kodiartist) + else: + self.logMsg("Artist compare finished.", 1) + + for kodialbum in all_kodialbums: + if kodialbum not in all_embyalbumsIds: + music.remove(kodialbum) + else: + self.logMsg("Albums compare finished.", 1) + + for kodisong in all_kodisongs: + if kodisong not in all_embysongsIds: + music.remove(kodisong) + else: + self.logMsg("Songs compare finished.", 1) + + return True \ No newline at end of file From 049c304f8b923e3177a00377e80668b9dd8711fc Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 23 Jan 2016 02:32:51 -0600 Subject: [PATCH 8/8] Clear property So artwork can be deleted when needed, after the initial sync has completed --- resources/lib/librarysync.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index b538016c..ae1fcd1b 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -293,6 +293,7 @@ class LibrarySync(threading.Thread): elapsedtotal = datetime.now() - starttotal utils.window('emby_dbScan', clear=True) + utils.window('emby_initialScan', clear=True) xbmcgui.Dialog().notification( heading="Emby for Kodi", message="%s completed in: %s" % @@ -927,7 +928,7 @@ class LibrarySync(threading.Thread): def resumeThread(self): self.suspend_thread = False self.logMsg("Resuming thread...", 0) - + class ManualSync(LibrarySync):