Fix some small glitches (#275)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Fri, 29 Apr 2022 19:31:03 +0000 (21:31 +0200)
committerGitHub <noreply@github.com>
Fri, 29 Apr 2022 19:31:03 +0000 (21:31 +0200)
music_assistant/constants.py
music_assistant/controllers/music/tracks.py
music_assistant/helpers/compare.py
music_assistant/helpers/database.py
music_assistant/mass.py
music_assistant/models/media_items.py
music_assistant/providers/filesystem.py
music_assistant/providers/qobuz.py
music_assistant/providers/spotify/__init__.py

index c2389a4fa8dbb7cc998700f9a91311e5520924ed..25506a42ab4548c0b65449042b963b9fdac7c1a1 100755 (executable)
@@ -66,6 +66,7 @@ class BackgroundJob:
             "id": self.id,
             "name": self.name,
             "timestamp": self.status.value,
+            "status": self.status.value,
         }
 
 
index 5cf65cdf750f951b908b7e7637de540292063b02..493a51c8abb910f1efe015fd33a28510aadc4289 100644 (file)
@@ -136,7 +136,7 @@ class TracksController(MediaControllerBase[Track]):
             track.sort_name = create_sort_name(track.name)
         cur_item = None
         async with self.mass.database.get_db() as _db:
