• 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.

    Parameters

    Returns Promise<void>

    May throw on API failures or cancellation.

    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`,
    );
    },
    );
    }