import { graphql } from "gql.tada"; import { GraphQLClient } from "graphql-request"; import { getCurrentAndNextSeason } from "~/libs/getCurrentAndNextSeason"; import { sleep } from "~/libs/sleep"; import { HomeTitleFragment } from "~/types/title/homeTitle"; import { mapTitle } from "../mapTitle"; const BrowsePopularQuery = graphql( ` query BrowsePopular( $season: MediaSeason! $seasonYear: Int! $nextSeason: MediaSeason! $nextYear: Int! $limit: Int! ) { trending: Page(page: 1, perPage: $limit) { media(sort: TRENDING_DESC, type: ANIME, isAdult: false) { ...HomeTitle } } season: Page(page: 1, perPage: $limit) { media( season: $season seasonYear: $seasonYear sort: POPULARITY_DESC type: ANIME isAdult: false ) { ...HomeTitle } } nextSeason: Page(page: 1, perPage: 1) { media( season: $nextSeason seasonYear: $nextYear sort: START_DATE_DESC type: ANIME isAdult: false ) { nextAiringEpisode { airingAt timeUntilAiring } } } } `, [HomeTitleFragment], ); const NextSeasonPopularQuery = graphql(` query NextSeasonPopular( $nextSeason: MediaSeason $nextYear: Int $limit: Int! ) { Page(page: 1, perPage: $limit) { media( season: $nextSeason seasonYear: $nextYear sort: POPULARITY_DESC type: ANIME isAdult: false ) { ...media } } } fragment media on Media { id title { english userPreferred } coverImage { extraLarge large medium } } `); export async function fetchPopularTitlesFromAnilist( limit: number, ): Promise { const client = new GraphQLClient("https://graphql.anilist.co/"); const { current: { season: currentSeason, year: currentYear }, next: { season: nextSeason, year: nextYear }, } = getCurrentAndNextSeason(); try { const data = await client.request(BrowsePopularQuery, { limit, season: currentSeason, seasonYear: currentYear, nextSeason, nextYear, }); if (!data) return undefined; const trendingTitles = data.trending?.media?.map((title) => mapTitle(title), ); const popularSeasonTitles = data.season?.media?.map((title) => mapTitle(title), ); if (!data.nextSeason?.media?.[0]?.nextAiringEpisode) { return { trending: trendingTitles, popular: popularSeasonTitles, }; } return await client .request(NextSeasonPopularQuery, { limit, nextSeason, nextYear, }) .then((data) => ({ trending: trendingTitles, popular: popularSeasonTitles, upcoming: data?.Page?.media?.map((title) => mapTitle(title)), })); } catch (error) { const response = error.response; if (response.status === 429) { console.log("429, retrying in", response.headers.get("Retry-After")); return sleep(Number(response.headers.get("Retry-After")!) * 1000).then( () => fetchPopularTitlesFromAnilist(limit), ); } throw error; } } type SearchResultsResponse = { results: | ({ id: number; title: { userPreferred: string | null; english: string | null } | null; coverImage: { extraLarge: string | null; large: string | null; medium: string | null; } | null; } | null)[] | null; hasNextPage: boolean | null | undefined; };