From 15e8abbcc05a7005da1e5bdecc0a81ec1bed83a2 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Tue, 16 Dec 2025 03:37:26 -0800 Subject: feat(Wrapped): Don't automatically fetch remote data --- src/lib/Tools/Wrapped/Tool.svelte | 645 +++++++++++++++++++++++++------------- 1 file changed, 426 insertions(+), 219 deletions(-) (limited to 'src') diff --git a/src/lib/Tools/Wrapped/Tool.svelte b/src/lib/Tools/Wrapped/Tool.svelte index bcc33f68..f060f444 100644 --- a/src/lib/Tools/Wrapped/Tool.svelte +++ b/src/lib/Tools/Wrapped/Tool.svelte @@ -2,10 +2,17 @@ import userIdentity from '$stores/identity'; import type { AniListAuthorisation } from '$lib/Data/AniList/identity'; import { onMount } from 'svelte'; - import { tops, wrapped, type TopMedia, SortOptions } from '$lib/Data/AniList/wrapped'; + import { + tops, + wrapped, + type TopMedia, + SortOptions, + type Wrapped + } from '$lib/Data/AniList/wrapped'; import { fullActivityHistory, - activityHistory as getActivityHistory + activityHistory as getActivityHistory, + type ActivityHistoryEntry } from '$lib/Data/AniList/activity'; import { Type, mediaListCollection, type Media } from '$lib/Data/AniList/media'; import anime from '$stores/anime'; @@ -74,6 +81,15 @@ let startDateFilter: Date | null = null; let endDateFilter: Date | null = null; let dateTicked = false; + let shouldFetchData = false; + let needsRefetch = false; + let dataFetched = false; + let fetchKey = 0; + let lastSelectedYear = selectedYear; + let lastUseFullActivityHistory = useFullActivityHistory; + let lastDisableLoopingActivityCounter = disableLoopingActivityCounter; + let lastStartDateFilter: Date | null = startDateFilter; + let lastEndDateFilter: Date | null = endDateFilter; $: { if (browser && mounted) { @@ -108,6 +124,26 @@ history.replaceState(null, '', `?${$page.url.searchParams.toString()}`); } } + + $: { + if (dataFetched) { + const yearChanged = selectedYear !== lastSelectedYear; + const fullActivityChanged = useFullActivityHistory !== lastUseFullActivityHistory; + const loopingChanged = disableLoopingActivityCounter !== lastDisableLoopingActivityCounter; + const startDateChanged = startDateFilter !== lastStartDateFilter; + const endDateChanged = endDateFilter !== lastEndDateFilter; + + if ( + yearChanged || + fullActivityChanged || + loopingChanged || + startDateChanged || + endDateChanged + ) + needsRefetch = true; + } + } + $: { includeMusic = includeMusic; includeSpecials = includeSpecials; @@ -285,6 +321,101 @@ await update().then(() => (mounted = true)); }); + const triggerFetch = () => { + shouldFetchData = true; + needsRefetch = false; + dataFetched = true; + fetchKey += 1; + lastSelectedYear = selectedYear; + lastUseFullActivityHistory = useFullActivityHistory; + lastDisableLoopingActivityCounter = disableLoopingActivityCounter; + lastStartDateFilter = startDateFilter; + lastEndDateFilter = endDateFilter; + }; + + const createDummyMedia = (type: 'ANIME' | 'MANGA'): Media => ({ + id: 0, + idMal: 0, + status: 'FINISHED', + type, + episodes: type === 'ANIME' ? 0 : 0, + chapters: type === 'MANGA' ? 0 : 0, + volumes: 0, + duration: 0, + format: type === 'ANIME' ? 'TV' : 'MANGA', + title: { + romaji: '...', + english: '...', + native: '...' + }, + synonyms: [], + mediaListEntry: { + progress: 0, + progressVolumes: 0, + status: 'COMPLETED', + score: 0, + repeat: 0, + startedAt: { + year: 0, + month: 0, + day: 0 + }, + completedAt: { + year: 0, + month: 0, + day: 0 + }, + createdAt: 0, + updatedAt: 0, + customLists: new Map() + }, + startDate: { + year: 0, + month: 0 + }, + endDate: { + year: 0, + month: 0 + }, + coverImage: { + extraLarge: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg', + medium: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg' + }, + tags: [], + genres: [], + season: 'WINTER', + isAdult: false, + relations: { + edges: [] + } + }); + + const dummyWrapped: Wrapped = { + statistics: { + anime: { + startYears: [], + genres: [], + tags: [] + }, + manga: { + startYears: [], + genres: [], + tags: [] + } + }, + activities: { + statusCount: 0, + messageCount: 0 + }, + avatar: { + large: 'https://s4.anilist.co/file/anilistcdn/user/avatar/large/3.jpg' + } + }; + + const dummyActivities: ActivityHistoryEntry[] = []; + const dummyAnimeList: Media[] = [createDummyMedia('ANIME')]; + const dummyMangaList: Media[] = [createDummyMedia('MANGA')]; + const update = async () => { if ($userIdentity.id === -1) return; @@ -614,235 +745,311 @@ {#if $userIdentity.id === -2 || user === undefined} {:else if $userIdentity.id !== -1} - {#await selectedYear !== currentYear || useFullActivityHistory || new Date().getMonth() <= 6 ? fullActivityHistory(user, $userIdentity, selectedYear, disableLoopingActivityCounter) : getActivityHistory($userIdentity)} - - - - {:then activities} - {#await wrapped(user, $userIdentity, selectedYear, false, disableLoopingActivityCounter)} - - - - {:then wrapped} -
-
-
- {#if !disableActivityHistory && activityHistoryPosition === 'TOP' && activities.length > 0 && selectedYear === currentYear} - - {/if} -
- - - +
+ {#if shouldFetchData} + {#key fetchKey} + {#await selectedYear !== currentYear || useFullActivityHistory || new Date().getMonth() <= 6 ? fullActivityHistory(user, $userIdentity, selectedYear, disableLoopingActivityCounter) : getActivityHistory($userIdentity)} + + + + {:then activities} + {#await wrapped(user, $userIdentity, selectedYear, false, disableLoopingActivityCounter)} + + + + {:then wrapped} +
+
+ {#if !disableActivityHistory && activityHistoryPosition === 'TOP' && activities.length > 0 && selectedYear === currentYear} + + {/if} +
+ + + +
+ {#if !disableActivityHistory && activityHistoryPosition === 'BELOW_TOP' && activities.length > 0 && selectedYear === currentYear} + + {/if} + + {#if topMedia && topGenresTags && ((topMedia.topGenreMedia && topMedia.genres.length > 0) || (topMedia.topTagMedia && topMedia.tags.length > 0))} + + {/if} + {#if !disableActivityHistory && activityHistoryPosition === 'ORIGINAL' && activities.length > 0 && selectedYear === currentYear} + + {/if} + {#if watermark} + + {/if} +
- {#if !disableActivityHistory && activityHistoryPosition === 'BELOW_TOP' && activities.length > 0 && selectedYear === currentYear} - + {:catch} + + {/await} + {:catch} + + {#if useFullActivityHistory} +

+ With many activities, it may take multiple attempts to obtain all of your activity + history from AniList. If this occurs, wait one minute and try again to continue populating + your local activity history database. +

{/if} - + {/await} + {/key} + {:else} +
+
+
+ - {#if topMedia && topGenresTags && ((topMedia.topGenreMedia && topMedia.genres.length > 0) || (topMedia.topTagMedia && topMedia.tags.length > 0))} - - {/if} - {#if !disableActivityHistory && activityHistoryPosition === 'ORIGINAL' && activities.length > 0 && selectedYear === currentYear} - - {/if} - {#if watermark} - - {/if} -
-
-
-
-
- - {#if generated} -

- -

- Click on the image to download, or right click and select "Save Image As...". -
- {/if} + +
- {#if generated} -

- {/if} - -

- - -
- Display - - Show watermark
- Enable background transparency
- - Enable light mode
- - Show top genres and tags
- - Hide activity history
- Show highest - rated media percentages
- Show highest - rated genre and tag percentages
- Show - ongoing media from previous years
- - Activity history position
- - Highest rated media count
- - Highest genre and tag count
- - - - Width adjustment
-
- -
- Calculation - - - Enable full-year activity -
- - Calculate for year
- { - dateTicked = true; - - update(); + + +
- -
- Advanced - - - Disable detailed activity information -
+ Click load data! +
+
- {:catch} - - {/await} - {:catch} - - {#if useFullActivityHistory} -

- With many activities, it may take multiple attempts to obtain all of your activity history - from AniList. If this occurs, wait one minute and try again to continue populating your local - activity history database. -

+ {/if} +
+
+
+ + {#if generated} +

+ +

+ Click on the image to download, or right click and select "Save Image As...". +
+ {/if} +
+ + {#if generated} +

{/if} - - {/await} + +

+ + {#if !shouldFetchData} + + {:else if needsRefetch} + + {/if} + +
+ Display + + Show watermark
+ Enable background transparency
+ + Enable light mode
+ + Show top genres and tags
+ + Hide activity history
+ Show highest rated + media percentages
+ Show highest rated + genre and tag percentages
+ Show ongoing + media from previous years
+ + Activity history position
+ + Highest rated media count
+ + Highest genre and tag count
+ + + + Width adjustment
+
+ +
+ Calculation + + + Enable full-year activity +
+ + Calculate for year
+ { + dateTicked = true; + + update(); + }} + /> + Start date filter
+ { + dateTicked = true; + + update(); + }} + /> + End date filter
+ + Anime and manga sort
+ + Genre and tag sort
+ Include music
+ Include rewatches & rereads
+ Include specials
+ Include OVAs
+ Include movies
+ Excluded unrated & + unwatched
+ { + e.key === 'Enter' && submitExcludedKeywords(); + }} + /> + Excluded keywords + +
+ Comma separated list (e.g., "My Hero, Kaguya") +
+ +
+ Advanced + + + Disable detailed activity information +
+
+
+
{:else} -- cgit v1.2.3