From 380b934316fc4527a529928924e6bd06318eaff3 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Wed, 18 Mar 2015 18:00:38 +0100 Subject: [PATCH] first attempt to get incremental sync for episodes --- resources/lib/LibrarySync.py | 207 ++++++++++++++++++++++++++++++++++- resources/lib/ReadEmbyDB.py | 41 ++++++- resources/lib/ReadKodiDB.py | 35 ++++++ 3 files changed, 273 insertions(+), 10 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 24808990..c866c4a3 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -41,7 +41,6 @@ class LibrarySync(): def syncDatabase(self): WINDOW = xbmcgui.Window( 10000 ) - WINDOW.setProperty("librarysync", "busy") pDialog = None #set some variable to check if this is the first run @@ -59,8 +58,10 @@ class LibrarySync(): #what sync method to perform ? if syncOption == "Full Sync": self.MoviesSync(True) + self.TvShowsSync(True) if syncOption == "Incremental Sync": self.MoviesSync(False) + self.TvShowsSync(False) WINDOW.setProperty("startup", "done") @@ -70,7 +71,6 @@ class LibrarySync(): WINDOW = xbmcgui.Window( 10000 ) - WINDOW.setProperty("librarysync", "busy") pDialog = None try: @@ -194,11 +194,210 @@ class LibrarySync(): return True finally: - WINDOW.clearProperty("librarysync") if(pDialog != None): pDialog.close() return True + + def TvShowsSync(self, fullsync=True): + + WINDOW = xbmcgui.Window( 10000 ) + pDialog = None + + try: + + if(addon.getSetting("enableProgressFullSync")): + pDialog = xbmcgui.DialogProgressBG() + if(pDialog != None): + pDialog.create('Sync DB', 'Sync DB') + + + # incremental sync --> new episodes only + if not fullsync: + latestMBEpisodes = ReadEmbyDB().getTVShows(True,True) + allKodiTvShowsIds = set(ReadKodiDB().getKodiTvShowsIds()) + + for tvshow in latestMBEpisodes: + + if tvshow["ParentId"] in allKodiTvShowsIds: + #only process tvshows that already exist in the db at incremental updates + + kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow["ParentId"]) + + if(self.ShouldStop()): + return True + + if(pDialog != None): + pDialog.update(0, "Sync DB : Processing Episodes") + total = len(episodeData) + 1 + count = 0 + + #we have to compare the lists somehow + xbmc.sleep(sleepVal) + comparestring1 = str(tvshow.get("ParentIndexNumber")) + "-" + str(tvshow.get("IndexNumber")) + matchFound = False + progMessage = "Processing" + if kodiEpisodes != None: + for KodiItem in kodiEpisodes: + + allEpisodes.append(KodiItem["episodeid"]) + comparestring2 = str(KodiItem["season"]) + "-" + str(KodiItem["episode"]) + if comparestring1 == comparestring2: + #match found - update episode + WriteKodiDB().updateEpisodeToKodiLibrary(tvshow,KodiItem,tvshow) + matchFound = True + progMessage = "Updating" + + if not matchFound: + #no match so we have to create it + print "episode not found...creating it: " + WriteKodiDB().addEpisodeToKodiLibrary(tvshow,tvshow) + updateNeeded = True + progMessage = "Adding" + + if(self.ShouldStop()): + return True + + # update progress bar + if(pDialog != None): + percentage = int(((float(count) / float(total)) * 100)) + pDialog.update(percentage, message=progMessage + " Episode: " + str(count)) + count += 1 + + # full sync --> Tv shows and Episodes + if fullsync: + allTVShows = list() + allEpisodes = list() + #FIXME --> for now pull all tv shows and use the incremental update only at episode level + tvShowData = ReadEmbyDB().getTVShows(True,True) + + if(self.ShouldStop()): + return True + + if (tvShowData == None): + return + + if(pDialog != None): + pDialog.update(0, "Sync DB : Processing TV Shows") + total = len(tvShowData) + 1 + count = 0 + + for item in tvShowData: + xbmc.sleep(sleepVal) + if item.get('IsFolder'): + kodiItem = ReadKodiDB().getKodiTVShow(item["Id"]) + allTVShows.append(item["Id"]) + progMessage = "Processing" + if kodiItem == None: + WriteKodiDB().addTVShowToKodiLibrary(item) + updateNeeded = True + progMessage = "Adding" + else: + WriteKodiDB().updateTVShowToKodiLibrary(item, kodiItem) + progMessage = "Updating" + + if(self.ShouldStop()): + return True + + # update progress bar + if(pDialog != None): + percentage = int(((float(count) / float(total)) * 100)) + pDialog.update(percentage, message=progMessage + " Tv Show: " + str(count)) + count += 1 + + #initiate library update and wait for finish before processing any updates + if updateNeeded: + self.doKodiLibraryUpdate() + updateNeeded = False + + #process episodes (will only be possible when tv show is scanned to library) + #TODO --> maybe pull full info only when needed ? + allEpisodes = list() + + for tvshow in allTVShows: + + episodeData = ReadEmbyDB().getEpisodes(tvshow,True) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow) + + if(self.ShouldStop()): + return True + + if(pDialog != None): + pDialog.update(0, "Sync DB : Processing Episodes") + total = len(episodeData) + 1 + count = 0 + + #we have to compare the lists somehow + for item in episodeData: + xbmc.sleep(sleepVal) + comparestring1 = str(item.get("ParentIndexNumber")) + "-" + str(item.get("IndexNumber")) + matchFound = False + progMessage = "Processing" + if kodiEpisodes != None: + for KodiItem in kodiEpisodes: + + allEpisodes.append(KodiItem["episodeid"]) + comparestring2 = str(KodiItem["season"]) + "-" + str(KodiItem["episode"]) + if comparestring1 == comparestring2: + #match found - update episode + WriteKodiDB().updateEpisodeToKodiLibrary(item,KodiItem,tvshow) + matchFound = True + progMessage = "Updating" + + if not matchFound: + #no match so we have to create it + print "episode not found...creating it: " + WriteKodiDB().addEpisodeToKodiLibrary(item,tvshow) + updateNeeded = True + progMessage = "Adding" + + if(self.ShouldStop()): + return True + + # update progress bar + if(pDialog != None): + percentage = int(((float(count) / float(total)) * 100)) + pDialog.update(percentage, message=progMessage + " Episode: " + str(count)) + count += 1 + + #initiate library update and wait for finish before processing any updates + if updateNeeded: + self.doKodiLibraryUpdate() + + if(pDialog != None): + pDialog.update(0, message="Removing Deleted Items") + + if(self.ShouldStop()): + return True + + cleanNeeded = False + + # process any deletes only at fullsync + # TODO --> process deletes for episodes !!! + if fullsync: + allLocaldirs, filesTVShows = xbmcvfs.listdir(tvLibrary) + allMB3TVShows = set(allTVShows) + for dir in allLocaldirs: + if not dir in allMB3TVShows: + WriteKodiDB().deleteTVShowFromKodiLibrary(dir) + cleanneeded = True + + if(self.ShouldStop()): + return True + + #initiate library clean and wait for finish before processing any updates + if cleanNeeded: + doKodiLibraryUpdate(True) + + if(self.ShouldStop()): + return True + + finally: + if(pDialog != None): + pDialog.close() + + return True + def doKodiLibraryUpdate(self,clean=False): #initiate library update and wait for finish before processing any updates @@ -216,7 +415,6 @@ class LibrarySync(): #update all playcounts from MB3 to Kodi library WINDOW = xbmcgui.Window( 10000 ) - WINDOW.setProperty("librarysync", "busy") pDialog = None try: @@ -311,7 +509,6 @@ class LibrarySync(): count += 1 finally: - WINDOW.clearProperty("librarysync") if(pDialog != None): pDialog.close() diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index 6a4eb6cf..311af485 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -41,7 +41,7 @@ class ReadEmbyDB(): return result - def getTVShows(self, fullinfo = False): + def getTVShows(self, fullinfo = False, fullSync = False): result = None addon = xbmcaddon.Addon(id='plugin.video.mb3sync') @@ -50,12 +50,18 @@ class ReadEmbyDB(): server = host + ":" + port downloadUtils = DownloadUtils() - userid = downloadUtils.getUserId() + userid = downloadUtils.getUserId() + + if not fullSync: + sortstring = "&Limit=20&SortBy=DateCreated" + else: + sortstring = "&SortBy=SortName" + if fullinfo: - url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1' + url = server + '/mediabrowser/Users/' + userid + '/Items?' + sortstring + '&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1' else: - url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1' + url = server + '/mediabrowser/Users/' + userid + '/Items?' + sortstring + '&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1' jsonData = downloadUtils.downloadUrl(url, suppress=True, popup=0) if jsonData != None and jsonData != "": @@ -64,7 +70,7 @@ class ReadEmbyDB(): result = result['Items'] return result - + def getEpisodes(self, showId, fullinfo = False): result = None @@ -89,6 +95,31 @@ class ReadEmbyDB(): result = result['Items'] return result + def getLatestEpisodes(self,fullinfo = False): + result = None + + addon = xbmcaddon.Addon(id='plugin.video.mb3sync') + port = addon.getSetting('port') + host = addon.getSetting('ipaddress') + server = host + ":" + port + + downloadUtils = DownloadUtils() + userid = downloadUtils.getUserId() + + if fullinfo: + url = server + '/mediabrowser/Users/' + userid + '/Items?Limit=20&SortBy=DateCreated&IsVirtualUnaired=false&IsMissing=False&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1' + else: + url = server + '/mediabrowser/Users/' + userid + '/Items?Limit=20&SortBy=DateCreated&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1' + + jsonData = downloadUtils.downloadUrl(url, suppress=True, popup=0) + + if jsonData != None and jsonData != "": + result = json.loads(jsonData) + if(result.has_key('Items')): + result = result['Items'] + return result + + def getCollections(self, type): #Build a list of the user views userid = DownloadUtils().getUserId() diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index f46720c0..83211b01 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -65,8 +65,43 @@ class ReadKodiDB(): return allKodiMovieIds + def getKodiTvShowsIds(self,returnMB3Ids = False): + # returns a list of tvshowIds or MB3 Id's from all tvshows currently in the Kodi library + allKodiTvShows = self.getKodiTvShows(False) + allKodiTvShowsIds = list() + + if allKodiTvShows != None: + for kodishow in allKodiTvShows: + if returnMB3Ids: + filepath = kodishow["file"] + filepath = filepath.replace(tvLibrary + os.sep, "") + filepath = filepath.replace(".strm", "") + filepath = filepath.split(os.sep)[0] + id = filepath + else: + id = str(kodimovie["movieid"]) + allKodiTvShowsIds.append(id) + + return allKodiTvShowsIds + + def getKodiTvShows(self,fullInfo = False): + #returns all tvshows in Kodi db inserted by MB + if fullInfo: + json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "filter": {"operator": "contains", "field": "path", "value": "plugin.video.mb3sync"}, "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "premiered", "rating", "thumbnail", "playcount", "file", "fanart"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') + else: + json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "filter": {"operator": "contains", "field": "path", "value": "plugin.video.mb3sync"}, "properties": ["sorttitle", "title", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') + jsonobject = json.loads(json_response.decode('utf-8','replace')) + tvshows = None + + if(jsonobject.has_key('result')): + result = jsonobject['result'] + if(result.has_key('tvshows')): + movies = result['tvshows'] + + return tvshows + def getKodiTVShow(self, id): json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "filter": {"operator": "contains", "field": "path", "value": "' + id + '"}, "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "premiered", "rating", "thumbnail", "playcount", "file", "fanart"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') jsonobject = json.loads(json_response.decode('utf-8','replace'))