Skip to content

Commit

Permalink
filter chapters by scanlator
Browse files Browse the repository at this point in the history
  • Loading branch information
Robonau authored and Robonau committed Sep 22, 2024
1 parent 8b9cc84 commit 9a2f24e
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 30 deletions.
3 changes: 2 additions & 1 deletion src/lib/simpleStores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ const mangaMetaDefaults = {
mobileFullScreenOnChapterPage: true,
doPageIndicator: false,
notes: '',
showMissingChapters: false
showMissingChapters: false,
groupPartials: [] as string[]
};
type mangaMeta = typeof mangaMetaDefaults;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
} from '@skeletonlabs/skeleton';
import { ChapterSort, ChapterTitle, MangaMeta } from '$lib/simpleStores';
import { enumKeys } from '$lib/util';
import Tooltip from '$lib/components/Tooltip.svelte';
const modalStore = getModalStore();
let tabSet = localStorageStore('libraryModalTabs', 0);
export let MangaID: number;
Expand Down Expand Up @@ -103,6 +104,26 @@
>
<span>Bookmarked</span>
</TriStateSlide>
<Tooltip tip="Comma seperated list">
<label
class="label flex w-full items-center justify-between rounded-full p-1 pl-2 hover:variant-glass-surface focus:outline-0"
>
<span class="pr-2">Groups</span>
<input
on:change={(e) => {
$mangaMeta.groupPartials = e.currentTarget.value
.split(',')
.map((a) => a.trim())
.filter((a) => a.length > 0);
e.currentTarget.value = $mangaMeta.groupPartials.join(',');
}}
value={$mangaMeta.groupPartials.join(',')}
class="input w-1/2"
type="text"
placeholder="asura,dex,..."
/>
</label>
</Tooltip>
{:else if $tabSet === 1}
<TriStateSlide
triState={false}
Expand Down
17 changes: 2 additions & 15 deletions src/routes/(app)/manga/[MangaID]/(manga)/chaptersSide.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
trackProgress,
updateChapters
} from '$lib/gql/Mutations';
import { filterChapters } from '../util';
export let manga: OperationResultStore<ResultOf<typeof getManga>> & Pausable;
export let MangaID: number;
Expand Down Expand Up @@ -91,21 +92,7 @@
$: chaptersInfo = $manga?.data?.manga?.chapters.nodes;
$: filteredChapters = chaptersInfo?.filter((chapter) => {
if ($mangaMeta.ChapterUnread === 1 && chapter.isRead) return false;
if ($mangaMeta.ChapterUnread === 2 && !chapter.isRead) return false;
if ($mangaMeta.ChapterDownloaded === 1 && !chapter.isDownloaded)
return false;
if ($mangaMeta.ChapterDownloaded === 2 && chapter.isDownloaded)
return false;
if ($mangaMeta.ChapterBookmarked === 1 && !chapter.isBookmarked)
return false;
if ($mangaMeta.ChapterBookmarked === 2 && chapter.isBookmarked)
return false;
return true;
});
$: filteredChapters = chaptersInfo?.filter(filterChapters(mangaMeta));
$: sortedChapters = filteredChapters
? [...filteredChapters].sort((a, b) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import { error } from '@sveltejs/kit';
import type { LayoutLoad } from './$types';

export const ssr = false;
export const prerender = false;

export const load: LayoutLoad = ({ params }) => {
const MangaID = parseInt(params.MangaID);
const ChapterID = parseInt(params.ChapterID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@
import IconButton from '$lib/components/IconButton.svelte';
import { getDrawerStore, AppShell } from '@skeletonlabs/skeleton';
import type { LayoutData } from './$types';
import { writable } from 'svelte/store';
export let data: LayoutData;
const drawerStore = getDrawerStore();
const dataStore = writable(data);
$: dataStore.set(data);
function draw() {
if ($drawerStore.open) drawerStore.close();
else {
drawerStore.open({
id: 'ChapterMenu',
width: 'w-[280px] md:w-[480px]',
meta: {
id: data.MangaID
}
meta: dataStore
});
}
}
Expand Down
43 changes: 35 additions & 8 deletions src/routes/(app)/manga/[MangaID]/chapter/[ChapterID]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { onMount } from 'svelte';
import type { PageData } from './$types';
import { ViewNav, chapterTitle, mangaTitle } from './chapterStores';
import { filterChapters } from '../../util';
import { paths, type PathLayout, type Paths, type TPath } from './paths';
import {
getContextClient,
Expand All @@ -33,10 +34,18 @@
updateChapter
} from '$lib/gql/Mutations';
import { ChapterTypeFragment } from '$lib/gql/Fragments';
import { queryParam, ssp } from 'sveltekit-search-params';
export let data: PageData;
let mangaMeta = MangaMeta(data.MangaID);
let pagenav = queryParam('pagenav', ssp.boolean(), { pushHistory: false });
$: if ($pagenav) {
$pagenav = null;
all = [];
}
onMount(() => {
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
Expand Down Expand Up @@ -135,28 +144,48 @@
if (next) currentChapterID = next.id;
}
$: filteredChapters = $manga.data?.manga?.chapters.nodes?.filter(
filterChapters(mangaMeta, true)
);
function getChapterOfID(
currentID: number
): ResultOf<typeof ChapterTypeFragment> | undefined {
return $manga.data?.manga?.chapters.nodes?.find((e) => e.id === currentID);
return filteredChapters?.find((e) => e.id === currentID);
}
function getChapterAfterID(
currentID: number,
_: unknown = undefined
): ResultOf<typeof ChapterTypeFragment> | undefined {
const currentChapter = getChapterOfID(currentID);
return $manga.data?.manga?.chapters.nodes?.find((e) =>
currentChapter ? e.sourceOrder === currentChapter.sourceOrder + 1 : false
if (!currentChapter) return undefined;
return filteredChapters?.reduce(
(acc, e) => {
if (e.sourceOrder > currentChapter.sourceOrder) {
if (!acc) acc = e;
if (e.sourceOrder < acc.sourceOrder) acc = e;
}
return acc;
},
undefined as ResultOf<typeof ChapterTypeFragment> | undefined
);
}
function getChapterBeforeID(
currentID: number
): ResultOf<typeof ChapterTypeFragment> | undefined {
const currentChapter = getChapterOfID(currentID);
return $manga.data?.manga?.chapters.nodes?.find((e) =>
currentChapter ? e.sourceOrder === currentChapter.sourceOrder - 1 : false
if (!currentChapter) return undefined;
return filteredChapters?.reduce(
(acc, e) => {
if (e.sourceOrder < currentChapter.sourceOrder) {
if (!acc) acc = e;
if (e.sourceOrder > acc.sourceOrder) acc = e;
}
return acc;
},
undefined as ResultOf<typeof ChapterTypeFragment> | undefined
);
}
Expand Down Expand Up @@ -200,7 +229,6 @@
return;
}
if (keyEvent.code === 'Space') {
console.log(keyEvent);
keyEvent.preventDefault();
keyEvent.stopPropagation();
if (keyEvent.shiftKey) {
Expand Down Expand Up @@ -427,8 +455,7 @@
$: $mangaTitle = $manga.data?.manga?.title ?? '';
$: $chapterTitle =
$manga.data?.manga?.chapters.nodes?.find((e) => e.id === currentChapterID)
?.name ?? '';
filteredChapters?.find((e) => e.id === currentChapterID)?.name ?? '';
$: currentChapterID, got();
function got() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@
import { enumKeys } from '$lib/util';
import { getDrawerStore } from '@skeletonlabs/skeleton';
import { ViewNav, chapterTitle, mangaTitle } from './chapterStores';
import { Layout, MangaMeta, Mode } from '$lib/simpleStores';
import { ChapterTitle, Layout, MangaMeta, Mode } from '$lib/simpleStores';
import { onMount } from 'svelte';
import { getContextClient, queryStore } from '@urql/svelte';
import { getManga } from '$lib/gql/Queries';
import { filterChapters } from '../../util';
import type { Writable } from 'svelte/store';
import IntersectionObserver from '$lib/components/IntersectionObserver.svelte';
import { onNavigate } from '$app/navigation';
const drawerStore = getDrawerStore();
const mangaMeta = MangaMeta($drawerStore.meta.id);
$: data = $drawerStore.meta as Writable<{
MangaID: number;
ChapterID: number;
}>;
$: mangaMeta = MangaMeta($data?.MangaID);
onMount(() => {
let elem = document.querySelector(`#chapter-${$data.ChapterID}`)!;
elem = elem.previousElementSibling ?? elem;
const to = elem?.getBoundingClientRect();
chapterSideElement?.scrollTo({
top:
chapterSideElement.scrollTop -
chapterSideElement.getBoundingClientRect().top +
(to?.top ?? 0)
});
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
Expand All @@ -36,9 +58,30 @@
}
};
});
const client = getContextClient();
$: manga = queryStore({
client,
query: getManga,
variables: { id: $data?.MangaID }
});
$: filteredChapters = $manga.data?.manga.chapters.nodes
.sort((a, b) => {
return b.sourceOrder - a.sourceOrder;
})
.filter(filterChapters(mangaMeta, true));
let chapterSideElement: HTMLDivElement | undefined;
onNavigate((e) => {
const match = e.to?.url.pathname.match(/\/manga\/(\d+)\/chapter\/(\d+)/);
if (!match) {
drawerStore.close();
}
});
</script>

{#if mangaMeta}
{#if $mangaMeta}
<div class="flex flex-col p-4">
<div class="mb-4 flex justify-end border-b border-surface-500 pb-4">
<IconButton
Expand Down Expand Up @@ -101,5 +144,61 @@
</select>
</label>
</div>
<div class="ml-3">
<div
bind:this={chapterSideElement}
id="chapterSideElement"
class="max-h-60 w-full overflow-y-auto"
>
{#each filteredChapters ?? [] as chapter}
<IntersectionObserver
let:intersecting
class="relative h-20"
root={chapterSideElement}
top={400}
bottom={400}
id="chapter-{chapter.id}"
>
{#if intersecting}
<a
data-sveltekit-replacestate
href="./{chapter.id}?pagenav"
class="h-20"
>
<div
class="w-full space-y-0 p-1
{chapter.id === $data?.ChapterID && 'variant-ghost'}
{chapter.isRead && 'opacity-50'}"
>
<div class="line-clamp-1 w-full text-xl md:text-2xl">
{$mangaMeta.ChapterTitle === ChapterTitle['Source Title']
? chapter.name
: `Chapter ${chapter.chapterNumber}`}
</div>
<div
class="line-clamp-1 w-full text-sm font-light md:text-base"
title="Fetched Date: {new Date(
parseInt(chapter.fetchedAt) * 1000
).toLocaleString()}&#013;Upload Date: {new Date(
parseInt(chapter.uploadDate)
).toLocaleString()}"
>
{new Date(
$mangaMeta.ChapterFetchUpload
? parseInt(chapter.uploadDate)
: parseInt(chapter.fetchedAt) * 1000
).toLocaleDateString()}{chapter.isDownloaded
? ' • Downloaded'
: ''}{chapter.scanlator ? ` • ${chapter.scanlator}` : ''}
</div>
</div>
</a>
{/if}
</IntersectionObserver>
{:else}
No chapters found
{/each}
</div>
</div>
</div>
{/if}
47 changes: 47 additions & 0 deletions src/routes/(app)/manga/[MangaID]/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2024 Contributors to the Suwayomi project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import { get } from 'svelte/store';
import type { MangaMeta } from '$lib/simpleStores';
import type { ResultOf } from 'gql.tada';
import type { getManga } from '$lib/gql/Queries';

export function filterChapters(
mangaMeta: ReturnType<typeof MangaMeta>,
reading = false
) {
return (
chapter: ResultOf<typeof getManga>['manga']['chapters']['nodes'][number]
) => {
if (get(mangaMeta).groupPartials.length > 0) {
if (
!get(mangaMeta)
.groupPartials.map((group) => {
return chapter.scanlator
?.toLowerCase()
.includes(group.toLowerCase());
})
.reduce((a, c) => a || c, false)
) {
return false;
}
}
if (!reading) {
if (get(mangaMeta).ChapterUnread === 1 && chapter.isRead) return false;
if (get(mangaMeta).ChapterUnread === 2 && !chapter.isRead) return false;

if (get(mangaMeta).ChapterDownloaded === 1 && !chapter.isDownloaded)
return false;
if (get(mangaMeta).ChapterDownloaded === 2 && chapter.isDownloaded)
return false;

if (get(mangaMeta).ChapterBookmarked === 1 && !chapter.isBookmarked)
return false;
if (get(mangaMeta).ChapterBookmarked === 2 && chapter.isBookmarked)
return false;
}
return true;
};
}

0 comments on commit 9a2f24e

Please sign in to comment.