diff --git a/src/renderer/api/navidrome/navidrome-controller.ts b/src/renderer/api/navidrome/navidrome-controller.ts index e2641dbd..0d95199f 100644 --- a/src/renderer/api/navidrome/navidrome-controller.ts +++ b/src/renderer/api/navidrome/navidrome-controller.ts @@ -4,7 +4,6 @@ import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller import { NDSongListSort } from '/@/shared/api/navidrome.types'; import { ndNormalize } from '/@/shared/api/navidrome/navidrome-normalize'; import { ssNormalize } from '/@/shared/api/subsonic/subsonic-normalize'; -import { SubsonicExtensions } from '/@/shared/api/subsonic/subsonic-types'; import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils'; import { albumArtistListSortMap, @@ -21,10 +20,11 @@ import { sortOrderMap, userListSortMap, } from '/@/shared/types/domain-types'; -import { ServerFeature, ServerFeatures } from '/@/shared/types/features-types'; +import { ServerFeature } from '/@/shared/types/features-types'; const VERSION_INFO: VersionInfo = [ - ['0.55.0', { [ServerFeature.BFR]: [1] }], + ['0.56.0', { [ServerFeature.TRACK_ALBUM_ARTIST_SEARCH]: [1] }], + ['0.55.0', { [ServerFeature.BFR]: [1], [ServerFeature.TAGS]: [1] }], ['0.49.3', { [ServerFeature.SHARING_ALBUM_SONG]: [1] }], ['0.48.0', { [ServerFeature.PLAYLISTS_SMART]: [1] }], ]; @@ -55,6 +55,9 @@ const excludeMissing = (server: null | ServerListItem) => { return undefined; }; +const getArtistSongKey = (server: null | ServerListItem) => + hasFeature(server, ServerFeature.TRACK_ALBUM_ARTIST_SEARCH) ? 'artists_id' : 'album_artist_id'; + export const NavidromeController: ControllerEndpoint = { addToPlaylist: async (args) => { const { apiClientProps, body, query } = args; @@ -463,38 +466,20 @@ export const NavidromeController: ControllerEndpoint = { ping.body.serverVersion = '0.55.0'; } - const navidromeFeatures: Record = getFeatures( - VERSION_INFO, - ping.body.serverVersion!, - ); + const navidromeFeatures = getFeatures(VERSION_INFO, ping.body.serverVersion!); + const subsonicArgs = await SubsonicController.getServerInfo(args); - if (ping.body.openSubsonic) { - const res = await ssApiClient(apiClientProps).getServerInfo(); - - if (res.status !== 200) { - throw new Error('Failed to get server extensions'); - } - - // The type here isn't necessarily an array (even though it's supposed to be). This is - // an implementation detail of Navidrome 0.50. Do a type check to make sure it's actually - // an array, and not an empty object. - if (Array.isArray(res.body.openSubsonicExtensions)) { - for (const extension of res.body.openSubsonicExtensions) { - navidromeFeatures[extension.name] = extension.versions; - } - } - } - - const features: ServerFeatures = { - bfr: navidromeFeatures[ServerFeature.BFR], - lyricsMultipleStructured: navidromeFeatures[SubsonicExtensions.SONG_LYRICS], - playlistsSmart: navidromeFeatures[ServerFeature.PLAYLISTS_SMART], + const features = { + ...navidromeFeatures, + ...subsonicArgs.features, publicPlaylist: [1], - sharingAlbumSong: navidromeFeatures[ServerFeature.SHARING_ALBUM_SONG], - tags: navidromeFeatures[ServerFeature.BFR], }; - return { features, id: apiClientProps.server?.id, version: ping.body.serverVersion! }; + return { + features, + id: apiClientProps.server?.id, + version: ping.body.serverVersion!, + }; }, getSimilarSongs: async (args) => { const { apiClientProps, query } = args; @@ -531,7 +516,7 @@ export const NavidromeController: ControllerEndpoint = { _order: 'ASC', _sort: NDSongListSort.RANDOM, _start: 0, - album_artist_id: query.albumArtistIds, + [getArtistSongKey(apiClientProps.server)]: query.albumArtistIds, ...excludeMissing(apiClientProps.server), }, }); @@ -572,10 +557,9 @@ export const NavidromeController: ControllerEndpoint = { _order: sortOrderMap.navidrome[query.sortOrder], _sort: songListSortMap.navidrome[query.sortBy], _start: query.startIndex, - album_artist_id: query.albumArtistIds, album_id: query.albumIds, - artist_id: query.artistIds, genre_id: query.genreIds, + [getArtistSongKey(apiClientProps.server)]: query.artistIds ?? query.albumArtistIds, starred: query.favorite, title: query.searchTerm, ...query._custom?.navidrome, diff --git a/src/shared/api/navidrome/navidrome-types.ts b/src/shared/api/navidrome/navidrome-types.ts index 0e3a3585..9a1e02b4 100644 --- a/src/shared/api/navidrome/navidrome-types.ts +++ b/src/shared/api/navidrome/navidrome-types.ts @@ -251,6 +251,7 @@ const songListParameters = paginationParameters.extend({ album_artist_id: z.array(z.string()).optional(), album_id: z.array(z.string()).optional(), artist_id: z.array(z.string()).optional(), + artists_id: z.array(z.string()).optional(), genre_id: z.array(z.string()).optional(), path: z.string().optional(), starred: z.boolean().optional(), diff --git a/src/shared/api/utils.ts b/src/shared/api/utils.ts index 308299ff..9bbcac1e 100644 --- a/src/shared/api/utils.ts +++ b/src/shared/api/utils.ts @@ -36,7 +36,9 @@ export const hasFeature = (server: null | ServerListItem, feature: ServerFeature return (server.features[feature]?.length || 0) > 0; }; -export type VersionInfo = ReadonlyArray<[string, Record]>; +export type VersionInfo = ReadonlyArray< + [string, Partial>] +>; /** * Returns the available server features given the version string. @@ -61,9 +63,9 @@ export type VersionInfo = ReadonlyArray<[string, Record => { +): Partial> => { const cleanVersion = semverCoerce(version); - const features: Record = {}; + const features: Partial> = {}; let matched = cleanVersion === null; for (const [version, supportedFeatures] of versionInfo) { diff --git a/src/shared/types/features-types.ts b/src/shared/types/features-types.ts index 872deafc..1d62d592 100644 --- a/src/shared/types/features-types.ts +++ b/src/shared/types/features-types.ts @@ -8,6 +8,7 @@ export enum ServerFeature { PUBLIC_PLAYLIST = 'publicPlaylist', SHARING_ALBUM_SONG = 'sharingAlbumSong', TAGS = 'tags', + TRACK_ALBUM_ARTIST_SEARCH = 'trackAlbumArtistSearch', } export type ServerFeatures = Partial>;