Fix (radio) browse listings (#1587)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 21 Aug 2024 10:19:58 +0000 (12:19 +0200)
committerGitHub <noreply@github.com>
Wed, 21 Aug 2024 10:19:58 +0000 (12:19 +0200)
music_assistant/server/models/music_provider.py
music_assistant/server/providers/radiobrowser/__init__.py

index e77b7aa764db582ecd69df9da8b8495500066734..051ee33daf50b4810fdcbf008f2f811bd3c10e8d 100644 (file)
@@ -4,7 +4,7 @@ from __future__ import annotations
 
 import asyncio
 from collections.abc import Sequence
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, cast
 
 from music_assistant.common.models.enums import CacheCategory, MediaType, ProviderFeature
 from music_assistant.common.models.errors import MediaNotFoundError, MusicAssistantError
@@ -300,15 +300,70 @@ class MusicProvider(Provider):
         subpath = path.split("://", 1)[1]
         # this reference implementation can be overridden with a provider specific approach
         if subpath == "artists":
-            return await self.mass.music.artists.library_items(provider=self.instance_id)
+            library_items = await self.mass.cache.get(
+                "artist",
+                default=[],
+                category=CacheCategory.LIBRARY_ITEMS,
+                base_key=self.instance_id,
+            )
+            library_items = cast(list[int], library_items)
+            query = "artists.item_id in :ids"
+            query_params = {"ids": library_items}
+            return await self.mass.music.artists.library_items(
+                provider=self.instance_id, extra_query=query, extra_query_params=query_params
+            )
         if subpath == "albums":
-            return await self.mass.music.albums.library_items(provider=self.instance_id)
+            library_items = await self.mass.cache.get(
+                "album",
+                default=[],
+                category=CacheCategory.LIBRARY_ITEMS,
+                base_key=self.instance_id,
+            )
+            library_items = cast(list[int], library_items)
+            query = "albums.item_id in :ids"
+            query_params = {"ids": library_items}
+            return await self.mass.music.albums.library_items(
+                extra_query=query, extra_query_params=query_params
+            )
         if subpath == "tracks":
-            return await self.mass.music.tracks.library_items(provider=self.instance_id)
+            library_items = await self.mass.cache.get(
+                "track",
+                default=[],
+                category=CacheCategory.LIBRARY_ITEMS,
+                base_key=self.instance_id,
+            )
+            library_items = cast(list[int], library_items)
+            query = "tracks.item_id in :ids"
+            query_params = {"ids": library_items}
+            return await self.mass.music.tracks.library_items(
+                extra_query=query, extra_query_params=query_params
+            )
         if subpath == "radios":
-            return await self.mass.music.radio.library_items(provider=self.instance_id)
+            library_items = await self.mass.cache.get(
+                "radio",
+                default=[],
+                category=CacheCategory.LIBRARY_ITEMS,
+                base_key=self.instance_id,
+            )
+            library_items = cast(list[int], library_items)
+            query = "radios.item_id in :ids"
+            query_params = {"ids": library_items}
+            return await self.mass.music.radio.library_items(
+                extra_query=query, extra_query_params=query_params
+            )
         if subpath == "playlists":
-            return await self.mass.music.playlists.library_items(provider=self.instance_id)
+            library_items = await self.mass.cache.get(
+                "playlist",
+                default=[],
+                category=CacheCategory.LIBRARY_ITEMS,
+                base_key=self.instance_id,
+            )
+            library_items = cast(list[int], library_items)
+            query = "playlists.item_id in :ids"
+            query_params = {"ids": library_items}
+            return await self.mass.music.playlists.library_items(
+                extra_query=query, extra_query_params=query_params
+            )
         if subpath:
             # unknown path
             msg = "Invalid subpath"
index 6ecc014188c40e6039bf64f5e1842bc00fa2883c..dde24e19ea5674b99e9cbb4951d5c419491db6f8 100644 (file)
@@ -139,8 +139,9 @@ class RadioBrowserProvider(MusicProvider):
 
         :param path: The path to browse, (e.g. provid://artists).
         """
-        subpath = path.split("://", 1)[1]
-        subsubpath = "" if "/" not in subpath else subpath.split("/")[-1]
+        part_parts = path.split("://")[1].split("/")
+        subpath = part_parts[0] if part_parts else ""
+        subsubpath = part_parts[1] if len(part_parts) > 1 else ""
 
         if not subpath:
             # return main listing
@@ -171,50 +172,18 @@ class RadioBrowserProvider(MusicProvider):
         if subpath == "popular":
             return await self.get_by_popularity()
 
+        if subpath == "tag" and subsubpath:
+            return await self.get_by_tag(subsubpath)
+
         if subpath == "tag":
-            tags = await self.radios.tags(
-                hide_broken=True,
-                order=Order.STATION_COUNT,
-                reverse=True,
-            )
-            tags.sort(key=lambda tag: tag.name)
-            return [
-                BrowseFolder(
-                    item_id=tag.name.lower(),
-                    provider=self.domain,
-                    path=path + "/" + tag.name.lower(),
-                    name=tag.name,
-                )
-                for tag in tags
-            ]
+            return await self.get_tag_folders(path)
 
-        if subpath == "country":
-            items: list[BrowseFolder | Radio] = []
-            for country in await self.radios.countries(order=Order.NAME, hide_broken=True):
-                folder = BrowseFolder(
-                    item_id=country.code.lower(),
-                    provider=self.domain,
-                    path=path + "/" + country.code.lower(),
-                    name=country.name,
-                )
-                folder.metadata.images = UniqueList(
-                    [
-                        MediaItemImage(
-                            type=ImageType.THUMB,
-                            path=country.favicon,
-                            provider=self.lookup_key,
-                            remotely_accessible=True,
-                        )
-                    ]
-                )
-                items.append(folder)
-            return items
+        if subpath == "country" and subsubpath:
+            return await self.get_by_country(subsubpath)
 
-        if subsubpath in await self.get_tag_names():
-            return await self.get_by_tag(subsubpath)
+        if subpath == "country":
+            return await self.get_country_folders(path)
 
-        if subsubpath in await self.get_country_codes():
-            return await self.get_by_country(subsubpath)
         return []
 
     async def get_library_radios(self) -> AsyncGenerator[Radio, None]:
@@ -254,28 +223,47 @@ class RadioBrowserProvider(MusicProvider):
         return True
 
     @use_cache(3600 * 24)
-    async def get_tag_names(self) -> Sequence[str]:
-        """Get a list of tag names."""
+    async def get_tag_folders(self, base_path: str) -> list[BrowseFolder]:
+        """Get a list of tag names as BrowseFolder."""
         tags = await self.radios.tags(
             hide_broken=True,
-            limit=10000,
             order=Order.STATION_COUNT,
             reverse=True,
         )
         tags.sort(key=lambda tag: tag.name)
-        tag_names = []
-        for tag in tags:
-            tag_names.append(tag.name.lower())
-        return tag_names
+        return [
+            BrowseFolder(
+                item_id=tag.name.lower(),
+                provider=self.domain,
+                path=base_path + "/" + tag.name.lower(),
+                name=tag.name,
+            )
+            for tag in tags
+        ]
 
     @use_cache(3600 * 24)
-    async def get_country_codes(self) -> Sequence[str]:
-        """Get a list of country names."""
-        countries = await self.radios.countries(order=Order.NAME, hide_broken=True)
-        country_codes = []
-        for country in countries:
-            country_codes.append(country.code.lower())
-        return country_codes
+    async def get_country_folders(self, base_path: str) -> list[BrowseFolder]:
+        """Get a list of country names as BrowseFolder."""
+        items: list[BrowseFolder] = []
+        for country in await self.radios.countries(order=Order.NAME, hide_broken=True):
+            folder = BrowseFolder(
+                item_id=country.code.lower(),
+                provider=self.domain,
+                path=base_path + "/" + country.code.lower(),
+                name=country.name,
+            )
+            folder.metadata.images = UniqueList(
+                [
+                    MediaItemImage(
+                        type=ImageType.THUMB,
+                        path=country.favicon,
+                        provider=self.lookup_key,
+                        remotely_accessible=True,
+                    )
+                ]
+            )
+            items.append(folder)
+        return items
 
     @use_cache(3600)
     async def get_by_popularity(self) -> Sequence[Radio]: