From 37020535e3cc626a7396f5de1cabc97297867eb8 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Mon, 13 May 2024 20:48:56 +0200 Subject: [PATCH] A few small optimizations and bugfixes (#1301) --- music_assistant/server/helpers/tags.py | 17 +++++++++++++++-- .../server/helpers/throttle_retry.py | 5 +++-- .../server/providers/builtin/__init__.py | 2 +- .../server/providers/builtin/manifest.json | 2 +- .../server/providers/qobuz/__init__.py | 6 ++++-- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/music_assistant/server/helpers/tags.py b/music_assistant/server/helpers/tags.py index 66fa6838..dc38e4c0 100644 --- a/music_assistant/server/helpers/tags.py +++ b/music_assistant/server/helpers/tags.py @@ -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 () diff --git a/music_assistant/server/helpers/throttle_retry.py b/music_assistant/server/helpers/throttle_retry.py index 890e2523..89b6f6bd 100644 --- a/music_assistant/server/helpers/throttle_retry.py +++ b/music_assistant/server/helpers/throttle_retry.py @@ -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 diff --git a/music_assistant/server/providers/builtin/__init__.py b/music_assistant/server/providers/builtin/__init__.py index 009e8905..3735afdb 100644 --- a/music_assistant/server/providers/builtin/__init__.py +++ b/music_assistant/server/providers/builtin/__init__.py @@ -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] diff --git a/music_assistant/server/providers/builtin/manifest.json b/music_assistant/server/providers/builtin/manifest.json index d451eee2..4ca5046e 100644 --- a/music_assistant/server/providers/builtin/manifest.json +++ b/music_assistant/server/providers/builtin/manifest.json @@ -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" ], diff --git a/music_assistant/server/providers/qobuz/__init__.py b/music_assistant/server/providers/qobuz/__init__.py index 178cd4b6..8e9a29bf 100644 --- a/music_assistant/server/providers/qobuz/__init__.py +++ b/music_assistant/server/providers/qobuz/__init__.py @@ -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"): -- 2.34.1