diff options
| author | Fuwn <[email protected]> | 2023-11-29 16:22:31 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-11-29 16:22:31 -0800 |
| commit | 09f12daf77e1c6e33e12d3da2859884064664789 (patch) | |
| tree | c62e83ef34fbf7926c073d2b6751b13a01f36653 /src/lib/AniList | |
| parent | feat(list): furigana (diff) | |
| download | due.moe-09f12daf77e1c6e33e12d3da2859884064664789.tar.xz due.moe-09f12daf77e1c6e33e12d3da2859884064664789.zip | |
feat(tools): sequel spy
Diffstat (limited to 'src/lib/AniList')
| -rw-r--r-- | src/lib/AniList/prequels.ts | 150 |
1 files changed, 150 insertions, 0 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; +}; |