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.media_items import MediaItem, MediaItemType
+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
from music_assistant.music_providers.qobuz import QobuzProvider
:param limit: number of items to return in the search (per type).
"""
# include results from all music providers
- provider_ids = ["database"] + [item.id for item in self.providers]
+ provider_ids = [item.id for item in self.providers]
# TODO: sort by name and filter out duplicates ?
return await asyncio.gather(
*[
:param media_types: A list of media_types to include. All types if None.
:param limit: number of items to return in the search (per type).
"""
- if provider == ProviderType.DATABASE or provider_id == "database":
- # get results from database
- return (
- await self.artists.search(search_query, provider, provider_id, limit)
- + await self.albums.search(search_query, provider, provider_id, limit)
- + await self.tracks.search(search_query, provider, provider_id, limit)
- + await self.playlists.search(
- search_query, provider, provider_id, limit
- )
- + await self.radio.search(search_query, provider, provider_id, limit)
+ assert provider or provider_id, "Provider needs to be supplied"
+ prov = self.get_provider(provider_id or provider)
+ await provider.search(search_query, media_types, limit)
+
+ # create safe search string
+ search_query = search_query.replace("/", " ").replace("'", "")
+
+ # prefer cache items (if any)
+ cache_key = f"{prov.type.value}.search.{search_query}.{limit}"
+ cache_key += "".join(media_types)
+
+ if cache := await self.mass.cache.get(cache_key):
+ return [media_from_dict(x) for x in cache]
+ # no items in cache - get listing from provider
+ items = await prov.search(
+ search_query,
+ media_types,
+ limit,
+ )
+ # store (serializable items) in cache
+ self.mass.create_task(
+ self.mass.cache.set(
+ cache_key, [x.to_dict() for x in items], expiration=86400 * 7
)
- provider = self.get_provider(provider_id or provider)
- return await provider.search(search_query, media_types, limit)
+ )
+ return items
async def get_item_by_uri(
self, uri: str, force_refresh: bool = False, lazy: bool = True
limit: int = 25,
) -> List[ItemCls]:
"""Search database or provider with given query."""
- search_query = search_query.replace("/", " ").replace(
- "'", ""
- ) # safe search string
+ # create safe search string
+ search_query = search_query.replace("/", " ").replace("'", "")
if provider == ProviderType.DATABASE or provider_id == "database":
return [
self.item_cls.from_db_row(db_row)
return {}
# prefer cache items (if any)
- cache_key = f"{prov.type.value}.search.{self.media_type.value}"
+ cache_key = (
+ f"{prov.type.value}.search.{self.media_type.value}.{search_query}.{limit}"
+ )
if cache := await self.mass.cache.get(cache_key):
return [self.media_type.from_dict(x) for x in cache]
# no items in cache - get listing from provider
)
# store (serializable items) in cache
self.mass.create_task(
- self.mass.cache.set(cache_key, [x.to_dict() for x in items])
+ self.mass.cache.set(
+ cache_key, [x.to_dict() for x in items], expiration=86400 * 7
+ )
)
return items
MediaItemType = Union[Artist, Album, Track, Radio, Playlist]
+def media_from_dict(media_item: dict) -> MediaItemType:
+ """Return MediaItem from dict."""
+ if media_item["media_type"] == "artist":
+ return Artist.from_dict(media_item)
+ if media_item["media_type"] == "album":
+ return Album.from_dict(media_item)
+ if media_item["media_type"] == "track":
+ return Track.from_dict(media_item)
+ if media_item["media_type"] == "playlist":
+ return Playlist.from_dict(media_item)
+ if media_item["media_type"] == "radio":
+ return Radio.from_dict(media_item)
+ return MediaItem.from_dict(media_item)
+
+
@dataclass
class StreamDetails(DataClassDictMixin):
"""Model for streamdetails."""