Full list of Kenmei manga.
Cancellation check function.
Progress update callback.
Whether to use Web Workers for parallel processing (default: true).
Array of complete match results.
export async function compileMatchResults(
mangaList: KenmeiManga[],
storage: CachedResultsStorage,
checkCancellation: () => void,
updateProgress: (index: number, title?: string) => void,
shouldUseWorkers = true,
): Promise<MangaMatchResult[]> {
const results: MangaMatchResult[] = [];
// Load existing match results to preserve statuses
const existingResults = getSavedMatchResults() || [];
const existingById = new Map<string, MangaMatchResult>();
const existingByTitle = new Map<string, MangaMatchResult>();
for (const result of existingResults) {
if (result.kenmeiManga.id) {
existingById.set(
String(result.kenmeiManga.id),
result as MangaMatchResult,
);
}
existingByTitle.set(
result.kenmeiManga.title.toLowerCase(),
result as MangaMatchResult,
);
}
// Helper function to preserve status from existing result
const preserveExistingStatus = (
newResult: MangaMatchResult,
manga: KenmeiManga,
): void => {
let existingResult = manga.id
? existingById.get(String(manga.id))
: undefined;
existingResult ??= existingByTitle.get(manga.title.toLowerCase());
if (existingResult?.status && existingResult.status !== "pending") {
newResult.status = existingResult.status;
newResult.selectedMatch = existingResult.selectedMatch;
newResult.matchDate = existingResult.matchDate;
}
};
const {
cachedResults,
cachedComickSources,
cachedMangaDexSources,
cachedFallbackIndices,
} = storage;
const fallbackIndices = cachedFallbackIndices;
// First fill in the results array to match the mangaList length
for (let i = 0; i < mangaList.length; i++) {
results[i] = {
kenmeiManga: mangaList[i],
anilistMatches: [],
status: "pending",
} as MangaMatchResult; // Use empty arrays instead of null
// Initialize empty Comick source maps for missing entries
if (!cachedComickSources[i]) {
cachedComickSources[i] = new Map();
}
if (!cachedMangaDexSources[i]) {
cachedMangaDexSources[i] = new Map();
}
}
const matchConfig = getMatchConfig();
// Try using workers for parallel processing if enabled
if (shouldUseWorkers) {
const workerResults = await processWithWorkers(
mangaList,
cachedResults,
matchConfig,
{
cachedComickSources,
cachedMangaDexSources,
checkCancellation,
updateProgress,
fallbackIndices,
preserveExistingStatus,
},
);
if (workerResults) {
return workerResults.filter((result) => result !== null);
}
// Fall through to synchronous processing if workers failed
}
// Fallback: Synchronous processing on main thread
for (let i = 0; i < mangaList.length; i++) {
// Check for cancellation periodically
if (i % 10 === 0) {
checkCancellation();
}
const manga = mangaList[i];
let potentialMatches = cachedResults[i] || [];
// Apply filtering rules based on match configuration
const isFallback = fallbackIndices?.has(i);
potentialMatches = applyMatchFiltering(
potentialMatches,
manga.title,
matchConfig,
manga,
{ skipSystemFilters: isFallback },
);
// Update progress for any remaining manga
updateProgress(i, manga.title);
// Create match result for this manga
const comickSourceMap = cachedComickSources[i] || new Map();
const mangaDexSourceMap = cachedMangaDexSources[i] || new Map();
const newResult = createMangaMatchResult(
manga,
potentialMatches,
comickSourceMap,
mangaDexSourceMap,
);
// Preserve status from existing result if it's not "pending"
preserveExistingStatus(newResult, manga);
results[i] = newResult;
}
// Filter out any null entries (though there shouldn't be any)
return results.filter((result) => result !== null);
}
Compile final match results from cached data with confidence scores.
Applies filtering, creates match results with confidence scores, and includes source info.