diff options
| author | Fuwn <[email protected]> | 2023-09-27 23:33:01 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-09-27 23:33:01 -0700 |
| commit | 8562ba4280c575b3f04df598b7954a2d28b19e50 (patch) | |
| tree | eaa43530441522b5104a1fd1e404ce6b663fc9b0 /src/lib/Tools | |
| parent | fix(anime): template increment render (diff) | |
| download | due.moe-8562ba4280c575b3f04df598b7954a2d28b19e50.tar.xz due.moe-8562ba4280c575b3f04df598b7954a2d28b19e50.zip | |
feat(wrapped): initial wrapped prototype
Diffstat (limited to 'src/lib/Tools')
| -rw-r--r-- | src/lib/Tools/ActivityHistory.svelte | 45 | ||||
| -rw-r--r-- | src/lib/Tools/Wrapped.svelte | 227 |
2 files changed, 235 insertions, 37 deletions
diff --git a/src/lib/Tools/ActivityHistory.svelte b/src/lib/Tools/ActivityHistory.svelte index 58ba4173..a8f3c45b 100644 --- a/src/lib/Tools/ActivityHistory.svelte +++ b/src/lib/Tools/ActivityHistory.svelte @@ -1,5 +1,9 @@ <script lang="ts"> - import { activityHistory, type ActivityHistoryEntry } from '$lib/AniList/activity.js'; + import { + activityHistory, + fillMissingDays, + type ActivityHistoryEntry + } from '$lib/AniList/activity.js'; import { onMount } from 'svelte'; import userIdentity from '../../stores/userIdentity.js'; import { @@ -11,7 +15,6 @@ let activityHistoryData: Promise<ActivityHistoryEntry[]>; let currentUserIdentity = { name: '', id: -1 }; - const timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000; onMount(async () => { if (user !== undefined) { @@ -22,43 +25,9 @@ currentUserIdentity = JSON.parse($userIdentity); currentUserIdentity.name = currentUserIdentity.name; activityHistoryData = activityHistory(currentUserIdentity); - console.log(fillMissingDays(await activityHistory(currentUserIdentity))); } }); - const fillMissingDays = (inputActivities: ActivityHistoryEntry[]): ActivityHistoryEntry[] => { - let activities = inputActivities; - const firstDate = new Date(activities[0].date * 1000 + timezoneOffset); - const lastDate = new Date(activities[activities.length - 1].date * 1000 + timezoneOffset); - const currentDate = firstDate; - - while (currentDate <= lastDate) { - const current_unix_timestamp = currentDate.getTime(); - let found = false; - - for (let i = 0; i < activities.length; i++) { - if (activities[i].date * 1000 + timezoneOffset === current_unix_timestamp) { - found = true; - - break; - } - } - - if (!found) { - activities.push({ - date: current_unix_timestamp / 1000, - amount: 0 - }); - } - - currentDate.setDate(currentDate.getDate() + 1); - } - - // activities.sort((a: { date: number }, b: { date: number }) => a.date - b.date); - - return activities; - }; - // const incrementDate = (date: Date): Date => { // date.setDate(date.getDate() + 1); @@ -83,7 +52,9 @@ {#each fillMissingDays(activities) as activity} {#if activity.amount === 0} <li> - {new Date(activity.date * 1000 + timezoneOffset).toDateString()} + {new Date( + activity.date * 1000 + new Date().getTimezoneOffset() * 60 * 1000 + ).toDateString()} </li> {/if} {/each} 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> |