# -*- coding: utf-8 -*- ################################################################################################## import logging import urllib from ntpath import dirname import api import common import embydb_functions as embydb import kodidb_functions as kodidb from utils import window, settings, language as lang, catch_except ################################################################################################## log = logging.getLogger("EMBY."+__name__) ################################################################################################## class TVShows(common.Items): def __init__(self, embycursor, kodicursor, pdialog=None): self.embycursor = embycursor self.emby_db = embydb.Embydb_Functions(self.embycursor) self.kodicursor = kodicursor self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor) self.pdialog = pdialog self.new_time = int(settings('newvideotime'))*1000 common.Items.__init__(self) def _get_func(self, item_type, action): if item_type == "Series": actions = { 'added': self.added, 'update': self.add_update, 'userdata': self.updateUserdata, 'remove': self.remove } elif item_type == "Season": actions = { 'added': self.added_season, 'update': self.add_updateSeason, 'remove': self.remove } elif item_type == "Episode": actions = { 'added': self.added_episode, 'update': self.add_updateEpisode, 'userdata': self.updateUserdata, 'remove': self.remove } else: log.info("Unsupported item_type: %s", item_type) actions = {} return actions.get(action) def compare_all(self): # Pull the list of movies and boxsets in Kodi pdialog = self.pdialog views = self.emby_db.getView_byType('tvshows') views += self.emby_db.getView_byType('mixed') log.info("Media folders: %s", views) # Pull the list of tvshows and episodes in Kodi try: all_koditvshows = dict(self.emby_db.get_checksum('Series')) except ValueError: all_koditvshows = {} log.info("all_koditvshows = %s", all_koditvshows) try: all_kodiepisodes = dict(self.emby_db.get_checksum('Episode')) except ValueError: all_kodiepisodes = {} all_embytvshowsIds = set() all_embyepisodesIds = set() updatelist = [] for view in views: if self.should_stop(): return False # Get items per view viewId = view['id'] viewName = view['name'] if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33029), viewName)) all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog) for embytvshow in all_embytvshows['Items']: if self.should_stop(): return False API = api.API(embytvshow) itemid = embytvshow['Id'] all_embytvshowsIds.add(itemid) if all_koditvshows.get(itemid) != API.get_checksum(): # Only update if movie is not in Kodi or checksum is different updatelist.append(itemid) log.info("TVShows to update for %s: %s", viewName, updatelist) embytvshows = self.emby.getFullItems(updatelist) self.total = len(updatelist) del updatelist[:] if pdialog: pdialog.update(heading="Processing %s / %s items" % (viewName, self.total)) self.count = 0 for embytvshow in embytvshows: # Process individual show if self.should_stop(): return False itemid = embytvshow['Id'] title = embytvshow['Name'] all_embytvshowsIds.add(itemid) self.update_pdialog() self.add_update(embytvshow, view) self.count += 1 else: # Get all episodes in view if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33030), viewName)) all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog) for embyepisode in all_embyepisodes['Items']: if self.should_stop(): return False API = api.API(embyepisode) itemid = embyepisode['Id'] all_embyepisodesIds.add(itemid) if "SeriesId" in embyepisode: all_embytvshowsIds.add(embyepisode['SeriesId']) if all_kodiepisodes.get(itemid) != API.get_checksum(): # Only update if movie is not in Kodi or checksum is different updatelist.append(itemid) log.info("Episodes to update for %s: %s", viewName, updatelist) embyepisodes = self.emby.getFullItems(updatelist) self.total = len(updatelist) del updatelist[:] self.count = 0 for episode in embyepisodes: # Process individual episode if self.should_stop(): return False self.title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name']) self.add_updateEpisode(episode) self.count += 1 ##### PROCESS DELETES ##### log.info("all_embytvshowsIds = %s ", all_embytvshowsIds) for koditvshow in all_koditvshows: if koditvshow not in all_embytvshowsIds: self.remove(koditvshow) log.info("TVShows compare finished.") for kodiepisode in all_kodiepisodes: if kodiepisode not in all_embyepisodesIds: self.remove(kodiepisode) log.info("Episodes compare finished.") return True def added(self, items, total=None, view=None): for item in super(TVShows, self).added(items, total): if self.add_update(item, view): # Add episodes all_episodes = self.emby.getEpisodesbyShow(item['Id']) self.added_episode(all_episodes['Items']) def added_season(self, items, total=None, view=None): update = True if not self.total else False for item in super(TVShows, self).added(items, total, update): self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title) if self.add_updateSeason(item): # Add episodes all_episodes = self.emby.getEpisodesbySeason(item['Id']) self.added_episode(all_episodes['Items']) def added_episode(self, items, total=None, view=None): update = True if not self.total else False for item in super(TVShows, self).added(items, total, update): self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title) if self.add_updateEpisode(item): self.content_pop(self.title) @catch_except() def add_update(self, item, view=None): # Process single tvshow kodicursor = self.kodicursor emby = self.emby emby_db = self.emby_db artwork = self.artwork API = api.API(item) if settings('syncEmptyShows') == "false" and not item.get('RecursiveItemCount'): log.info("Skipping empty show: %s", item['Name']) return # If the item already exist in the local Kodi DB we'll perform a full item update # If the item doesn't exist, we'll add it to the database update_item = True force_episodes = False itemid = item['Id'] emby_dbitem = emby_db.getItem_byId(itemid) try: showid = emby_dbitem[0] pathid = emby_dbitem[2] log.info("showid: %s pathid: %s", showid, pathid) except TypeError: update_item = False log.debug("showid: %s not found", itemid) kodicursor.execute("select coalesce(max(idShow),0) from tvshow") showid = kodicursor.fetchone()[0] + 1 else: # Verification the item is still in Kodi query = "SELECT * FROM tvshow WHERE idShow = ?" kodicursor.execute(query, (showid,)) try: kodicursor.fetchone()[0] except TypeError: # item is not found, let's recreate it. update_item = False log.info("showid: %s missing from Kodi, repairing the entry", showid) # Force re-add episodes after the show is re-created. force_episodes = True if view is None: # Get view tag from emby viewtag, viewid, mediatype = emby.getView_embyId(itemid) log.debug("View tag found: %s", viewtag) else: viewtag = view['name'] viewid = view['id'] # fileId information checksum = API.get_checksum() userdata = API.get_userdata() # item details genres = item['Genres'] title = item['Name'] plot = API.get_overview() rating = item.get('CommunityRating') premieredate = API.get_premiere_date() tvdb = API.get_provider('Tvdb') sorttitle = item['SortName'] mpaa = API.get_mpaa() genre = " / ".join(genres) studios = API.get_studios() studio = " / ".join(studios) # Verify series pooling if not update_item and tvdb: query = "SELECT idShow FROM tvshow WHERE C12 = ?" kodicursor.execute(query, (tvdb,)) try: temp_showid = kodicursor.fetchone()[0] except TypeError: pass else: emby_other = emby_db.getItem_byKodiId(temp_showid, "tvshow") if emby_other and viewid == emby_other[2]: log.info("Applying series pooling for %s", title) emby_other_item = emby_db.getItem_byId(emby_other[0]) showid = emby_other_item[0] pathid = emby_other_item[2] log.info("showid: %s pathid: %s", showid, pathid) # Create the reference in emby table emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid, checksum=checksum, mediafolderid=viewid) update_item = True ##### GET THE FILE AND PATH ##### playurl = API.get_file_path() if self.direct_path: # Direct paths is set the Kodi way if "\\" in playurl: # Local path path = "%s\\" % playurl toplevelpath = "%s\\" % dirname(dirname(path)) else: # Network path path = "%s/" % playurl toplevelpath = "%s/" % dirname(dirname(path)) if not self.path_validation(path): return False window('emby_pathverified', value="true") else: # Set plugin path toplevelpath = "plugin://plugin.video.emby.tvshows/" path = "%s%s/" % (toplevelpath, itemid) ##### UPDATE THE TVSHOW ##### if update_item: log.info("UPDATE tvshow itemid: %s - Title: %s", itemid, title) # Update the tvshow entry query = ' '.join(( "UPDATE tvshow", "SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,", "c12 = ?, c13 = ?, c14 = ?, c15 = ?", "WHERE idShow = ?" )) kodicursor.execute(query, (title, plot, rating, premieredate, genre, title, tvdb, mpaa, studio, sorttitle, showid)) # Update the checksum in emby table emby_db.updateReference(itemid, checksum) ##### OR ADD THE TVSHOW ##### else: log.info("ADD tvshow itemid: %s - Title: %s", itemid, title) # Add top path toppathid = self.kodi_db.addPath(toplevelpath) query = ' '.join(( "UPDATE path", "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?", "WHERE idPath = ?" )) kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid)) # Add path pathid = self.kodi_db.addPath(path) # Create the tvshow entry query = ( ''' INSERT INTO tvshow(idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14, c15) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' ) kodicursor.execute(query, (showid, title, plot, rating, premieredate, genre, title, tvdb, mpaa, studio, sorttitle)) # Link the path query = "INSERT INTO tvshowlinkpath(idShow, idPath) values(?, ?)" kodicursor.execute(query, (showid, pathid)) # Create the reference in emby table emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid, checksum=checksum, mediafolderid=viewid) # Update the path query = ' '.join(( "UPDATE path", "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?", "WHERE idPath = ?" )) kodicursor.execute(query, (path, None, None, 1, pathid)) # Process cast people = artwork.get_people_artwork(item['People']) self.kodi_db.addPeople(showid, people, "tvshow") # Process genres self.kodi_db.addGenres(showid, genres, "tvshow") # Process artwork artwork.add_artwork(artwork.get_all_artwork(item), showid, "tvshow", kodicursor) # Process studios self.kodi_db.addStudios(showid, studios, "tvshow") # Process tags: view, emby tags tags = [viewtag] tags.extend(item['Tags']) if userdata['Favorite']: tags.append("Favorite tvshows") self.kodi_db.addTags(showid, tags, "tvshow") # Process seasons all_seasons = emby.getSeasons(itemid) for season in all_seasons['Items']: self.add_updateSeason(season, showid=showid) else: # Finally, refresh the all season entry seasonid = self.kodi_db.addSeason(showid, -1) # Process artwork artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor) if force_episodes: # We needed to recreate the show entry. Re-add episodes now. log.info("Repairing episodes for showid: %s %s", showid, title) all_episodes = emby.getEpisodesbyShow(itemid) self.added_episode(all_episodes['Items'], None) return True def add_updateSeason(self, item, showid=None): kodicursor = self.kodicursor emby_db = self.emby_db artwork = self.artwork seasonnum = item.get('IndexNumber', 1) if showid is None: try: seriesId = item['SeriesId'] showid = emby_db.getItem_byId(seriesId)[0] except KeyError: return except TypeError: # Show is missing, update show instead. show = self.emby.getItem(seriesId) self.add_update(show) return seasonid = self.kodi_db.addSeason(showid, seasonnum, item['Name']) if item['LocationType'] != "Virtual": # Create the reference in emby table emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid) # Process artwork artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor) return True @catch_except() def add_updateEpisode(self, item): # Process single episode kodicursor = self.kodicursor emby_db = self.emby_db artwork = self.artwork API = api.API(item) if item.get('LocationType') == "Virtual": # TODO: Filter via api instead log.info("Skipping virtual episode: %s", item['Name']) return # If the item already exist in the local Kodi DB we'll perform a full item update # If the item doesn't exist, we'll add it to the database update_item = True itemid = item['Id'] emby_dbitem = emby_db.getItem_byId(itemid) try: episodeid = emby_dbitem[0] fileid = emby_dbitem[1] pathid = emby_dbitem[2] log.info("episodeid: %s fileid: %s pathid: %s", episodeid, fileid, pathid) except TypeError: update_item = False log.debug("episodeid: %s not found", itemid) # episodeid kodicursor.execute("select coalesce(max(idEpisode),0) from episode") episodeid = kodicursor.fetchone()[0] + 1 else: # Verification the item is still in Kodi query = "SELECT * FROM episode WHERE idEpisode = ?" kodicursor.execute(query, (episodeid,)) try: kodicursor.fetchone()[0] except TypeError: # item is not found, let's recreate it. update_item = False log.info("episodeid: %s missing from Kodi, repairing the entry", episodeid) # fileId information checksum = API.get_checksum() dateadded = API.get_date_created() userdata = API.get_userdata() playcount = userdata['PlayCount'] dateplayed = userdata['LastPlayedDate'] # item details people = API.get_people() writer = " / ".join(people['Writer']) director = " / ".join(people['Director']) title = item['Name'] plot = API.get_overview() rating = item.get('CommunityRating') runtime = API.get_runtime() premieredate = API.get_premiere_date() # episode details try: seriesId = item['SeriesId'] except KeyError: # Missing seriesId, skip log.error("Skipping: %s. SeriesId is missing.", itemid) return False season = item.get('ParentIndexNumber') episode = item.get('IndexNumber', -1) if season is None: if item.get('AbsoluteEpisodeNumber'): # Anime scenario season = 1 episode = item['AbsoluteEpisodeNumber'] else: season = -1 if "Specials" not in item['Path'] else 0 # Specials ordering within season if item.get('AirsAfterSeasonNumber'): airsBeforeSeason = item['AirsAfterSeasonNumber'] airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering else: airsBeforeSeason = item.get('AirsBeforeSeasonNumber') airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber') # Append multi episodes to title if item.get('IndexNumberEnd'): title = "| %02d | %s" % (item['IndexNumberEnd'], title) # Get season id show = emby_db.getItem_byId(seriesId) try: showid = show[0] except TypeError: # Show is missing from database show = self.emby.getItem(seriesId) self.add_update(show) show = emby_db.getItem_byId(seriesId) try: showid = show[0] except TypeError: log.error("Skipping: %s. Unable to add series: %s", itemid, seriesId) return False seasonid = self.kodi_db.addSeason(showid, season) ##### GET THE FILE AND PATH ##### playurl = API.get_file_path() if "\\" in playurl: # Local path filename = playurl.rsplit("\\", 1)[1] else: # Network share filename = playurl.rsplit("/", 1)[1] if self.direct_path: # Direct paths is set the Kodi way if not self.path_validation(playurl): return False path = playurl.replace(filename, "") window('emby_pathverified', value="true") else: # Set plugin path and media flags using real filename path = "plugin://plugin.video.emby.tvshows/%s/" % seriesId params = { 'filename': filename.encode('utf-8'), 'id': itemid, 'dbid': episodeid, 'mode': "play" } filename = "%s?%s" % (path, urllib.urlencode(params)) ##### UPDATE THE EPISODE ##### if update_item: log.info("UPDATE episode itemid: %s - Title: %s", itemid, title) # Update the movie entry if self.kodi_version in (16, 17): # Kodi Jarvis, Krypton query = ' '.join(( "UPDATE episode", "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,", "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idSeason = ?, idShow = ?", "WHERE idEpisode = ?" )) kodicursor.execute(query, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, airsBeforeSeason, airsBeforeEpisode, seasonid, showid, episodeid)) else: query = ' '.join(( "UPDATE episode", "SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?,", "c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, idShow = ?", "WHERE idEpisode = ?" )) kodicursor.execute(query, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, airsBeforeSeason, airsBeforeEpisode, showid, episodeid)) # Update the checksum in emby table emby_db.updateReference(itemid, checksum) # Update parentid reference emby_db.updateParentId(itemid, seasonid) ##### OR ADD THE EPISODE ##### else: log.info("ADD episode itemid: %s - Title: %s", itemid, title) # Add path pathid = self.kodi_db.addPath(path) # Add the file fileid = self.kodi_db.addFile(filename, pathid) # Create the episode entry if self.kodi_version in (16, 17): # Kodi Jarvis, Krypton query = ( ''' INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14, idShow, c15, c16, idSeason) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' ) kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, airsBeforeSeason, airsBeforeEpisode, seasonid)) else: query = ( ''' INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14, idShow, c15, c16) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' ) kodicursor.execute(query, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, airsBeforeSeason, airsBeforeEpisode)) # Create the reference in emby table emby_db.addReference(itemid, episodeid, "Episode", "episode", fileid, pathid, seasonid, checksum) # Update the path query = ' '.join(( "UPDATE path", "SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?", "WHERE idPath = ?" )) kodicursor.execute(query, (path, None, None, 1, pathid)) # Update the file query = ' '.join(( "UPDATE files", "SET idPath = ?, strFilename = ?, dateAdded = ?", "WHERE idFile = ?" )) kodicursor.execute(query, (pathid, filename, dateadded, fileid)) # Process cast people = artwork.get_people_artwork(item['People']) self.kodi_db.addPeople(episodeid, people, "episode") # Process artwork artworks = artwork.get_all_artwork(item) artwork.add_update_art(artworks['Primary'], episodeid, "episode", "thumb", kodicursor) # Process stream details streams = API.get_media_streams() self.kodi_db.addStreams(fileid, streams, runtime) # Process playstates resume = API.adjust_resume(userdata['Resume']) total = round(float(runtime), 6) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) if not self.direct_path and resume: # Create additional entry for widgets. This is only required for plugin/episode. temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/") tempfileid = self.kodi_db.addFile(filename, temppathid) query = ' '.join(( "UPDATE files", "SET idPath = ?, strFilename = ?, dateAdded = ?", "WHERE idFile = ?" )) kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid)) self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed) return True def updateUserdata(self, item): # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks # Poster with progress bar emby_db = self.emby_db API = api.API(item) # Get emby information itemid = item['Id'] checksum = API.get_checksum() userdata = API.get_userdata() runtime = API.get_runtime() dateadded = API.get_date_created() # Get Kodi information emby_dbitem = emby_db.getItem_byId(itemid) try: kodiid = emby_dbitem[0] fileid = emby_dbitem[1] mediatype = emby_dbitem[4] log.info("Update playstate for %s: %s fileid: %s", mediatype, item['Name'], fileid) except TypeError: return # Process favorite tags if mediatype == "tvshow": if userdata['Favorite']: self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow") else: self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow") elif mediatype == "episode": # Process playstates playcount = userdata['PlayCount'] dateplayed = userdata['LastPlayedDate'] resume = API.adjust_resume(userdata['Resume']) total = round(float(runtime), 6) log.debug("%s New resume point: %s", itemid, resume) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) if not self.direct_path and not resume: # Make sure there's no other bookmarks created by widget. filename = self.kodi_db.getFile(fileid) self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename) if not self.direct_path and resume: # Create additional entry for widgets. This is only required for plugin/episode. filename = self.kodi_db.getFile(fileid) temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/") tempfileid = self.kodi_db.addFile(filename, temppathid) query = ' '.join(( "UPDATE files", "SET idPath = ?, strFilename = ?, dateAdded = ?", "WHERE idFile = ?" )) self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid)) self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed) emby_db.updateReference(itemid, checksum) def remove(self, itemid): # Remove showid, fileid, pathid, emby reference emby_db = self.emby_db kodicursor = self.kodicursor emby_dbitem = emby_db.getItem_byId(itemid) try: kodiid = emby_dbitem[0] fileid = emby_dbitem[1] parentid = emby_dbitem[3] mediatype = emby_dbitem[4] log.info("Removing %s kodiid: %s fileid: %s", mediatype, kodiid, fileid) except TypeError: return ##### PROCESS ITEM ##### # Remove the emby reference emby_db.removeItem(itemid) ##### IF EPISODE ##### if mediatype == "episode": # Delete kodi episode and file, verify season and tvshow self.removeEpisode(kodiid, fileid) # Season verification season = emby_db.getItem_byKodiId(parentid, "season") try: showid = season[1] except TypeError: return season_episodes = emby_db.getItem_byParentId(parentid, "episode") if not season_episodes: self.removeSeason(parentid) emby_db.removeItem(season[0]) # Show verification show = emby_db.getItem_byKodiId(showid, "tvshow") query = ' '.join(( "SELECT totalCount", "FROM tvshowcounts", "WHERE idShow = ?" )) kodicursor.execute(query, (showid,)) result = kodicursor.fetchone() if result and result[0] is None: # There's no episodes left, delete show and any possible remaining seasons seasons = emby_db.getItem_byParentId(showid, "season") for season in seasons: self.removeSeason(season[1]) else: # Delete emby season entries emby_db.removeItems_byParentId(showid, "season") self.removeShow(showid) emby_db.removeItem(show[0]) ##### IF TVSHOW ##### elif mediatype == "tvshow": # Remove episodes, seasons, tvshow seasons = emby_db.getItem_byParentId(kodiid, "season") for season in seasons: seasonid = season[1] season_episodes = emby_db.getItem_byParentId(seasonid, "episode") for episode in season_episodes: self.removeEpisode(episode[1], episode[2]) else: # Remove emby episodes emby_db.removeItems_byParentId(seasonid, "episode") else: # Remove emby seasons emby_db.removeItems_byParentId(kodiid, "season") # Remove tvshow self.removeShow(kodiid) ##### IF SEASON ##### elif mediatype == "season": # Remove episodes, season, verify tvshow season_episodes = emby_db.getItem_byParentId(kodiid, "episode") for episode in season_episodes: self.removeEpisode(episode[1], episode[2]) else: # Remove emby episodes emby_db.removeItems_byParentId(kodiid, "episode") # Remove season self.removeSeason(kodiid) # Show verification seasons = emby_db.getItem_byParentId(parentid, "season") if not seasons: # There's no seasons, delete the show self.removeShow(parentid) emby_db.removeItem_byKodiId(parentid, "tvshow") log.info("Deleted %s: %s from kodi database", mediatype, itemid) def removeShow(self, kodiid): kodicursor = self.kodicursor self.artwork.delete_artwork(kodiid, "tvshow", kodicursor) kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,)) log.debug("Removed tvshow: %s", kodiid) def removeSeason(self, kodiid): kodicursor = self.kodicursor self.artwork.delete_artwork(kodiid, "season", kodicursor) kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,)) log.debug("Removed season: %s", kodiid) def removeEpisode(self, kodiid, fileid): kodicursor = self.kodicursor self.artwork.delete_artwork(kodiid, "episode", kodicursor) kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,)) kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) log.debug("Removed episode: %s", kodiid)