The list of Kenmei manga entries to match.
Optional
token: stringOptional authentication token.
Optional search service configuration.
Optional
progressCallback: (current: number, total: number, currentTitle?: string) => voidOptional callback for progress updates.
Optional
shouldCancel: () => booleanOptional function to check for cancellation.
Optional
abortSignal: AbortSignalOptional abort signal to cancel the batch process.
A promise resolving to an array of MangaMatchResult objects.
export async function batchMatchManga(
mangaList: KenmeiManga[],
token?: string,
config: Partial<SearchServiceConfig> = {},
progressCallback?: (
current: number,
total: number,
currentTitle?: string,
) => void,
shouldCancel?: () => boolean,
abortSignal?: AbortSignal,
): Promise<MangaMatchResult[]> {
// Ensure we have the latest cache data
syncWithClientCache();
const searchConfig = { ...DEFAULT_SEARCH_CONFIG, ...config };
// Create a set to track which manga have been reported in the progress
const reportedIndices = new Set<number>();
// Function to check if the operation should be cancelled
const checkCancellation = () => {
// Check the abort signal first
if (abortSignal?.aborted) {
console.log("Batch matching process aborted by abort signal");
throw new Error("Operation aborted by abort signal");
}
// Then check the cancellation function
if (shouldCancel?.()) {
console.log("Batch matching process cancelled by user");
throw new Error("Operation cancelled by user");
}
return false;
};
// Update progress with deduplication
const updateProgress = (index: number, title?: string) => {
if (progressCallback && !reportedIndices.has(index)) {
reportedIndices.add(index);
progressCallback(reportedIndices.size, mangaList.length, title);
}
};
try {
// Categorize manga based on cache status
const { cachedResults, cachedComickSources, uncachedManga, knownMangaIds } =
categorizeMangaForBatching(mangaList, searchConfig, updateProgress);
// Check for cancellation
checkCancellation();
// Process manga with known IDs first
await processKnownMangaIds(
{ knownMangaIds, mangaList, uncachedManga },
{ searchConfig, token },
{ shouldCancel, abortSignal },
{ updateProgress },
{ cachedResults, cachedComickSources },
);
// Check for cancellation
checkCancellation();
// Process uncached manga
try {
await processUncachedManga(
{ uncachedManga, mangaList, reportedIndices },
{ token, searchConfig },
{ abortSignal, checkCancellation },
{ updateProgress },
{ cachedResults, cachedComickSources },
);
} catch (error) {
console.log("Processing cancelled:", error);
// If we got here due to cancellation, return the partial results we've managed to gather
if (
error instanceof Error &&
(error.message.includes("cancelled") ||
error.message.includes("aborted"))
) {
console.log(`Cancellation completed, returning partial results`);
return handleCancellationResults(mangaList, cachedResults);
}
// If it's a different kind of error, rethrow it
throw error;
}
// Check for cancellation after the batch completes
checkCancellation();
// Compile final results
return compileMatchResults(
mangaList,
cachedResults,
cachedComickSources,
checkCancellation,
updateProgress,
);
} catch (error) {
console.error("Error in batch matching process:", error);
// If we got here due to cancellation, return whatever partial results we have
if (
error instanceof Error &&
(error.message.includes("cancelled") || error.message.includes("aborted"))
) {
console.log(`Cancellation detected, returning partial results`);
// We don't have access to the variables in this scope, so return empty array
return [];
}
// Otherwise rethrow the error
throw error;
}
}
Process matches for a batch of manga.