fix some remaining queries
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 21 Aug 2024 11:01:39 +0000 (13:01 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 21 Aug 2024 11:01:39 +0000 (13:01 +0200)
music_assistant/client/music.py
music_assistant/server/controllers/media/albums.py
music_assistant/server/controllers/media/artists.py
music_assistant/server/controllers/media/base.py
music_assistant/server/controllers/media/tracks.py

index be70dbd9a038a3c4f51beee9cf91d2e070eb1098..797c10a5946887feede41c322ce16a69ca1fefdc 100644 (file)
@@ -5,7 +5,7 @@ from __future__ import annotations
 import urllib.parse
 from typing import TYPE_CHECKING, cast
 
-from music_assistant.common.models.enums import ImageType, MediaType
+from music_assistant.common.models.enums import AlbumType, ImageType, MediaType
 from music_assistant.common.models.media_items import (
     Album,
     Artist,
@@ -124,6 +124,7 @@ class Music:
         limit: int | None = None,
         offset: int | None = None,
         order_by: str | None = None,
+        album_types: list[AlbumType] | None = None,
     ) -> list[Album]:
         """Get Albums listing from the server."""
         return [
@@ -135,6 +136,7 @@ class Music:
                 limit=limit,
                 offset=offset,
                 order_by=order_by,
+                album_types=album_types,
             )
         ]
 
index bbd79a38763047d06229cb5c1df9430940ce2408..189c9e22bd68b53ffff0779843e9032faf3ff842 100644 (file)
@@ -103,6 +103,98 @@ class AlbumsController(MediaControllerBase[Album]):
         album.artists = album_artists
         return album
 
+    async def library_items(
+        self,
+        favorite: bool | None = None,
+        search: str | None = None,
+        limit: int = 500,
+        offset: int = 0,
+        order_by: str = "sort_name",
+        provider: str | None = None,
+        extra_query: str | None = None,
+        extra_query_params: dict[str, Any] | None = None,
+        album_types: list[AlbumType] | None = None,
+    ) -> list[Artist]:
+        """Get in-database albums."""
+        extra_query_params: dict[str, Any] = extra_query_params or {}
+        extra_query_parts: list[str] = [extra_query] if extra_query else []
+        extra_join_parts: list[str] = []
+        # optional album type filter
+        if album_types:
+            extra_query_parts.append("albums.album_type IN :album_types")
+            extra_query_params["album_types"] = [x.value for x in album_types]
+        if order_by and "artist_name" in order_by:
+            # join artist table to allow sorting on artist name
+            extra_join_parts.append(
+                "JOIN album_artists ON album_artists.album_id = albums.item_id "
+                "JOIN artists ON artists.item_id = album_artists.artist_id "
+            )
+            artist_table_joined = True
+        if search and " - " in search:
+            # handle combined artist + title search
+            artist_str, title_str = search.split(" - ", 1)
+            search = None
+            extra_query_parts.append("albums.name LIKE :search_title")
+            extra_query_params["search_title"] = f"%{title_str}%"
+            # use join with artists table to filter on artist name
+            extra_join_parts.append(
+                "JOIN album_artists ON album_artists.album_id = albums.item_id "
+                "JOIN artists ON artists.item_id = album_artists.artist_id "
+                "AND artists.name LIKE :search_artist"
+                if not artist_table_joined
+                else "AND artists.name LIKE :search_artist"
+            )
+            artist_table_joined = True
+            extra_query_params["search_artist"] = f"%{artist_str}%"
+        result = await self._get_library_items_by_query(
+            favorite=favorite,
+            search=search,
+            limit=limit,
+            offset=offset,
+            order_by=order_by,
+            provider=provider,
+            extra_query_parts=extra_query_parts,
+            extra_query_params=extra_query_params,
+            extra_join_parts=extra_join_parts,
+        )
+        if search and len(result) < 25 and not offset:
+            # append artist items to result
+            extra_join_parts.append(
+                "JOIN album_artists ON album_artists.album_id = albums.item_id "
+                "JOIN artists ON artists.item_id = album_artists.artist_id "
+                "AND artists.name LIKE :search_artist"
+                if not artist_table_joined
+                else "AND artists.name LIKE :search_artist"
+            )
+            extra_query_params["search_artist"] = f"%{search}%"
+            return result + await self._get_library_items_by_query(
+                favorite=favorite,
+                search=None,
+                limit=limit,
+                order_by=order_by,
+                provider=provider,
+                extra_query_parts=extra_query_parts,
+                extra_query_params=extra_query_params,
+                extra_join_parts=extra_join_parts,
+            )
+        return result
+
+    async def library_count(
+        self, favorite_only: bool = False, album_types: list[AlbumType] | None = None
+    ) -> int:
+        """Return the total number of items in the library."""
+        sql_query = f"SELECT item_id FROM {self.db_table}"
+        query_parts: list[str] = []
+        query_params: dict[str, Any] = {}
+        if favorite_only:
+            query_parts.append("favorite = 1")
+        if album_types:
+            query_parts.append("albums.album_type IN :album_types")
+            query_params["album_types"] = [x.value for x in album_types]
+        if query_parts:
+            sql_query += f" WHERE {' AND '.join(query_parts)}"
+        return await self.mass.music.database.get_count_from_query(sql_query, query_params)
+
     async def remove_item_from_library(self, item_id: str | int) -> None:
         """Delete record from the database."""
         db_id = int(item_id)  # ensure integer
