Files
aniplay-api/src/controllers/internal/upcoming-titles/anilist.ts

76 lines
2.1 KiB
TypeScript

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<number>();
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;
}