From f6786def871f37e5153fe1e24bcefdc4d05c9467 Mon Sep 17 00:00:00 2001 From: Youwes09 Date: Sun, 29 Mar 2026 14:03:28 -0500 Subject: [PATCH] Fix: SeriesDetail passing Incorrect Args to Reader --- src/components/pages/Discover.svelte | 12 +++++++--- src/components/pages/Library.svelte | 13 +++++++---- src/components/pages/Search.svelte | 28 ++++++++++++++++-------- src/components/pages/SeriesDetail.svelte | 17 ++++++++++---- src/lib/util.ts | 28 ++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/components/pages/Discover.svelte b/src/components/pages/Discover.svelte index 77b4c68..48825c5 100644 --- a/src/components/pages/Discover.svelte +++ b/src/components/pages/Discover.svelte @@ -4,7 +4,7 @@ import { gql, thumbUrl } from "../../lib/client"; import { GET_SOURCES, FETCH_SOURCE_MANGA, UPDATE_MANGA, GET_CATEGORIES, CREATE_CATEGORY, UPDATE_MANGA_CATEGORIES } from "../../lib/queries"; import { cache, CACHE_KEYS } from "../../lib/cache"; - import { dedupeSources, dedupeMangaByTitle, dedupeMangaById } from "../../lib/util"; + import { dedupeSources, dedupeMangaByTitle, dedupeMangaById, isNsfwManga } from "../../lib/util"; import { store, setPreviewManga, clearDiscoverCache } from "../../store/state.svelte"; import type { Manga, Source, Category } from "../../lib/types"; import ContextMenu from "../shared/ContextMenu.svelte"; @@ -60,7 +60,11 @@ } function filterOut(mangas: Manga[]): Manga[] { - return dedup(mangas.filter(m => !m.inLibrary && !store.discoverLibraryIds.has(m.id))); + return dedup(mangas.filter(m => { + if (m.inLibrary || store.discoverLibraryIds.has(m.id)) return false; + if (!store.settings.showNsfw && isNsfwManga(m)) return false; + return true; + })); } function rotatedSources(): Source[] { @@ -183,7 +187,9 @@ ); if (ctrl.signal.aborted) return; - const local = dedup(d.mangas.nodes); + const local = dedup( + d.mangas.nodes.filter(m => store.settings.showNsfw || !isNsfwManga(m)) + ); store.discoverCache.set(localKey, local); genreResults.set(genre, local.slice(0, GRID_LIMIT)); genreResults = new Map(genreResults); diff --git a/src/components/pages/Library.svelte b/src/components/pages/Library.svelte index 72ea58b..cac101f 100644 --- a/src/components/pages/Library.svelte +++ b/src/components/pages/Library.svelte @@ -4,7 +4,7 @@ import { gql, thumbUrl } from "../../lib/client"; import { GET_CATEGORIES, GET_LIBRARY, UPDATE_MANGA, GET_CHAPTERS, DELETE_DOWNLOADED_CHAPTERS, DEQUEUE_DOWNLOAD, CREATE_CATEGORY, UPDATE_MANGA_CATEGORIES, UPDATE_CATEGORY_ORDER } from "../../lib/queries"; import { cache, CACHE_KEYS, CACHE_GROUPS, DEFAULT_TTL_MS } from "../../lib/cache"; - import { dedupeMangaById, dedupeMangaByTitle } from "../../lib/util"; + import { dedupeMangaById, dedupeMangaByTitle, isNsfwManga } from "../../lib/util"; import { store, setLibraryFilter, checkAndMarkCompleted as storeCheckAndMarkCompleted, updateSettings, setCategories } from "../../store/state.svelte"; import type { LibrarySortMode, LibrarySortDir, LibraryStatusFilter } from "../../store/state.svelte"; import type { Manga, Category, Chapter } from "../../lib/types"; @@ -319,10 +319,15 @@ items = categoryMangaMap.get(Number(store.libraryFilter)) ?? []; } - // 2. Text search + // 2. NSFW filter — always applied before text search or sort + if (!store.settings.showNsfw) { + items = items.filter(m => !isNsfwManga(m)); + } + + // 3. Text search if (q) items = items.filter(m => m.title.toLowerCase().includes(q)); - // 3. Status filter + // 4. Status filter if (status !== "ALL") { items = items.filter(m => { const s = m.status?.toUpperCase().replace(/\s+/g, "_") ?? "UNKNOWN"; @@ -330,7 +335,7 @@ }); } - // 4. Sort + // 5. Sort const recentlyReadMap = new Map(); if (mode === "recentlyRead") { for (const h of store.history) { diff --git a/src/components/pages/Search.svelte b/src/components/pages/Search.svelte index 9eb7313..5360814 100644 --- a/src/components/pages/Search.svelte +++ b/src/components/pages/Search.svelte @@ -3,7 +3,7 @@ import { gql, thumbUrl } from "../../lib/client"; import { GET_SOURCES, FETCH_SOURCE_MANGA } from "../../lib/queries"; import { cache, CACHE_KEYS, getPageSet } from "../../lib/cache"; - import { dedupeSources, dedupeMangaById, dedupeMangaByTitle } from "../../lib/util"; + import { dedupeSources, dedupeMangaById, dedupeMangaByTitle, isNsfwManga } from "../../lib/util"; import { store, setSearchPrefill, setPreviewManga } from "../../store/state.svelte"; import type { Manga, Source } from "../../lib/types"; @@ -146,8 +146,11 @@ FETCH_SOURCE_MANGA, { source: src.id, type: "SEARCH", page: 1, query: trimmed }, ctrl.signal, ); if (ctrl.signal.aborted) return; + const mangas = store.settings.showNsfw + ? d.fetchSourceManga.mangas + : d.fetchSourceManga.mangas.filter((m) => !isNsfwManga(m)); kw_results = kw_results.map((r) => - r.source.id === src.id ? { ...r, mangas: d.fetchSourceManga.mangas, loading: false } : r, + r.source.id === src.id ? { ...r, mangas, loading: false } : r, ); } catch (e: any) { if (ctrl.signal.aborted || e?.name === "AbortError") return; @@ -243,7 +246,8 @@ ctrl.signal, ).then((d) => { if (ctrl.signal.aborted) return; - tag_localResults = d.mangas.nodes; + const nsfwFilter = (m: Manga) => store.settings.showNsfw || !isNsfwManga(m); + tag_localResults = d.mangas.nodes.filter(nsfwFilter); tag_totalCount = d.mangas.totalCount; tag_localHasNext = d.mangas.pageInfo.hasNextPage; tag_localOffset = (store.settings.renderLimit ?? 48); @@ -279,9 +283,10 @@ ps.add(1); tag_srcNextPage.set(src.id, result.hasNextPage ? 2 : -1); tag_srcNextPage = new Map(tag_srcNextPage); - const matching = activeTags.length > 1 + const matching = (activeTags.length > 1 ? result.mangas.filter((m) => matchesAllTags(m, activeTags)) - : result.mangas; + : result.mangas + ).filter((m) => store.settings.showNsfw || !isNsfwManga(m)); if (matching.length > 0) { tag_sourceResults = dedupeMangaByTitle(dedupeMangaById([...tag_sourceResults, ...matching]), store.settings.mangaLinks); tag_loadingSourceSearch = false; @@ -304,7 +309,8 @@ ctrl.signal, ); if (ctrl.signal.aborted) return; - tag_localResults = [...tag_localResults, ...d.mangas.nodes]; + const nsfwFilter = (m: Manga) => store.settings.showNsfw || !isNsfwManga(m); + tag_localResults = [...tag_localResults, ...d.mangas.nodes.filter(nsfwFilter)]; tag_localHasNext = d.mangas.pageInfo.hasNextPage; tag_localOffset += (store.settings.renderLimit ?? 48); } catch (e: any) { @@ -340,9 +346,10 @@ ps.add(page); tag_srcNextPage.set(src.id, result.hasNextPage ? page + 1 : -1); tag_srcNextPage = new Map(tag_srcNextPage); - const matching = tag_activeTags.length > 1 + const matching = (tag_activeTags.length > 1 ? result.mangas.filter((m) => matchesAllTags(m, tag_activeTags)) - : result.mangas; + : result.mangas + ).filter((m) => store.settings.showNsfw || !isNsfwManga(m)); if (matching.length > 0) { tag_sourceResults = dedupeMangaByTitle(dedupeMangaById([...tag_sourceResults, ...matching]), store.settings.mangaLinks); } @@ -422,7 +429,10 @@ FETCH_SOURCE_MANGA, { source: src.id, type, page, query: q ?? null }, ctrl.signal, ); if (ctrl.signal.aborted) return; - src_browseResults = page === 1 ? d.fetchSourceManga.mangas : [...src_browseResults, ...d.fetchSourceManga.mangas]; + const incoming = store.settings.showNsfw + ? d.fetchSourceManga.mangas + : d.fetchSourceManga.mangas.filter((m) => !isNsfwManga(m)); + src_browseResults = page === 1 ? incoming : [...src_browseResults, ...incoming]; src_hasNextPage = d.fetchSourceManga.hasNextPage; src_currentPage = page; } catch (e: any) { diff --git a/src/components/pages/SeriesDetail.svelte b/src/components/pages/SeriesDetail.svelte index 06de0a2..a79d8c2 100644 --- a/src/components/pages/SeriesDetail.svelte +++ b/src/components/pages/SeriesDetail.svelte @@ -87,6 +87,15 @@ } return sortDir === "desc" ? base.reverse() : base; }); + + /** + * Chapter list in canonical reading order (ch1 -> ch2 -> ch3). + * Always passed to openReader so the Reader's idx-based prev/next + * navigation is direction-independent of the user's display sort. + */ + const chaptersAsc = $derived( + [...chapters].sort((a, b) => a.sourceOrder - b.sourceOrder) + ); const totalPages = $derived(Math.ceil(sortedChapters.length / CHAPTERS_PER_PAGE)); const pageChapters = $derived(sortedChapters.slice((chapterPage - 1) * CHAPTERS_PER_PAGE, chapterPage * CHAPTERS_PER_PAGE)); const readCount = $derived(chapters.filter(c => c.isRead).length); @@ -444,7 +453,7 @@
{#if continueChapter} -