aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools
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
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')
-rw-r--r--src/lib/Tools/ActivityHistory.svelte45
-rw-r--r--src/lib/Tools/Wrapped.svelte227
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>