import { graphql } from "gql.tada"; import { GraphQLClient } from "graphql-request"; import { AnilistTitleNotFoundError } from "~/libs/errors/TitleNotFound"; import type { WatchStatus } from "~/types/title/watchStatus"; const UpdateWatchStatusMutation = graphql(` mutation UpdateWatchStatus($titleId: Int!, $watchStatus: MediaListStatus!) { SaveMediaListEntry(mediaId: $titleId, status: $watchStatus) { id } } `); const GetMediaListEntryQuery = graphql(` query GetMediaListEntry($titleId: Int!) { Media(id: $titleId) { mediaListEntry { id } } } `); const DeleteMediaListEntryMutation = graphql(` mutation DeleteMediaListEntry($entryId: Int!) { DeleteMediaListEntry(id: $entryId) { deleted } } `); /** Updates the watch status for a title on Anilist. If the token is null, the watch status will not be updated. * * @returns true if the watch status was updated or if the token was null, false if it was not */ export async function maybeUpdateWatchStatusOnAnilist( titleId: number, watchStatus: WatchStatus | null, aniListToken: string | undefined, ) { if (!aniListToken) { return true; } const client = new GraphQLClient("https://graphql.anilist.co/"); const headers = new Headers({ Authorization: `Bearer ${aniListToken}` }); if (!watchStatus) { return client .request(GetMediaListEntryQuery, { titleId }, headers) .then((data) => data?.Media?.mediaListEntry?.id) .then((mediaListEntryId) => { if (!mediaListEntryId) { throw new AnilistTitleNotFoundError(); } return client .request( DeleteMediaListEntryMutation, { entryId: mediaListEntryId }, headers, ) .then((data) => !!data?.DeleteMediaListEntry?.deleted); }); } return client .request(UpdateWatchStatusMutation, { titleId, watchStatus }, headers) .then((data) => !!data?.SaveMediaListEntry?.id); }