• Process matches for a batch of manga.

    Parameters

    • mangaList: KenmeiManga[]

      The list of Kenmei manga entries to match.

    • Optionaltoken: string

      Optional authentication token.

    • config: Partial<SearchServiceConfig> = {}

      Optional search service configuration.

    • OptionalprogressCallback: (current: number, total: number, currentTitle?: string) => void

      Optional callback for progress updates.

    • OptionalshouldCancel: () => boolean

      Optional function to check for cancellation.

    • OptionalabortSignal: AbortSignal

      Optional abort signal to cancel the batch process.

    Returns Promise<MangaMatchResult[]>

    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;
    }
    }