Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mapping and database issues #395

Merged
merged 13 commits into from
Jul 4, 2022
Prev Previous commit
Next Next commit
fixes
marcelveldt committed Jul 4, 2022
commit 6cfc91b1b9bb42bc6b789f4b65070ecffe9222c2
10 changes: 3 additions & 7 deletions music_assistant/controllers/metadata/__init__.py
Original file line number Diff line number Diff line change
@@ -111,14 +111,12 @@ async def get_playlist_metadata(self, playlist: Playlist) -> None:

async def get_radio_metadata(self, radio: Radio) -> None:
"""Get/update rich metadata for a radio station."""
# NOTE: we do not have any metadata for radiso so consider this future proofing ;-)
# NOTE: we do not have any metadata for radio so consider this future proofing ;-)
radio.metadata.last_refresh = int(time())

async def get_artist_musicbrainz_id(self, artist: Artist) -> str | None:
"""Fetch musicbrainz id by performing search using the artist name, albums and tracks."""
ref_albums = await self.mass.music.artists.get_provider_artist_albums(
artist.item_id, artist.provider
)
ref_albums = await self.mass.music.artists.albums(artist=artist)
# first try audiodb
if musicbrainz_id := await self.audiodb.get_musicbrainz_id(artist, ref_albums):
return musicbrainz_id
@@ -137,9 +135,7 @@ async def get_artist_musicbrainz_id(self, artist: Artist) -> str | None:
return musicbrainz_id

