Add top song list for jellyfin

This commit is contained in:
jeffvli 2023-02-27 12:17:22 -08:00
parent f08538cbfb
commit c0a703be7a
7 changed files with 48 additions and 12 deletions

View file

@ -115,7 +115,7 @@ const endpoints: ApiController = {
getPlaylistSongList: jellyfinApi.getPlaylistSongList, getPlaylistSongList: jellyfinApi.getPlaylistSongList,
getSongDetail: undefined, getSongDetail: undefined,
getSongList: jellyfinApi.getSongList, getSongList: jellyfinApi.getSongList,
getTopSongs: undefined, getTopSongs: jellyfinApi.getTopSongList,
getUserList: undefined, getUserList: undefined,
removeFromPlaylist: jellyfinApi.removeFromPlaylist, removeFromPlaylist: jellyfinApi.removeFromPlaylist,
scrobble: jellyfinApi.scrobble, scrobble: jellyfinApi.scrobble,

View file

@ -1,6 +1,6 @@
import ky from 'ky'; import ky from 'ky';
import { nanoid } from 'nanoid/non-secure'; import { nanoid } from 'nanoid/non-secure';
import type { import {
JFAddToPlaylist, JFAddToPlaylist,
JFAddToPlaylistParams, JFAddToPlaylistParams,
JFAlbum, JFAlbum,
@ -35,8 +35,9 @@ import type {
JFSongList, JFSongList,
JFSongListParams, JFSongListParams,
JFSongListResponse, JFSongListResponse,
JFSongListSort,
JFCollectionType,
} from '/@/renderer/api/jellyfin.types'; } from '/@/renderer/api/jellyfin.types';
import { JFCollectionType } from '/@/renderer/api/jellyfin.types';
import { import {
Album, Album,
AlbumArtist, AlbumArtist,
@ -72,6 +73,8 @@ import {
AddToPlaylistArgs, AddToPlaylistArgs,
ScrobbleArgs, ScrobbleArgs,
RawScrobbleResponse, RawScrobbleResponse,
TopSongListArgs,
SortOrder,
} from '/@/renderer/api/types'; } from '/@/renderer/api/types';
import { useAuthStore } from '/@/renderer/store'; import { useAuthStore } from '/@/renderer/store';
import { ServerListItem, ServerType } from '/@/renderer/types'; import { ServerListItem, ServerType } from '/@/renderer/types';
@ -326,6 +329,36 @@ const getAlbumList = async (args: AlbumListArgs): Promise<JFAlbumList> => {
}; };
}; };
const getTopSongList = async (args: TopSongListArgs): Promise<any> => {
const { signal, server, query } = args;
const searchParams: any = {
artistIds: query.artistId,
fields: 'Genres, DateCreated, MediaSources, ParentId',
includeItemTypes: 'Audio',
limit: query.limit,
recursive: true,
sortBy: JFSongListSort.COMMUNITY_RATING,
sortOrder: SortOrder.DESC,
userId: server?.userId || '',
};
const data = await api
.get(`users/${server?.userId}/items`, {
headers: { 'X-MediaBrowser-Token': server?.credential },
prefixUrl: server?.url,
searchParams: parseSearchParams(searchParams),
signal,
})
.json<any>();
return {
items: data.Items,
startIndex: 0,
totalRecordCount: data.TotalRecordCount,
};
};
const getSongList = async (args: SongListArgs): Promise<JFSongList> => { const getSongList = async (args: SongListArgs): Promise<JFSongList> => {
const { query, server, signal } = args; const { query, server, signal } = args;
@ -1007,6 +1040,7 @@ export const jellyfinApi = {
getPlaylistList, getPlaylistList,
getPlaylistSongList, getPlaylistSongList,
getSongList, getSongList,
getTopSongList,
removeFromPlaylist, removeFromPlaylist,
scrobble, scrobble,
updatePlaylist, updatePlaylist,

View file

@ -567,6 +567,7 @@ export enum JFSongListSort {
ALBUM = 'Album,SortName', ALBUM = 'Album,SortName',
ALBUM_ARTIST = 'AlbumArtist,Album,SortName', ALBUM_ARTIST = 'AlbumArtist,Album,SortName',
ARTIST = 'Artist,Album,SortName', ARTIST = 'Artist,Album,SortName',
COMMUNITY_RATING = 'CommunityRating,SortName',
DURATION = 'Runtime,AlbumArtist,Album,SortName', DURATION = 'Runtime,AlbumArtist,Album,SortName',
NAME = 'Name,SortName', NAME = 'Name,SortName',
PLAY_COUNT = 'PlayCount,SortName', PLAY_COUNT = 'PlayCount,SortName',

View file

@ -99,6 +99,7 @@ const topSongList = (data: RawTopSongListResponse | undefined, server: ServerLis
switch (server?.type) { switch (server?.type) {
case 'jellyfin': case 'jellyfin':
songs = data?.items.map((item) => jfNormalize.song(item as JFSong, server, ''));
break; break;
case 'navidrome': case 'navidrome':
songs = data?.items?.map((item) => ssNormalize.song(item as SSSong, server, '')); songs = data?.items?.map((item) => ssNormalize.song(item as SSSong, server, ''));

View file

@ -1009,12 +1009,13 @@ export const userListSortMap: UserListSortMap = {
}; };
// Top Songs List // Top Songs List
export type RawTopSongListResponse = SSTopSongList | undefined; export type RawTopSongListResponse = SSTopSongList | JFSongList | undefined;
export type TopSongListResponse = BasePaginatedResponse<Song[]>; export type TopSongListResponse = BasePaginatedResponse<Song[]>;
export type TopSongListQuery = { export type TopSongListQuery = {
artist: string; artist: string;
artistId: string;
limit?: number; limit?: number;
}; };

View file

@ -105,8 +105,8 @@ export const AlbumArtistDetailContent = () => {
}); });
const topSongsQuery = useTopSongsList( const topSongsQuery = useTopSongsList(
{ artist: detailQuery?.data?.name || '' }, { artist: detailQuery?.data?.name || '', artistId: albumArtistId },
{ enabled: server?.type !== ServerType.JELLYFIN && !!detailQuery?.data?.name }, { enabled: !!detailQuery?.data?.name },
); );
const topSongsColumnDefs: ColDef[] = useMemo( const topSongsColumnDefs: ColDef[] = useMemo(
@ -270,11 +270,13 @@ export const AlbumArtistDetailContent = () => {
ARTIST_CONTEXT_MENU_ITEMS, ARTIST_CONTEXT_MENU_ITEMS,
); );
console.log('topSongsQuery?.data :>> ', topSongsQuery?.data);
const topSongs = topSongsQuery?.data?.items?.slice(0, 10); const topSongs = topSongsQuery?.data?.items?.slice(0, 10);
const showBiography = const showBiography =
detailQuery?.data?.biography !== undefined && detailQuery?.data?.biography !== null; detailQuery?.data?.biography !== undefined && detailQuery?.data?.biography !== null;
const showTopSongs = server?.type !== ServerType.JELLYFIN && topSongsQuery?.data?.items?.length; const showTopSongs = topSongsQuery?.data?.items?.length;
const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false; const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false;
const isLoading = const isLoading =

View file

@ -6,19 +6,16 @@ import { AlbumArtistDetailTopSongsListHeader } from '/@/renderer/features/artist
import { useAlbumArtistDetail } from '/@/renderer/features/artists/queries/album-artist-detail-query'; import { useAlbumArtistDetail } from '/@/renderer/features/artists/queries/album-artist-detail-query';
import { useTopSongsList } from '/@/renderer/features/artists/queries/top-songs-list-query'; import { useTopSongsList } from '/@/renderer/features/artists/queries/top-songs-list-query';
import { AnimatedPage } from '/@/renderer/features/shared'; import { AnimatedPage } from '/@/renderer/features/shared';
import { useCurrentServer } from '/@/renderer/store';
import { ServerType } from '/@/renderer/types';
const AlbumArtistDetailTopSongsListRoute = () => { const AlbumArtistDetailTopSongsListRoute = () => {
const tableRef = useRef<AgGridReactType | null>(null); const tableRef = useRef<AgGridReactType | null>(null);
const { albumArtistId } = useParams() as { albumArtistId: string }; const { albumArtistId } = useParams() as { albumArtistId: string };
const server = useCurrentServer();
const detailQuery = useAlbumArtistDetail({ id: albumArtistId }); const detailQuery = useAlbumArtistDetail({ id: albumArtistId });
const topSongsQuery = useTopSongsList( const topSongsQuery = useTopSongsList(
{ artist: detailQuery?.data?.name || '' }, { artist: detailQuery?.data?.name || '', artistId: albumArtistId },
{ enabled: server?.type !== ServerType.JELLYFIN && !!detailQuery?.data?.name }, { enabled: !!detailQuery?.data?.name },
); );
const itemCount = topSongsQuery?.data?.items?.length || 0; const itemCount = topSongsQuery?.data?.items?.length || 0;