Array of previously stored manga items.
Array of newly imported manga items to merge.
Object with merged manga array and import statistics.
export function mergeMangaData(
previousManga: NormalizedMangaItem[],
normalizedManga: NormalizedMangaItem[],
): { mergedManga: NormalizedMangaItem[]; results: ImportResults } {
console.debug(
`[MangaImport] Merging ${normalizedManga.length} new items with ${previousManga.length} existing items`,
);
const mergedManga = [...previousManga];
const previousTitles = new Set(
previousManga.map((m) => m.title.toLowerCase()),
);
const previousIds = new Set(
previousManga.map((m) => m.id?.toString()).filter(Boolean),
);
let newMangaCount = 0;
let updatedMangaCount = 0;
for (const manga of normalizedManga) {
const idMatch = manga.id && previousIds.has(manga.id.toString());
const titleMatch = previousTitles.has(manga.title.toLowerCase());
if (idMatch || titleMatch) {
// Update existing manga
const existingIndex = mergedManga.findIndex(
(existing) =>
existing.id?.toString() === manga.id.toString() ||
existing.title.toLowerCase() === manga.title.toLowerCase(),
);
if (existingIndex !== -1) {
const existing = mergedManga[existingIndex];
mergedManga[existingIndex] = {
...existing,
...manga,
};
updatedMangaCount++;
}
} else {
// Add new manga
mergedManga.push(manga);
newMangaCount++;
previousTitles.add(manga.title.toLowerCase());
if (manga.id) {
previousIds.add(manga.id.toString());
}
}
}
console.info(
`[MangaImport] ✅ Merge complete: ${newMangaCount} new, ${updatedMangaCount} updated, ${mergedManga.length} total`,
);
return {
mergedManga,
results: {
newMangaCount,
updatedMangaCount,
totalManga: mergedManga.length,
},
};
}
Merges new manga with existing manga by ID/title match; updates existing, appends new.