From: Marcel van der Veldt Date: Sun, 22 May 2022 20:41:55 +0000 (+0200) Subject: Fix artist not marked as 'in library' when exists on multiple providers (#337) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=bb0887b6aa59ad8813b8971c6cff6287241f23e1;p=music-assistant-server.git Fix artist not marked as 'in library' when exists on multiple providers (#337) Fix filesystem library race condition with streaming provider --- diff --git a/music_assistant/controllers/music/providers/filesystem.py b/music_assistant/controllers/music/providers/filesystem.py index b7328fda..97bd135e 100644 --- a/music_assistant/controllers/music/providers/filesystem.py +++ b/music_assistant/controllers/music/providers/filesystem.py @@ -153,14 +153,30 @@ class FileSystemProvider(MusicProvider): if track := await self._parse_track(entry.path, checksum): # process album if track.album: - await self.mass.music.albums.add_db_item(track.album, db=db) + db_album = await self.mass.music.albums.add_db_item( + track.album, db=db + ) + if not db_album.in_library: + await self.mass.music.albums.set_db_library( + db_album.item_id, True, db=db + ) # process (album)artist if track.album.artist: - await self.mass.music.artists.add_db_item( + db_artist = await self.mass.music.artists.add_db_item( track.album.artist, db=db ) + if not db_artist.in_library: + await self.mass.music.artists.set_db_library( + db_artist.item_id, True, db=db + ) # add/update track to db - await self.mass.music.tracks.add_db_item(track, db=db) + db_track = await self.mass.music.tracks.add_db_item( + track, db=db + ) + if not db_track.in_library: + await self.mass.music.tracks.set_db_library( + db_track.item_id, True, db=db + ) elif playlist := await self._parse_playlist(entry.path, checksum): # add/update] playlist to db await self.mass.music.playlists.add_db_item(playlist, db=db) @@ -321,7 +337,7 @@ class FileSystemProvider(MusicProvider): raise MediaNotFoundError(f"Artist not found: {prov_artist_id}") # TODO: adjust to json query instead of text search query = f"SELECT * FROM albums WHERE artist LIKE '%\"{db_artist.item_id}\"%'" - query += f" AND provider_ids like '%\"{self.type.value}\"%'" + query += f" AND provider_ids LIKE '%\"{self.type.value}\"%'" return await self.mass.music.albums.get_db_items(query) async def get_artist_toptracks(self, prov_artist_id: str) -> List[Track]: @@ -334,7 +350,7 @@ class FileSystemProvider(MusicProvider): raise MediaNotFoundError(f"Artist not found: {prov_artist_id}") # TODO: adjust to json query instead of text search query = f"SELECT * FROM tracks WHERE artists LIKE '%\"{db_artist.item_id}\"%'" - query += f" AND provider_ids like '%\"{self.type.value}\"%'" + query += f" AND provider_ids LIKE '%\"{self.type.value}\"%'" return await self.mass.music.tracks.get_db_items(query) async def library_add(self, *args, **kwargs) -> bool: @@ -430,7 +446,6 @@ class FileSystemProvider(MusicProvider): if tags.title: track_title = tags.title else: - ext = track_path.split(".")[-1] track_title = track_path.split(os.sep)[-1] track_title = track_title.replace(f".{ext}", "").replace("_", " ") diff --git a/music_assistant/models/config.py b/music_assistant/models/config.py index b2a8d8b2..a5680d29 100644 --- a/music_assistant/models/config.py +++ b/music_assistant/models/config.py @@ -24,7 +24,7 @@ class MusicProviderConfig: def __post_init__(self): """Call after init.""" # create a default (hopefully unique enough) id from type + username/path - if not self.id: + if not self.id and (self.path or self.username): prov_id = f"{self.type.value}_" base_str = (self.path or self.username).lower() prov_id += ( diff --git a/music_assistant/models/provider.py b/music_assistant/models/provider.py index 588505bd..ffded981 100644 --- a/music_assistant/models/provider.py +++ b/music_assistant/models/provider.py @@ -191,7 +191,7 @@ class MusicProvider: """Run library sync for this provider.""" # this reference implementation can be overridden with provider specific approach # this logic is aimed at streaming/online providers, - # which all have more or less the same structure. + # which all have more or less the same structure. # filesystem implementation(s) just override this. async with self.mass.database.get_db() as db: for media_type in self.supported_mediatypes: @@ -199,8 +199,17 @@ class MusicProvider: controller = self.mass.music.get_controller(media_type) # create a set of all previous and current db id's + # note we only store the items in the prev_ids list that are + # unique to this provider to avoid getting into a mess where + # for example an item still exists on disk (in case of file provider) + # and no longer favorite on streaming provider. + # Bottomline this means that we don't do a full 2 way sync if multiple + # providers are attached to the same media item. prev_ids = set() for db_item in await controller.library(): + prov_types = {x.prov_type for x in db_item.provider_ids} + if len(prov_types) > 1: + continue for prov_id in db_item.provider_ids: if prov_id.prov_id == self.id: prev_ids.add(db_item.item_id)