import { graphql } from "gql.tada"; import { GraphQLClient } from "graphql-request"; import { sleep } from "~/libs/sleep"; const SearchQuery = graphql(` query Search($query: String!, $page: Int!, $limit: Int!) { Page(page: $page, perPage: $limit) { media(search: $query, type: ANIME, sort: [POPULARITY_DESC, SCORE_DESC]) { id title { userPreferred english } coverImage { extraLarge large medium } } pageInfo { hasNextPage } } } `); export async function fetchSearchResultsFromAnilist( query: string, page: number, limit: number, ): Promise { const client = new GraphQLClient("https://graphql.anilist.co/"); return client .request(SearchQuery, { page, query, limit }) .then((data) => data?.Page) .then((page) => { if (!page || page.media?.length === 0) { return undefined; } const { media: results, pageInfo } = page; return { results: results?.map((result) => { if (!result) return null; return { id: result.id, title: result.title?.userPreferred ?? result.title?.english, coverImage: result.coverImage, }; }), hasNextPage: pageInfo?.hasNextPage, }; }) .catch((err) => { const response = err.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( () => fetchSearchResultsFromAnilist(query, page, limit), ); } throw err; }); } 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; };