A few small optimizations and bugfixes (#1301)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 13 May 2024 18:48:56 +0000 (20:48 +0200)
committerGitHub <noreply@github.com>
Mon, 13 May 2024 18:48:56 +0000 (20:48 +0200)
music_assistant/server/helpers/tags.py
music_assistant/server/helpers/throttle_retry.py
music_assistant/server/providers/builtin/__init__.py
music_assistant/server/providers/builtin/manifest.json
music_assistant/server/providers/qobuz/__init__.py

index 66fa6838527098fea46f5e567687cabe47b40cbc..dc38e4c02f26d6de1b54f2ba0069ec2198df7d46 100644 (file)
@@ -45,13 +45,17 @@ def split_items(org_str: str, allow_unsafe_splitters: bool = False) -> tuple[str
     return (org_str.strip(),)
 
 
-def split_artists(org_artists: str | tuple[str, ...]) -> tuple[str, ...]:
+def split_artists(
+    org_artists: str | tuple[str, ...], allow_ampersand: bool = False
+) -> tuple[str, ...]:
     """Parse all artists from a string."""
     final_artists = set()
     # when not using the multi artist tag, the artist string may contain
     # multiple artists in freeform, even featuring artists may be included in this
     # string. Try to parse the featuring artists and separate them.
-    splitters = ("featuring", " feat. ", " feat ", "feat.")
+    splitters = ("featuring", " feat. ", " feat ", "feat.", " & ")
+    if allow_ampersand:
+        splitters = (*splitters, " & ")
     for item in split_items(org_artists):
         for splitter in splitters:
             for subitem in item.split(splitter):
@@ -117,6 +121,10 @@ class AudioTags:
         if tag := self.tags.get("artist"):
             if TAG_SPLITTER in tag:
                 return split_items(tag)
+            if len(self.musicbrainz_artistids) > 1:
+                # special case: artist noted as 2 artists with ampersand
+                # but with 2 mb ids so they should be treated as 2 artists
+                return split_artists(tag, allow_ampersand=True)
             return split_artists(tag)
         # fallback to parsing from filename
         title = self.filename.rsplit(os.sep, 1)[-1].split(".")[0]
@@ -136,6 +144,11 @@ class AudioTags:
         if tag := self.tags.get("albumartist"):
             if TAG_SPLITTER in tag:
                 return split_items(tag)
+            if len(self.musicbrainz_albumartistids) > 1:
+                # special case: album artist noted as 2 artists with ampersand
+                # but with 2 mb ids so they should be treated as 2 artists
+                # example: John Travolta & Olivia Newton John on the Grease album
+                return split_artists(tag, allow_ampersand=True)
             return split_artists(tag)
         return ()
 
index 890e2523d09b23b23fc12c636988fe173147d83e..89b6f6bd74b9a6364ec783d479194cc4e620705b 100644 (file)
@@ -44,9 +44,10 @@ class ThrottlerManager(Throttler):
             except ResourceTemporarilyUnavailable as e:
                 if e.backoff_time:
                     backoff_time = e.backoff_time
-                LOGGER.info(f"Attempt {attempt + 1}/{self.retry_attempts} failed: {e}")
+                level = logging.DEBUG if attempt > 1 else logging.INFO
+                LOGGER.log(level, f"Attempt {attempt + 1}/{self.retry_attempts} failed: {e}")
                 if attempt < self.retry_attempts - 1:
-                    LOGGER.info(f"Retrying in {backoff_time} seconds...")
+                    LOGGER.log(level, f"Retrying in {backoff_time} seconds...")
                     await asyncio.sleep(backoff_time)
                     backoff_time *= 2
         else:  # noqa: PLW0120
index 009e8905535425b6e038705e6c56c6dd6d7a297f..3735afdb1de19908a784b6a66e1b08b185c1f076 100644 (file)
@@ -316,7 +316,7 @@ class BuiltinProvider(MusicProvider):
             return False
         stored_item = StoredItem(item_id=item.item_id, name=item.name)
         if item.image:
-            stored_item["image_url"] = item.image
+            stored_item["image_url"] = item.image.path
         stored_items: list[StoredItem] = self.mass.config.get(key, [])
         # filter out existing
         stored_items = [x for x in stored_items if x["item_id"] != item.item_id]
index d451eee2b847d6116f6af217e5329b37ca58ae61..4ca5046eedd763665aecfd043a9ecce07ce7f930 100644 (file)
@@ -2,7 +2,7 @@
   "type": "music",
   "domain": "builtin",
   "name": "Music Assistant",
-  "description": "Built-in/generic provider to handle media from files and (remote) urls.",
+  "description": "Built-in/generic provider that handles generic urls and playlists.",
   "codeowners": [
     "@music-assistant"
   ],
index 178cd4b69b7ed8e997154085b7add2268a7affb6..8e9a29bf768daaa95960494ce1d284e1405ee4a2 100644 (file)
@@ -5,6 +5,7 @@ from __future__ import annotations
 import datetime
 import hashlib
 import time
+from contextlib import suppress
 from typing import TYPE_CHECKING
 
 from music_assistant.common.helpers.json import json_loads
@@ -555,8 +556,9 @@ class QobuzProvider(MusicProvider):
             ]
         if "label" in album_obj:
             album.metadata.label = album_obj["label"]["name"]
-        if (released_at := album_obj.get("released_at")) and released_at != 0:
-            album.year = datetime.datetime.fromtimestamp(album_obj["released_at"]).year
+        if released_at := album_obj.get("released_at"):
+            with suppress(ValueError):
+                album.year = datetime.datetime.fromtimestamp(released_at).year
         if album_obj.get("copyright"):
             album.metadata.copyright = album_obj["copyright"]
         if album_obj.get("description"):