fix global search caching
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 23 Jun 2022 13:41:57 +0000 (15:41 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 23 Jun 2022 13:41:57 +0000 (15:41 +0200)
music_assistant/controllers/music/__init__.py
music_assistant/models/media_controller.py
music_assistant/models/media_items.py

index 8f6a4d88245c020a15e32be5833d311108eda2d0..786a348d24df6993e929190e12c7c0c76ffc1f0c 100755 (executable)
@@ -20,7 +20,7 @@ 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.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
@@ -132,7 +132,7 @@ class MusicController:
             :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(
             *[
@@ -159,19 +159,32 @@ class MusicController:
             :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
index 0e436b736f50039b77ec27b3f1684da17a1cb7a7..fc7f5e04441a2d7974b76761676bbc1ddc8b34e1 100644 (file)
@@ -144,9 +144,8 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         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)
@@ -160,7 +159,9 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
             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
@@ -171,7 +172,9 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         )
         # 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
 
index 0a075dfde4d56da41ae2b53f47724b6e96b6ef9a..7b89b001a74f2b9097f8d5194f2e5f0bf1e69ef5 100755 (executable)
@@ -344,6 +344,21 @@ class Radio(MediaItem):
 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."""