Replace startScan (full library refresh) with refreshItem (individual item refresh) for jellyfin metadata editing

This commit is contained in:
ChrisScott9456
2026-06-28 20:19:12 -04:00
parent aa12585b20
commit 56f05ddafc
7 changed files with 32 additions and 29 deletions
+3 -3
View File
@@ -864,15 +864,15 @@ export const controller: GeneralController = {
server.type, server.type,
)?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } })); )?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } }));
}, },
startScan(args) { refreshItems(args) {
const server = getServerById(args.apiClientProps.serverId); const server = getServerById(args.apiClientProps.serverId);
if (!server) { if (!server) {
throw new Error(`${i18n.t('error.apiRouteError')}: startScan`); throw new Error(`${i18n.t('error.apiRouteError')}: refreshItems`);
} }
return apiController( return apiController(
'startScan', 'refreshItems',
server.type, server.type,
)?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } })); )?.(addContext({ ...args, apiClientProps: { ...args.apiClientProps, server } }));
}, },
+5 -3
View File
@@ -365,11 +365,13 @@ export const contract = c.router({
400: jfType._response.error, 400: jfType._response.error,
}, },
}, },
startScan: { refreshItem: {
body: z.null(), body: z.null(),
method: 'POST', method: 'POST',
path: 'Library/Refresh', path: 'Items/:id/Refresh',
query: z.object({}), query: z.object({
MetadataRefreshMode: z.string().optional(),
}),
responses: { responses: {
204: z.null(), 204: z.null(),
400: jfType._response.error, 400: jfType._response.error,
@@ -1931,17 +1931,18 @@ export const JellyfinController: InternalControllerEndpoint = {
return null; return null;
}, },
startScan: async (args) => { refreshItems: async (args) => {
const { apiClientProps } = args; const { apiClientProps, query } = args;
const res = await jfApiClient(apiClientProps).startScan({ await Promise.all(
body: null, query.ids.map((id) =>
query: {}, jfApiClient(apiClientProps).refreshItem({
}); body: null,
params: { id },
if (res.status !== 204) { query: { MetadataRefreshMode: 'FullRefresh' },
throw new Error('Failed to start scan'); }),
} ),
);
return null; return null;
}, },
@@ -1261,7 +1261,7 @@ export const NavidromeController: InternalControllerEndpoint = {
id: res.body.data.id, id: res.body.data.id,
}; };
}, },
startScan: SubsonicController.startScan, refreshItems: SubsonicController.refreshItems,
updateInternetRadioStation: async (args) => { updateInternetRadioStation: async (args) => {
const { apiClientProps, body, query } = args; const { apiClientProps, body, query } = args;
@@ -2461,7 +2461,7 @@ export const SubsonicController: InternalControllerEndpoint = {
return null; return null;
}, },
startScan: async (args) => { refreshItems: async (args) => {
const { apiClientProps } = args; const { apiClientProps } = args;
const res = await ssApiClient(apiClientProps).startScan({ query: {} }); const res = await ssApiClient(apiClientProps).startScan({ query: {} });
@@ -2470,7 +2470,7 @@ export const SubsonicController: InternalControllerEndpoint = {
throw new Error('Failed to start scan'); throw new Error('Failed to start scan');
} }
return res.body.scanStatus; return null;
}, },
updateInternetRadioStation: async (args) => { updateInternetRadioStation: async (args) => {
const { apiClientProps, body, query } = args; const { apiClientProps, body, query } = args;
@@ -286,7 +286,10 @@ export const useMetadataEditor = ({ browser, songs: songsProp, utils }: UseMetad
if (rescan && server) { if (rescan && server) {
try { try {
await controller.startScan({ apiClientProps: { serverId: server.id } }); await controller.refreshItems({
apiClientProps: { serverId: server.id },
query: { ids: resolvedSongs.map((s) => s.id) },
});
toast.success({ message: t('page.itemDetail.rescanStarted') }); toast.success({ message: t('page.itemDetail.rescanStarted') });
} catch { } catch {
// non-fatal // non-fatal
+6 -9
View File
@@ -1418,14 +1418,9 @@ export type SearchSongsQuery = {
songStartIndex?: number; songStartIndex?: number;
}; };
export type StartScanArgs = BaseEndpointArgs; export type RefreshItemsArgs = BaseEndpointArgs & { query: { ids: string[] } };
export type StartScanResponse = null | { export type RefreshItemsResponse = null;
count: number;
folderCount: number;
lastScan?: string;
scanning: boolean;
};
export type SynchronizedLyricsArray = Array<[number, string]>; export type SynchronizedLyricsArray = Array<[number, string]>;
@@ -1532,6 +1527,7 @@ export type ControllerEndpoint = {
getUserInfo: (args: UserInfoArgs) => Promise<UserInfoResponse>; getUserInfo: (args: UserInfoArgs) => Promise<UserInfoResponse>;
getUserList?: (args: UserListArgs) => Promise<UserListResponse>; getUserList?: (args: UserListArgs) => Promise<UserListResponse>;
movePlaylistItem?: (args: MoveItemArgs) => Promise<void>; movePlaylistItem?: (args: MoveItemArgs) => Promise<void>;
refreshItems: (args: RefreshItemsArgs) => Promise<RefreshItemsResponse>;
removeFromPlaylist: (args: RemoveFromPlaylistArgs) => Promise<RemoveFromPlaylistResponse>; removeFromPlaylist: (args: RemoveFromPlaylistArgs) => Promise<RemoveFromPlaylistResponse>;
replacePlaylist: (args: ReplacePlaylistArgs) => Promise<ReplacePlaylistResponse>; replacePlaylist: (args: ReplacePlaylistArgs) => Promise<ReplacePlaylistResponse>;
savePlayQueue: (args: SaveQueueArgs) => Promise<void>; savePlayQueue: (args: SaveQueueArgs) => Promise<void>;
@@ -1540,7 +1536,6 @@ export type ControllerEndpoint = {
setPlaylistSongs: (args: SetPlaylistSongsArgs) => Promise<SetPlaylistSongsResponse>; setPlaylistSongs: (args: SetPlaylistSongsArgs) => Promise<SetPlaylistSongsResponse>;
setRating?: (args: SetRatingArgs) => Promise<RatingResponse>; setRating?: (args: SetRatingArgs) => Promise<RatingResponse>;
shareItem?: (args: ShareItemArgs) => Promise<ShareItemResponse>; shareItem?: (args: ShareItemArgs) => Promise<ShareItemResponse>;
startScan: (args: StartScanArgs) => Promise<StartScanResponse>;
updateInternetRadioStation: ( updateInternetRadioStation: (
args: UpdateInternetRadioStationArgs, args: UpdateInternetRadioStationArgs,
) => Promise<UpdateInternetRadioStationResponse>; ) => Promise<UpdateInternetRadioStationResponse>;
@@ -1695,6 +1690,9 @@ export type InternalControllerEndpoint = {
getUserInfo: (args: ReplaceApiClientProps<UserInfoArgs>) => Promise<UserInfoResponse>; getUserInfo: (args: ReplaceApiClientProps<UserInfoArgs>) => Promise<UserInfoResponse>;
getUserList?: (args: ReplaceApiClientProps<UserListArgs>) => Promise<UserListResponse>; getUserList?: (args: ReplaceApiClientProps<UserListArgs>) => Promise<UserListResponse>;
movePlaylistItem?: (args: ReplaceApiClientProps<MoveItemArgs>) => Promise<void>; movePlaylistItem?: (args: ReplaceApiClientProps<MoveItemArgs>) => Promise<void>;
refreshItems: (
args: ReplaceApiClientProps<RefreshItemsArgs>,
) => Promise<RefreshItemsResponse>;
removeFromPlaylist: ( removeFromPlaylist: (
args: ReplaceApiClientProps<RemoveFromPlaylistArgs>, args: ReplaceApiClientProps<RemoveFromPlaylistArgs>,
) => Promise<RemoveFromPlaylistResponse>; ) => Promise<RemoveFromPlaylistResponse>;
@@ -1709,7 +1707,6 @@ export type InternalControllerEndpoint = {
) => Promise<SetPlaylistSongsResponse>; ) => Promise<SetPlaylistSongsResponse>;
setRating?: (args: ReplaceApiClientProps<SetRatingArgs>) => Promise<RatingResponse>; setRating?: (args: ReplaceApiClientProps<SetRatingArgs>) => Promise<RatingResponse>;
shareItem?: (args: ReplaceApiClientProps<ShareItemArgs>) => Promise<ShareItemResponse>; shareItem?: (args: ReplaceApiClientProps<ShareItemArgs>) => Promise<ShareItemResponse>;
startScan: (args: ReplaceApiClientProps<StartScanArgs>) => Promise<StartScanResponse>;
updateInternetRadioStation: ( updateInternetRadioStation: (
args: ReplaceApiClientProps<UpdateInternetRadioStationArgs>, args: ReplaceApiClientProps<UpdateInternetRadioStationArgs>,
) => Promise<UpdateInternetRadioStationResponse>; ) => Promise<UpdateInternetRadioStationResponse>;