import { env } from "cloudflare:workers"; import type { HonoRequest } from "hono"; import { DateTime } from "luxon"; import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode"; import { getValue, setValue } from "~/models/kv"; import { filterUnreleasedTitles } from "~/models/unreleasedTitles"; import type { Title } from "~/types/title"; type AiringSchedule = { media: Title; episode: number; timeUntilAiring: number; airingAt: number; id: number; }; export async function getUpcomingTitlesFromAnilist(req: HonoRequest) { const durableObjectId = env.ANILIST_DO.idFromName("GLOBAL"); const stub = env.ANILIST_DO.get(durableObjectId); const lastCheckedScheduleAt = await getValue("schedule_last_checked_at").then( (value) => (value ? Number(value) : DateTime.now().toUnixInteger()), ); const twoDaysFromNow = DateTime.now().plus({ days: 2 }).toUnixInteger(); let currentPage = 1; let plannedToWatchTitles = new Set(); let scheduleList: AiringSchedule[] = []; let shouldContinue = true; do { const Page = await stub.getUpcomingTitles( currentPage++, lastCheckedScheduleAt, twoDaysFromNow, ); if (!Page) break; const { airingSchedules, pageInfo } = Page; plannedToWatchTitles = plannedToWatchTitles.union( await filterUnreleasedTitles( airingSchedules!.map((schedule: any) => schedule!.media?.id!), ), ); scheduleList = scheduleList.concat( airingSchedules!.filter( (schedule: any): schedule is AiringSchedule => !!schedule && !plannedToWatchTitles.has(schedule.media?.id) && schedule.media?.countryOfOrigin === "JP" && schedule.episode == 1, ), ); shouldContinue = pageInfo?.hasNextPage ?? false; } while (shouldContinue); await Promise.all( Array.from(plannedToWatchTitles).map((titleId) => maybeScheduleNextAiringEpisode(titleId), ), ); if (scheduleList.length === 0) { return []; } await setValue( "schedule_last_checked_at", scheduleList[scheduleList.length - 1].airingAt.toString(), ); return scheduleList; }