diff --git a/app/api/favorites.py b/app/api/favorites.py index 2a40d64d..eeb5a3c7 100644 --- a/app/api/favorites.py +++ b/app/api/favorites.py @@ -117,6 +117,9 @@ class GetAllOfTypeQuery(GenericLimitSchema): def get_favorite_albums(query: GetAllOfTypeQuery): """ Get favorite albums + + Note: Only the first request will return the total number of favorites. + Others will return -1 """ fav_albums, total = FavoritesTable.get_fav_albums(query.start, query.limit) fav_albums.reverse() @@ -129,6 +132,9 @@ def get_favorite_albums(query: GetAllOfTypeQuery): def get_favorite_tracks(query: GetAllOfTypeQuery): """ Get favorite tracks + + Note: Only the first request will return the total number of favorites. + Others will return -1 """ tracks, total = FavoritesTable.get_fav_tracks(query.start, query.limit) tracks.reverse() @@ -141,6 +147,9 @@ def get_favorite_tracks(query: GetAllOfTypeQuery): def get_favorite_artists(query: GetAllOfTypeQuery): """ Get favorite artists + + Note: Only the first request will return the total number of favorites. + Others will return -1 """ artists, total = FavoritesTable.get_fav_artists( start=query.start, @@ -188,7 +197,7 @@ def get_all_favorites(query: GetAllFavoritesQuery): # largest is x2 to accound for broken hashes if any largest = max(track_limit, album_limit, artist_limit) - favs = FavoritesTable.get_all() + favs = FavoritesTable.get_all(with_user=True) favs = sorted(favs, key=lambda x: x.timestamp, reverse=True) tracks = [] diff --git a/app/api/search.py b/app/api/search.py index 19265185..05fcafc9 100644 --- a/app/api/search.py +++ b/app/api/search.py @@ -2,6 +2,7 @@ Contains all the search routes. """ +from typing import Any, Literal from unidecode import unidecode from pydantic import Field from flask_openapi3 import Tag @@ -18,7 +19,29 @@ tag = Tag(name="Search", description="Search for tracks, albums and artists") api = APIBlueprint("search", __name__, url_prefix="/search", abp_tags=[tag]) SEARCH_COUNT = 30 -"""The max amount of items to return per request""" +""" +The max amount of items to return per request +""" + + +class SearchQuery(GenericLimitSchema): + q: str = Field(description="The search query", example=Defaults.API_ARTISTNAME) + start: int = Field(description="The index to start from", default=0, example=0) + limit: int = Field( + description="The number of items to return", default=SEARCH_COUNT + ) + + +class TopResultsQuery(SearchQuery): + limit: int = Field( + description="The number of items to return", default=Defaults.API_CARD_LIMIT + ) + + +class SearchLoadMoreQuery(SearchQuery): + itemtype: Literal["tracks", "albums", "artists"] = Field( + description="The type of search", example="tracks" + ) class Search: @@ -54,61 +77,6 @@ class Search: return finder.search(self.query, limit=limit) -class SearchQuery(GenericLimitSchema): - q: str = Field(description="The search query", example=Defaults.API_ARTISTNAME) - start: int = Field(description="The index to start from", default=0, example=0) - - -@api.get("/tracks") -def search_tracks(query: SearchQuery): - """ - Search tracks - """ - tracks = Search(query.q).search_tracks() - - return { - "tracks": tracks[:SEARCH_COUNT], - "more": len(tracks) > SEARCH_COUNT, - } - - -@api.get("/albums") -def search_albums( - query: SearchQuery, -): - """ - Search albums. - """ - albums = Search(query.q).search_albums() - - return { - "albums": albums[:SEARCH_COUNT], - "more": len(albums) > SEARCH_COUNT, - } - - -@api.get("/artists") -def search_artists(query: SearchQuery): - """ - Search artists. - """ - if not query.q: - return {"error": "No query provided"}, 400 - - artists = Search(query.q).search_artists() - - return { - "artists": artists[:SEARCH_COUNT], - "more": len(artists) > SEARCH_COUNT, - } - - -class TopResultsQuery(SearchQuery): - limit: int = Field( - description="The number of items to return", default=Defaults.API_CARD_LIMIT - ) - - @api.get("/top") def get_top_results(query: TopResultsQuery): """ @@ -122,44 +90,29 @@ def get_top_results(query: TopResultsQuery): return Search(query.q).get_top_results(limit=query.limit) -class SearchLoadMoreQuery(SearchQuery): - type: str = Field(description="The type of search", example="tracks") - start: int = Field(description="The index to start from", default=0) - - -@api.get("/loadmore") -def search_load_more(query: SearchLoadMoreQuery): +@api.get("/") +def search_items(query: SearchLoadMoreQuery): """ - Load more - - Returns more songs, albums or artists from a search query. - - NOTE: You must first initiate a search using the `/search` endpoint. + Find tracks, albums or artists from a search query. """ - q = query.q - item_type = query.type - index = query.start + results: Any = [] - if item_type == "tracks": - t = Search(q).search_tracks() - return { - "tracks": t[index : index + SEARCH_COUNT], - "more": len(t) > index + SEARCH_COUNT, - } + match query.itemtype: + case "tracks": + results = Search(query.q).search_tracks() + case "albums": + results = Search(query.q).search_albums() + case "artists": + results = Search(query.q).search_artists() + case _: + return { + "error": "Invalid item type. Valid types are 'tracks', 'albums' and 'artists'" + }, 400 - elif item_type == "albums": - a = Search(q).search_albums() - return { - "albums": a[index : index + SEARCH_COUNT], - "more": len(a) > index + SEARCH_COUNT, - } - - elif item_type == "artists": - a = Search(q).search_artists() - return { - "artists": a[index : index + SEARCH_COUNT], - "more": len(a) > index + SEARCH_COUNT, - } + return { + "results": results[query.start : query.start + query.limit], + "more": len(results) > query.start + query.limit, + } # TODO: Rewrite this file using generators where possible diff --git a/app/db/userdata.py b/app/db/userdata.py index d0e7de98..f7a90d0d 100644 --- a/app/db/userdata.py +++ b/app/db/userdata.py @@ -184,9 +184,14 @@ class FavoritesTable(Base): ) @classmethod - def get_all(cls): + def get_all(cls, with_user: bool = False): with DbEngine.manager() as conn: - result = conn.execute(select(cls)) + if with_user: + result = conn.execute( + select(cls).where(cls.userid == get_current_userid()) + ) + else: + result = conn.execute(select(cls)) return favorites_to_dataclass(result.fetchall()) @classmethod