@@ -451,76 +543,3 @@ class AlbumsController(MediaControllerBase[Album]):
                     db_album.name,
                     provider.name,
                 )
-
-    async def _get_library_items_by_query(
-        self,
-        favorite: bool | None = None,
-        search: str | None = None,
-        limit: int = 500,
-        offset: int = 0,
-        order_by: str | None = None,
-        provider: str | None = None,
-        extra_query_parts: list[str] | None = None,
-        extra_query_params: dict[str, Any] | None = None,
-        extra_join_parts: list[str] | None = None,
-    ) -> list[Album]:
-        """Fetch MediaItem records from database by building the query."""
-        extra_query_params = extra_query_params or {}
-        extra_query_parts: list[str] = extra_query_parts or []
-        extra_join_parts: list[str] = extra_join_parts or []
-        artist_table_joined = False
-        if order_by and "artist_name" in order_by:
-            # join artist table to allow sorting on artist name
-            extra_join_parts.append(
-                "JOIN album_artists ON album_artists.album_id = albums.item_id "
-                "JOIN artists ON artists.item_id = album_artists.artist_id "
-            )
-            artist_table_joined = True
-        if search and " - " in search:
-            # handle combined artist + title search
-            artist_str, title_str = search.split(" - ", 1)
-            search = None
-            extra_query_parts.append("albums.name LIKE :search_title")
-            extra_query_params["search_title"] = f"%{title_str}%"
-            # use join with artists table to filter on artist name
-            extra_join_parts.append(
-                "JOIN album_artists ON album_artists.album_id = albums.item_id "
-                "JOIN artists ON artists.item_id = album_artists.artist_id "
-                "AND artists.name LIKE :search_artist"
-                if not artist_table_joined
-                else "AND artists.name LIKE :search_artist"
-            )
-            artist_table_joined = True
-            extra_query_params["search_artist"] = f"%{artist_str}%"
-        result = await super()._get_library_items_by_query(
-            favorite=favorite,
-            search=search,
-            limit=limit,
-            offset=offset,
-            order_by=order_by,
-            provider=provider,
-            extra_query_parts=extra_query_parts,
-            extra_query_params=extra_query_params,
-            extra_join_parts=extra_join_parts,
-        )
-        if search and len(result) < 25 and not offset:
-            # append artist items to result
-            extra_join_parts.append(
-                "JOIN album_artists ON album_artists.album_id = albums.item_id "
-                "JOIN artists ON artists.item_id = album_artists.artist_id "
-                "AND artists.name LIKE :search_artist"
-                if not artist_table_joined
-                else "AND artists.name LIKE :search_artist"
-            )
-            extra_query_params["search_artist"] = f"%{search}%"
-            return result + await super()._get_library_items_by_query(
-                favorite=favorite,
-                search=None,
-                limit=limit,
-                order_by=order_by,
-                provider=provider,
-                extra_query_parts=extra_query_parts,
-                extra_query_params=extra_query_params,
-                extra_join_parts=extra_join_parts,
-            )
-        return result
index 0238381ba42dad377b2029bfd651a24a00fff910..b6ba3fdc02b2d6574c497c1105f44c5a24c8c457 100644 (file)
@@ -83,20 +83,21 @@ class ArtistsController(MediaControllerBase[Artist]):
         album_artists_only: bool = False,
     ) -> list[Artist]:
         """Get in-database (album) artists."""
