diff options
| author | Fuwn <[email protected]> | 2023-08-28 15:28:00 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-08-28 15:28:00 -0700 |
| commit | 31f0df5e6041b3fd761fef9239056a7b9e6ed48c (patch) | |
| tree | 21191877688bbe5920a469b6d0d2e1762d4ef339 /src/lib | |
| parent | feat(settings): add info text (diff) | |
| download | due.moe-31f0df5e6041b3fd761fef9239056a7b9e6ed48c.tar.xz due.moe-31f0df5e6041b3fd761fef9239056a7b9e6ed48c.zip | |
feat(list): upcoming episodes
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/List/Due/AnimeList.svelte | 1 | ||||
| -rw-r--r-- | src/lib/List/Due/MangaList.svelte | 1 | ||||
| -rw-r--r-- | src/lib/List/UpcomingAnimeList.svelte | 147 |
3 files changed, 149 insertions, 0 deletions
diff --git a/src/lib/List/Due/AnimeList.svelte b/src/lib/List/Due/AnimeList.svelte index 334b47fe..6569d76f 100644 --- a/src/lib/List/Due/AnimeList.svelte +++ b/src/lib/List/Due/AnimeList.svelte @@ -147,6 +147,7 @@ <a href={`https://anilist.co/anime/${anime['id']}`} target="_blank"> {anime['title']['english'] || anime['title']['romaji']} </a> + <span style="opacity: 50%;">|</span> {(anime['mediaListEntry'] || { progress: 0 })['progress']}{@html totalEpisodes(anime)} <a href="#" on:click={() => updateMedia(anime.id, anime.mediaListEntry?.progress)}>+</a> [{anime.nextAiringEpisode?.episode === -1 diff --git a/src/lib/List/Due/MangaList.svelte b/src/lib/List/Due/MangaList.svelte index e2c0ad05..f6e1323d 100644 --- a/src/lib/List/Due/MangaList.svelte +++ b/src/lib/List/Due/MangaList.svelte @@ -120,6 +120,7 @@ <a href={`https://anilist.co/manga/${manga['id']}`} target="_blank"> {manga['title']['english'] || manga['title']['romaji'] || manga['title']['native']} </a> + <span style="opacity: 50%;">|</span> {(manga['mediaListEntry'] || { progress: 0 })['progress']} <a href="#" on:click={() => updateMedia(manga.id, manga.mediaListEntry?.progress)}>+</a> [{manga['episodes'] || '?'}] diff --git a/src/lib/List/UpcomingAnimeList.svelte b/src/lib/List/UpcomingAnimeList.svelte new file mode 100644 index 00000000..ea421241 --- /dev/null +++ b/src/lib/List/UpcomingAnimeList.svelte @@ -0,0 +1,147 @@ +<script lang="ts"> + import { mediaListCollection, Type, flattenLists, type Media } from '$lib/AniList/media'; + import type { UserIdentity, AniListAuthorisation } from '$lib/AniList/identity'; + import { onMount } from 'svelte'; + import anime from '../../stores/anime'; + import animeLastPrune from '../../stores/mangaLastPrune'; + + export let user: AniListAuthorisation; + export let identity: UserIdentity; + export let displayUnresolved: boolean; + + let animeLists: any; + let startTime: number; + let endTime: number; + + onMount(async () => { + startTime = performance.now(); + animeLists = mediaListCollection(user, identity, Type.Anime, $anime, $animeLastPrune); + }); + + const cleanMedia = (media: object[][], displayUnresolved: boolean) => { + if (media === undefined) { + return []; + } + + const flattenedLists = flattenLists(media); + const releasingMedia = flattenedLists.filter( + (media: Media) => media['status'] == 'RELEASING' /* && + (media['mediaListEntry'] || { progress: 0 })['progress'] >= + ($displayNotStarted === 'true' ? 0 : 1) */ + ); + const outdatedMedia = releasingMedia.filter((media: Media) => { + return ( + (media['nextAiringEpisode'] || { episode: 0 })['episode'] - 1 <= + (media['mediaListEntry'] || { progress: 0 })['progress'] + ); + }); + let finalMedia = outdatedMedia.map((media: Media) => { + if ((media['nextAiringEpisode'] || { episode: 0 })['episode'] - 1 <= 0) { + media['nextAiringEpisode'] = { episode: -1 }; + } + + return media; + }); + + if (!displayUnresolved) { + finalMedia = finalMedia.filter((media: Media) => media.nextAiringEpisode?.episode !== -1); + } + + finalMedia.sort((a: Media, b: Media) => { + return ( + (a.nextAiringEpisode?.timeUntilAiring || 9999) - + (b.nextAiringEpisode?.timeUntilAiring || 9999) + ); + }); + + finalMedia = finalMedia.filter((item, index, array) => { + return ( + array.findIndex((i) => { + return i.id === item.id; + }) === index + ); + }); + endTime = performance.now() - startTime; + + return finalMedia; + }; + + const airingTime = (anime: Media) => { + const untilAiring = anime.nextAiringEpisode?.timeUntilAiring; + let timeFrame; + + if (untilAiring !== undefined) { + let hours = untilAiring / 3600; + + if (hours >= 24) { + let weeks = Math.floor(Math.floor(hours / 24) / 7); + + if (weeks >= 1) { + weeks = Math.round(weeks); + + timeFrame = `${weeks} week${weeks === 1 ? '' : 's'}`; + } else { + const days = Math.round(Math.floor(hours / 24)); + + timeFrame = `${days} day${days === 1 ? '' : 's'}`; + } + } else { + hours = Math.round(hours); + + timeFrame = `${hours} hour${hours === 1 ? '' : 's'}`; + } + + return `${anime.nextAiringEpisode?.episode}${totalEpisodes(anime)} in ${timeFrame}`; + } + + return ''; + }; + + const totalEpisodes = (anime: Media) => { + return anime['episodes'] === null + ? '' + : `<span style="opacity: 50%">/${anime['episodes']}</span>`; + }; +</script> + +{#await animeLists} + <summary>Upcoming Episodes [...] <small style="opacity: 50%">...s</small></summary> + + <ul><li>Loading ...</li></ul> +{:then media} + {@const cleanedMedia = cleanMedia(media, displayUnresolved)} + + <summary + >Upcoming Episodes [{cleanedMedia.length}] + <small style="opacity: 50%">{endTime / 1000}s</small></summary + > + + <ul> + {#each cleanedMedia as anime} + <li> + <a href={`https://anilist.co/anime/${anime['id']}`} target="_blank"> + {anime['title']['english'] || anime['title']['romaji']} + </a> + <span style="opacity: 50%;">|</span> + {@html airingTime(anime)} + </li> + {/each} + </ul> +{:catch} + <summary>Upcoming Episodes [?] <small style="opacity: 50%">0s</small></summary> + + <ul> + <li> + <p> + Media could not be loaded. You might have been <a + href="https://en.wikipedia.org/wiki/Rate_limiting" + target="_blank">rate limited</a + >. + </p> + <p> + Try again in a few minutes. If the problem persists, please contact + <a href="https://anilist.co/user/fuwn" target="_blank">@fuwn</a> on AniList. + </p> + </li> + </ul> +{/await} |