From f4ba82531c848052ad6cf2b078b7d09fea92e3ff Mon Sep 17 00:00:00 2001 From: jeffvli Date: Thu, 29 Dec 2022 17:11:25 -0800 Subject: [PATCH] Add album detail api --- src/renderer/api/jellyfin.api.ts | 71 +++++++++--------- src/renderer/api/navidrome.api.ts | 74 ++++++++++--------- src/renderer/api/navidrome.types.ts | 2 +- src/renderer/api/normalize.ts | 22 ++++++ src/renderer/api/types.ts | 2 +- .../albums/queries/album-detail-query.ts | 10 ++- 6 files changed, 106 insertions(+), 75 deletions(-) diff --git a/src/renderer/api/jellyfin.api.ts b/src/renderer/api/jellyfin.api.ts index 6d325e76..14356319 100644 --- a/src/renderer/api/jellyfin.api.ts +++ b/src/renderer/api/jellyfin.api.ts @@ -543,41 +543,6 @@ const getSongCoverArtUrl = (args: { baseUrl: string; item: JFSong; size: number ); }; -const normalizeAlbum = (item: JFAlbum, server: ServerListItem, imageSize?: number): Album => { - return { - albumArtists: - item.AlbumArtists?.map((entry) => ({ - id: entry.Id, - name: entry.Name, - })) || [], - artists: item.ArtistItems?.map((entry) => ({ id: entry.Id, name: entry.Name })), - backdropImageUrl: null, - createdAt: item.DateCreated, - duration: item.RunTimeTicks / 10000000, - genres: item.GenreItems?.map((entry) => ({ id: entry.Id, name: entry.Name })), - id: item.Id, - imagePlaceholderUrl: null, - imageUrl: getAlbumCoverArtUrl({ - baseUrl: server.url, - item, - size: imageSize || 300, - }), - isCompilation: null, - isFavorite: item.UserData?.IsFavorite || false, - lastPlayedAt: null, - name: item.Name, - playCount: item.UserData?.PlayCount || 0, - rating: null, - releaseDate: item.PremiereDate?.split('T')[0] || null, - releaseYear: item.ProductionYear, - serverType: ServerType.JELLYFIN, - size: null, - songCount: item?.ChildCount || null, - uniqueId: nanoid(), - updatedAt: item?.DateLastMediaAdded || item.DateCreated, - }; -}; - const normalizeSong = ( item: JFSong, server: ServerListItem, @@ -627,6 +592,42 @@ const normalizeSong = ( }; }; +const normalizeAlbum = (item: JFAlbum, server: ServerListItem, imageSize?: number): Album => { + return { + albumArtists: + item.AlbumArtists.map((entry) => ({ + id: entry.Id, + name: entry.Name, + })) || [], + artists: item.ArtistItems?.map((entry) => ({ id: entry.Id, name: entry.Name })), + backdropImageUrl: null, + createdAt: item.DateCreated, + duration: item.RunTimeTicks / 10000000, + genres: item.GenreItems?.map((entry) => ({ id: entry.Id, name: entry.Name })), + id: item.Id, + imagePlaceholderUrl: null, + imageUrl: getAlbumCoverArtUrl({ + baseUrl: server.url, + item, + size: imageSize || 300, + }), + isCompilation: null, + isFavorite: item.UserData?.IsFavorite || false, + lastPlayedAt: null, + name: item.Name, + playCount: item.UserData?.PlayCount || 0, + rating: null, + releaseDate: item.PremiereDate?.split('T')[0] || null, + releaseYear: item.ProductionYear, + serverType: ServerType.JELLYFIN, + size: null, + songCount: item?.ChildCount || null, + songs: item.songs?.map((song) => normalizeSong(song, server, '', imageSize)), + uniqueId: nanoid(), + updatedAt: item?.DateLastMediaAdded || item.DateCreated, + }; +}; + // const normalizeArtist = (item: any) => { // return { // album: (item.album || []).map((entry: any) => normalizeAlbum(entry)), diff --git a/src/renderer/api/navidrome.api.ts b/src/renderer/api/navidrome.api.ts index 9ee4d840..c48c7fe5 100644 --- a/src/renderer/api/navidrome.api.ts +++ b/src/renderer/api/navidrome.api.ts @@ -401,42 +401,6 @@ const getCoverArtUrl = (args: { ); }; -const normalizeAlbum = (item: NDAlbum, server: ServerListItem, imageSize?: number): Album => { - const imageUrl = getCoverArtUrl({ - baseUrl: server.url, - coverArtId: item.coverArtId, - credential: server.credential, - size: imageSize || 300, - }); - - const imagePlaceholderUrl = imageUrl?.replace(/size=\d+/, 'size=50') || null; - - return { - albumArtists: [{ id: item.albumArtistId, name: item.albumArtist }], - artists: [{ id: item.artistId, name: item.artist }], - backdropImageUrl: null, - createdAt: item.createdAt.split('T')[0], - duration: item.duration || null, - genres: item.genres, - id: item.id, - imagePlaceholderUrl, - imageUrl, - isCompilation: item.compilation, - isFavorite: item.starred, - lastPlayedAt: item.playDate ? item.playDate.split('T')[0] : null, - name: item.name, - playCount: item.playCount, - rating: item.rating, - releaseDate: new Date(item.minYear, 0, 1).toISOString(), - releaseYear: item.minYear, - serverType: ServerType.NAVIDROME, - size: item.size, - songCount: item.songCount, - uniqueId: nanoid(), - updatedAt: item.updatedAt, - }; -}; - const normalizeSong = ( item: NDSong, server: ServerListItem, @@ -485,6 +449,44 @@ const normalizeSong = ( }; }; +const normalizeAlbum = (item: NDAlbum, server: ServerListItem, imageSize?: number): Album => { + const imageUrl = getCoverArtUrl({ + baseUrl: server.url, + coverArtId: item.coverArtId, + credential: server.credential, + size: imageSize || 300, + }); + + const imagePlaceholderUrl = imageUrl?.replace(/size=\d+/, 'size=50') || null; + const imageBackdropUrl = imageUrl?.replace(/size=\d+/, 'size=1000') || null; + + return { + albumArtists: [{ id: item.albumArtistId, name: item.albumArtist }], + artists: [{ id: item.artistId, name: item.artist }], + backdropImageUrl: imageBackdropUrl, + createdAt: item.createdAt.split('T')[0], + duration: item.duration || null, + genres: item.genres, + id: item.id, + imagePlaceholderUrl, + imageUrl, + isCompilation: item.compilation, + isFavorite: item.starred, + lastPlayedAt: item.playDate ? item.playDate.split('T')[0] : null, + name: item.name, + playCount: item.playCount, + rating: item.rating, + releaseDate: new Date(item.minYear, 0, 1).toISOString(), + releaseYear: item.minYear, + serverType: ServerType.NAVIDROME, + size: item.size, + songCount: item.songCount, + songs: item.songs ? item.songs.map((song) => normalizeSong(song, server, '')) : undefined, + uniqueId: nanoid(), + updatedAt: item.updatedAt, + }; +}; + export const navidromeApi = { authenticate, createPlaylist, diff --git a/src/renderer/api/navidrome.types.ts b/src/renderer/api/navidrome.types.ts index effa21ae..ef5e5e01 100644 --- a/src/renderer/api/navidrome.types.ts +++ b/src/renderer/api/navidrome.types.ts @@ -45,7 +45,7 @@ export type NDAlbum = { starred: boolean; starredAt: string; updatedAt: string; -}; +} & { songs?: NDSong[] }; export type NDSong = { album: string; diff --git a/src/renderer/api/normalize.ts b/src/renderer/api/normalize.ts index 69420933..0a143c3c 100644 --- a/src/renderer/api/normalize.ts +++ b/src/renderer/api/normalize.ts @@ -9,6 +9,8 @@ import { ndNormalize } from '/@/renderer/api/navidrome.api'; import type { NDAlbum, NDGenreList, NDSong } from '/@/renderer/api/navidrome.types'; import { SSGenreList, SSMusicFolderList } from '/@/renderer/api/subsonic.types'; import type { + Album, + RawAlbumDetailResponse, RawAlbumListResponse, RawGenreListResponse, RawMusicFolderListResponse, @@ -36,6 +38,25 @@ const albumList = (data: RawAlbumListResponse | undefined, server: ServerListIte }; }; +const albumDetail = ( + data: RawAlbumDetailResponse | undefined, + server: ServerListItem | null, +): Album | undefined => { + let album: Album | undefined; + switch (server?.type) { + case 'jellyfin': + album = jfNormalize.album(data as JFAlbum, server); + break; + case 'navidrome': + album = ndNormalize.album(data as NDAlbum, server); + break; + case 'subsonic': + break; + } + + return album; +}; + const songList = (data: RawSongListResponse | undefined, server: ServerListItem | null) => { let songs; switch (server?.type) { @@ -116,6 +137,7 @@ const genreList = (data: RawGenreListResponse | undefined, server: ServerListIte }; export const normalize = { + albumDetail, albumList, genreList, musicFolderList, diff --git a/src/renderer/api/types.ts b/src/renderer/api/types.ts index 2e1b24cd..e81b8f5b 100644 --- a/src/renderer/api/types.ts +++ b/src/renderer/api/types.ts @@ -165,7 +165,7 @@ export type Album = { songs?: Song[]; uniqueId: string; updatedAt: string; -}; +} & { songs?: Song[] }; export type Song = { album: string; diff --git a/src/renderer/features/albums/queries/album-detail-query.ts b/src/renderer/features/albums/queries/album-detail-query.ts index f13b6d92..cd6a83a6 100644 --- a/src/renderer/features/albums/queries/album-detail-query.ts +++ b/src/renderer/features/albums/queries/album-detail-query.ts @@ -2,15 +2,21 @@ import { useQuery } from '@tanstack/react-query'; import { queryKeys } from '/@/renderer/api/query-keys'; import type { QueryOptions } from '/@/renderer/lib/react-query'; import { useCurrentServer } from '../../../store/auth.store'; -import type { AlbumDetailQuery } from '/@/renderer/api/types'; +import type { AlbumDetailQuery, RawAlbumDetailResponse } from '/@/renderer/api/types'; import { controller } from '/@/renderer/api/controller'; +import { useCallback } from 'react'; +import { api } from '/@/renderer/api'; -export const useAlbumDetail = (query: AlbumDetailQuery, options: QueryOptions) => { +export const useAlbumDetail = (query: AlbumDetailQuery, options?: QueryOptions) => { const server = useCurrentServer(); return useQuery({ queryFn: ({ signal }) => controller.getAlbumDetail({ query, server, signal }), queryKey: queryKeys.albums.detail(server?.id || '', query), + select: useCallback( + (data: RawAlbumDetailResponse | undefined) => api.normalize.albumDetail(data, server), + [server], + ), ...options, }); };