From 09f12daf77e1c6e33e12d3da2859884064664789 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Wed, 29 Nov 2023 16:22:31 -0800 Subject: feat(tools): sequel spy --- src/lib/AniList/prequels.ts | 150 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/lib/AniList/prequels.ts (limited to 'src/lib/AniList') 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 => + 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 => { + 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; +}; -- cgit v1.2.3