mirror of
https://github.com/antebudimir/feishin.git
synced 2025-12-31 18:13:31 +00:00
handle playback on new artist list
This commit is contained in:
parent
b9611589ba
commit
4a3604b1a8
12 changed files with 121 additions and 31 deletions
|
|
@ -700,7 +700,9 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
: undefined;
|
||||
const artistIdsFilter = query.artistIds
|
||||
? formatCommaDelimitedString(query.artistIds)
|
||||
: undefined;
|
||||
: query.albumArtistIds
|
||||
? formatCommaDelimitedString(query.albumArtistIds)
|
||||
: undefined;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).getSongList({
|
||||
params: {
|
||||
|
|
|
|||
|
|
@ -548,8 +548,9 @@ export const NavidromeController: ControllerEndpoint = {
|
|||
_order: sortOrderMap.navidrome[query.sortOrder],
|
||||
_sort: songListSortMap.navidrome[query.sortBy],
|
||||
_start: query.startIndex,
|
||||
album_artist_id: query.artistIds,
|
||||
album_artist_id: query.albumArtistIds,
|
||||
album_id: query.albumIds,
|
||||
artist_id: query.artistIds,
|
||||
genre_id: query.genreIds,
|
||||
starred: query.favorite,
|
||||
title: query.searchTerm,
|
||||
|
|
|
|||
|
|
@ -494,6 +494,7 @@ export interface SongListQuery extends BaseQuery<SongListSort> {
|
|||
jellyfin?: Partial<z.infer<typeof jfType._parameters.songList>>;
|
||||
navidrome?: Partial<z.infer<typeof ndType._parameters.songList>>;
|
||||
};
|
||||
albumArtistIds?: string[];
|
||||
albumIds?: string[];
|
||||
artistIds?: string[];
|
||||
favorite?: boolean;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,11 @@ interface AlbumArtistDetailContentProps {
|
|||
export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailContentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { artistItems, externalLinks } = useGeneralSettings();
|
||||
const { albumArtistId } = useParams() as { albumArtistId: string };
|
||||
const { albumArtistId, artistId } = useParams() as {
|
||||
albumArtistId?: string;
|
||||
artistId?: string;
|
||||
};
|
||||
const routeId = (artistId || albumArtistId) as string;
|
||||
const cq = useContainerQuery();
|
||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||
const server = useCurrentServer();
|
||||
|
|
@ -85,24 +89,24 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
}, [artistItems]);
|
||||
|
||||
const detailQuery = useAlbumArtistDetail({
|
||||
query: { id: albumArtistId },
|
||||
query: { id: routeId },
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
const artistDiscographyLink = `${generatePath(
|
||||
AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_DISCOGRAPHY,
|
||||
{
|
||||
albumArtistId,
|
||||
albumArtistId: routeId,
|
||||
},
|
||||
)}?${createSearchParams({
|
||||
artistId: albumArtistId,
|
||||
artistId: routeId,
|
||||
artistName: detailQuery?.data?.name || '',
|
||||
})}`;
|
||||
|
||||
const artistSongsLink = `${generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_SONGS, {
|
||||
albumArtistId,
|
||||
albumArtistId: routeId,
|
||||
})}?${createSearchParams({
|
||||
artistId: albumArtistId,
|
||||
artistId: routeId,
|
||||
artistName: detailQuery?.data?.name || '',
|
||||
})}`;
|
||||
|
||||
|
|
@ -111,7 +115,7 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
enabled: enabledItem.recentAlbums,
|
||||
},
|
||||
query: {
|
||||
artistIds: [albumArtistId],
|
||||
artistIds: [routeId],
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
sortOrder: SortOrder.DESC,
|
||||
|
|
@ -125,7 +129,7 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
enabled: enabledItem.compilations && server?.type !== ServerType.SUBSONIC,
|
||||
},
|
||||
query: {
|
||||
artistIds: [albumArtistId],
|
||||
artistIds: [routeId],
|
||||
compilation: true,
|
||||
limit: 15,
|
||||
sortBy: AlbumListSort.RELEASE_DATE,
|
||||
|
|
@ -141,7 +145,7 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
},
|
||||
query: {
|
||||
artist: detailQuery?.data?.name || '',
|
||||
artistId: albumArtistId,
|
||||
artistId: routeId,
|
||||
},
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
|
@ -292,8 +296,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
const handlePlay = async (playType?: Play) => {
|
||||
handlePlayQueueAdd?.({
|
||||
byItemType: {
|
||||
id: [albumArtistId],
|
||||
type: LibraryItem.ALBUM_ARTIST,
|
||||
id: [routeId],
|
||||
type: albumArtistId ? LibraryItem.ALBUM : LibraryItem.ALBUM_ARTIST,
|
||||
},
|
||||
playType: playType || playButtonBehavior,
|
||||
});
|
||||
|
|
@ -528,7 +532,7 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
|
|||
to={generatePath(
|
||||
AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_TOP_SONGS,
|
||||
{
|
||||
albumArtistId,
|
||||
albumArtistId: routeId,
|
||||
},
|
||||
)}
|
||||
variant="subtle"
|
||||
|
|
|
|||
|
|
@ -16,11 +16,15 @@ interface AlbumArtistDetailHeaderProps {
|
|||
|
||||
export const AlbumArtistDetailHeader = forwardRef(
|
||||
({ background }: AlbumArtistDetailHeaderProps, ref: Ref<HTMLDivElement>) => {
|
||||
const { albumArtistId } = useParams() as { albumArtistId: string };
|
||||
const { albumArtistId, artistId } = useParams() as {
|
||||
albumArtistId?: string;
|
||||
artistId?: string;
|
||||
};
|
||||
const routeId = (artistId || albumArtistId) as string;
|
||||
const server = useCurrentServer();
|
||||
const { t } = useTranslation();
|
||||
const detailQuery = useAlbumArtistDetail({
|
||||
query: { id: albumArtistId },
|
||||
query: { id: routeId },
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -156,12 +156,12 @@ export const ArtistListGridView = ({ itemCount, gridRef }: ArtistListGridViewPro
|
|||
itemCount={itemCount || 0}
|
||||
itemGap={grid?.itemGap ?? 10}
|
||||
itemSize={grid?.itemSize || 200}
|
||||
itemType={LibraryItem.ALBUM_ARTIST}
|
||||
itemType={LibraryItem.ARTIST}
|
||||
loading={itemCount === undefined || itemCount === null}
|
||||
minimumBatchSize={40}
|
||||
route={{
|
||||
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
|
||||
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
|
||||
route: AppRoute.LIBRARY_ARTISTS_DETAIL,
|
||||
slugs: [{ idProperty: 'id', slugProperty: 'artistId' }],
|
||||
}}
|
||||
width={width}
|
||||
onScroll={handleGridScroll}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,21 @@ const AlbumArtistDetailRoute = () => {
|
|||
const headerRef = useRef<HTMLDivElement>(null);
|
||||
const server = useCurrentServer();
|
||||
|
||||
const { albumArtistId } = useParams() as { albumArtistId: string };
|
||||
const { albumArtistId, artistId } = useParams() as {
|
||||
albumArtistId?: string;
|
||||
artistId?: string;
|
||||
};
|
||||
|
||||
const routeId = (artistId || albumArtistId) as string;
|
||||
|
||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const detailQuery = useAlbumArtistDetail({
|
||||
query: { id: albumArtistId },
|
||||
query: { id: routeId },
|
||||
serverId: server?.id,
|
||||
});
|
||||
const { color: background, colorId } = useFastAverageColor({
|
||||
id: albumArtistId,
|
||||
id: routeId,
|
||||
src: detailQuery.data?.imageUrl,
|
||||
srcLoaded: !detailQuery.isLoading,
|
||||
});
|
||||
|
|
@ -32,19 +38,19 @@ const AlbumArtistDetailRoute = () => {
|
|||
const handlePlay = () => {
|
||||
handlePlayQueueAdd?.({
|
||||
byItemType: {
|
||||
id: [albumArtistId],
|
||||
id: [routeId],
|
||||
type: LibraryItem.ALBUM_ARTIST,
|
||||
},
|
||||
playType: playButtonBehavior,
|
||||
});
|
||||
};
|
||||
|
||||
if (!background || colorId !== albumArtistId) {
|
||||
if (!background || colorId !== routeId) {
|
||||
return <Spinner container />;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimatedPage key={`album-artist-detail-${albumArtistId}`}>
|
||||
<AnimatedPage key={`album-artist-detail-${routeId}`}>
|
||||
<NativeScrollArea
|
||||
ref={scrollAreaRef}
|
||||
pageHeaderProps={{
|
||||
|
|
|
|||
|
|
@ -12,18 +12,22 @@ import { ListContext } from '/@/renderer/context/list-context';
|
|||
|
||||
const AlbumArtistDetailTopSongsListRoute = () => {
|
||||
const tableRef = useRef<AgGridReactType | null>(null);
|
||||
const { albumArtistId } = useParams() as { albumArtistId: string };
|
||||
const { albumArtistId, artistId } = useParams() as {
|
||||
albumArtistId?: string;
|
||||
artistId?: string;
|
||||
};
|
||||
const routeId = (artistId || albumArtistId) as string;
|
||||
const server = useCurrentServer();
|
||||
const pageKey = LibraryItem.SONG;
|
||||
|
||||
const detailQuery = useAlbumArtistDetail({
|
||||
query: { id: albumArtistId },
|
||||
query: { id: routeId },
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
const topSongsQuery = useTopSongsList({
|
||||
options: { enabled: !!detailQuery?.data?.name },
|
||||
query: { artist: detailQuery?.data?.name || '', artistId: albumArtistId },
|
||||
query: { artist: detailQuery?.data?.name || '', artistId: routeId },
|
||||
serverId: server?.id,
|
||||
});
|
||||
|
||||
|
|
@ -31,10 +35,10 @@ const AlbumArtistDetailTopSongsListRoute = () => {
|
|||
|
||||
const providerValue = useMemo(() => {
|
||||
return {
|
||||
id: albumArtistId,
|
||||
id: routeId,
|
||||
pageKey,
|
||||
};
|
||||
}, [albumArtistId, pageKey]);
|
||||
}, [routeId, pageKey]);
|
||||
|
||||
return (
|
||||
<AnimatedPage>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
getAlbumArtistSongsById,
|
||||
getSongsByQuery,
|
||||
getGenreSongsById,
|
||||
getArtistSongsById,
|
||||
} from '/@/renderer/features/player/utils';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
|
@ -75,6 +76,8 @@ export const useHandlePlayQueueAdd = () => {
|
|||
let songs: QueueSong[] | null = null;
|
||||
let initialSongIndex = 0;
|
||||
|
||||
console.log('options :>> ', options);
|
||||
|
||||
if (byItemType) {
|
||||
let songList: SongListResponse | undefined;
|
||||
const { type: itemType, id } = byItemType;
|
||||
|
|
@ -119,6 +122,13 @@ export const useHandlePlayQueueAdd = () => {
|
|||
queryClient,
|
||||
server,
|
||||
});
|
||||
} else if (itemType === LibraryItem.ARTIST) {
|
||||
songList = await getArtistSongsById({
|
||||
id,
|
||||
query,
|
||||
queryClient,
|
||||
server,
|
||||
});
|
||||
} else if (itemType === LibraryItem.GENRE) {
|
||||
songList = await getGenreSongsById({ id, query, queryClient, server });
|
||||
} else if (itemType === LibraryItem.SONG) {
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ export const getAlbumArtistSongsById = async (args: {
|
|||
const { id, queryClient, server, query } = args;
|
||||
|
||||
const queryFilter: SongListQuery = {
|
||||
artistIds: id || [],
|
||||
albumArtistIds: id || [],
|
||||
sortBy: SongListSort.ALBUM_ARTIST,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
|
|
@ -174,6 +174,43 @@ export const getAlbumArtistSongsById = async (args: {
|
|||
return res;
|
||||
};
|
||||
|
||||
export const getArtistSongsById = async (args: {
|
||||
id: string[];
|
||||
query?: Partial<SongListQuery>;
|
||||
queryClient: QueryClient;
|
||||
server: ServerListItem;
|
||||
}) => {
|
||||
const { id, queryClient, server, query } = args;
|
||||
|
||||
const queryFilter: SongListQuery = {
|
||||
artistIds: id,
|
||||
sortBy: SongListSort.ALBUM,
|
||||
sortOrder: SortOrder.ASC,
|
||||
startIndex: 0,
|
||||
...query,
|
||||
};
|
||||
|
||||
const queryKey = queryKeys.songs.list(server?.id, queryFilter);
|
||||
|
||||
const res = await queryClient.fetchQuery(
|
||||
queryKey,
|
||||
async ({ signal }) =>
|
||||
api.controller.getSongList({
|
||||
apiClientProps: {
|
||||
server,
|
||||
signal,
|
||||
},
|
||||
query: queryFilter,
|
||||
}),
|
||||
{
|
||||
cacheTime: 1000 * 60,
|
||||
staleTime: 1000 * 60,
|
||||
},
|
||||
);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getSongsByQuery = async (args: {
|
||||
query?: Partial<SongListQuery>;
|
||||
queryClient: QueryClient;
|
||||
|
|
|
|||
|
|
@ -150,6 +150,24 @@ export const AppRouter = () => {
|
|||
errorElement={<RouteErrorBoundary />}
|
||||
path={AppRoute.LIBRARY_ARTISTS}
|
||||
/>
|
||||
<Route path={AppRoute.LIBRARY_ARTISTS_DETAIL}>
|
||||
<Route
|
||||
index
|
||||
element={<AlbumArtistDetailRoute />}
|
||||
/>
|
||||
<Route
|
||||
element={<AlbumListRoute />}
|
||||
path={AppRoute.LIBRARY_ARTISTS_DETAIL_DISCOGRAPHY}
|
||||
/>
|
||||
<Route
|
||||
element={<SongListRoute />}
|
||||
path={AppRoute.LIBRARY_ARTISTS_DETAIL_SONGS}
|
||||
/>
|
||||
<Route
|
||||
element={<AlbumArtistDetailTopSongsListRoute />}
|
||||
path={AppRoute.LIBRARY_ARTISTS_DETAIL_TOP_SONGS}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
element={<DummyAlbumDetailRoute />}
|
||||
errorElement={<RouteErrorBoundary />}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ export enum AppRoute {
|
|||
LIBRARY_ALBUM_ARTISTS_DETAIL_TOP_SONGS = '/library/album-artists/:albumArtistId/top-songs',
|
||||
LIBRARY_ARTISTS = '/library/artists',
|
||||
LIBRARY_ARTISTS_DETAIL = '/library/artists/:artistId',
|
||||
LIBRARY_ARTISTS_DETAIL_DISCOGRAPHY = '/library/artists/:artistId/discography',
|
||||
LIBRARY_ARTISTS_DETAIL_SONGS = '/library/artists/:artistId/songs',
|
||||
LIBRARY_ARTISTS_DETAIL_TOP_SONGS = '/library/artists/:artistId/top-songs',
|
||||
LIBRARY_FOLDERS = '/library/folders',
|
||||
LIBRARY_GENRES = '/library/genres',
|
||||
LIBRARY_GENRES_ALBUMS = '/library/genres/:genreId/albums',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue