diff options
| author | Fuwn <[email protected]> | 2023-11-06 18:23:53 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-11-06 18:23:53 -0800 |
| commit | cfc1a9221e4ddabcd0f7090358f19ad374346e3a (patch) | |
| tree | 4a68a03af410c29031be93ddaa83f623637d00c9 /src/lib/List/Manga | |
| parent | fix(manga): wait for prune on clean (diff) | |
| download | due.moe-cfc1a9221e4ddabcd0f7090358f19ad374346e3a.tar.xz due.moe-cfc1a9221e4ddabcd0f7090358f19ad374346e3a.zip | |
refactor(list): move modules to sub-modules
Diffstat (limited to 'src/lib/List/Manga')
| -rw-r--r-- | src/lib/List/Manga/CleanMangaList.svelte | 81 | ||||
| -rw-r--r-- | src/lib/List/Manga/MangaListTemplate.svelte | 200 |
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} → {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} |