batch jellyfin song list requests when fetching by albumId (#922)

This commit is contained in:
jeffvli 2025-05-07 01:42:32 -07:00
parent 58f6535ba6
commit f03d88cd8c

View file

@ -695,58 +695,98 @@ export const JellyfinController: ControllerEndpoint = {
} }
const yearsFilter = yearsGroup.length ? formatCommaDelimitedString(yearsGroup) : undefined; const yearsFilter = yearsGroup.length ? formatCommaDelimitedString(yearsGroup) : undefined;
const albumIdsFilter = query.albumIds
? formatCommaDelimitedString(query.albumIds)
: undefined;
const artistIdsFilter = query.artistIds const artistIdsFilter = query.artistIds
? formatCommaDelimitedString(query.artistIds) ? formatCommaDelimitedString(query.artistIds)
: query.albumArtistIds : query.albumArtistIds
? formatCommaDelimitedString(query.albumArtistIds) ? formatCommaDelimitedString(query.albumArtistIds)
: undefined; : undefined;
const res = await jfApiClient(apiClientProps).getSongList({ let items: z.infer<typeof jfType._response.song>[] = [];
params: { let totalRecordCount = 0;
userId: apiClientProps.server?.userId, const batchSize = 50;
},
query: {
AlbumIds: albumIdsFilter,
ArtistIds: artistIdsFilter,
Fields: 'Genres, DateCreated, MediaSources, ParentId',
GenreIds: query.genreIds?.join(','),
IncludeItemTypes: 'Audio',
IsFavorite: query.favorite,
Limit: query.limit,
ParentId: query.musicFolderId,
Recursive: true,
SearchTerm: query.searchTerm,
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
StartIndex: query.startIndex,
...query._custom?.jellyfin,
Years: yearsFilter,
},
});
if (res.status !== 200) { // Handle albumIds fetches in batches to prevent HTTP 414 errors
throw new Error('Failed to get song list'); if (query.albumIds && query.albumIds.length > batchSize) {
} const albumIdBatches = chunk(query.albumIds, batchSize);
let items: z.infer<typeof jfType._response.song>[]; for (const batch of albumIdBatches) {
const albumIdsFilter = formatCommaDelimitedString(batch);
// Jellyfin Bodge because of code from https://github.com/jellyfin/jellyfin/blob/c566ccb63bf61f9c36743ddb2108a57c65a2519b/Emby.Server.Implementations/Data/SqliteItemRepository.cs#L3622 const res = await jfApiClient(apiClientProps).getSongList({
// If the Album ID filter is passed, Jellyfin will search for params: {
// 1. the matching album id userId: apiClientProps.server?.userId,
// 2. An album with the name of the album. },
// It is this second condition causing issues, query: {
if (query.albumIds) { AlbumIds: albumIdsFilter,
const albumIdSet = new Set(query.albumIds); ArtistIds: artistIdsFilter,
items = res.body.Items.filter((item) => albumIdSet.has(item.AlbumId!)); Fields: 'Genres, DateCreated, MediaSources, ParentId',
GenreIds: query.genreIds?.join(','),
IncludeItemTypes: 'Audio',
IsFavorite: query.favorite,
Limit: query.limit,
ParentId: query.musicFolderId,
Recursive: true,
SearchTerm: query.searchTerm,
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
StartIndex: query.startIndex,
...query._custom?.jellyfin,
Years: yearsFilter,
},
});
if (items.length < res.body.Items.length) { if (res.status !== 200) {
res.body.TotalRecordCount -= res.body.Items.length - items.length; throw new Error('Failed to get song list');
}
items = [...items, ...res.body.Items];
totalRecordCount += res.body.Items.length;
} }
} else { } else {
items = res.body.Items; const albumIdsFilter = query.albumIds
? formatCommaDelimitedString(query.albumIds)
: undefined;
const res = await jfApiClient(apiClientProps).getSongList({
params: {
userId: apiClientProps.server?.userId,
},
query: {
AlbumIds: albumIdsFilter,
ArtistIds: artistIdsFilter,
Fields: 'Genres, DateCreated, MediaSources, ParentId',
GenreIds: query.genreIds?.join(','),
IncludeItemTypes: 'Audio',
IsFavorite: query.favorite,
Limit: query.limit,
ParentId: query.musicFolderId,
Recursive: true,
SearchTerm: query.searchTerm,
SortBy: songListSortMap.jellyfin[query.sortBy] || 'Album,SortName',
SortOrder: sortOrderMap.jellyfin[query.sortOrder],
StartIndex: query.startIndex,
...query._custom?.jellyfin,
Years: yearsFilter,
},
});
if (res.status !== 200) {
throw new Error('Failed to get song list');
}
// Jellyfin Bodge because of code from https://github.com/jellyfin/jellyfin/blob/c566ccb63bf61f9c36743ddb2108a57c65a2519b/Emby.Server.Implementations/Data/SqliteItemRepository.cs#L3622
// If the Album ID filter is passed, Jellyfin will search for
// 1. the matching album id
// 2. An album with the name of the album.
// It is this second condition causing issues,
if (query.albumIds) {
const albumIdSet = new Set(query.albumIds);
items = res.body.Items.filter((item) => albumIdSet.has(item.AlbumId!));
totalRecordCount = items.length;
} else {
items = res.body.Items;
totalRecordCount = res.body.TotalRecordCount;
}
} }
return { return {
@ -754,7 +794,7 @@ export const JellyfinController: ControllerEndpoint = {
jfNormalize.song(item, apiClientProps.server, '', query.imageSize), jfNormalize.song(item, apiClientProps.server, '', query.imageSize),
), ),
startIndex: query.startIndex, startIndex: query.startIndex,
totalRecordCount: res.body.TotalRecordCount, totalRecordCount,
}; };
}, },
getSongListCount: async ({ apiClientProps, query }) => getSongListCount: async ({ apiClientProps, query }) =>