# try again with matching on track isrc
ref_tracks = await self.mass.music.artists.toptracks(
artist.item_id, artist.provider
)
ref_tracks = await self.mass.music.artists.toptracks(artist=artist)
for ref_track in ref_tracks:
for isrc in ref_track.isrcs:
if musicbrainz_id := await self.musicbrainz.get_mb_artist_id(
3 changes: 2 additions & 1 deletion music_assistant/controllers/metadata/audiodb.py
Original file line number Diff line number Diff line change
@@ -166,7 +166,8 @@ async def get_musicbrainz_id(
musicbrainz_id = None
if data := await self._get_data("searchalbum.php", s=artist.name):
# NOTE: object is 'null' when no records found instead of empty array
for item in data.get("album", []) or []:
albums = data.get("album") or []
for item in albums:
if not compare_strings(item["strArtistStripped"], artist.name):
continue
for ref_album in ref_albums:
13 changes: 7 additions & 6 deletions music_assistant/controllers/music/__init__.py
Original file line number Diff line number Diff line change
@@ -19,7 +19,11 @@
from music_assistant.helpers.uri import parse_uri
from music_assistant.models.config import MusicProviderConfig
from music_assistant.models.enums import MediaType, ProviderType
from music_assistant.models.errors import MusicAssistantError, SetupFailedError
from music_assistant.models.errors import (
MusicAssistantError,
ProviderUnavailableError,
SetupFailedError,
)
from music_assistant.models.media_items import MediaItem, MediaItemType, media_from_dict
from music_assistant.models.music_provider import MusicProvider
from music_assistant.music_providers.filesystem import FileSystemProvider
@@ -109,17 +113,14 @@ def providers(self) -> Tuple[MusicProvider]:
"""Return all (available) music providers."""
return tuple(x for x in self._providers.values() if x.available)

def get_provider(
self, provider_id: Union[str, ProviderType]
) -> MusicProvider | None:
def get_provider(self, provider_id: Union[str, ProviderType]) -> MusicProvider:
"""Return Music provider by id (or type)."""
if prov := self._providers.get(provider_id):
return prov
for prov in self._providers.values():
if provider_id in (prov.type, prov.id, prov.type.value):
return prov
self.logger.warning("Provider %s is not available", provider_id)
return None
raise ProviderUnavailableError(f"Provider {provider_id} is not available")

async def search(
self, search_query, media_types: List[MediaType], limit: int = 10
2 changes: 1 addition & 1 deletion music_assistant/controllers/music/albums.py
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ async def tracks(
db_album = await self.get_db_item(item_id)
coros = [
self.get_provider_album_tracks(
item.item_id, item.prov_id, cache_checksum=db_album.metadata.checksum
item.item_id, item.prov_type, cache_checksum=db_album.metadata.checksum
)
for item in db_album.provider_ids
]
29 changes: 21 additions & 8 deletions music_assistant/controllers/music/artists.py
Original file line number Diff line number Diff line change
@@ -31,16 +31,21 @@ class ArtistsController(MediaControllerBase[Artist]):

async def toptracks(
self,
item_id: str,
item_id: Optional[str] = None,
provider: Optional[ProviderType] = None,
provider_id: Optional[str] = None,
artist: Optional[Artist] = None,
) -> List[Track]:
"""Return top tracks for an artist."""
artist = await self.get(item_id, provider, provider_id)
if not artist:
artist = await self.get(item_id, provider, provider_id)
# get results from all providers
coros = [
self.get_provider_artist_toptracks(
item.item_id, item.prov_id, cache_checksum=artist.metadata.checksum
item.item_id,
provider=item.prov_type,
provider_id=item.prov_id,
cache_checksum=artist.metadata.checksum,
)
for item in artist.provider_ids
]
@@ -57,15 +62,19 @@ async def toptracks(

async def albums(
self,
item_id: str,
item_id: Optional[str] = None,
provider: Optional[ProviderType] = None,
provider_id: Optional[str] = None,
artist: Optional[Artist] = None,
) -> List[Album]:
"""Return (all/most popular) albums for an artist."""
artist = await self.get(item_id, provider, provider_id)
if not artist:
artist = await self.get(item_id, provider, provider_id)
# get results from all providers
coros = [
self.get_provider_artist_albums(item.item_id, item.prov_id)
self.get_provider_artist_albums(
item.item_id, item.prov_type, cache_checksum=artist.metadata.checksum
)
for item in artist.provider_ids
]
albums = itertools.chain.from_iterable(await asyncio.gather(*coros))
@@ -271,7 +280,9 @@ async def _match(self, db_artist: Artist, provider: MusicProvider) -> bool:
"Trying to match artist %s on provider %s", db_artist.name, provider.name
)
# try to get a match with some reference tracks of this artist
for ref_track in await self.toptracks(db_artist.item_id, db_artist.provider):
for ref_track in await self.toptracks(
db_artist.item_id, db_artist.provider, artist=db_artist
):
# make sure we have a full track
if isinstance(ref_track.album, ItemMapping):
ref_track = await self.mass.music.tracks.get(
@@ -300,7 +311,9 @@ async def _match(self, db_artist: Artist, provider: MusicProvider) -> bool:
await self.update_db_item(db_artist.item_id, prov_artist)
return True
# try to get a match with some reference albums of this artist
artist_albums = await self.albums(db_artist.item_id, db_artist.provider)
artist_albums = await self.albums(
db_artist.item_id, db_artist.provider, artist=db_artist
)
for ref_album in artist_albums:
if ref_album.album_type == AlbumType.COMPILATION:
continue
6 changes: 4 additions & 2 deletions music_assistant/helpers/cache.py
Original file line number Diff line number Diff line change
@@ -136,8 +136,10 @@ async def wrapped(*args, **kwargs):
if not skip_cache and cachedata is not None:
return cachedata
result = await func(*args, **kwargs)
await method_class.cache.set(
cache_key, result, expiration=expiration, checksum=cache_checksum
asyncio.create_task(
method_class.cache.set(
cache_key, result, expiration=expiration, checksum=cache_checksum
)
)
return result

6 changes: 1 addition & 5 deletions music_assistant/models/media_controller.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@

from databases import Database as Db

from music_assistant.models.errors import MediaNotFoundError, ProviderUnavailableError
from music_assistant.models.errors import MediaNotFoundError
from music_assistant.models.event import MassEvent

from .enums import EventType, MediaType, ProviderType
@@ -360,10 +360,6 @@ async def get_provider_item(
item = await self.get_db_item(item_id)
else:
provider = self.mass.music.get_provider(provider_id)
if not provider:
raise ProviderUnavailableError(
f"Provider {provider_id} is not available!"
)
item = await provider.get_item(self.media_type, item_id)
if not item:
raise MediaNotFoundError(