From 09e62d570cabcf19f68adc98bb571a16b105a8e8 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 20 Mar 2015 20:26:37 +0100 Subject: [PATCH] support for episode deletions --- resources/lib/CreateFiles.py | 2 ++ resources/lib/KodiMonitor.py | 12 +++--------- resources/lib/LibrarySync.py | 33 +++++++++++++++++++++++++-------- resources/lib/ReadKodiDB.py | 25 +++++++++++++------------ resources/lib/WriteKodiDB.py | 20 ++++++++++++++++++++ 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/resources/lib/CreateFiles.py b/resources/lib/CreateFiles.py index 96110f77..e6f21227 100644 --- a/resources/lib/CreateFiles.py +++ b/resources/lib/CreateFiles.py @@ -108,6 +108,8 @@ class CreateFiles(): xbmcvfs.mkdir(itemPath) root = Element(rootelement) SubElement(root, "id").text = item["Id"] + SubElement(root, "uniqueid").text = item["Id"] + if item.get("Tag") != None: for tag in item.get("Tag"): SubElement(root, "tag").text = tag diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 74af9610..66810370 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -20,15 +20,9 @@ class Kodi_Monitor(xbmc.Monitor): #this library monitor is used to detect a watchedstate change by the user through the library def onNotification (self,sender,method,data): + if method == "VideoLibrary.OnUpdate": - - #check windowprop if the sync is busy to prevent any false updates - #WINDOW = xbmcgui.Window( 10000 ) - #if WINDOW.getProperty("librarysync") != "busy": - # I don't thing we need this, the playcount is not present in updates that don't touch that - # and when the playcount is updated byt he sync it just sends the same data back to the server - # if you add this back in you will never be able to trigger a play status update while the sync is running - + jsondata = json.loads(data) if jsondata != None: @@ -37,6 +31,6 @@ class Kodi_Monitor(xbmc.Monitor): item = jsondata.get("item").get("id") type = jsondata.get("item").get("type") if playcount != None: - xbmc.log("Kodi_Monitor -> onNotification -> VideoLibrary.OnUpdate : " + str(data)) + utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2) WriteKodiDB().updatePlayCountFromKodi(item, type, playcount) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 792b2837..edec389a 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -251,7 +251,7 @@ class LibrarySync(): for episode in latestMBEpisodes: if episode["SeriesId"] in allKodiTvShowsIds: #only process tvshows that already exist in the db at incremental updates - kodiEpisodes = ReadKodiDB().getKodiEpisodes(episode["SeriesId"]) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(episode["SeriesId"],True,True) if(self.ShouldStop(pDialog)): return True @@ -295,7 +295,7 @@ class LibrarySync(): for episode in latestMBEpisodes: if episode["SeriesId"] in allKodiTvShowsIds: #only process tvshows that already exist in the db at incremental updates - kodiEpisodes = ReadKodiDB().getKodiEpisodes(episode["SeriesId"]) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(episode["SeriesId"],True,True) if(self.ShouldStop(pDialog)): return True @@ -321,8 +321,9 @@ class LibrarySync(): # 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 + allMB3EpisodeIds = list() #for use with deletions + allKodiEpisodeIds = [] # for use with deletions + tvShowData = ReadEmbyDB().getTVShows(True,True) allKodiIds = set(ReadKodiDB().getKodiTvShowsIds(True)) updateNeeded = False @@ -366,7 +367,7 @@ class LibrarySync(): for tvshow in allTVShows: episodeData = ReadEmbyDB().getEpisodes(tvshow,True) - kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow,True,True) if(self.ShouldStop(pDialog)): return True @@ -458,7 +459,7 @@ class LibrarySync(): for tvshow in allTVShows: episodeData = ReadEmbyDB().getEpisodes(tvshow,True) - kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(tvshow,True,True) if(self.ShouldStop(pDialog)): return True @@ -471,6 +472,10 @@ class LibrarySync(): #we have to compare the lists somehow for item in episodeData: + + #add episodeId to the list of all episodes for use later on the deletes + allMB3EpisodeIds.append(item["Id"]) + comparestring1 = str(item.get("ParentIndexNumber")) + "-" + str(item.get("IndexNumber")) matchFound = False if kodiEpisodes != None: @@ -486,7 +491,14 @@ class LibrarySync(): percentage = int(((float(count) / float(total)) * 100)) pDialog.update(percentage, progressTitle, "Updating Episode: " + str(count)) count += 1 - + + + #add all kodi episodes to a list with episodes for use later on to delete episodes + #the mediabrowser ID is set as uniqueID in the NFO... for some reason this has key 'unknown' in the json response + for episode in ReadKodiDB().getKodiEpisodes(tvshow,False,False): + dict = {'mbid': str(episode["uniqueid"]["unknown"]),'kodiid': str(episode["episodeid"])} + allKodiEpisodeIds.append(dict) + showCurrent += 1 if(pDialog != None): @@ -499,6 +511,11 @@ class LibrarySync(): cleanNeeded = False # process any deletes only at fullsync + allMB3EpisodeIds = set(allMB3EpisodeIds) + for episode in allKodiEpisodeIds: + if episode.get('mbid') not in allMB3EpisodeIds: + WriteKodiDB().deleteEpisodeFromKodiLibrary(episode.get('kodiid')) + # TODO --> process deletes for episodes !!! if fullsync: allLocaldirs, filesTVShows = xbmcvfs.listdir(tvLibrary) @@ -631,7 +648,7 @@ class LibrarySync(): for item in tvshowData: episodeData = ReadEmbyDB().getEpisodes(item["Id"], False) - kodiEpisodes = ReadKodiDB().getKodiEpisodes(item["Id"],False) + kodiEpisodes = ReadKodiDB().getKodiEpisodes(item["Id"],False,True) if (episodeData != None): if(pDialog != None): diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index 0c49d908..c4b59a30 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -134,7 +134,7 @@ class ReadKodiDB(): tvshow = tvshows[0] return tvshow - def getKodiEpisodes(self, id, fullInfo = True): + def getKodiEpisodes(self, id, fullInfo = True, returnmap = True): xbmc.sleep(sleepVal) episodes = None json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "filter": {"operator": "contains", "field": "path", "value": "' + id + '"}, "properties": ["title", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') @@ -146,24 +146,25 @@ class ReadKodiDB(): tvshows = result['tvshows'] tvshow = tvshows[0] if fullInfo: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "plot", "season", "episode", "showtitle", "file", "lastplayed", "rating", "resume", "art", "streamdetails", "firstaired", "runtime", "writer", "cast", "dateadded"], "sort": {"method": "episode"}}, "id": 1}' %tvshow['tvshowid']) + json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "plot", "season", "episode", "showtitle", "file", "lastplayed", "rating", "resume", "art", "streamdetails", "firstaired", "runtime", "writer", "cast", "dateadded","uniqueid"], "sort": {"method": "episode"}}, "id": 1}' %tvshow['tvshowid']) else: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "season", "episode", "lastplayed", "resume"], "sort": {"method": "episode"}}, "id": 1}' %tvshow['tvshowid']) + json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "season", "episode", "lastplayed", "resume","file","uniqueid"], "sort": {"method": "episode"}}, "id": 1}' %tvshow['tvshowid']) jsonobject = json.loads(json_response.decode('utf-8','replace')) episodes = None if(jsonobject.has_key('result')): result = jsonobject['result'] if(result.has_key('episodes')): episodes = result['episodes'] - - episodeMap = None - if(episodes != None): - episodeMap = {} - for KodiItem in episodes: - key = str(KodiItem["season"]) + "-" + str(KodiItem["episode"]) - episodeMap[key] = KodiItem - - return episodeMap + if returnmap: + episodeMap = None + if(episodes != None): + episodeMap = {} + for KodiItem in episodes: + key = str(KodiItem["season"]) + "-" + str(KodiItem["episode"]) + episodeMap[key] = KodiItem + return episodeMap + else: + return episodes def getKodiEpisodeByMbItem(self, MBitem): xbmc.sleep(sleepVal) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 4b2bd50f..a115286e 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -419,7 +419,27 @@ class WriteKodiDB(): path = os.path.join(movieLibrary,id) xbmcvfs.rmdir(path) + + def deleteEpisodeFromKodiLibrary(self, episodeid ): + utils.logMsg("deleting movie from Kodi library",id) + json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": { "episodeid": %i}, "properties" : ["file","episodeid"] }, "id": "libTvShows"}' %(int(episodeid))) + jsonobject = json.loads(json_response.decode('utf-8','replace')) + + print jsonobject + if(jsonobject.has_key('result')): + result = jsonobject['result'] + if(result.has_key('episodedetails')): + episodedetails = result['episodedetails'] + + strmfile = episodedetails["file"] + nfofile = strmfile.replace(".strm",".nfo") + + xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveEpisode", "params": { "episodeid": %i}, "id": 1 }' %(int(episodeid))) + + xbmcvfs.delete(strmfile) + xbmcvfs.delete(nfofile) + def addTVShowToKodiLibrary( self, item ): itemPath = os.path.join(tvLibrary,item["Id"])