Array of AniList manga IDs to fetch.
Optionaltoken: stringOptional authentication token.
OptionalshouldCancel: () => booleanOptional function to check for cancellation request.
OptionalabortSignal: AbortSignalOptional abort signal to cancel the operation.
Promise resolving to array of AniListManga objects.
export async function getBatchedMangaIds(
ids: number[],
token?: string,
shouldCancel?: () => boolean,
abortSignal?: AbortSignal,
): Promise<AniListManga[]> {
return withGroupAsync(
`[MangaSearchService] Fetch Batched IDs (${ids.length} IDs)`,
async () => {
if (!ids.length) return [];
// Check for cancellation
if (shouldCancel?.()) {
throw new CancelledError("Operation cancelled by user");
}
// Abort if signal is aborted
if (abortSignal?.aborted) {
throw new CancelledError("Operation aborted by abort signal");
}
const results: AniListManga[] = [];
const batchSize = 25; // AniList allows 25 ids per request
// Process in batches to avoid overloading the API
for (let i = 0; i < ids.length; i += batchSize) {
// Check for cancellation between batches
if (shouldCancel?.()) {
throw new CancelledError("Operation cancelled by user");
}
// Abort if signal is aborted
if (abortSignal?.aborted) {
throw new CancelledError("Operation aborted by abort signal");
}
const batchIds = ids.slice(i, i + batchSize);
try {
const batchResults = await getMangaByIds(
batchIds,
token,
abortSignal,
);
results.push(...batchResults);
} catch (error) {
console.error(
`[MangaSearchService] ❌ Error fetching manga batch ${i} to ${i + batchSize}:`,
error,
);
captureError(
ErrorType.UNKNOWN,
`Failed to fetch manga batch`,
error,
{
batchNumber: Math.floor(i / batchSize),
batchSize: batchIds.length,
totalIds: ids.length,
stage: "batch_fetch",
},
);
// Continue with next batch even if one fails
}
}
return results;
},
);
}
Fetches multiple manga by AniList ID in batches with cancellation support.
Processes IDs in groups of 25 (API limit) with cancellation checks between batches. Continues processing even if individual batches fail.