Uncached manga items with indices.
AniList token and search config.
Abort signal and cancellation check.
Progress update callbacks.
Results, source maps, and cache storage.
export async function processBatchedUncachedManga(
data: UncachedMangaData,
config: UncachedMangaConfig,
control: UncachedMangaControl,
callbacks: UpdateProgressCallbacks,
storage: CachedResultsStorage,
): Promise<void> {
return withGroupAsync(
`[MangaSearchService] Batched Search (${data.uncachedManga.length} manga, ${Math.ceil(data.uncachedManga.length / BATCH_SIZE)} batches)`,
async () => {
const { uncachedManga } = data;
const { token, searchConfig } = config;
const { abortSignal, checkCancellation } = control;
const { updateProgress } = callbacks;
if (uncachedManga.length === 0) {
return;
}
console.info(
`[MangaSearchService] 🚀 Processing ${uncachedManga.length} uncached manga with batched queries (batch size: ${BATCH_SIZE})`,
);
// Filter out anything that became cached since categorization ran.
const trulyUncachedManga = uncachedManga.filter(({ manga, index }) => {
const cacheKey = generateCacheKey(manga.title);
if (!searchConfig.bypassCache && isCacheValid(cacheKey)) {
storage.cachedResults[index] = mangaCache[cacheKey].manga;
initializeSourceMaps(index, storage);
updateProgress(index, manga.title);
return false;
}
return true;
});
if (trulyUncachedManga.length === 0) {
console.info(
`[MangaSearchService] ✅ All uncached manga were found in cache, skipping batch search`,
);
return;
}
console.info(
`[MangaSearchService] 🔍 ${trulyUncachedManga.length} manga need AniList queries`,
);
const totalBatches = Math.ceil(trulyUncachedManga.length / BATCH_SIZE);
for (let batchIndex = 0; batchIndex < totalBatches; batchIndex++) {
ensureNotCancelled(abortSignal, checkCancellation);
const start = batchIndex * BATCH_SIZE;
const batch = trulyUncachedManga.slice(start, start + BATCH_SIZE);
await processBatch(batch, {
token,
searchConfig,
abortSignal,
checkCancellation,
updateProgress,
storage,
batchNumber: batchIndex + 1,
totalBatches,
hasMoreBatches: batchIndex + 1 < totalBatches,
});
}
console.info(
`[MangaSearchService] ✅ Batched processing complete for ${trulyUncachedManga.length} manga`,
);
},
);
}
Process uncached manga using batched GraphQL queries with fallback searches.
Divides uncached manga into batches (per batch size controlled by BATCH_SIZE) respecting AniList's rate limits. Performs batched GraphQL queries and fallback searches on Comick/MangaDex for misses. Supports early termination, abort signals, and cancellation checks.