From: Marcel van der Veldt Date: Wed, 21 Aug 2024 11:01:39 +0000 (+0200) Subject: fix some remaining queries X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=4ea9e1df57bc5269664a06aae05b2d8adce96ca6;p=music-assistant-server.git fix some remaining queries --- diff --git a/music_assistant/client/music.py b/music_assistant/client/music.py index be70dbd9..797c10a5 100644 --- a/music_assistant/client/music.py +++ b/music_assistant/client/music.py @@ -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, ) ] diff --git a/music_assistant/server/controllers/media/albums.py b/music_assistant/server/controllers/media/albums.py index bbd79a38..189c9e22 100644 --- a/music_assistant/server/controllers/media/albums.py +++ b/music_assistant/server/controllers/media/albums.py @@ -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 diff --git a/music_assistant/server/controllers/media/artists.py b/music_assistant/server/controllers/media/artists.py index 0238381b..b6ba3fdc 100644 --- a/music_assistant/server/controllers/media/artists.py +++ b/music_assistant/server/controllers/media/artists.py @@ -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, ) diff --git a/music_assistant/server/controllers/media/base.py b/music_assistant/server/controllers/media/base.py index 17f984a5..222e6d3c 100644 --- a/music_assistant/server/controllers/media/base.py +++ b/music_assistant/server/controllers/media/base.py @@ -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: diff --git a/music_assistant/server/controllers/media/tracks.py b/music_assistant/server/controllers/media/tracks.py index 16e59b0c..377515f4 100644 --- a/music_assistant/server/controllers/media/tracks.py +++ b/music_assistant/server/controllers/media/tracks.py @@ -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