From: nldroid <13297091+nldroid@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:27:41 +0000 (+0200) Subject: Fix cleanup of orphaned artists and albums on local file provider (#1323) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=e281dc8d60203a884e76598b00fcaaca041fcce0;p=music-assistant-server.git Fix cleanup of orphaned artists and albums on local file provider (#1323) --- diff --git a/music_assistant/server/providers/filesystem_local/base.py b/music_assistant/server/providers/filesystem_local/base.py index 09532d21..e0b49894 100644 --- a/music_assistant/server/providers/filesystem_local/base.py +++ b/music_assistant/server/providers/filesystem_local/base.py @@ -39,7 +39,16 @@ from music_assistant.common.models.media_items import ( Track, ) from music_assistant.common.models.streamdetails import StreamDetails -from music_assistant.constants import DB_TABLE_PROVIDER_MAPPINGS, VARIOUS_ARTISTS_NAME +from music_assistant.constants import ( + DB_TABLE_ALBUM_ARTISTS, + DB_TABLE_ALBUM_TRACKS, + DB_TABLE_ALBUMS, + DB_TABLE_ARTISTS, + DB_TABLE_PLAYLOG, + DB_TABLE_PROVIDER_MAPPINGS, + DB_TABLE_TRACK_ARTISTS, + VARIOUS_ARTISTS_NAME, +) from music_assistant.server.controllers.cache import use_cache from music_assistant.server.controllers.music import DB_SCHEMA_VERSION from music_assistant.server.helpers.compare import compare_strings @@ -388,6 +397,69 @@ class FileSystemProviderBase(MusicProvider): deleted_files = prev_filenames - cur_filenames await self._process_deletions(deleted_files) + # process orphaned albums and artists + await self._process_orphaned_albums_and_artists() + + async def _process_orphaned_albums_and_artists(self) -> None: + """Process deletion of orphaned albums and artists.""" + # process orphaned albums and artists + + # Remove albums without any tracks + query = ( + f"SELECT item_id FROM {DB_TABLE_ALBUMS} " + f"WHERE item_id not in (select album_id from {DB_TABLE_ALBUM_TRACKS})" + ) + for db_row in await self.mass.music.database.get_rows_from_query( + query, + limit=100000, + ): + await self.mass.music.albums.remove_item_from_library(db_row["item_id"]) + + # Remove artists without any tracks or albums + query = ( + f"SELECT item_id FROM {DB_TABLE_ARTISTS} " + f"WHERE item_id not in (" + f"select artist_id from {DB_TABLE_TRACK_ARTISTS} " + f"UNION " + f"select artist_id from {DB_TABLE_ALBUM_ARTISTS}" + ")" + ) + for db_row in await self.mass.music.database.get_rows_from_query( + query, + limit=100000, + ): + await self.mass.music.artists.remove_item_from_library(db_row["item_id"]) + + # Provider mappings where the album is removed + query = ( + f"SELECT item_id FROM {DB_TABLE_PROVIDER_MAPPINGS} " + f"WHERE media_type = 'album' " + f"and item_id not in (select item_id from {DB_TABLE_ALBUMS})" + ) + for db_row in await self.mass.music.database.get_rows_from_query(query, limit=100000): + await self.mass.music.albums.remove_provider_mappings( + db_row["item_id"], self.instance_id + ) + + # Provider mappings where the artist is removed + query = ( + f"SELECT item_id FROM {DB_TABLE_PROVIDER_MAPPINGS} " + f"WHERE media_type = 'artist' " + f"and item_id not in (select item_id from {DB_TABLE_ARTISTS})" + ) + for db_row in await self.mass.music.database.get_rows_from_query(query, limit=100000): + await self.mass.music.artists.remove_provider_mappings( + db_row["item_id"], self.instance_id + ) + + # Remove albums that are removed from the playlog + where_clause = ( + f"media_type = 'album' " + f"and provider = '{self.instance_id}' " + f"and item_id not in (select item_id from albums)" + ) + await self.mass.music.database.delete_where_query(DB_TABLE_PLAYLOG, where_clause) + async def _process_deletions(self, deleted_files: set[str]) -> None: """Process all deletions.""" # process deleted tracks/playlists