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,
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(
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(
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)
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
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):
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 (
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()
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)
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 = [