-            if track.album:
+            if track.album and not isinstance(track.album, ItemMapping):
                 track.album = ItemMapping.from_item(
                     await self.get_db_item_by_prov_id(
                         track.album.provider, track.album.item_id, db=_db
@@ -194,23 +194,24 @@ class TracksController(MediaControllerBase[Track]):
         async with self.mass.database.get_db() as _db:
             cur_item = await self.get_db_item(item_id, db=_db)
             if overwrite:
-                metadata = track.metadata
                 provider_ids = track.provider_ids
                 track_artists = track.artists
+                track_album = track.album or cur_item.album
             else:
-                metadata = cur_item.metadata.update(track.metadata)
                 provider_ids = {*cur_item.provider_ids, *track.provider_ids}
-                track_artists = await self._get_track_artists(track, cur_item.artists)
-            if track.album and not isinstance(track.album, ItemMapping):
-                track.album = ItemMapping.from_item(
+                track_artists = cur_item.artists + track.artists
+                track_album = cur_item.album or track.album
+            metadata = cur_item.metadata.update(track.metadata, overwrite)
+            if track_album and not isinstance(track_album, ItemMapping):
+                track_album = ItemMapping.from_item(
                     await self.get_db_item_by_prov_id(
-                        track.album.provider, track.album.item_id, db=_db
+                        track_album.provider, track_album.item_id, db=_db
                     )
-                    or await self.mass.music.albums.add_db_item(track.album)
+                    or await self.mass.music.albums.add_db_item(track_album)
                 )
 
             # we store a mapping to artists on the track for easier access/listings
-            track_artists = await self._get_track_artists(track, cur_item.artists)
+            track_artists = await self._get_track_artists(track, track_artists)
             await self.mass.database.update(
                 self.db_table,
                 {"item_id": item_id},
@@ -220,6 +221,7 @@ class TracksController(MediaControllerBase[Track]):
                     "version": track.version if overwrite else cur_item.version,
                     "duration": track.duration if overwrite else cur_item.duration,
                     "artists": json_serializer(track_artists),
+                    "album": json_serializer(track_album),
                     "metadata": json_serializer(metadata),
                     "provider_ids": json_serializer(provider_ids),
                     "isrc": track.isrc or cur_item.isrc,
index 56c5cebeb007acdc4cf41e33f4f3fe4ac09d9448..5f6aabc0d40ff31e2fbeee9bd0d76b627199dc54 100644 (file)
@@ -6,6 +6,8 @@ from typing import TYPE_CHECKING, List
 
 import unidecode
 
+from music_assistant.models.media_items import ItemMapping
+
 if TYPE_CHECKING:
     from music_assistant.models.media_items import (
         Album,
@@ -81,14 +83,19 @@ def compare_album(left_album: "Album", right_album: "Album"):
         and left_album.item_id == right_album.item_id
     ):
         return True
-    if left_album.upc and right_album.upc:
-        if (left_album.upc in right_album.upc) or (right_album.upc in left_album.upc):
-            # UPC is always 100% accurate match
-            return True
-    if left_album.musicbrainz_id and right_album.musicbrainz_id:
-        if left_album.musicbrainz_id == right_album.musicbrainz_id:
-            # musicbrainz_id is always 100% accurate match
-            return True
+    if not (
+        isinstance(left_album, ItemMapping) or isinstance(right_album, ItemMapping)
+    ):
+        if left_album.upc and right_album.upc:
+            if (left_album.upc in right_album.upc) or (
+                right_album.upc in left_album.upc
+            ):
+                # UPC is always 100% accurate match
+                return True
+        if left_album.musicbrainz_id and right_album.musicbrainz_id:
+            if left_album.musicbrainz_id == right_album.musicbrainz_id:
+                # musicbrainz_id is always 100% accurate match
+                return True
     if not compare_strings(left_album.name, right_album.name):
         return False
     if not compare_version(left_album.version, right_album.version):
index 8de2359b496ab286c9e1706ff68cc53e81ecbccc..0f652745f3b82db28f47ae2780c3242a42c605a3 100755 (executable)
@@ -11,7 +11,7 @@ from music_assistant.helpers.typing import MusicAssistant
 
 # pylint: disable=invalid-name
 
-SCHEMA_VERSION = 3
+SCHEMA_VERSION = 4
 
 TABLE_PROV_MAPPINGS = "provider_mappings"
 TABLE_TRACK_LOUDNESS = "track_loudness"
@@ -21,6 +21,7 @@ TABLE_ALBUMS = "albums"
 TABLE_TRACKS = "tracks"
 TABLE_PLAYLISTS = "playlists"
 TABLE_RADIOS = "radios"
+TABLE_CACHE = "cache"
 
 
 class Database:
@@ -164,15 +165,22 @@ class Database:
             if prev_version < 3:
                 # schema version 3: too many breaking changes, rebuild db
                 async with self.get_db() as _db:
-                    await _db.execute("DROP TABLE IF EXISTS artists")
-                    await _db.execute("DROP TABLE IF EXISTS albums")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_ARTISTS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_ALBUMS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_TRACKS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_PLAYLISTS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_RADIOS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_PROV_MAPPINGS}")
+                    await _db.execute(f"DROP TABLE IF EXISTS {TABLE_CACHE}")
+
+            if prev_version < 4:
+                # schema version 4: add album to tracks table
+                async with self.get_db() as _db:
                     await _db.execute("DROP TABLE IF EXISTS tracks")
-                    await _db.execute("DROP TABLE IF EXISTS playlists")
-                    await _db.execute("DROP TABLE IF EXISTS radios")
-                    await _db.execute("DROP TABLE IF EXISTS playlist_tracks")
-                    await _db.execute("DROP TABLE IF EXISTS album_tracks")
-                    await _db.execute("DROP TABLE IF EXISTS provider_mappings")
-                    await _db.execute("DROP TABLE IF EXISTS cache")
+                    if await self.exists(TABLE_PROV_MAPPINGS, _db):
+                        await self.delete(
+                            TABLE_PROV_MAPPINGS, {"media_type": "track"}, db=_db
+                        )
 
         # create db tables
         await self.__create_database_tables()
@@ -248,6 +256,7 @@ class Database:
                         isrc TEXT,
                         musicbrainz_id TEXT,
                         artists json,
+                        album json,
                         metadata json,
                         provider_ids json
                     );"""
index 96eab68e102313cc54612ec203a2f43658ce9d6a..b5dc53111adc55a87c21d78cedbb5e175787915f 100644 (file)
@@ -233,6 +233,8 @@ class MusicAssistant:
 
     def __job_done_cb(self, task: asyncio.Task, job: BackgroundJob):
         """Call when background job finishes."""
+        execution_time = round(time() - job.timestamp, 2)
+        job.timestamp = execution_time
         if task.cancelled():
             job.status = JobStatus.CANCELLED
             self.logger.debug("Job [%s] is cancelled.", job.name)
@@ -246,7 +248,6 @@ class MusicAssistant:
             )
         else:
             job.status = JobStatus.FINISHED
-            execution_time = round(time() - job.timestamp, 2)
             self.logger.info(
                 "Finished job [%s] in %s seconds.", job.name, execution_time
             )
index 765c293308c248706e0d280579054b19f2229fd0..2fe9b9d8160ad9971db67286369508862eca8209 100755 (executable)
@@ -12,7 +12,7 @@ from music_assistant.helpers.util import create_sort_name
 
 MetadataTypes = Union[int, bool, str, List[str]]
 
-JSON_KEYS = ("artists", "artist", "metadata", "provider_ids")
+JSON_KEYS = ("artists", "artist", "album", "metadata", "provider_ids")
 
 
 class MediaType(Enum):
@@ -182,7 +182,7 @@ class MediaItem(DataClassDictMixin):
         db_row = dict(db_row)
         db_row["provider"] = "database"
         for key in JSON_KEYS:
-            if key in db_row:
+            if key in db_row and db_row[key] is not None:
                 db_row[key] = json.loads(db_row[key])
         if "in_library" in db_row:
             db_row["in_library"] = bool(db_row["in_library"])
index 39ae574f643e978be170e5645908cca23b15d6fa..e87334ce3e4d88ceb53c333c7faf1f947efcaefc 100644 (file)
@@ -390,7 +390,7 @@ class FileSystemProvider(MusicProvider):
             MediaItemProviderId(provider=self.id, item_id=prov_item_id, url=filename)
         )
         playlist.owner = self._attr_name
-        playlist.checksum = os.path.getmtime(filename)
+        playlist.checksum = str(os.path.getmtime(filename))
         return playlist
 
     async def _parse_track_from_uri(self, uri):
index 254c8039f85a3ad9bd326b6b09bfd65812bdf67e..caeedf46d4deecb271bb159273a0163d68d209ad 100644 (file)
@@ -561,7 +561,9 @@ class QobuzProvider(MusicProvider):
         if track_obj.get("isrc"):
             track.isrc = track_obj["isrc"]
         if track_obj.get("performers"):
-            track.metadata.performers = track_obj["performers"]
+            track.metadata.performers = {
+                x.strip() for x in track_obj["performers"].split("-")
+            }
         if track_obj.get("copyright"):
             track.metadata.copyright = track_obj["copyright"]
         if track_obj.get("audio_info"):
@@ -620,7 +622,7 @@ class QobuzProvider(MusicProvider):
         )
         if img := self.__get_image(playlist_obj):
             playlist.metadata.images = {MediaItemImage(ImageType.THUMB, img)}
-        playlist.checksum = playlist_obj["updated_at"]
+        playlist.checksum = str(playlist_obj["updated_at"])
         return playlist
 
     async def _auth_token(self):
index dbe84b01ea9c247171d95fa4453f30f8e679fe9a..ec6f8f38e446f7773aea6a27947351d13303b811 100644 (file)
@@ -425,7 +425,7 @@ class SpotifyProvider(MusicProvider):
             playlist.metadata.images = {
                 MediaItemImage(ImageType.THUMB, playlist_obj["images"][0]["url"])
             }
-        playlist.checksum = playlist_obj["snapshot_id"]
+        playlist.checksum = str(playlist_obj["snapshot_id"])
         return playlist
 
     async def get_token(self):