From dcff85e20338150bd8fe3b8f744523beff4c33c3 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 30 Jan 2019 10:58:20 +0100 Subject: [PATCH 1/5] Fix TV sections not being deleted e.g. after user switch --- resources/lib/library_sync/sections.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/lib/library_sync/sections.py b/resources/lib/library_sync/sections.py index 9b5eca66..8c03178a 100644 --- a/resources/lib/library_sync/sections.py +++ b/resources/lib/library_sync/sections.py @@ -215,16 +215,16 @@ def delete_sections(old_sections): LOG.info("Removing entire Plex library sections: %s", old_sections) with kodi_db.KodiVideoDB(texture_db=True) as kodidb: for section in old_sections: - if section[2] == v.KODI_TYPE_PHOTO: + if section[2] == v.PLEX_TYPE_PHOTO: # not synced plexdb.remove_section(section[0]) continue - elif section[2] == v.KODI_TYPE_MOVIE: + elif section[2] == v.PLEX_TYPE_MOVIE: video_library_update = True context = itemtypes.Movie(None, plexdb=plexdb, kodidb=kodidb) - elif section[2] == v.KODI_TYPE_SHOW: + elif section[2] == v.PLEX_TYPE_SHOW: video_library_update = True context = itemtypes.Show(None, plexdb=plexdb, @@ -238,7 +238,7 @@ def delete_sections(old_sections): with kodi_db.KodiMusicDB(texture_db=True) as kodidb: for section in old_sections: - if section[2] == v.KODI_TYPE_ARTIST: + if section[2] == v.PLEX_TYPE_ARTIST: music_library_update = True context = itemtypes.Artist(None, plexdb=plexdb, From a279cf519891859b80b09a75f3e52201ead9e632 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 30 Jan 2019 14:34:35 +0100 Subject: [PATCH 2/5] Fix deleting entire Plex library sections Typo plex_type - section_type --- resources/lib/library_sync/sections.py | 102 ++++++++++++++----------- resources/lib/plex_db/common.py | 9 ++- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/resources/lib/library_sync/sections.py b/resources/lib/library_sync/sections.py index 8c03178a..fdb1b89d 100644 --- a/resources/lib/library_sync/sections.py +++ b/resources/lib/library_sync/sections.py @@ -13,12 +13,17 @@ from .. import plex_functions as PF, music, utils, variables as v, app LOG = getLogger('PLEX.sync.sections') +BATCH_SIZE = 200 VNODES = videonodes.VideoNodes() PLAYLISTS = {} NODES = {} SECTIONS = [] +def isCanceled(): + return app.APP.stop_pkc or app.APP.suspend_threads or app.SYNC.stop_sync + + def sync_from_pms(): """ Sync the Plex library sections @@ -198,56 +203,61 @@ def _process_section(section_xml, kodidb, plexdb, sorted_sections, return totalnodes +def _delete_kodi_db_items(section_id, section_type): + if section_type == v.PLEX_TYPE_MOVIE: + kodi_context = kodi_db.KodiVideoDB + types = ((v.PLEX_TYPE_MOVIE, itemtypes.Movie), ) + elif section_type == v.PLEX_TYPE_SHOW: + kodi_context = kodi_db.KodiVideoDB + types = ((v.PLEX_TYPE_SHOW, itemtypes.Show), + (v.PLEX_TYPE_SEASON, itemtypes.Season), + (v.PLEX_TYPE_EPISODE, itemtypes.Episode)) + elif section_type == v.PLEX_TYPE_ARTIST: + kodi_context = kodi_db.KodiMusicDB + types = ((v.PLEX_TYPE_ARTIST, itemtypes.Artist), + (v.PLEX_TYPE_ALBUM, itemtypes.Album), + (v.PLEX_TYPE_SONG, itemtypes.Song)) + for plex_type, context in types: + while True: + with PlexDB() as plexdb: + plex_ids = list(plexdb.plexid_by_sectionid(section_id, + plex_type, + BATCH_SIZE)) + with kodi_context(texture_db=True) as kodidb: + typus = context(None, plexdb=plexdb, kodidb=kodidb) + for plex_id in plex_ids: + if isCanceled(): + return False + typus.remove(plex_id) + if len(plex_ids) < BATCH_SIZE: + break + return True + + def delete_sections(old_sections): """ Deletes all elements for a Plex section that has been deleted. (e.g. all TV shows, Seasons and Episodes of a Show section) """ - utils.dialog('notification', - heading='{plex}', - message=utils.lang(30052), - icon='{plex}', - sound=False) - video_library_update = False - music_library_update = False - with PlexDB() as plexdb: - old_sections = [plexdb.section(x) for x in old_sections] + try: + with PlexDB() as plexdb: + old_sections = [plexdb.section(x) for x in old_sections] LOG.info("Removing entire Plex library sections: %s", old_sections) - with kodi_db.KodiVideoDB(texture_db=True) as kodidb: - for section in old_sections: - if section[2] == v.PLEX_TYPE_PHOTO: - # not synced - plexdb.remove_section(section[0]) - continue - elif section[2] == v.PLEX_TYPE_MOVIE: - video_library_update = True - context = itemtypes.Movie(None, - plexdb=plexdb, - kodidb=kodidb) - elif section[2] == v.PLEX_TYPE_SHOW: - video_library_update = True - context = itemtypes.Show(None, - plexdb=plexdb, - kodidb=kodidb) - else: - continue - for plex_id in plexdb.plexid_by_sectionid(section[0], section[2]): - context.remove(plex_id) - # Only remove Plex entry if we've removed all items first + for section in old_sections: + # "Deleting " + utils.dialog('notification', + heading='{plex}', + message='%s %s' % (utils.lang(30052), section[1]), + icon='{plex}', + sound=False) + if section[2] == v.PLEX_TYPE_PHOTO: + # not synced - just remove the link in our Plex sections table + pass + else: + if not _delete_kodi_db_items(section[0], section[2]): + return + # Only remove Plex entry if we've removed all items first + with PlexDB() as plexdb: plexdb.remove_section(section[0]) - - with kodi_db.KodiMusicDB(texture_db=True) as kodidb: - for section in old_sections: - if section[2] == v.PLEX_TYPE_ARTIST: - music_library_update = True - context = itemtypes.Artist(None, - plexdb=plexdb, - kodidb=kodidb) - else: - continue - for plex_id in plexdb.plexid_by_sectionid(section[0], section[2]): - context.remove(plex_id) - # Only remove Plex entry if we've removed all items first - plexdb.remove_section(section[0]) - common.update_kodi_library(video=video_library_update, - music=music_library_update) + finally: + common.update_kodi_library() diff --git a/resources/lib/plex_db/common.py b/resources/lib/plex_db/common.py index 8d6db16e..0ce2af9b 100644 --- a/resources/lib/plex_db/common.py +++ b/resources/lib/plex_db/common.py @@ -162,10 +162,11 @@ class PlexDBBase(object): self.cursor.execute('UPDATE %s SET fanart_synced = 1 WHERE plex_id = ?' % plex_type, (plex_id, )) - def plexid_by_sectionid(self, section_id, plex_type): - return (x[0] for x in - self.cursor.execute('SELECT plex_id FROM %s WHERE section_id = ?' % plex_type, - (section_id, ))) + def plexid_by_sectionid(self, section_id, plex_type, limit): + query = ''' + SELECT plex_id FROM %s WHERE section_id = ? LIMIT %s + ''' % (plex_type, limit) + return (x[0] for x in self.cursor.execute(query, (section_id, ))) def kodiid_by_sectionid(self, section_id, plex_type): return (x[0] for x in From 624fe87fd125f6190252b156a53074733ede3992 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 30 Jan 2019 15:41:13 +0100 Subject: [PATCH 3/5] Fix to cleanly delete all episodes and seasons --- resources/lib/itemtypes/tvshows.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/resources/lib/itemtypes/tvshows.py b/resources/lib/itemtypes/tvshows.py index 9df90157..f8fd5759 100644 --- a/resources/lib/itemtypes/tvshows.py +++ b/resources/lib/itemtypes/tvshows.py @@ -70,7 +70,8 @@ class TvShowMixin(object): # SEASON ##### elif db_item['plex_type'] == v.PLEX_TYPE_SEASON: # Remove episodes, season, verify tvshow - for episode in self.plexdb.episode_by_season(db_item['plex_id']): + episodes = list(self.plexdb.episode_by_season(db_item['plex_id'])) + for episode in episodes: self.remove_episode(episode['kodi_id'], episode['kodi_fileid']) self.plexdb.remove(episode['plex_id'], v.PLEX_TYPE_EPISODE) # Remove season @@ -84,13 +85,15 @@ class TvShowMixin(object): # TVSHOW ##### elif db_item['plex_type'] == v.PLEX_TYPE_SHOW: # Remove episodes, seasons and the tvshow itself - for episode in self.plexdb.episode_by_show(db_item['plex_id']): + seasons = list(self.plexdb.season_by_show(db_item['plex_id'])) + for season in seasons: + self.remove_season(season['kodi_id']) + self.plexdb.remove(season['plex_id'], v.PLEX_TYPE_SEASON) + episodes = list(self.plexdb.episode_by_show(db_item['plex_id'])) + for episode in episodes: self.remove_episode(episode['kodi_id'], episode['kodi_fileid']) self.plexdb.remove(episode['plex_id'], v.PLEX_TYPE_EPISODE) - for season in self.plexdb.season_by_show(db_item['plex_id']): - self.remove_season(season['kodi_id']) - self.plexdb.remove(season['plex_id'], v.PLEX_TYPE_SEASON) self.remove_show(db_item['kodi_id']) LOG.debug('Deleted %s %s from all databases', From 8cb4e5f8fc88774743f14453c51854895c491625 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 30 Jan 2019 15:47:26 +0100 Subject: [PATCH 4/5] Fix to cleanly delete all songs and albums --- resources/lib/itemtypes/music.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/resources/lib/itemtypes/music.py b/resources/lib/itemtypes/music.py index a182f7ef..20dc516c 100644 --- a/resources/lib/itemtypes/music.py +++ b/resources/lib/itemtypes/music.py @@ -81,7 +81,7 @@ class MusicMixin(object): self.remove_song(db_item['kodi_id'], db_item['kodi_pathid']) # Album verification if not self.plexdb.album_has_songs(db_item['album_id']): - # No episode left for this season - so delete the season + # No songleft for this album - so delete the album self.remove_album(db_item['parent_id']) self.plexdb.remove(db_item['album_id'], v.PLEX_TYPE_ALBUM) # Artist verification @@ -91,8 +91,9 @@ class MusicMixin(object): self.plexdb.remove(db_item['artist_id'], v.PLEX_TYPE_ARTIST) # ALBUM ##### elif db_item['plex_type'] == v.PLEX_TYPE_ALBUM: - # Remove episodes, season, verify tvshow - for song in self.plexdb.song_by_album(db_item['plex_id']): + # Remove songs, album, verify artist + songs = list(self.plexdb.song_by_album(db_item['plex_id'])) + for song in songs: self.remove_song(song['kodi_id'], song['kodi_pathid']) self.plexdb.remove(song['plex_id'], v.PLEX_TYPE_SONG) # Remove the album @@ -100,16 +101,18 @@ class MusicMixin(object): # Show verification if (not self.plexdb.artist_has_albums(db_item['kodi_id']) and not self.plexdb.artist_has_songs(db_item['kodi_id'])): - # There's no other season or episode left, delete the show + # There's no other album or song left, delete the artist self.remove_artist(db_item['parent_id']) self.plexdb.remove(db_item['artist_id'], v.KODI_TYPE_ARTIST) # ARTIST ##### elif db_item['plex_type'] == v.PLEX_TYPE_ARTIST: # Remove songs, albums and the artist himself - for song in self.plexdb.song_by_artist(db_item['plex_id']): + songs = list(self.plexdb.song_by_artist(db_item['plex_id'])) + for song in songs: self.remove_song(song['kodi_id'], song['kodi_pathid']) self.plexdb.remove(song['plex_id'], v.PLEX_TYPE_SONG) - for album in self.plexdb.album_by_artist(db_item['plex_id']): + albums = list(self.plexdb.album_by_artist(db_item['plex_id'])) + for album in albums: self.remove_album(album['kodi_id']) self.plexdb.remove(album['plex_id'], v.PLEX_TYPE_ALBUM) self.remove_artist(db_item['kodi_id']) From 4e10a9da8b6e885774aa6552dad76c68c962f148 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 30 Jan 2019 17:40:20 +0100 Subject: [PATCH 5/5] Force database reset --- resources/lib/variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/variables.py b/resources/lib/variables.py index 10885a23..34b48c93 100644 --- a/resources/lib/variables.py +++ b/resources/lib/variables.py @@ -91,7 +91,7 @@ COMPANION_PORT = int(_ADDON.getSetting('companionPort')) PKC_MACHINE_IDENTIFIER = None # Minimal PKC version needed for the Kodi database - otherwise need to recreate -MIN_DB_VERSION = '2.5.12' +MIN_DB_VERSION = '2.6.1' # Supported databases SUPPORTED_VIDEO_DB = {