[enhancement]: Make related tab on full screen player useful

Resolves #50. Adds a new set of components for fetching similar songs
from the current playing song. For Jellyfin, use the `/items/{itemId}/similar`
endpoint (may not work well for small libraries), and for Navidrome/Subsonic
use `getSimilarSongs`. _In theory_, this component can be used to get similar
songs anywhere.
This commit is contained in:
Kendall Garner 2024-02-19 08:53:50 -08:00
parent 74075fc374
commit 025124c379
No known key found for this signature in database
GPG key ID: 18D2767419676C87
14 changed files with 247 additions and 16 deletions

View file

@ -167,6 +167,15 @@ export const contract = c.router({
400: jfType._response.error,
},
},
getSimilarSongs: {
method: 'GET',
path: 'items/:itemId/similar',
query: jfType._parameters.similarSongs,
responses: {
200: jfType._response.similarSongs,
400: jfType._response.error,
},
},
getSongDetail: {
method: 'GET',
path: 'users/:userId/items/:id',

View file

@ -51,6 +51,8 @@ import {
SongDetailResponse,
ServerInfo,
ServerInfoArgs,
SimilarSongsArgs,
Song,
} from '/@/renderer/api/types';
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
import { jfNormalize } from './jellyfin-normalize';
@ -960,6 +962,27 @@ const getServerInfo = async (args: ServerInfoArgs): Promise<ServerInfo> => {
return { id: apiClientProps.server?.id, version: res.body.Version };
};
const getSimilarSongs = async (args: SimilarSongsArgs): Promise<Song[]> => {
const { apiClientProps, query } = args;
const res = await jfApiClient(apiClientProps).getSimilarSongs({
params: {
itemId: query.song.id,
},
query: {
Fields: 'Genres, DateCreated, MediaSources, ParentId',
Limit: query.count,
UserId: apiClientProps.server?.userId || undefined,
},
});
if (res.status !== 200) {
throw new Error('Failed to get music folder list');
}
return res.body.Items.map((song) => jfNormalize.song(song, apiClientProps.server, ''));
};
export const jfController = {
addToPlaylist,
authenticate,
@ -980,6 +1003,7 @@ export const jfController = {
getPlaylistSongList,
getRandomSongList,
getServerInfo,
getSimilarSongs,
getSongDetail,
getSongList,
getTopSongList,

View file

@ -665,6 +665,16 @@ const serverInfo = z.object({
Version: z.string(),
});
const similarSongsParameters = z.object({
Fields: z.string().optional(),
Limit: z.number().optional(),
UserId: z.string().optional(),
});
const similarSongs = pagination.extend({
Items: z.array(song),
});
export const jfType = {
_enum: {
albumArtistList: albumArtistListSort,
@ -694,6 +704,7 @@ export const jfType = {
scrobble: scrobbleParameters,
search: searchParameters,
similarArtistList: similarArtistListParameters,
similarSongs: similarSongsParameters,
songList: songListParameters,
updatePlaylist: updatePlaylistParameters,
},
@ -719,6 +730,7 @@ export const jfType = {
scrobble,
search,
serverInfo,
similarSongs,
song,
songList,
topSongsList,