Array of manga match results to filter.
Filter options to apply.
User's existing AniList library.
Sync configuration for change detection.
Filtered array of manga matches.
export function filterMangaMatches(
mangaMatches: MangaMatchResult[],
filters: FilterOptions,
userLibrary: UserMediaList,
syncConfig: SyncConfig,
): MangaMatchResult[] {
const statusMap = {
reading: "reading",
completed: "completed",
planned: "plan_to_read",
paused: "on_hold",
dropped: "dropped",
} as const;
const isStatusMatch = (match: MangaMatchResult) => {
if (filters.status === "all") return true;
const mapped = (statusMap as Record<string, string>)[filters.status];
return mapped === match.kenmeiManga.status.toLowerCase();
};
const doesMatchChangeFilter = (match: MangaMatchResult) => {
if (filters.changes === "all") return true;
const anilist = match.selectedMatch!;
const userEntry = userLibrary[anilist.id];
const isCompletedAndPreserved =
userEntry?.status === "COMPLETED" && syncConfig.preserveCompletedStatus;
if (isCompletedAndPreserved) {
return filters.changes !== "with-changes";
}
const changeCount = getChangeCount(match, userLibrary, syncConfig);
const hasChanges = changeCount > 0;
if (filters.changes === "with-changes") return hasChanges;
if (filters.changes === "no-changes") return !hasChanges;
return true;
};
const isLibraryMatch = (match: MangaMatchResult) => {
if (filters.library === "all") return true;
const anilist = match.selectedMatch!;
const isNewEntry = !userLibrary[anilist.id];
if (filters.library === "new") return isNewEntry;
if (filters.library === "existing") return !isNewEntry;
return true;
};
return mangaMatches
.filter((match) => match.status === "matched" || match.status === "manual")
.filter((match) => match.selectedMatch !== undefined)
.filter(
(match) =>
isStatusMatch(match) &&
doesMatchChangeFilter(match) &&
isLibraryMatch(match),
);
}
Apply filters to manga matches based on status, changes, and library membership.