fix some other matching cases
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 3 Apr 2023 20:05:11 +0000 (22:05 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 3 Apr 2023 20:05:11 +0000 (22:05 +0200)
music_assistant/server/controllers/media/albums.py
music_assistant/server/controllers/media/tracks.py
music_assistant/server/controllers/music.py
music_assistant/server/helpers/compare.py
music_assistant/server/providers/qobuz/__init__.py
music_assistant/server/providers/ytmusic/__init__.py

index 3c4faa53929bc42f85b0e0bc9448f932466ffc86..f9e57856f0391ac38fbd9fd4766b42b7b887aff0 100644 (file)
@@ -113,6 +113,7 @@ class AlbumsController(MediaControllerBase[Album]):
                 if not await self.mass.music.tracks.get_db_item_by_prov_id(
                     track.item_id, track.provider
                 ):
+                    track.album = db_item
                     await self.mass.music.tracks.add(track, skip_metadata_lookup=True)
         self.mass.signal_event(
             EventType.MEDIA_ITEM_UPDATED if existing else EventType.MEDIA_ITEM_ADDED,
index e187966fe1f25a4c60b71c38f56bd4c4ff32a1b0..47d982f0e50af4783c1906092dacd3a7386aec86 100644 (file)
@@ -227,7 +227,7 @@ class TracksController(MediaControllerBase[Track]):
                     if not search_result_item.available:
                         continue
                     # do a basic compare first
-                    if not compare_track(search_result_item, db_track):
+                    if not compare_track(search_result_item, db_track, False):
                         continue
                     # we must fetch the full version, search results are simplified objects
                     prov_track = await self.get_provider_item(
index e36b31c75b5b6d17322462d1a5ce8b4be8f4b0c2..b74aebcb403e41dc5845b01119055ae67d85e038 100755 (executable)
@@ -398,7 +398,9 @@ class MusicController:
             result = searchresult.radio
         for item in result:
             if item.available:
-                await self.get_item(item.media_type, item.item_id, item.provider, lazy=False)
+                await self.get_item(
+                    item.media_type, item.item_id, item.provider, lazy=False, add_to_db=True
+                )
         return None
 
     async def set_track_loudness(
index 2616651dcb10de461809e0fd3f50402ad45a07e2..c980d1c9671f0ba6e61a042d8ff5a499cb370483 100644 (file)
@@ -36,7 +36,13 @@ def compare_strings(str1: str, str2: str, strict: bool = True) -> bool:
     if abs(len(str1) - len(str2)) > 4:
         return False
     if not strict:
+        # handle '&' vs 'And'
+        if " & " in str1 and " and " in str2.lower():
+            str2 = str2.lower().replace(" and ", " & ")
+        elif " and " in str1.lower() and " & " in str2:
+            str2 = str2.replace(" & ", " and ")
         return create_safe_string(str1) == create_safe_string(str2)
+
     return create_sort_name(str1) == create_sort_name(str2)
 
 
@@ -231,7 +237,7 @@ def compare_album(
     return left_album.sort_name == right_album.sort_name
 
 
-def compare_track(left_track: Track, right_track: Track):
+def compare_track(left_track: Track, right_track: Track, strict: bool = True):
     """Compare two track items and return True if they match."""
     if left_track is None or right_track is None:
         return False
@@ -244,7 +250,7 @@ def compare_track(left_track: Track, right_track: Track):
     if compare_strings(left_track.musicbrainz_id, right_track.musicbrainz_id):
         return True
     # album is required for track linking
-    if left_track.album is None or right_track.album is None:
+    if strict and left_track.album is None or right_track.album is None:
         return False
     # track name must match
     if not compare_strings(left_track.name, right_track.name, False):
@@ -256,7 +262,7 @@ def compare_track(left_track: Track, right_track: Track):
     if not compare_artists(left_track.artists, right_track.artists):
         return False
     # track if both tracks are (not) explicit
-    if not compare_explicit(left_track.metadata, right_track.metadata):
+    if strict and not compare_explicit(left_track.metadata, right_track.metadata):
         return False
     # exact albumtrack match = 100% match
     if (
index 9e50a13c69f82e16995ec1f14116be716582a668..df8b9c5fcaa2e6ee833cd96df007099d19de3b59 100644 (file)
@@ -647,7 +647,7 @@ class QobuzProvider(MusicProvider):
             kwargs["user_auth_token"] = await self._auth_token()
         async with self._throttler:
             async with self.mass.http_session.get(
-                url, headers=headers, params=kwargs, ssl=False, raise_for_status=True
+                url, headers=headers, params=kwargs, ssl=False
             ) as response:
                 try:
                     result = await response.json()
index 2eeca05e9b6986f9e41a234ad417916b83ef9dc8..bb76de9fc4f472d7c304e257cd9db62dd3621469 100644 (file)
@@ -224,7 +224,10 @@ class YoutubeMusicProvider(MusicProvider):
             return []
         tracks = []
         for idx, track_obj in enumerate(album_obj["tracks"], 1):
-            track = await self._parse_track(track_obj=track_obj)
+            try:
+                track = await self._parse_track(track_obj=track_obj)
+            except InvalidDataError:
+                continue
             track.disc_number = 0
             track.track_number = idx
             tracks.append(track)
@@ -601,6 +604,8 @@ class YoutubeMusicProvider(MusicProvider):
 
     async def _parse_track(self, track_obj: dict) -> Track:
         """Parse a YT Track response to a Track model object."""
+        if not track_obj["videoId"]:
+            raise InvalidDataError("Track is missing videoId")
         track = Track(item_id=track_obj["videoId"], provider=self.domain, name=track_obj["title"])
         if "artists" in track_obj:
             track.artists = [