mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 10:23:33 +00:00
add jellyfin, improvements
This commit is contained in:
parent
85d2576bdc
commit
58f38b2655
11 changed files with 168 additions and 17 deletions
|
|
@ -46,6 +46,8 @@ import type {
|
|||
AuthenticationResponse,
|
||||
SearchArgs,
|
||||
SearchResponse,
|
||||
LyricsArgs,
|
||||
SynchronizedLyricsArray,
|
||||
} from '/@/renderer/api/types';
|
||||
import { ServerType } from '/@/renderer/types';
|
||||
import { DeletePlaylistResponse, RandomSongListArgs } from './types';
|
||||
|
|
@ -76,6 +78,7 @@ export type ControllerEndpoint = Partial<{
|
|||
getFolderList: () => void;
|
||||
getFolderSongs: () => void;
|
||||
getGenreList: (args: GenreListArgs) => Promise<GenreListResponse>;
|
||||
getLyrics: (args: LyricsArgs) => Promise<SynchronizedLyricsArray>;
|
||||
getMusicFolderList: (args: MusicFolderListArgs) => Promise<MusicFolderListResponse>;
|
||||
getPlaylistDetail: (args: PlaylistDetailArgs) => Promise<PlaylistDetailResponse>;
|
||||
getPlaylistList: (args: PlaylistListArgs) => Promise<PlaylistListResponse>;
|
||||
|
|
@ -119,6 +122,7 @@ const endpoints: ApiController = {
|
|||
getFolderList: undefined,
|
||||
getFolderSongs: undefined,
|
||||
getGenreList: jfController.getGenreList,
|
||||
getLyrics: jfController.getLyrics,
|
||||
getMusicFolderList: jfController.getMusicFolderList,
|
||||
getPlaylistDetail: jfController.getPlaylistDetail,
|
||||
getPlaylistList: jfController.getPlaylistList,
|
||||
|
|
@ -154,6 +158,7 @@ const endpoints: ApiController = {
|
|||
getFolderList: undefined,
|
||||
getFolderSongs: undefined,
|
||||
getGenreList: ndController.getGenreList,
|
||||
getLyrics: undefined,
|
||||
getMusicFolderList: ssController.getMusicFolderList,
|
||||
getPlaylistDetail: ndController.getPlaylistDetail,
|
||||
getPlaylistList: ndController.getPlaylistList,
|
||||
|
|
@ -188,6 +193,7 @@ const endpoints: ApiController = {
|
|||
getFolderList: undefined,
|
||||
getFolderSongs: undefined,
|
||||
getGenreList: undefined,
|
||||
getLyrics: undefined,
|
||||
getMusicFolderList: ssController.getMusicFolderList,
|
||||
getPlaylistDetail: undefined,
|
||||
getPlaylistList: undefined,
|
||||
|
|
@ -448,6 +454,12 @@ const getRandomSongList = async (args: RandomSongListArgs) => {
|
|||
)?.(args);
|
||||
};
|
||||
|
||||
const getLyrics = async (args: LyricsArgs) => {
|
||||
return (
|
||||
apiController('getLyrics', args.apiClientProps.server?.type) as ControllerEndpoint['getLyrics']
|
||||
)?.(args);
|
||||
};
|
||||
|
||||
export const controller = {
|
||||
addToPlaylist,
|
||||
authenticate,
|
||||
|
|
@ -461,6 +473,7 @@ export const controller = {
|
|||
getAlbumList,
|
||||
getArtistList,
|
||||
getGenreList,
|
||||
getLyrics,
|
||||
getMusicFolderList,
|
||||
getPlaylistDetail,
|
||||
getPlaylistList,
|
||||
|
|
|
|||
|
|
@ -174,6 +174,14 @@ export const contract = c.router({
|
|||
400: jfType._response.error,
|
||||
},
|
||||
},
|
||||
getSongLyrics: {
|
||||
method: 'GET',
|
||||
path: 'users/:userId/Items/:id/Lyrics',
|
||||
responses: {
|
||||
200: jfType._response.lyrics,
|
||||
404: jfType._response.error,
|
||||
},
|
||||
},
|
||||
getTopSongsList: {
|
||||
method: 'GET',
|
||||
path: 'users/:userId/items',
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ import {
|
|||
SearchResponse,
|
||||
RandomSongListResponse,
|
||||
RandomSongListArgs,
|
||||
LyricsArgs,
|
||||
SynchronizedLyricsArray,
|
||||
} from '/@/renderer/api/types';
|
||||
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
||||
import { jfNormalize } from './jellyfin-normalize';
|
||||
|
|
@ -846,6 +848,28 @@ const getRandomSongList = async (args: RandomSongListArgs): Promise<RandomSongLi
|
|||
totalRecordCount: res.body.Items.length || 0,
|
||||
};
|
||||
};
|
||||
|
||||
const getLyrics = async (args: LyricsArgs): Promise<SynchronizedLyricsArray> => {
|
||||
const { query, apiClientProps } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
}
|
||||
|
||||
const res = await jfApiClient(apiClientProps).getSongLyrics({
|
||||
params: {
|
||||
id: query.songId,
|
||||
userId: apiClientProps.server?.userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
throw new Error('Failed to get lyrics');
|
||||
}
|
||||
|
||||
return res.body.Lyrics.map((lyric) => [lyric.Start / 1e4, lyric.Text]);
|
||||
};
|
||||
|
||||
export const jfController = {
|
||||
addToPlaylist,
|
||||
authenticate,
|
||||
|
|
@ -859,6 +883,7 @@ export const jfController = {
|
|||
getAlbumList,
|
||||
getArtistList,
|
||||
getGenreList,
|
||||
getLyrics,
|
||||
getMusicFolderList,
|
||||
getPlaylistDetail,
|
||||
getPlaylistList,
|
||||
|
|
|
|||
|
|
@ -631,6 +631,15 @@ const searchParameters = paginationParameters.merge(baseParameters);
|
|||
|
||||
const search = z.any();
|
||||
|
||||
const lyricText = z.object({
|
||||
Start: z.number(),
|
||||
Text: z.string(),
|
||||
});
|
||||
|
||||
const lyrics = z.object({
|
||||
Lyrics: z.array(lyricText),
|
||||
});
|
||||
|
||||
export const jfType = {
|
||||
_enum: {
|
||||
collection: jfCollection,
|
||||
|
|
@ -670,6 +679,7 @@ export const jfType = {
|
|||
favorite,
|
||||
genre,
|
||||
genreList,
|
||||
lyrics,
|
||||
musicFolderList,
|
||||
playlist,
|
||||
playlistList,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import type {
|
|||
SearchQuery,
|
||||
SongDetailQuery,
|
||||
RandomSongListQuery,
|
||||
LyricsQuery,
|
||||
} from './types';
|
||||
|
||||
export const queryKeys: Record<
|
||||
|
|
@ -102,6 +103,10 @@ export const queryKeys: Record<
|
|||
if (query) return [serverId, 'songs', 'list', query] as const;
|
||||
return [serverId, 'songs', 'list'] as const;
|
||||
},
|
||||
lyrics: (serverId: string, query?: LyricsQuery) => {
|
||||
if (query) return [serverId, 'song', 'lyrics', query] as const;
|
||||
return [serverId, 'song', 'lyrics'] as const;
|
||||
},
|
||||
randomSongList: (serverId: string, query?: RandomSongListQuery) => {
|
||||
if (query) return [serverId, 'songs', 'randomSongList', query] as const;
|
||||
return [serverId, 'songs', 'randomSongList'] as const;
|
||||
|
|
|
|||
|
|
@ -1017,6 +1017,16 @@ export type RandomSongListArgs = {
|
|||
|
||||
export type RandomSongListResponse = SongListResponse;
|
||||
|
||||
export type LyricsQuery = {
|
||||
songId: string;
|
||||
};
|
||||
|
||||
export type LyricsArgs = {
|
||||
query: LyricsQuery;
|
||||
} & BaseEndpointArgs;
|
||||
|
||||
export type SynchronizedLyricsArray = Array<[number, string]>;
|
||||
|
||||
export const instanceOfCancellationError = (error: any) => {
|
||||
return 'revert' in error;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue