aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools/Wrapped.svelte
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-09-27 23:33:01 -0700
committerFuwn <[email protected]>2023-09-27 23:33:01 -0700
commit8562ba4280c575b3f04df598b7954a2d28b19e50 (patch)
treeeaa43530441522b5104a1fd1e404ce6b663fc9b0 /src/lib/Tools/Wrapped.svelte
parentfix(anime): template increment render (diff)
downloaddue.moe-8562ba4280c575b3f04df598b7954a2d28b19e50.tar.xz
due.moe-8562ba4280c575b3f04df598b7954a2d28b19e50.zip
feat(wrapped): initial wrapped prototype
Diffstat (limited to 'src/lib/Tools/Wrapped.svelte')
-rw-r--r--src/lib/Tools/Wrapped.svelte227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/lib/Tools/Wrapped.svelte b/src/lib/Tools/Wrapped.svelte
new file mode 100644
index 00000000..bd40e5ef
--- /dev/null
+++ b/src/lib/Tools/Wrapped.svelte
@@ -0,0 +1,227 @@
+<script lang="ts">
+ import userIdentity from '../../stores/userIdentity.js';
+ import {
+ userIdentity as getUserIdentity,
+ type AniListAuthorisation
+ } from '$lib/AniList/identity';
+ import { onMount } from 'svelte';
+ import { wrapped } from '$lib/AniList/wrapped.js';
+ import { activityHistory, fillMissingDays } from '$lib/AniList/activity.js';
+ import { Type, mediaListCollection, type Media } from '$lib/AniList/media.js';
+ import anime from '../../stores/anime.js';
+ import lastPruneTimes from '../../stores/lastPruneTimes.js';
+ import manga from '../../stores/manga.js';
+
+ export let user: AniListAuthorisation;
+
+ let currentUserIdentity = { name: '', id: -1 };
+ let episodes = 0;
+ let animeList: Media[] | undefined = undefined;
+ let mangaList: Media[] | undefined = undefined;
+
+ onMount(async () => {
+ if (user !== undefined) {
+ if ($userIdentity === '') {
+ userIdentity.set(JSON.stringify(await getUserIdentity(user)));
+ }
+
+ currentUserIdentity = JSON.parse($userIdentity);
+ currentUserIdentity.name = currentUserIdentity.name;
+ animeList = await mediaListCollection(
+ user,
+ currentUserIdentity,
+ Type.Anime,
+ $anime,
+ $lastPruneTimes.anime,
+ true,
+ true
+ );
+ mangaList = await mediaListCollection(
+ user,
+ currentUserIdentity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ true,
+ true
+ );
+ animeList = animeList.sort((a, b) => {
+ if (a.mediaListEntry?.score === undefined) {
+ return 1;
+ } else if (b.mediaListEntry?.score === undefined) {
+ return -1;
+ } else {
+ return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ }
+ });
+ mangaList = mangaList.sort((a, b) => {
+ if (a.mediaListEntry?.score === undefined) {
+ return 1;
+ } else if (b.mediaListEntry?.score === undefined) {
+ return -1;
+ } else {
+ return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ }
+ });
+
+ for (const media of animeList) {
+ if (media.startDate.year === new Date(Date.now()).getFullYear()) {
+ episodes += media.mediaListEntry?.progress || 0;
+ }
+ }
+ }
+ });
+
+ /* eslint-disable @typescript-eslint/no-explicit-any */
+ const year = (statistic: { startYears: any }) => {
+ return statistic.startYears.find((y: { startYear: number }) => y.startYear === 2023);
+ };
+</script>
+
+{#if currentUserIdentity.id !== -1}
+ {#await wrapped(user, currentUserIdentity)}
+ Loading ...
+ {:then wrapped}
+ {@const anime = year(wrapped.statistics.anime)}
+ {@const manga = year(wrapped.statistics.manga)}
+
+ <div class="categories-grid">
+ <div class="grid-item image-grid">
+ <img src={wrapped.avatar.large} alt="User Avatar" />
+ <div>
+ <div>
+ <b>
+ {currentUserIdentity.name}
+ </b>
+ </div>
+ <div>
+ Status Posts: {wrapped.activities.statusCount}
+ </div>
+ <div>
+ Messages: {wrapped.activities.messageCount}
+ </div>
+ <div>
+ Days Active: {#await activityHistory(currentUserIdentity)}
+ Loading ...
+ {:then activities}
+ {#if activities === undefined}
+ Loading ...
+ {:else}
+ {fillMissingDays(activities, true).filter((a) => a.amount !== 0).length}/365
+ {/if}
+ {/await}
+ </div>
+ </div>
+ </div>
+ <div class="category-grid">
+ <div class="grid-item">
+ <b>Anime</b>
+ </div>
+ <div class="grid-item">
+ Time Watched: {((anime.minutesWatched || 0) / 60 / 24).toFixed(2)} days
+ </div>
+ <div class="grid-item">
+ Completed: {anime.count}
+ </div>
+ <div class="grid-item">Episodes: {episodes}</div>
+ </div>
+ <div class="category-grid">
+ <div class="grid-item">
+ <b>Manga</b>
+ </div>
+ <div class="grid-item">
+ Time Read: {(((manga.chaptersRead || 0) * 8.58) / 60 / 24).toFixed(2)} days
+ </div>
+ <div class="grid-item">
+ Completed: {manga.count}
+ </div>
+ <div class="grid-item">
+ Chapters: {manga.chaptersRead || 0}
+ </div>
+ </div>
+ <div class="category-grid">
+ <div class="grid-item image-grid">
+ {#if animeList !== undefined}
+ <img
+ src={animeList[0].coverImage.extraLarge}
+ alt="Highest Rated Anime Cover"
+ class="cover-image"
+ />
+ <div>
+ <b>Highest Rated Anime</b>
+ <ol>
+ {#each animeList?.slice(0, 5) as anime}
+ <li>
+ {anime.title.english || anime.title.romaji || anime.title.native}
+ </li>
+ {/each}
+ </ol>
+ </div>
+ {:else}
+ Loading ...
+ {/if}
+ </div>
+ </div>
+ <div class="category-grid">
+ <div class="grid-item image-grid">
+ {#if mangaList !== undefined}
+ <img
+ src={mangaList[0].coverImage.extraLarge}
+ alt="Highest Rated Manga Cover"
+ class="cover-image"
+ />
+ <div>
+ <b>Highest Rated Manga</b>
+ <ol>
+ {#each mangaList?.slice(0, 5) as manga}
+ <li>
+ {manga.title.english || manga.title.romaji || manga.title.native}
+ </li>
+ {/each}
+ </ol>
+ </div>
+ {:else}
+ Loading ...
+ {/if}
+ </div>
+ </div>
+ </div>
+ {:catch error}
+ {error}
+ {/await}
+{:else}
+ Loading ...
+{/if}
+
+<style>
+ .categories-grid {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 1em;
+ column-gap: 1em;
+ }
+
+ .category-grid {
+ display: grid;
+ }
+
+ .image-grid {
+ display: grid;
+ column-gap: 1em;
+ grid-template-columns: 1fr 2fr;
+ }
+
+ .image-grid img {
+ height: 6em;
+ }
+
+ .cover-image {
+ height: 8.75em !important;
+ }
+
+ .grid-item {
+ min-width: 300px;
+ flex: 1 1 300px;
+ /* text-align: center; */
+ }
+</style>