aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-08-28 15:28:00 -0700
committerFuwn <[email protected]>2023-08-28 15:28:00 -0700
commit31f0df5e6041b3fd761fef9239056a7b9e6ed48c (patch)
tree21191877688bbe5920a469b6d0d2e1762d4ef339 /src/lib
parentfeat(settings): add info text (diff)
downloaddue.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.svelte1
-rw-r--r--src/lib/List/Due/MangaList.svelte1
-rw-r--r--src/lib/List/UpcomingAnimeList.svelte147
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}