refactor api controller to internalize server fetch

This commit is contained in:
jeffvli 2025-11-02 21:56:35 -08:00
parent 8dbaec3943
commit c7a473d864
79 changed files with 904 additions and 399 deletions

View file

@ -2,18 +2,19 @@ import i18n from '/@/i18n/i18n';
import { JellyfinController } from '/@/renderer/api/jellyfin/jellyfin-controller';
import { NavidromeController } from '/@/renderer/api/navidrome/navidrome-controller';
import { SubsonicController } from '/@/renderer/api/subsonic/subsonic-controller';
import { useAuthStore } from '/@/renderer/store';
import { getServerById, useAuthStore } from '/@/renderer/store';
import { toast } from '/@/shared/components/toast/toast';
import {
AuthenticationResponse,
ControllerEndpoint,
InternalControllerEndpoint,
ServerType,
} from '/@/shared/types/domain-types';
type ApiController = {
jellyfin: ControllerEndpoint;
navidrome: ControllerEndpoint;
subsonic: ControllerEndpoint;
jellyfin: InternalControllerEndpoint;
navidrome: InternalControllerEndpoint;
subsonic: InternalControllerEndpoint;
};
const endpoints: ApiController = {
@ -25,7 +26,7 @@ const endpoints: ApiController = {
const apiController = <K extends keyof ControllerEndpoint>(
endpoint: K,
type?: ServerType,
): NonNullable<ControllerEndpoint[K]> => {
): NonNullable<InternalControllerEndpoint[K]> => {
const serverType = type || useAuthStore.getState().currentServer?.type;
if (!serverType) {
@ -68,129 +69,580 @@ export interface GeneralController extends Omit<Required<ControllerEndpoint>, 'a
export const controller: GeneralController = {
addToPlaylist(args) {
return apiController('addToPlaylist', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: addToPlaylist`,
);
}
return apiController(
'addToPlaylist',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
authenticate(url, body, type) {
return apiController('authenticate', type)(url, body);
},
createFavorite(args) {
return apiController('createFavorite', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: createFavorite`,
);
}
return apiController(
'createFavorite',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
createPlaylist(args) {
return apiController('createPlaylist', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: createPlaylist`,
);
}
return apiController(
'createPlaylist',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
deleteFavorite(args) {
return apiController('deleteFavorite', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: deleteFavorite`,
);
}
return apiController(
'deleteFavorite',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
deletePlaylist(args) {
return apiController('deletePlaylist', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: deletePlaylist`,
);
}
return apiController(
'deletePlaylist',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumArtistDetail(args) {
return apiController('getAlbumArtistDetail', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumArtistDetail`,
);
}
return apiController(
'getAlbumArtistDetail',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumArtistList(args) {
return apiController('getAlbumArtistList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumArtistList`,
);
}
return apiController(
'getAlbumArtistList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumArtistListCount(args) {
return apiController('getAlbumArtistListCount', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumArtistListCount`,
);
}
return apiController(
'getAlbumArtistListCount',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumDetail(args) {
return apiController('getAlbumDetail', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumDetail`,
);
}
return apiController(
'getAlbumDetail',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumInfo(args) {
return apiController('getAlbumInfo', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumInfo`,
);
}
return apiController(
'getAlbumInfo',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumList(args) {
return apiController('getAlbumList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumList`,
);
}
return apiController(
'getAlbumList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getAlbumListCount(args) {
return apiController('getAlbumListCount', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getAlbumListCount`,
);
}
return apiController(
'getAlbumListCount',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getArtistList(args) {
return apiController('getArtistList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getArtistList`,
);
}
return apiController(
'getArtistList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getArtistListCount(args) {
return apiController('getArtistListCount', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getArtistListCount`,
);
}
return apiController(
'getArtistListCount',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getDownloadUrl(args) {
return apiController('getDownloadUrl', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getDownloadUrl`,
);
}
return apiController(
'getDownloadUrl',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getGenreList(args) {
return apiController('getGenreList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getGenreList`,
);
}
return apiController(
'getGenreList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getLyrics(args) {
return apiController('getLyrics', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getLyrics`,
);
}
return apiController(
'getLyrics',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getMusicFolderList(args) {
return apiController('getMusicFolderList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getMusicFolderList`,
);
}
return apiController(
'getMusicFolderList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getPlaylistDetail(args) {
return apiController('getPlaylistDetail', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getPlaylistDetail`,
);
}
return apiController(
'getPlaylistDetail',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getPlaylistList(args) {
return apiController('getPlaylistList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getPlaylistList`,
);
}
return apiController(
'getPlaylistList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getPlaylistListCount(args) {
return apiController('getPlaylistListCount', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getPlaylistListCount`,
);
}
return apiController(
'getPlaylistListCount',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getPlaylistSongList(args) {
return apiController('getPlaylistSongList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getPlaylistSongList`,
);
}
return apiController(
'getPlaylistSongList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getRandomSongList(args) {
return apiController('getRandomSongList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getRandomSongList`,
);
}
return apiController(
'getRandomSongList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getRoles(args) {
return apiController('getRoles', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getRoles`,
);
}
return apiController(
'getRoles',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getServerInfo(args) {
return apiController('getServerInfo', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getServerInfo`,
);
}
return apiController(
'getServerInfo',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getSimilarSongs(args) {
return apiController('getSimilarSongs', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getSimilarSongs`,
);
}
return apiController(
'getSimilarSongs',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getSongDetail(args) {
return apiController('getSongDetail', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getSongDetail`,
);
}
return apiController(
'getSongDetail',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getSongList(args) {
return apiController('getSongList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getSongList`,
);
}
return apiController(
'getSongList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getSongListCount(args) {
return apiController('getSongListCount', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getSongListCount`,
);
}
return apiController(
'getSongListCount',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getStructuredLyrics(args) {
return apiController('getStructuredLyrics', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getStructuredLyrics`,
);
}
return apiController(
'getStructuredLyrics',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getTags(args) {
return apiController('getTags', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getTags`,
);
}
return apiController(
'getTags',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getTopSongs(args) {
return apiController('getTopSongs', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getTopSongs`,
);
}
return apiController(
'getTopSongs',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getTranscodingUrl(args) {
return apiController('getTranscodingUrl', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getTranscodingUrl`,
);
}
return apiController(
'getTranscodingUrl',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
getUserList(args) {
return apiController('getUserList', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: getUserList`,
);
}
return apiController(
'getUserList',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
movePlaylistItem(args) {
return apiController('movePlaylistItem', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: movePlaylistItem`,
);
}
return apiController(
'movePlaylistItem',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
removeFromPlaylist(args) {
return apiController('removeFromPlaylist', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: removeFromPlaylist`,
);
}
return apiController(
'removeFromPlaylist',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
scrobble(args) {
return apiController('scrobble', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: scrobble`,
);
}
return apiController(
'scrobble',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
search(args) {
return apiController('search', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: search`,
);
}
return apiController(
'search',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
setRating(args) {
return apiController('setRating', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: setRating`,
);
}
return apiController(
'setRating',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
shareItem(args) {
return apiController('shareItem', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: shareItem`,
);
}
return apiController(
'shareItem',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
updatePlaylist(args) {
return apiController('updatePlaylist', args.apiClientProps.server?.type)?.(args);
const server = getServerById(args.apiClientProps.serverId);
if (!server) {
throw new Error(
`${i18n.t('error.apiRouteError', { postProcess: 'sentenceCase' })}: updatePlaylist`,
);
}
return apiController(
'updatePlaylist',
server.type,
)?.({ ...args, apiClientProps: { ...args.apiClientProps, server } });
},
};

View file

@ -11,7 +11,7 @@ import { authenticationFailure } from '/@/renderer/api/utils';
import { useAuthStore } from '/@/renderer/store';
import { jfType } from '/@/shared/api/jellyfin/jellyfin-types';
import { getClientType } from '/@/shared/api/utils';
import { ServerListItem } from '/@/shared/types/domain-types';
import { ServerListItemWithCredential } from '/@/shared/types/domain-types';
const c = initContract();
@ -359,7 +359,7 @@ export const createAuthHeader = (): string => {
};
export const jfApiClient = (args: {
server: null | ServerListItem;
server: null | ServerListItemWithCredential;
signal?: AbortSignal;
url?: string;
}) => {

View file

@ -9,8 +9,8 @@ import { getFeatures, hasFeature, VersionInfo } from '/@/shared/api/utils';
import {
albumArtistListSortMap,
albumListSortMap,
ControllerEndpoint,
genreListSortMap,
InternalControllerEndpoint,
LibraryItem,
Played,
playlistListSortMap,
@ -40,7 +40,7 @@ const VERSION_INFO: VersionInfo = [
['10.0.0', { [ServerFeature.TAGS]: [1] }],
];
export const JellyfinController: ControllerEndpoint = {
export const JellyfinController: InternalControllerEndpoint = {
addToPlaylist: async (args) => {
const { apiClientProps, body, query } = args;

View file

@ -11,7 +11,7 @@ import { useAuthStore } from '/@/renderer/store';
import { ndType } from '/@/shared/api/navidrome/navidrome-types';
import { resultWithHeaders } from '/@/shared/api/utils';
import { toast } from '/@/shared/components/toast/toast';
import { ServerListItem } from '/@/shared/types/domain-types';
import { ServerListItemWithCredential } from '/@/shared/types/domain-types';
const localSettings = isElectron() ? window.api.localSettings : null;
@ -379,7 +379,7 @@ axiosClient.interceptors.response.use(
);
export const ndApiClient = (args: {
server: null | ServerListItem;
server: null | ServerListItemWithCredential;
signal?: AbortSignal;
url?: string;
}) => {

View file

@ -9,12 +9,12 @@ import {
albumArtistListSortMap,
albumListSortMap,
AuthenticationResponse,
ControllerEndpoint,
genreListSortMap,
InternalControllerEndpoint,
playlistListSortMap,
PlaylistSongListArgs,
PlaylistSongListResponse,
ServerListItem,
ServerListItemWithCredential,
Song,
songListSortMap,
sortOrderMap,
@ -47,7 +47,11 @@ const NAVIDROME_ROLES: Array<string | { label: string; value: string }> = [
const EXCLUDED_TAGS = new Set<string>(['disctotal', 'genre', 'tracktotal']);
const excludeMissing = (server: null | ServerListItem) => {
const excludeMissing = (server?: null | ServerListItemWithCredential) => {
if (!server) {
return undefined;
}
if (hasFeature(server, ServerFeature.BFR)) {
return { missing: false };
}
@ -55,10 +59,10 @@ const excludeMissing = (server: null | ServerListItem) => {
return undefined;
};
const getArtistSongKey = (server: null | ServerListItem) =>
const getArtistSongKey = (server: null | ServerListItemWithCredential) =>
hasFeature(server, ServerFeature.TRACK_ALBUM_ARTIST_SEARCH) ? 'artists_id' : 'album_artist_id';
export const NavidromeController: ControllerEndpoint = {
export const NavidromeController: InternalControllerEndpoint = {
addToPlaylist: async (args) => {
const { apiClientProps, body, query } = args;
@ -156,7 +160,7 @@ export const NavidromeController: ControllerEndpoint = {
throw new Error('Failed to get album artist detail');
}
if (!apiClientProps.server) {
if (!apiClientProps.serverId) {
throw new Error('Server is required');
}
@ -431,7 +435,7 @@ export const NavidromeController: ControllerEndpoint = {
getPlaylistSongList: async (args: PlaylistSongListArgs): Promise<PlaylistSongListResponse> => {
const { apiClientProps, query } = args;
const res = await ndApiClient(apiClientProps).getPlaylistSongList({
const res = await ndApiClient(apiClientProps as any).getPlaylistSongList({
params: {
id: query.id,
},
@ -481,7 +485,7 @@ export const NavidromeController: ControllerEndpoint = {
return {
features,
id: apiClientProps.server?.id,
id: apiClientProps.serverId,
version: ping.body.serverVersion!,
};
},

View file

@ -7,7 +7,7 @@ import { z } from 'zod';
import i18n from '/@/i18n/i18n';
import { ssType } from '/@/shared/api/subsonic/subsonic-types';
import { toast } from '/@/shared/components/toast/toast';
import { ServerListItem } from '/@/shared/types/domain-types';
import { ServerListItemWithCredential } from '/@/shared/types/domain-types';
const c = initContract();
@ -288,7 +288,7 @@ const silentlyTransformResponse = (data: any) => {
};
export const ssApiClient = (args: {
server: null | ServerListItem;
server: null | ServerListItemWithCredential;
signal?: AbortSignal;
silent?: boolean;
url?: string;

View file

@ -16,8 +16,8 @@ import {
} from '/@/shared/api/subsonic/subsonic-types';
import {
AlbumListSort,
ControllerEndpoint,
GenreListSort,
InternalControllerEndpoint,
LibraryItem,
PlaylistListSort,
Song,
@ -51,7 +51,7 @@ const MAX_SUBSONIC_ITEMS = 500;
// A trick to skip ahead 10x
const SUBSONIC_FAST_BATCH_SIZE = MAX_SUBSONIC_ITEMS * 10;
export const SubsonicController: ControllerEndpoint = {
export const SubsonicController: InternalControllerEndpoint = {
addToPlaylist: async ({ apiClientProps, body, query }) => {
const res = await ssApiClient(apiClientProps).updatePlaylist({
query: {