Add jellyfin search api
This commit is contained in:
parent
deb4e34895
commit
a7ea54cf4b
4 changed files with 116 additions and 1 deletions
|
@ -128,7 +128,7 @@ const endpoints: ApiController = {
|
||||||
getUserList: undefined,
|
getUserList: undefined,
|
||||||
removeFromPlaylist: jfController.removeFromPlaylist,
|
removeFromPlaylist: jfController.removeFromPlaylist,
|
||||||
scrobble: jfController.scrobble,
|
scrobble: jfController.scrobble,
|
||||||
search: undefined,
|
search: jfController.search,
|
||||||
setRating: undefined,
|
setRating: undefined,
|
||||||
updatePlaylist: jfController.updatePlaylist,
|
updatePlaylist: jfController.updatePlaylist,
|
||||||
},
|
},
|
||||||
|
|
|
@ -224,6 +224,15 @@ export const contract = c.router({
|
||||||
400: jfType._response.error,
|
400: jfType._response.error,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
search: {
|
||||||
|
method: 'GET',
|
||||||
|
path: 'users/:userId/items',
|
||||||
|
query: jfType._parameters.search,
|
||||||
|
responses: {
|
||||||
|
200: jfType._response.search,
|
||||||
|
400: jfType._response.error,
|
||||||
|
},
|
||||||
|
},
|
||||||
updatePlaylist: {
|
updatePlaylist: {
|
||||||
body: jfType._parameters.updatePlaylist,
|
body: jfType._parameters.updatePlaylist,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|
|
@ -40,11 +40,14 @@ import {
|
||||||
RemoveFromPlaylistResponse,
|
RemoveFromPlaylistResponse,
|
||||||
PlaylistDetailResponse,
|
PlaylistDetailResponse,
|
||||||
PlaylistListResponse,
|
PlaylistListResponse,
|
||||||
|
SearchArgs,
|
||||||
|
SearchResponse,
|
||||||
} from '/@/renderer/api/types';
|
} from '/@/renderer/api/types';
|
||||||
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
||||||
import { jfNormalize } from './jellyfin-normalize';
|
import { jfNormalize } from './jellyfin-normalize';
|
||||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||||
import packageJson from '../../../../package.json';
|
import packageJson from '../../../../package.json';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
const formatCommaDelimitedString = (value: string[]) => {
|
const formatCommaDelimitedString = (value: string[]) => {
|
||||||
return value.join(',');
|
return value.join(',');
|
||||||
|
@ -704,6 +707,97 @@ const scrobble = async (args: ScrobbleArgs): Promise<ScrobbleResponse> => {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const search = async (args: SearchArgs): Promise<SearchResponse> => {
|
||||||
|
const { query, apiClientProps } = args;
|
||||||
|
|
||||||
|
if (!apiClientProps.server?.userId) {
|
||||||
|
throw new Error('No userId found');
|
||||||
|
}
|
||||||
|
|
||||||
|
let albums: z.infer<typeof jfType._response.albumList>['Items'] = [];
|
||||||
|
let albumArtists: z.infer<typeof jfType._response.albumArtistList>['Items'] = [];
|
||||||
|
let songs: z.infer<typeof jfType._response.songList>['Items'] = [];
|
||||||
|
|
||||||
|
if (query.albumLimit) {
|
||||||
|
const res = await jfApiClient(apiClientProps).getAlbumList({
|
||||||
|
params: {
|
||||||
|
userId: apiClientProps.server?.userId,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
EnableTotalRecordCount: true,
|
||||||
|
ImageTypeLimit: 1,
|
||||||
|
IncludeItemTypes: 'MusicAlbum',
|
||||||
|
Limit: query.albumLimit,
|
||||||
|
Recursive: true,
|
||||||
|
SearchTerm: query.query,
|
||||||
|
SortBy: 'SortName',
|
||||||
|
SortOrder: 'Ascending',
|
||||||
|
StartIndex: query.albumStartIndex || 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status !== 200) {
|
||||||
|
throw new Error('Failed to get album list');
|
||||||
|
}
|
||||||
|
|
||||||
|
albums = res.body.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.albumArtistLimit) {
|
||||||
|
const res = await jfApiClient(apiClientProps).getAlbumArtistList({
|
||||||
|
query: {
|
||||||
|
EnableTotalRecordCount: true,
|
||||||
|
Fields: 'Genres, DateCreated, ExternalUrls, Overview',
|
||||||
|
ImageTypeLimit: 1,
|
||||||
|
IncludeArtists: true,
|
||||||
|
Limit: query.albumArtistLimit,
|
||||||
|
Recursive: true,
|
||||||
|
SearchTerm: query.query,
|
||||||
|
StartIndex: query.albumArtistStartIndex || 0,
|
||||||
|
UserId: apiClientProps.server?.userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status !== 200) {
|
||||||
|
throw new Error('Failed to get album artist list');
|
||||||
|
}
|
||||||
|
|
||||||
|
albumArtists = res.body.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.songLimit) {
|
||||||
|
const res = await jfApiClient(apiClientProps).getSongList({
|
||||||
|
params: {
|
||||||
|
userId: apiClientProps.server?.userId,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
EnableTotalRecordCount: true,
|
||||||
|
Fields: 'Genres, DateCreated, MediaSources, ParentId',
|
||||||
|
IncludeItemTypes: 'Audio',
|
||||||
|
Limit: query.songLimit,
|
||||||
|
Recursive: true,
|
||||||
|
SearchTerm: query.query,
|
||||||
|
SortBy: 'Album,SortName',
|
||||||
|
SortOrder: 'Ascending',
|
||||||
|
StartIndex: query.songStartIndex || 0,
|
||||||
|
UserId: apiClientProps.server?.userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status !== 200) {
|
||||||
|
throw new Error('Failed to get song list');
|
||||||
|
}
|
||||||
|
|
||||||
|
songs = res.body.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
albumArtists: albumArtists.map((item) => jfNormalize.albumArtist(item, apiClientProps.server)),
|
||||||
|
albums: albums.map((item) => jfNormalize.album(item, apiClientProps.server)),
|
||||||
|
songs: songs.map((item) => jfNormalize.song(item, apiClientProps.server, '')),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const jfController = {
|
export const jfController = {
|
||||||
addToPlaylist,
|
addToPlaylist,
|
||||||
authenticate,
|
authenticate,
|
||||||
|
@ -725,5 +819,6 @@ export const jfController = {
|
||||||
getTopSongList,
|
getTopSongList,
|
||||||
removeFromPlaylist,
|
removeFromPlaylist,
|
||||||
scrobble,
|
scrobble,
|
||||||
|
search,
|
||||||
updatePlaylist,
|
updatePlaylist,
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,12 @@ const baseParameters = z.object({
|
||||||
ExcludeItemTypes: z.string().optional(),
|
ExcludeItemTypes: z.string().optional(),
|
||||||
Fields: z.string().optional(),
|
Fields: z.string().optional(),
|
||||||
ImageTypeLimit: z.number().optional(),
|
ImageTypeLimit: z.number().optional(),
|
||||||
|
IncludeArtists: z.boolean().optional(),
|
||||||
|
IncludeGenres: z.boolean().optional(),
|
||||||
IncludeItemTypes: z.string().optional(),
|
IncludeItemTypes: z.string().optional(),
|
||||||
|
IncludeMedia: z.boolean().optional(),
|
||||||
|
IncludePeople: z.boolean().optional(),
|
||||||
|
IncludeStudios: z.boolean().optional(),
|
||||||
IsFavorite: z.boolean().optional(),
|
IsFavorite: z.boolean().optional(),
|
||||||
Limit: z.number().optional(),
|
Limit: z.number().optional(),
|
||||||
MediaTypes: z.string().optional(),
|
MediaTypes: z.string().optional(),
|
||||||
|
@ -622,6 +627,10 @@ const favorite = z.object({
|
||||||
|
|
||||||
const favoriteParameters = z.object({});
|
const favoriteParameters = z.object({});
|
||||||
|
|
||||||
|
const searchParameters = paginationParameters.merge(baseParameters);
|
||||||
|
|
||||||
|
const search = z.any();
|
||||||
|
|
||||||
export const jfType = {
|
export const jfType = {
|
||||||
_enum: {
|
_enum: {
|
||||||
collection: jfCollection,
|
collection: jfCollection,
|
||||||
|
@ -643,6 +652,7 @@ export const jfType = {
|
||||||
playlistList: playlistListParameters,
|
playlistList: playlistListParameters,
|
||||||
removeFromPlaylist: removeFromPlaylistParameters,
|
removeFromPlaylist: removeFromPlaylistParameters,
|
||||||
scrobble: scrobbleParameters,
|
scrobble: scrobbleParameters,
|
||||||
|
search: searchParameters,
|
||||||
similarArtistList: similarArtistListParameters,
|
similarArtistList: similarArtistListParameters,
|
||||||
songList: songListParameters,
|
songList: songListParameters,
|
||||||
updatePlaylist: updatePlaylistParameters,
|
updatePlaylist: updatePlaylistParameters,
|
||||||
|
@ -666,6 +676,7 @@ export const jfType = {
|
||||||
playlistSongList,
|
playlistSongList,
|
||||||
removeFromPlaylist,
|
removeFromPlaylist,
|
||||||
scrobble,
|
scrobble,
|
||||||
|
search,
|
||||||
song,
|
song,
|
||||||
songList,
|
songList,
|
||||||
topSongsList,
|
topSongsList,
|
||||||
|
|
Reference in a new issue