From 8a8cf810e4a03453b8254eaad56c27529dc107ef Mon Sep 17 00:00:00 2001 From: Fuwn Date: Fri, 22 Dec 2023 06:53:35 -0800 Subject: feat(wrapped): genres and tags --- src/lib/AniList/media.ts | 18 +++++++++++ src/lib/AniList/wrapped.ts | 52 +++++++++++++++++++++---------- src/lib/Tools/Wrapped.svelte | 74 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 17 deletions(-) (limited to 'src/lib') diff --git a/src/lib/AniList/media.ts b/src/lib/AniList/media.ts index 039b9db6..6fc83296 100644 --- a/src/lib/AniList/media.ts +++ b/src/lib/AniList/media.ts @@ -342,3 +342,21 @@ export const recentMediaActivities = async ( return null; }; + +export const mediaCover = async (id: number) => + ( + await ( + await fetch('https://graphql.anilist.co', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json' + }, + body: JSON.stringify({ + query: `{ + Media(id: ${id}) { coverImage { extraLarge } } + }` + }) + }) + ).json() + )['data']['Media']['coverImage']['extraLarge']; diff --git a/src/lib/AniList/wrapped.ts b/src/lib/AniList/wrapped.ts index d3c67fa2..35ce7554 100644 --- a/src/lib/AniList/wrapped.ts +++ b/src/lib/AniList/wrapped.ts @@ -1,21 +1,33 @@ import type { AniListAuthorisation, UserIdentity } from './identity'; +export interface WrappedMediaFormat { + startYears: { + startYear: number; + minutesWatched: number; + count: number; + }; + genres: { + meanScore: number; + minutesWatched: number; + chaptersRead: number; + genre: string; + mediaIds: number[]; + }[]; + tags: { + meanScore: number; + minutesWatched: number; + chaptersRead: number; + tag: { + name: string; + }; + mediaIds: number[]; + }[]; +} + export interface Wrapped { statistics: { - anime: { - startYears: { - startYear: number; - minutesWatched: number; - count: number; - }[]; - }; - manga: { - startYears: { - startYear: number; - chaptersRead: number; - count: number; - }[]; - }; + anime: WrappedMediaFormat; + manga: WrappedMediaFormat; }; activities: { statusCount: number; @@ -104,8 +116,16 @@ export const wrapped = async ( User(name: "${identity.name}") { avatar { large } statistics { - anime { startYears { startYear minutesWatched count } } - manga { startYears { startYear chaptersRead count } } + anime { + startYears { startYear minutesWatched count } + genres(sort: [ MEAN_SCORE_DESC ]) { meanScore minutesWatched chaptersRead genre mediaIds } + tags(sort: [ MEAN_SCORE_DESC ]) { meanScore minutesWatched chaptersRead tag { name } mediaIds } + } + manga { + startYears { startYear chaptersRead count } + genres(sort: [ MEAN_SCORE_DESC ]) { meanScore minutesWatched chaptersRead genre mediaIds } + tags(sort: [ MEAN_SCORE_DESC ]) { meanScore minutesWatched chaptersRead tag { name } mediaIds } + } } } }` diff --git a/src/lib/Tools/Wrapped.svelte b/src/lib/Tools/Wrapped.svelte index 57ec09b7..0d8f0834 100644 --- a/src/lib/Tools/Wrapped.svelte +++ b/src/lib/Tools/Wrapped.svelte @@ -10,7 +10,7 @@ fullActivityHistory, activityHistory as getActivityHistory } from '$lib/AniList/activity.js'; - import { Type, mediaListCollection, type Media } from '$lib/AniList/media.js'; + import { Type, mediaListCollection, type Media, mediaCover } from '$lib/AniList/media.js'; import anime from '../../stores/anime.js'; import lastPruneTimes from '../../stores/lastPruneTimes.js'; import manga from '../../stores/manga.js'; @@ -50,6 +50,7 @@ let excludedKeywordsInput = ''; let excludedKeywords: string[] = []; let useFullActivityHistory = false; + let topGenresTags = true; $: { if (browser && mounted) { @@ -344,6 +345,17 @@ const pruneFullYear = async () => { await database.activities.bulkDelete((await database.activities.toArray()).map((m) => m.page)); }; + + const mergeArraySort = (a: any, b: any) => [...a, ...b].sort((a, b) => b.meanScore - a.meanScore); + + const randomCoverFromTop10 = ( + statistics: { anime: any; manga: any }, + mode: 'tags' | 'genres' + ) => { + const top = mergeArraySort(statistics.anime[mode], statistics.manga[mode]); + + return mediaCover(top[Math.floor(Math.random() * top.length)].mediaIds[0]); + }; {#if currentUserIdentity.id === -2} @@ -470,6 +482,64 @@ + {#if topGenresTags} +
+
+
+ {#await randomCoverFromTop10(wrapped.statistics, 'genres') then cover} + Highest Rated Genre Cover + {/await} +
+ Highest Rated Genres +
    + {#each mergeArraySort(wrapped.statistics.anime.genres, wrapped.statistics.manga.genres).slice(0, highestRatedCount) as genre} +
  1. + + {genre.genre}: {genre.meanScore}% + +
  2. + {/each} +
+
+
+
+
+
+ {#await randomCoverFromTop10(wrapped.statistics, 'tags') then cover} + Highest Rated Tag Cover + {/await} +
+ Highest Rated Tags +
    + {#each mergeArraySort(wrapped.statistics.anime.tags, wrapped.statistics.manga.tags).slice(0, highestRatedCount) as tag} +
  1. + + {tag.tag.name}: {tag.meanScore}% + +
  2. + {/each} +
+
+
+
+
+ {/if} {#if !disableActivityHistory}
@@ -501,6 +571,8 @@ Enable background transparency
Enable light mode
+ + Enable top genres and tags
Disable activity history
{#if !disableActivityHistory} -- cgit v1.2.3