diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/AniList/prequels.ts | 150 | ||||
| -rw-r--r-- | src/lib/List/Anime/CleanAnimeList.svelte | 2 | ||||
| -rw-r--r-- | src/lib/List/Manga/CleanMangaList.svelte | 2 | ||||
| -rw-r--r-- | src/lib/List/MediaTitleDisplay.svelte (renamed from src/lib/List/MediaTitle.svelte) | 0 | ||||
| -rw-r--r-- | src/lib/Tools/SequelSpy.svelte | 56 |
5 files changed, 208 insertions, 2 deletions
diff --git a/src/lib/AniList/prequels.ts b/src/lib/AniList/prequels.ts new file mode 100644 index 00000000..82e470f4 --- /dev/null +++ b/src/lib/AniList/prequels.ts @@ -0,0 +1,150 @@ +import type { AniListAuthorisation } from './identity'; + +export interface MediaPrequel { + id: number; + title: { english: string; romaji: string }; + episodes: number; + seen: number; +} + +interface PrequelRelations { + edges: { + relationType: string; + node: { + title: { + english: string; + romaji: string; + }; + episodes: number; + mediaListEntry: { + status: string; + progress: number; + }; + }; + }[]; +} + +interface PrequelsPage { + data: { + Page: { + media: { + title: { + english: string; + romaji: string; + }; + id: number; + relations: PrequelRelations; + }[]; + pageInfo: { + hasNextPage: boolean; + }; + }; + }; +} + +const prequelsPage = async ( + page: number, + anilistAuthorisation: AniListAuthorisation, + year: number, + season: 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL' +): Promise<PrequelsPage> => + await ( + await fetch('https://graphql.anilist.co', { + method: 'POST', + headers: { + Authorization: `${anilistAuthorisation.tokenType} ${anilistAuthorisation.accessToken}`, + 'Content-Type': 'application/json', + Accept: 'application/json' + }, + body: JSON.stringify({ + query: `{ + Page(page: ${page}) { + pageInfo { + hasNextPage + } + media(season: ${season}, seasonYear: ${year}) { + title { + english + romaji + } + id + relations { + edges { + relationType + node { + title { + english + romaji + } + episodes + mediaListEntry { + status + progress + } + } + } + } + } + } +}` + }) + }) + ).json(); + +export const prequels = async ( + anilistAuthorisation: AniListAuthorisation, + year: number, + season: 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL' +): Promise<MediaPrequel[]> => { + const candidates = []; + let page = 1; + let currentPage = await prequelsPage(page, anilistAuthorisation, year, season); + + for (const candidate of currentPage.data.Page.media) { + candidates.push(candidate); + } + + while (currentPage['data']['Page']['pageInfo']['hasNextPage']) { + for (const candidate of currentPage.data.Page.media) { + candidates.push(candidate); + } + + page += 1; + currentPage = await prequelsPage(page, anilistAuthorisation, year, season); + } + + const media: MediaPrequel[] = []; + + for (const candidate of candidates) { + let episodes = 0; + let seen = 0; + + for (const relation of candidate.relations.edges) { + if (relation.relationType === 'PREQUEL') { + if ( + relation.node.mediaListEntry === null || + relation.node.mediaListEntry.status !== 'COMPLETED' + ) { + episodes += relation.node.episodes; + + if (relation.node.mediaListEntry !== null) { + seen += relation.node.mediaListEntry.progress || 0; + } + } + } + } + + if (media.some((m) => m.id === candidate.id)) continue; + + if (episodes !== 0) { + media.push({ + id: candidate.id, + title: candidate.title, + episodes, + seen + }); + } + } + + return media; +}; diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte index 2da182d5..e7388066 100644 --- a/src/lib/List/Anime/CleanAnimeList.svelte +++ b/src/lib/List/Anime/CleanAnimeList.svelte @@ -6,7 +6,7 @@ import { airingTime, cleanCache, totalEpisodes, updateMedia } from '$lib/Media/anime'; import type { AniListAuthorisation, UserIdentity } from '$lib/AniList/identity'; import ListTitle from '../ListTitle.svelte'; - import MediaTitle from '../MediaTitle.svelte'; + import MediaTitle from '../MediaTitleDisplay.svelte'; export let media: Media[]; export let title: string; diff --git a/src/lib/List/Manga/CleanMangaList.svelte b/src/lib/List/Manga/CleanMangaList.svelte index 009fb868..c08c9ef6 100644 --- a/src/lib/List/Manga/CleanMangaList.svelte +++ b/src/lib/List/Manga/CleanMangaList.svelte @@ -3,7 +3,7 @@ import { volumeCount } from '$lib/Media/manga'; import settings from '../../../stores/settings'; import ListTitle from '../ListTitle.svelte'; - import MediaTitle from '../MediaTitle.svelte'; + import MediaTitle from '../MediaTitleDisplay.svelte'; export let media: Media[]; export let cleanCache: () => void; diff --git a/src/lib/List/MediaTitle.svelte b/src/lib/List/MediaTitleDisplay.svelte index b98f4125..b98f4125 100644 --- a/src/lib/List/MediaTitle.svelte +++ b/src/lib/List/MediaTitleDisplay.svelte diff --git a/src/lib/Tools/SequelSpy.svelte b/src/lib/Tools/SequelSpy.svelte new file mode 100644 index 00000000..4e92f199 --- /dev/null +++ b/src/lib/Tools/SequelSpy.svelte @@ -0,0 +1,56 @@ +<script lang="ts"> + import type { AniListAuthorisation } from '$lib/AniList/identity'; + import { prequels, type MediaPrequel } from '$lib/AniList/prequels'; + import MediaTitle from '$lib/List/MediaTitleDisplay.svelte'; + + export let user: AniListAuthorisation; + + let currentPrequels: Promise<MediaPrequel[]> = []; + let year = new Date().getFullYear(); + let season = (() => { + if (new Date().getMonth() >= 0 && new Date().getMonth() <= 2) { + return 'WINTER' as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL'; + } else if (new Date().getMonth() >= 3 && new Date().getMonth() <= 5) { + return 'SPRING' as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL'; + } else if (new Date().getMonth() >= 6 && new Date().getMonth() <= 8) { + return 'SUMMER' as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL'; + } else if (new Date().getMonth() >= 9 && new Date().getMonth() <= 11) { + return 'FALL' as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL'; + } else { + return 'WINTER' as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL'; + } + })(); + + $: currentPrequels = prequels(user, year, season); +</script> + +<p> + <select bind:value={season}> + <option value="WINTER">Winter</option> + <option value="SPRING">Spring</option> + <option value="SUMMER">Summer</option> + <option value="FALL">Fall</option> + </select> + <input type="number" bind:value={year} /> +</p> + +{#await currentPrequels} + <p>Loading ...</p> +{:then currentPrequels} + <ul> + {#each currentPrequels as prequel} + <li> + <a href={`https://anilist.co/anime/${prequel.id}`}> + <MediaTitle media={prequel} /> + </a> + <span style="opacity: 50%;">|</span> + {prequel.seen}<span style="opacity: 50%;">/{prequel.episodes}</span> + </li> + {/each} + </ul> +{/await} + +<p style="opacity: 50%;"> + The count ratio is the number of episodes you've seen of any direct prequels, and the total number + of episodes of all direct prequels. +</p> |