aboutsummaryrefslogtreecommitdiff
path: root/src/lib/List/Manga/MangaListTemplate.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/List/Manga/MangaListTemplate.svelte')
-rw-r--r--src/lib/List/Manga/MangaListTemplate.svelte492
1 files changed, 271 insertions, 221 deletions
diff --git a/src/lib/List/Manga/MangaListTemplate.svelte b/src/lib/List/Manga/MangaListTemplate.svelte
index 0b967cb2..c9f66dd4 100644
--- a/src/lib/List/Manga/MangaListTemplate.svelte
+++ b/src/lib/List/Manga/MangaListTemplate.svelte
@@ -1,32 +1,32 @@
<script lang="ts">
-import sampleManga from '$lib/Data/Static/SampleMedia/manga.json';
-import { mediaListCollection, Type, type Media } from '$lib/Data/AniList/media';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import { onDestroy, onMount } from 'svelte';
-import { chapterCount } from '$lib/Media/Manga/chapters';
-import { pruneAllManga } from '$lib/Media/Manga/cache';
-import manga from '$stores/manga';
-import { database } from '$lib/Database/IDB/chapters';
-import settings from '$stores/settings';
-import lastPruneTimes from '$stores/lastPruneTimes';
-import ListTitle from '../ListTitle.svelte';
-import RateLimitedError from '$lib/Error/RateLimited.svelte';
-import CleanMangaList from './CleanMangaList.svelte';
-import { incrementMediaProgress } from '$lib/Media/Anime/cache';
-import { addNotification } from '$lib/Notification/store';
-import { options } from '$lib/Notification/options';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import locale from '$stores/locale';
-import { browser } from '$app/environment';
-import identity from '$stores/identity';
-import privilegedUser from '$lib/Utility/privilegedUser';
-import localforage from 'localforage';
+import sampleManga from "$lib/Data/Static/SampleMedia/manga.json";
+import { mediaListCollection, Type, type Media } from "$lib/Data/AniList/media";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import { onDestroy, onMount } from "svelte";
+import { chapterCount } from "$lib/Media/Manga/chapters";
+import { pruneAllManga } from "$lib/Media/Manga/cache";
+import manga from "$stores/manga";
+import { database } from "$lib/Database/IDB/chapters";
+import settings from "$stores/settings";
+import lastPruneTimes from "$stores/lastPruneTimes";
+import ListTitle from "../ListTitle.svelte";
+import RateLimitedError from "$lib/Error/RateLimited.svelte";
+import CleanMangaList from "./CleanMangaList.svelte";
+import { incrementMediaProgress } from "$lib/Media/Anime/cache";
+import { addNotification } from "$lib/Notification/store";
+import { options } from "$lib/Notification/options";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import locale from "$stores/locale";
+import { browser } from "$app/environment";
+import identity from "$stores/identity";
+import privilegedUser from "$lib/Utility/privilegedUser";
+import localforage from "localforage";
export let user: AniListAuthorisation = {
- accessToken: '',
- refreshToken: '',
- expiresIn: 0,
- tokenType: ''
+ accessToken: "",
+ refreshToken: "",
+ expiresIn: 0,
+ tokenType: "",
};
export let displayUnresolved: boolean;
export let due: boolean;
@@ -49,215 +49,265 @@ let keyCacher: ReturnType<typeof setInterval> | undefined;
let keyCacheMinutes = -1;
const restartKeyCacher = (cacheMinutes: number) => {
- if (keyCacher) clearInterval(keyCacher);
-
- keyCacheMinutes = cacheMinutes;
- keyCacher = setInterval(
- () => {
- startTime = performance.now();
- endTime = -1;
- mangaLists = mediaListCollection(user, $identity, Type.Manga, $manga, $lastPruneTimes.manga, {
- addNotification
- });
- },
- cacheMinutes * 1000 * 60
- );
+ if (keyCacher) clearInterval(keyCacher);
+
+ keyCacheMinutes = cacheMinutes;
+ keyCacher = setInterval(
+ () => {
+ startTime = performance.now();
+ endTime = -1;
+ mangaLists = mediaListCollection(
+ user,
+ $identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ {
+ addNotification,
+ },
+ );
+ },
+ cacheMinutes * 1000 * 60,
+ );
};
onMount(async () => {
- restartKeyCacher(Math.max($settings.cacheMangaMinutes, 5));
-
- if (browser) {
- const lastStoredList = (await localforage.getItem(
- `last${due ? '' : 'Completed'}MangaListLength`
- )) as number | null;
-
- if (lastStoredList) lastListSize = parseInt(String(lastStoredList));
- }
-
- startTime = performance.now();
-
- if (dummy) {
- // Use deterministic selection for consistent display
- const filtered = sampleManga.filter(
- (manga) =>
- manga.chapters &&
- !manga.tags.some((tag) => tag.name === 'Nudity') &&
- !manga.tags.some((tag) => tag.name === 'Rape') &&
- !manga.tags.some((tag) => tag.name === 'Tragedy') &&
- !manga.tags.some((tag) => tag.name === 'Bondage') &&
- !manga.genres.some((genre) => genre === 'Hentai') &&
- manga.genres.some((genre) => genre === 'Comedy') &&
- manga.status !== 'NOT_YET_RELEASED'
- );
- mangaLists = Promise.resolve(
- filtered.slice(0, dummyCount).map((manga) => {
- manga.status = 'FINISHED';
- manga.episodes = Math.floor((manga.chapters || 10) * 0.7) as unknown as null;
- manga.mediaListEntry.progress = Math.floor((manga.episodes || 5) * 0.5) + 1;
- return manga;
- }) as unknown as Media[]
- );
- } else {
- mangaLists = mediaListCollection(user, $identity, Type.Manga, $manga, $lastPruneTimes.manga, {
- addNotification
- });
- }
+ restartKeyCacher(Math.max($settings.cacheMangaMinutes, 5));
+
+ if (browser) {
+ const lastStoredList = (await localforage.getItem(
+ `last${due ? "" : "Completed"}MangaListLength`,
+ )) as number | null;
+
+ if (lastStoredList) lastListSize = parseInt(String(lastStoredList));
+ }
+
+ startTime = performance.now();
+
+ if (dummy) {
+ // Use deterministic selection for consistent display
+ const filtered = sampleManga.filter(
+ (manga) =>
+ manga.chapters &&
+ !manga.tags.some((tag) => tag.name === "Nudity") &&
+ !manga.tags.some((tag) => tag.name === "Rape") &&
+ !manga.tags.some((tag) => tag.name === "Tragedy") &&
+ !manga.tags.some((tag) => tag.name === "Bondage") &&
+ !manga.genres.some((genre) => genre === "Hentai") &&
+ manga.genres.some((genre) => genre === "Comedy") &&
+ manga.status !== "NOT_YET_RELEASED",
+ );
+ mangaLists = Promise.resolve(
+ filtered.slice(0, dummyCount).map((manga) => {
+ manga.status = "FINISHED";
+ manga.episodes = Math.floor(
+ (manga.chapters || 10) * 0.7,
+ ) as unknown as null;
+ manga.mediaListEntry.progress =
+ Math.floor((manga.episodes || 5) * 0.5) + 1;
+ return manga;
+ }) as unknown as Media[],
+ );
+ } else {
+ mangaLists = mediaListCollection(
+ user,
+ $identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ {
+ addNotification,
+ },
+ );
+ }
});
-$: if (keyCacher && keyCacheMinutes !== Math.max($settings.cacheMangaMinutes, 5))
- restartKeyCacher(Math.max($settings.cacheMangaMinutes, 5));
+$: if (
+ keyCacher &&
+ keyCacheMinutes !== Math.max($settings.cacheMangaMinutes, 5)
+)
+ restartKeyCacher(Math.max($settings.cacheMangaMinutes, 5));
onDestroy(() => {
- if (keyCacher) clearInterval(keyCacher);
+ if (keyCacher) clearInterval(keyCacher);
});
-const cleanMedia = async (manga: Media[], displayUnresolved: boolean, force: boolean) => {
- progress = 0;
-
- if (manga && dummy) return manga;
-
- if (manga === undefined) return [];
-
- if (!authorised && (await database.chapters.toArray()).length <= 0 && !force) return [];
-
- if (authorised) {
- let refreshing = false;
-
- if ($lastPruneTimes.chapters === 1) {
- refreshing = true;
-
- lastPruneTimes.setKey('chapters', new Date().getTime());
- } else {
- const currentDate = new Date();
-
- if (
- (currentDate.getTime() - $lastPruneTimes.chapters) / 1000 / 60 >
- Math.max($settings.cacheMangaMinutes, 5)
- ) {
- refreshing = true;
-
- lastPruneTimes.setKey('chapters', currentDate.getTime());
- (async () => {
- await database.chapters.bulkDelete((await database.chapters.toArray()).map((m) => m.id));
- })();
- }
- }
-
- if (refreshing) {
- addNotification(
- options({
- heading: 'Manga',
- description: 'Re-freshing manga data ...'
- })
- );
- }
- }
-
- const releasingMedia = manga.filter(
- (media: Media) =>
- (due ? media.status === 'RELEASING' : media.status === 'FINISHED') &&
- (media.mediaListEntry || { status: 'DROPPED' }).status !==
- ($settings.displayPausedMedia ? '' : 'PAUSED') &&
- (media.mediaListEntry || { status: 'DROPPED' }).status !== 'DROPPED' &&
- (media.mediaListEntry || { progress: 0 }).progress >=
- ($settings.displayNotStarted === true ? 0 : 1)
- );
- let finalMedia = releasingMedia;
- const progressStep = 100 / finalMedia.length / 2;
- const chapterPromises = finalMedia.map((m: Media) =>
- database.chapters.get(m.id).then((c) => {
- if (progress < 100) progress += progressStep;
-
- if (!due) return new Promise((resolve) => resolve(m.chapters)) as Promise<number | null>;
-
- if (c !== undefined) return chapterCount($identity, m, $settings.calculateGuessingDisabled);
- else {
- // A = On 1 second interval,
- // B = a maximum of 5 requests per second are allowed.
- // C = chapterCount makes 3 requests per call.
- // F = A / (B / C) = 0.6 seconds
- return new Promise((resolve) => setTimeout(resolve, 600)).then(() =>
- chapterCount($identity, m, $settings.calculateGuessingDisabled)
- );
- }
- })
- );
- const chapterCounts: (number | null)[] = [];
-
- for (let i = 0; i < chapterPromises.length; i++) {
- const count = await chapterPromises[i];
-
- if (count === -22) {
- rateLimited = true;
-
- break;
- }
-
- chapterCounts.push(count);
-
- if (progress < 100) progress += progressStep;
- }
-
- finalMedia.forEach((m: Media, i) => {
- m.episodes = chapterCounts[i] || -1337;
- });
-
- if (!displayUnresolved) finalMedia = finalMedia.filter((m: Media) => m.episodes !== -1337);
-
- finalMedia.sort(
- (a: Media, b: Media) =>
- (a.episodes || 9999) -
- (a.mediaListEntry || { progress: 0 }).progress -
- ((b.episodes || 9999) - (b.mediaListEntry || { progress: 0 }).progress)
- );
-
- finalMedia = finalMedia.filter(
- (item, index, array) =>
- array.findIndex((i) => i.id === item.id) === index &&
- (item.episodes === -1337 && displayUnresolved
- ? true
- : (item.mediaListEntry?.progress || 0) <
- ($settings.calculateChaptersRoundedDown === true
- ? Math.floor(item.episodes)
- : item.episodes))
- );
-
- if (!endTime || endTime === -1) endTime = performance.now() - startTime;
-
- return finalMedia;
+const cleanMedia = async (
+ manga: Media[],
+ displayUnresolved: boolean,
+ force: boolean,
+) => {
+ progress = 0;
+
+ if (manga && dummy) return manga;
+
+ if (manga === undefined) return [];
+
+ if (!authorised && (await database.chapters.toArray()).length <= 0 && !force)
+ return [];
+
+ if (authorised) {
+ let refreshing = false;
+
+ if ($lastPruneTimes.chapters === 1) {
+ refreshing = true;
+
+ lastPruneTimes.setKey("chapters", new Date().getTime());
+ } else {
+ const currentDate = new Date();
+
+ if (
+ (currentDate.getTime() - $lastPruneTimes.chapters) / 1000 / 60 >
+ Math.max($settings.cacheMangaMinutes, 5)
+ ) {
+ refreshing = true;
+
+ lastPruneTimes.setKey("chapters", currentDate.getTime());
+ (async () => {
+ await database.chapters.bulkDelete(
+ (await database.chapters.toArray()).map((m) => m.id),
+ );
+ })();
+ }
+ }
+
+ if (refreshing) {
+ addNotification(
+ options({
+ heading: "Manga",
+ description: "Re-freshing manga data ...",
+ }),
+ );
+ }
+ }
+
+ const releasingMedia = manga.filter(
+ (media: Media) =>
+ (due ? media.status === "RELEASING" : media.status === "FINISHED") &&
+ (media.mediaListEntry || { status: "DROPPED" }).status !==
+ ($settings.displayPausedMedia ? "" : "PAUSED") &&
+ (media.mediaListEntry || { status: "DROPPED" }).status !== "DROPPED" &&
+ (media.mediaListEntry || { progress: 0 }).progress >=
+ ($settings.displayNotStarted === true ? 0 : 1),
+ );
+ let finalMedia = releasingMedia;
+ const progressStep = 100 / finalMedia.length / 2;
+ const chapterPromises = finalMedia.map((m: Media) =>
+ database.chapters.get(m.id).then((c) => {
+ if (progress < 100) progress += progressStep;
+
+ if (!due)
+ return new Promise((resolve) => resolve(m.chapters)) as Promise<
+ number | null
+ >;
+
+ if (c !== undefined)
+ return chapterCount($identity, m, $settings.calculateGuessingDisabled);
+ else {
+ // A = On 1 second interval,
+ // B = a maximum of 5 requests per second are allowed.
+ // C = chapterCount makes 3 requests per call.
+ // F = A / (B / C) = 0.6 seconds
+ return new Promise((resolve) => setTimeout(resolve, 600)).then(() =>
+ chapterCount($identity, m, $settings.calculateGuessingDisabled),
+ );
+ }
+ }),
+ );
+ const chapterCounts: (number | null)[] = [];
+
+ for (let i = 0; i < chapterPromises.length; i++) {
+ const count = await chapterPromises[i];
+
+ if (count === -22) {
+ rateLimited = true;
+
+ break;
+ }
+
+ chapterCounts.push(count);
+
+ if (progress < 100) progress += progressStep;
+ }
+
+ finalMedia.forEach((m: Media, i) => {
+ m.episodes = chapterCounts[i] || -1337;
+ });
+
+ if (!displayUnresolved)
+ finalMedia = finalMedia.filter((m: Media) => m.episodes !== -1337);
+
+ finalMedia.sort(
+ (a: Media, b: Media) =>
+ (a.episodes || 9999) -
+ (a.mediaListEntry || { progress: 0 }).progress -
+ ((b.episodes || 9999) - (b.mediaListEntry || { progress: 0 }).progress),
+ );
+
+ finalMedia = finalMedia.filter(
+ (item, index, array) =>
+ array.findIndex((i) => i.id === item.id) === index &&
+ (item.episodes === -1337 && displayUnresolved
+ ? true
+ : (item.mediaListEntry?.progress || 0) <
+ ($settings.calculateChaptersRoundedDown === true
+ ? Math.floor(item.episodes)
+ : item.episodes)),
+ );
+
+ if (!endTime || endTime === -1) endTime = performance.now() - startTime;
+
+ return finalMedia;
};
-const updateMedia = async (id: number, progress: number | undefined, media: Media[]) => {
- pendingUpdate = id;
- lastUpdatedMedia = id;
-
- await database.chapters.delete(id);
-
- incrementMediaProgress(id, progress, user, () => {
- previousMangaList = media;
-
- const foundEntry = media.find((m) => m.id === id);
-
- if (foundEntry && foundEntry.mediaListEntry)
- foundEntry.mediaListEntry.progress = (progress || 0) + 1;
-
- mangaLists = mediaListCollection(user, $identity, Type.Manga, $manga, $lastPruneTimes.manga, {
- forcePrune: true
- });
- pendingUpdate = null;
- });
+const updateMedia = async (
+ id: number,
+ progress: number | undefined,
+ media: Media[],
+) => {
+ pendingUpdate = id;
+ lastUpdatedMedia = id;
+
+ await database.chapters.delete(id);
+
+ incrementMediaProgress(id, progress, user, () => {
+ previousMangaList = media;
+
+ const foundEntry = media.find((m) => m.id === id);
+
+ if (foundEntry && foundEntry.mediaListEntry)
+ foundEntry.mediaListEntry.progress = (progress || 0) + 1;
+
+ mangaLists = mediaListCollection(
+ user,
+ $identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ {
+ forcePrune: true,
+ },
+ );
+ pendingUpdate = null;
+ });
};
const cleanCache = () => {
- startTime = performance.now();
- endTime = -1;
-
- pruneAllManga().then(() => {
- mangaLists = mediaListCollection(user, $identity, Type.Manga, $manga, $lastPruneTimes.manga, {
- forcePrune: true
- });
- });
+ startTime = performance.now();
+ endTime = -1;
+
+ pruneAllManga().then(() => {
+ mangaLists = mediaListCollection(
+ user,
+ $identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ {
+ forcePrune: true,
+ },
+ );
+ });
};
</script>