Skip to content

Commit

Permalink
Merge pull request #54 from CalPinSW/add-search-by-album-functionality
Browse files Browse the repository at this point in the history
Add functionality to search for albums across playlists
  • Loading branch information
CalPinSW authored Oct 30, 2024
2 parents 9f8152b + 92a2a3e commit 6693f1a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 9 deletions.
21 changes: 21 additions & 0 deletions backend/src/controllers/music_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
get_recent_user_playlists,
get_user_playlists,
search_playlist_names,
search_playlists_by_albums,
update_playlist_info,
)
from src.dataclasses.playlist import Playlist
Expand All @@ -20,6 +21,26 @@ def music_controller(spotify: SpotifyClient):
name="music_controller", import_name=__name__, url_prefix="/music"
)

@music_controller.route("playlist_album_search")
def album_search():
user_id = request.cookies.get("user_id")
limit = request.args.get("limit", type=int)
offset = request.args.get("offset", type=int)
search = request.args.get("search")
sort_by = request.args.get("sort_by")
desc = request.args.get("desc") == "True"
return jsonify(
search_playlists_by_albums(
user_id=user_id,
limit=limit,
offset=offset,
search=search,
sort_by=sort_by,
desc=desc,
as_dicts=True,
)
)

@music_controller.route("playlists")
def index():
user_id = request.cookies.get("user_id")
Expand Down
49 changes: 49 additions & 0 deletions backend/src/database/crud/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,55 @@ def get_recent_user_playlists(
return playlists


def search_playlists_by_albums(
user_id: str,
limit: Optional[int] = None,
offset: Optional[int] = None,
search: Optional[str] = None,
sort_by: Optional[str] = None,
desc: bool = True,
as_dicts: bool = False,
) -> List[DbPlaylist]:
# Subquery to find albums where the album name or artist name contains the search query
albums_with_artists_query = (
DbAlbum.select(DbAlbum.id).join(AlbumArtistRelationship).join(DbArtist)
)

if search:
albums_with_artists_query = albums_with_artists_query.where(
(DbAlbum.name.contains(search)) | (DbArtist.name.contains(search))
)

# Query to find playlists containing the matching albums
playlists_with_albums_query = (
DbPlaylist.select(DbPlaylist)
.join(PlaylistAlbumRelationship)
.join(DbAlbum)
.where(DbAlbum.id.in_(albums_with_artists_query))
)

if sort_by:
sort_field = getattr(DbPlaylist, sort_by)
if desc:
playlists_with_albums_query = playlists_with_albums_query.order_by(
sort_field.desc()
)
else:
playlists_with_albums_query = playlists_with_albums_query.order_by(
sort_field.asc()
)

if limit is not None:
playlists_with_albums_query = playlists_with_albums_query.limit(limit)
if offset is not None:
playlists_with_albums_query = playlists_with_albums_query.offset(offset)

if as_dicts:
return list(playlists_with_albums_query.dicts())
else:
return list(playlists_with_albums_query.execute())


def get_playlist_albums(playlist_id: str) -> List[DbAlbum]:
query = (
DbAlbum.select()
Expand Down
26 changes: 18 additions & 8 deletions frontend/src/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { getPlaylists, getRecentPlaylists } from "./api";
import { getRecentPlaylists, searchPlaylistsByAlbums } from "./api";
import { Playlist } from "./interfaces/Playlist";
import Box from "./components/Box";
import AddPlaylistForm from "./AddPlaylistForm";
Expand All @@ -16,26 +16,36 @@ interface PaginationState {

export const Index: FC = () => {
const { isMobileView } = useWindowSize();
const [searchRecent, setSearchRecent] = useState<string>("")
const [search, setSearch] = useState<string>("")
const [playlistSearch, setPlaylistSearch] = useState<string>("")
const [albumSearch, setAlbumSearch] = useState<string>("")
const [pagination, ] = useState<PaginationState>({
pageIndex: 0,
pageSize: isMobileView ? 8 : 8,
});

const playlistQuery = useQuery<Playlist[]>({
queryKey: ["playlists", pagination, playlistSearch],
queryFn: () => {
return getRecentPlaylists(playlistSearch, pagination.pageIndex, pagination.pageSize);
},
});

const recentQuery = useQuery<Playlist[]>({
queryKey: ["playlists", pagination, search],
const albumQuery = useQuery<Playlist[]>({
queryKey: ["albums", pagination, albumSearch],
queryFn: () => {
return getRecentPlaylists(search, pagination.pageIndex, pagination.pageSize);
return searchPlaylistsByAlbums(albumSearch, pagination.pageIndex, pagination.pageSize);
},
});

return (
<div className="py-4 px-2 space-y-2">
<Box className="space-y-2">
<SearchBar search={searchRecent} setSearch={setSearchRecent}/>
<Carousel slides={(recentQuery.data ?? createUndefinedArray(pagination.pageSize)).map(PlaylistSlide)} />
<SearchBar search={playlistSearch} setSearch={setPlaylistSearch}/>
<Carousel slides={(playlistQuery.data ?? createUndefinedArray(pagination.pageSize)).map(PlaylistSlide)} />
</Box>
<Box className="space-y-2">
<SearchBar search={albumSearch} setSearch={setAlbumSearch}/>
<Carousel slides={(albumQuery.data ?? createUndefinedArray(pagination.pageSize)).map(PlaylistSlide)} />
</Box>
<Box>
<AddPlaylistForm />
Expand Down
16 changes: 15 additions & 1 deletion frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ export const getCurrentUserDetails = async (): Promise<User> => {
);
};

export const searchPlaylistsByAlbums = async (
search: string,
offset: number,
limit: number,
): Promise<Playlist[]> => {
const searchParams = new URLSearchParams();
searchParams.append("limit", String(limit));
searchParams.append("offset", String(offset));
if (search !== "") {searchParams.append("search", search);}
searchParams.toString();
const endpoint = `music/playlist_album_search?${searchParams.toString()}`;
return jsonRequest(endpoint, RequestMethod.GET);
};

export const getRecentPlaylists = async (
search: string,
offset: number,
Expand All @@ -49,7 +63,7 @@ export const getRecentPlaylists = async (
searchParams.append("limit", String(limit));
searchParams.append("offset", String(offset));
if (search !== "") {searchParams.append("search", search);}
searchParams.toString(); // "type=all&query=coins"
searchParams.toString();
const endpoint = `music/playlists/recent?${searchParams.toString()}`;
return jsonRequest(endpoint, RequestMethod.GET);
};
Expand Down

0 comments on commit 6693f1a

Please sign in to comment.