aboutsummaryrefslogtreecommitdiff
path: root/src/lib/List/Manga
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/List/Manga')
-rw-r--r--src/lib/List/Manga/CleanMangaList.svelte81
-rw-r--r--src/lib/List/Manga/MangaListTemplate.svelte200
2 files changed, 281 insertions, 0 deletions
diff --git a/src/lib/List/Manga/CleanMangaList.svelte b/src/lib/List/Manga/CleanMangaList.svelte
new file mode 100644
index 00000000..659388ea
--- /dev/null
+++ b/src/lib/List/Manga/CleanMangaList.svelte
@@ -0,0 +1,81 @@
+<script lang="ts">
+ import type { Media } from '$lib/AniList/media';
+ import { volumeCount } from '$lib/Media/manga';
+ import settings from '../../../stores/settings';
+ import ListTitle from '../ListTitle.svelte';
+
+ export let media: Media[];
+ export let cleanCache: () => void;
+ export let endTime: number;
+ export let lastUpdatedMedia: number;
+ export let updateMedia: (
+ id: number,
+ progress: number | undefined,
+ media: Media[]
+ ) => Promise<void>;
+ export let disableIncrement = false;
+ export let pendingUpdate: number | null;
+ export let due: boolean;
+</script>
+
+<ListTitle count={media.length} time={endTime / 1000}>
+ <a href={'#'} title="Force a full refresh" on:click={cleanCache}>Refresh</a>
+</ListTitle>
+
+{#if media.length === 0}
+ <ul>
+ <li>No manga to display. <a href={'#'} on:click={cleanCache}>Force refresh</a></li>
+ </ul>
+{/if}
+
+<ul>
+ {#each media as manga}
+ {@const progress = (manga.mediaListEntry || { progress: 0 }).progress}
+
+ <li>
+ <a href={`https://anilist.co/manga/${manga.id}`} target="_blank">
+ <span
+ style={lastUpdatedMedia === manga.id && manga.chapters !== progress
+ ? 'color: lightcoral'
+ : ''}
+ >
+ {#if $settings.displayNativeTitles}
+ <span title={manga.title.english || manga.title.romaji || manga.title.native}>
+ {manga.title.native}
+ </span>
+ {:else}
+ <span title={manga.title.native}>
+ {manga.title.english || manga.title.romaji || manga.title.native}
+ </span>
+ {/if}
+ </span>
+ </a>
+ {#if $settings.displaySocialButton}
+ [<a href={`https://anilist.co/manga/${manga.id}/social`} target="_blank">S</a>]
+ {/if}
+ <span style="opacity: 50%;">|</span>
+ {pendingUpdate === manga.id ? progress + 1 : progress}{#if !due}
+ <span style="opacity: 50%;">/{manga.chapters || '?'}</span>
+ {/if}
+ <a
+ href={'#'}
+ style={disableIncrement ? 'pointer-events: none; opacity: 50%;' : ''}
+ on:click={() =>
+ disableIncrement ? null : updateMedia(manga.id, manga.mediaListEntry?.progress, media)}
+ >
+ +
+ </a>
+ {#if due || manga.episodes !== manga.chapters}
+ [{manga.episodes || '?'}]
+ {#await volumeCount(manga) then volumes}
+ {@const volumeProgress = manga.mediaListEntry?.progressVolumes}
+ {#if volumes !== null && (volumeProgress || 0) < volumes}
+ <span style="color: lightcoral;">
+ Vol. {volumeProgress} &#8594; {volumes}
+ </span>
+ {/if}
+ {/await}
+ {/if}
+ </li>
+ {/each}
+</ul>
diff --git a/src/lib/List/Manga/MangaListTemplate.svelte b/src/lib/List/Manga/MangaListTemplate.svelte
new file mode 100644
index 00000000..49796f50
--- /dev/null
+++ b/src/lib/List/Manga/MangaListTemplate.svelte
@@ -0,0 +1,200 @@
+<script lang="ts">
+ import { mediaListCollection, Type, type Media } from '$lib/AniList/media';
+ import type { UserIdentity, AniListAuthorisation } from '$lib/AniList/identity';
+ import { onDestroy, onMount } from 'svelte';
+ import { chapterCount, pruneAllManga } from '$lib/Media/manga';
+ import manga from '../../../stores/manga';
+ import { chapterDatabase } from '$lib/Media/chapters';
+ import settings from '../../../stores/settings';
+ import lastPruneTimes from '../../../stores/lastPruneTimes';
+ import ListTitle from '../ListTitle.svelte';
+ import Error from '$lib/Error.svelte';
+ import CleanMangaList from './CleanMangaList.svelte';
+
+ export let user: AniListAuthorisation;
+ export let identity: UserIdentity;
+ export let displayUnresolved: boolean;
+ export let due: boolean;
+
+ let mangaLists: Promise<Media[]>;
+ let startTime: number;
+ let endTime: number;
+ let lastUpdatedMedia = -1;
+ let previousMangaList: Media[];
+ let pendingUpdate: number | null = null;
+
+ const keyCacher = setInterval(() => {
+ startTime = performance.now();
+ endTime = -1;
+ mangaLists = mediaListCollection(user, identity, Type.Manga, $manga, $lastPruneTimes.manga);
+ }, $settings.cacheMinutes * 1000 * 60);
+
+ onMount(async () => {
+ startTime = performance.now();
+ mangaLists = mediaListCollection(user, identity, Type.Manga, $manga, $lastPruneTimes.manga);
+ });
+
+ onDestroy(() => clearInterval(keyCacher));
+
+ const cleanMedia = async (media: Media[], displayUnresolved: boolean) => {
+ if (media === undefined) {
+ return [];
+ }
+
+ if ($lastPruneTimes.chapters === 1) {
+ lastPruneTimes.setKey('chapters', new Date().getTime());
+ } else {
+ const currentDate = new Date();
+
+ if (
+ (currentDate.getTime() - $lastPruneTimes.chapters) / 1000 / 60 >
+ $settings.cacheMangaMinutes
+ ) {
+ const unresolved = await chapterDatabase.chapters.where('chapters').equals(-1).toArray();
+ const ids = unresolved.map((m) => m.id);
+
+ lastPruneTimes.setKey('chapters', currentDate.getTime());
+ (async () => {
+ await chapterDatabase.chapters.bulkDelete(ids);
+ })();
+ }
+ }
+
+ const releasingMedia = media.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 chapterPromises = finalMedia.map((m: Media) =>
+ chapterCount(identity, m, $settings.disableGuessing)
+ );
+ const chapterCounts = await Promise.all(chapterPromises);
+
+ 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) => {
+ return (
+ (a.episodes || 9999) -
+ (a.mediaListEntry || { progress: 0 }).progress -
+ ((b.episodes || 9999) - (b.mediaListEntry || { progress: 0 }).progress)
+ );
+ });
+
+ finalMedia = finalMedia.filter((item, index, array) => {
+ return (
+ array.findIndex((i) => {
+ return i.id === item.id;
+ }) === index &&
+ (item.episodes === -1337 && displayUnresolved
+ ? true
+ : (item.mediaListEntry?.progress || 0) <
+ ($settings.roundDownChapters === 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 chapterDatabase.chapters.delete(id);
+ await fetch(`/api/anilist-increment?id=${id}&progress=${(progress || 0) + 1}`).then(() => {
+ previousMangaList = media;
+ media.find((m) => m.id === id)!.mediaListEntry!.progress = (progress || 0) + 1;
+ mangaLists = mediaListCollection(
+ user,
+ identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ true
+ );
+ pendingUpdate = null;
+ });
+ };
+
+ const cleanCache = () => {
+ startTime = performance.now();
+ endTime = -1;
+
+ pruneAllManga().then(() => {
+ mangaLists = mediaListCollection(
+ user,
+ identity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ true
+ );
+ });
+ };
+</script>
+
+{#await mangaLists}
+ {#if previousMangaList}
+ <CleanMangaList
+ media={previousMangaList}
+ {cleanCache}
+ {endTime}
+ {lastUpdatedMedia}
+ {updateMedia}
+ disableIncrement
+ {pendingUpdate}
+ {due}
+ />
+ {:else}
+ <ListTitle />
+
+ <ul><li>Loading ...</li></ul>
+ {/if}
+{:then media}
+ {#await cleanMedia(media, displayUnresolved)}
+ {#if previousMangaList}
+ <CleanMangaList
+ media={previousMangaList}
+ {cleanCache}
+ {endTime}
+ {lastUpdatedMedia}
+ {updateMedia}
+ disableIncrement
+ {pendingUpdate}
+ {due}
+ />
+ {:else}
+ <ListTitle />
+
+ <ul><li>Loading ...</li></ul>
+ {/if}
+ {:then cleanedMedia}
+ <CleanMangaList
+ media={cleanedMedia}
+ {cleanCache}
+ {endTime}
+ {lastUpdatedMedia}
+ {updateMedia}
+ {pendingUpdate}
+ {due}
+ />
+ {:catch}
+ <ListTitle count={-1337} time={0} />
+
+ <Error />
+ {/await}
+{/await}