+        extra_query_params: dict[str, Any] = extra_query_params or {}
+        extra_query_parts: list[str] = [extra_query] if extra_query else []
         if album_artists_only:
-            artist_query = (
+            extra_query_parts.append(
                 f"artists.item_id in (select {DB_TABLE_ALBUM_ARTISTS}.artist_id "
                 f"from {DB_TABLE_ALBUM_ARTISTS})"
             )
-            extra_query = f"{extra_query} AND {artist_query}" if extra_query else artist_query
-        return await super().library_items(
+        return await self._get_library_items_by_query(
             favorite=favorite,
             search=search,
             limit=limit,
             offset=offset,
             order_by=order_by,
             provider=provider,
-            extra_query=extra_query,
+            extra_query_parts=extra_query_parts,
             extra_query_params=extra_query_params,
         )
 
index 17f984a5eac50ea13a050c649dd828a1192b3d1a..222e6d3cdfdb209dd29743bfd49ab452b63ec8a3 100644 (file)
@@ -235,6 +235,7 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         favorite: bool | None = None,
         search: str | None = None,
         order_by: str = "sort_name",
+        provider: str | None = None,
         extra_query: str | None = None,
         extra_query_params: dict[str, Any] | None = None,
     ) -> AsyncGenerator[ItemCls, None]:
@@ -242,13 +243,14 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         limit: int = 500
         offset: int = 0
         while True:
-            next_items = await self._get_library_items_by_query(
+            next_items = await self.library_items(
                 favorite=favorite,
                 search=search,
                 limit=limit,
                 offset=offset,
                 order_by=order_by,
-                extra_query_parts=[extra_query] if extra_query else None,
+                provider=provider,
+                extra_query=extra_query,
                 extra_query_params=extra_query_params,
             )
             for item in next_items:
index 16e59b0c45a70cace75c6225e58ed565bc95240c..377515f4ce4404214a3e3af45a944f7d343c2908 100644 (file)
@@ -148,6 +148,65 @@ class TracksController(MediaControllerBase[Track]):
         track.artists = track_artists
         return track
 
+    async def library_items(
+        self,
+        favorite: bool | None = None,
+        search: str | None = None,
+        limit: int = 500,
+        offset: int = 0,
+        order_by: str = "sort_name",
+        provider: str | None = None,
+        extra_query: str | None = None,
+        extra_query_params: dict[str, Any] | None = None,
+    ) -> list[Track]:
+        """Get in-database tracks."""
+        extra_query_params: dict[str, Any] = extra_query_params or {}
+        extra_query_parts: list[str] = [extra_query] if extra_query else []
+        extra_join_parts: list[str] = []
+        if search and " - " in search:
+            # handle combined artist + title search
+            artist_str, title_str = search.split(" - ", 1)
+            search = None
+            extra_query_parts.append("tracks.name LIKE :search_title")
+            extra_query_params["search_title"] = f"%{title_str}%"
+            # use join with artists table to filter on artist name
+            extra_join_parts.append(
+                "JOIN track_artists ON track_artists.track_id = tracks.item_id "
+                "JOIN artists ON artists.item_id = track_artists.artist_id "
+                "AND artists.name LIKE :search_artist"
+            )
+            extra_query_params["search_artist"] = f"%{artist_str}%"
+        result = await self._get_library_items_by_query(
+            favorite=favorite,
+            search=search,
+            limit=limit,
+            offset=offset,
+            order_by=order_by,
+            provider=provider,
+            extra_query_parts=extra_query_parts,
+            extra_query_params=extra_query_params,
+            extra_join_parts=extra_join_parts,
+        )
+        if search and len(result) < 25 and not offset:
+            # append artist items to result
+            extra_join_parts.append(
+                "JOIN track_artists ON track_artists.track_id = tracks.item_id "
+                "JOIN artists ON artists.item_id = track_artists.artist_id "
+                "AND artists.name LIKE :search_artist"
+            )
+            extra_query_params["search_artist"] = f"%{search}%"
+            return result + await self._get_library_items_by_query(
+                favorite=favorite,
+                search=None,
+                limit=limit,
+                order_by=order_by,
+                provider=provider,
+                extra_query_parts=extra_query_parts,
+                extra_query_params=extra_query_params,
+                extra_join_parts=extra_join_parts,
+            )
+        return result
+
     async def versions(
         self,
         item_id: str,
@@ -523,63 +582,3 @@ class TracksController(MediaControllerBase[Track]):
             },
         )
         return ItemMapping.from_item(db_artist)
-
-    async def _get_library_items_by_query(
-        self,
-        favorite: bool | None = None,
-        search: str | None = None,
-        limit: int = 500,
-        offset: int = 0,
-        order_by: str | None = None,
-        provider: str | None = None,
-        extra_query_parts: list[str] | None = None,
-        extra_query_params: dict[str, Any] | None = None,
-        extra_join_parts: list[str] | None = None,
-    ) -> list[Track]:
-        """Fetch MediaItem records from database by building the query."""
-        extra_query_params = extra_query_params or {}
-        extra_query_parts: list[str] = extra_query_parts or []
-        extra_join_parts: list[str] = extra_join_parts or []
-        if search and " - " in search:
-            # handle combined artist + title search
-            artist_str, title_str = search.split(" - ", 1)
-            search = None
-            extra_query_parts.append("tracks.name LIKE :search_title")
-            extra_query_params["search_title"] = f"%{title_str}%"
-            # use join with artists table to filter on artist name
-            extra_join_parts.append(
-                "JOIN track_artists ON track_artists.track_id = tracks.item_id "
-                "JOIN artists ON artists.item_id = track_artists.artist_id "
-                "AND artists.name LIKE :search_artist"
-            )
-            extra_query_params["search_artist"] = f"%{artist_str}%"
-        result = await super()._get_library_items_by_query(
-            favorite=favorite,
-            search=search,
-            limit=limit,
-            offset=offset,
-            order_by=order_by,
-            provider=provider,
-            extra_query_parts=extra_query_parts,
-            extra_query_params=extra_query_params,
-            extra_join_parts=extra_join_parts,
-        )
-        if search and len(result) < 25 and not offset:
-            # append artist items to result
-            extra_join_parts.append(
-                "JOIN track_artists ON track_artists.track_id = tracks.item_id "
-                "JOIN artists ON artists.item_id = track_artists.artist_id "
-                "AND artists.name LIKE :search_artist"
-            )
-            extra_query_params["search_artist"] = f"%{search}%"
-            return result + await super()._get_library_items_by_query(
-                favorite=favorite,
-                search=None,
-                limit=limit,
-                order_by=order_by,
-                provider=provider,
-                extra_query_parts=extra_query_parts,
-                extra_query_params=extra_query_params,
-                extra_join_parts=extra_join_parts,
-            )
-        return result