From b772b94c6c35428091ea0a2c81b5e4398f85a866 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Thu, 19 Mar 2026 21:39:51 -0500 Subject: [PATCH] Chore: Attempted De-Dupe Patch #1 & Alternative Thumbnails --- src/components/pages/Discover.svelte | 37 +++++- src/components/pages/Home.svelte | 5 +- src/components/pages/Library.svelte | 13 +- src/components/search/Search.svelte | 38 +++++- src/components/settings/Settings.svelte | 2 - src/components/shared/MangaPreview.svelte | 83 ++++++++++++- src/lib/cache.ts | 145 ++++++++++++++++------ src/lib/util.ts | 94 ++++++++++++-- 8 files changed, 349 insertions(+), 68 deletions(-) diff --git a/src/components/pages/Discover.svelte b/src/components/pages/Discover.svelte index afa57f2..e804535 100644 --- a/src/components/pages/Discover.svelte +++ b/src/components/pages/Discover.svelte @@ -4,12 +4,13 @@ import { gql, thumbUrl } from "../../lib/client"; import { GET_SOURCES, FETCH_SOURCE_MANGA, UPDATE_MANGA } from "../../lib/queries"; import { cache, CACHE_KEYS } from "../../lib/cache"; - import { dedupeSources, dedupeMangaByTitle, dedupeMangaById } from "../../lib/util"; + import { dedupeSources, dedupeMangaByTitle, dedupeMangaById, groupDuplicates, normalizeTitle } from "../../lib/util"; import { settings, previewManga, activeSource, addFolder, assignMangaToFolder } from "../../store"; import type { Manga, Source } from "../../lib/types"; import ContextMenu from "../shared/ContextMenu.svelte"; import type { MenuEntry } from "../shared/ContextMenu.svelte"; import SourceBrowse from "../sources/SourceBrowse.svelte"; + import MangaPreview from "../shared/MangaPreview.svelte"; // ── Config ──────────────────────────────────────────────────────────────────── const GENRE_TABS = ["All", "Action", "Romance", "Fantasy", "Comedy", "Drama", "Horror", "Sci-Fi", "Adventure", "Thriller"]; @@ -56,6 +57,32 @@ // Context menu let ctx: { x: number; y: number; manga: Manga } | null = null; + // Raw pool of ALL items before dedup — used to find alternates for the preview switcher. + // Keyed by normalised title → array of Manga with that title from different sources. + let rawPool = new Map(); + + function addToPool(items: Manga[]) { + for (const m of items) { + const k = normalizeTitle(m.title); + if (!rawPool.has(k)) rawPool.set(k, []); + const group = rawPool.get(k)!; + if (!group.some(x => x.id === m.id)) group.push(m); + } + } + + // Get alternates (other source variants) for a given manga, excluding itself + function getAlternates(m: Manga): Manga[] { + const k = normalizeTitle(m.title); + return (rawPool.get(k) ?? []).filter(x => x.id !== m.id); + } + + // Open preview with alternates pre-computed + let previewAlternates: Manga[] = []; + function openPreview(m: Manga) { + previewAlternates = getAlternates(m); + previewManga.set(m); + } + // ── Derived ─────────────────────────────────────────────────────────────────── $: visibleGrid = genreResults.get(currentGenre) ?? []; $: isLoading = genreLoading || (currentGenre === "All" && loadingLib); @@ -86,11 +113,12 @@ batchTimer = setInterval(() => { if (batchAccum.size === 0) return; for (const [genre, incoming] of batchAccum) { + addToPool(incoming); const current = genreResults.get(genre) ?? []; genreResults.set(genre, dedup([...current, ...incoming]).slice(0, GRID_LIMIT)); } batchAccum.clear(); - genreResults = new Map(genreResults); // single Svelte reactivity trigger + genreResults = new Map(genreResults); }, BATCH_INTERVAL); } @@ -242,6 +270,7 @@ gql<{ mangas: { nodes: Manga[] } }>(EXPLORE_ALL_MANGA).then(d => d.mangas.nodes) ).then(m => { allManga = dedupeMangaById(m); + addToPool(allManga); genreResults.set("All", dedup(allManga).slice(0, GRID_LIMIT)); genreResults = new Map(genreResults); }).catch(e => { console.error(e); loadError = true; }) @@ -313,7 +342,7 @@ {#each visibleGrid as m (m.id)} + + {#each alternates as alt (alt.id)} + + {/each} + + + {/if}