import type { AniListAuthorisation } from './identity'; import type { MediaTitle } from './media'; export interface MediaPrequel { id: number; title: MediaTitle; episodes: number; seen: number; } interface PrequelRelations { edges: { relationType: string; node: { title: MediaTitle; episodes: number; mediaListEntry: { status: string; progress: number; }; }; }[]; } interface PrequelsPage { data: { Page: { media: { title: MediaTitle; 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; };