119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import { zValidator } from "@hono/zod-validator";
|
|
import { Hono } from "hono";
|
|
import { env } from "hono/adapter";
|
|
import mapKeys from "lodash.mapkeys";
|
|
import { z } from "zod";
|
|
|
|
import { fetchEpisodeUrlFromAllProviders } from "~/controllers/episodes/getEpisodeUrl";
|
|
import { Case, changeStringCase } from "~/libs/changeStringCase";
|
|
import type { AdminSdkCredentials } from "~/libs/gcloud/getGoogleAuthToken";
|
|
import { sendFcmMessage } from "~/libs/gcloud/sendFcmMessage";
|
|
import { maybeScheduleNextAiringEpisode } from "~/libs/maybeScheduleNextAiringEpisode";
|
|
import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader";
|
|
import { readEnvVariable } from "~/libs/readEnvVariable";
|
|
import { getTokensSubscribedToTitle } from "~/models/token";
|
|
import { isWatchingTitle } from "~/models/watchStatus";
|
|
import type { Env } from "~/types/env";
|
|
import {
|
|
AniListIdSchema,
|
|
EpisodeNumberSchema,
|
|
ErrorResponse,
|
|
SuccessResponse,
|
|
} from "~/types/schema";
|
|
|
|
const app = new Hono();
|
|
|
|
app.post(
|
|
"/",
|
|
zValidator(
|
|
"json",
|
|
z.object({
|
|
aniListId: AniListIdSchema,
|
|
episodeNumber: EpisodeNumberSchema,
|
|
}),
|
|
),
|
|
async (c) => {
|
|
const { aniListId, episodeNumber } = await c.req.json<{
|
|
aniListId: number;
|
|
episodeNumber: number;
|
|
}>();
|
|
console.log(
|
|
`Internal new episode route, aniListId: ${aniListId}, episodeNumber: ${episodeNumber}`,
|
|
);
|
|
|
|
if (!(await verifyQstashHeader(env<Env, typeof c>(c, "workerd"), c.req))) {
|
|
return c.json(ErrorResponse, { status: 401 });
|
|
}
|
|
|
|
if (!(await isWatchingTitle(env<Env, typeof c>(c, "workerd"), aniListId))) {
|
|
console.log(`Title ${aniListId} is no longer being watched`);
|
|
return c.json(
|
|
{ success: true, result: { isNoLongerWatching: true } },
|
|
200,
|
|
);
|
|
}
|
|
|
|
const { episodes, fetchUrlResult } = await fetchEpisodeUrlFromAllProviders(
|
|
aniListId,
|
|
episodeNumber,
|
|
env<Env, typeof c>(c, "workerd"),
|
|
);
|
|
|
|
if (!episodes) {
|
|
console.error(`Failed to fetch episodes for title ${aniListId}`);
|
|
return c.json(
|
|
{ success: false, message: "Failed to fetch episodes" },
|
|
500,
|
|
);
|
|
}
|
|
|
|
if (!fetchUrlResult) {
|
|
console.error(`Failed to fetch episode URL for episode`);
|
|
return c.json(
|
|
{ success: false, message: "Failed to fetch episode URL" },
|
|
500,
|
|
);
|
|
}
|
|
|
|
const tokens = await getTokensSubscribedToTitle(
|
|
env<Env, typeof c>(c, "workerd"),
|
|
aniListId,
|
|
);
|
|
|
|
await Promise.allSettled(
|
|
tokens.map(async (token) => {
|
|
return sendFcmMessage(
|
|
mapKeys(
|
|
readEnvVariable<AdminSdkCredentials>(
|
|
env<Env, typeof c>(c, "workerd"),
|
|
"ADMIN_SDK_JSON",
|
|
),
|
|
(_, key) => changeStringCase(key, Case.snake_case, Case.camelCase),
|
|
) as unknown as AdminSdkCredentials,
|
|
{
|
|
token,
|
|
data: {
|
|
type: "new_episode",
|
|
episodes: JSON.stringify(episodes),
|
|
episodeStreamInfo: JSON.stringify(fetchUrlResult),
|
|
aniListId: aniListId.toString(),
|
|
episodeNumber: episodeNumber.toString(),
|
|
},
|
|
android: { priority: "high" },
|
|
},
|
|
);
|
|
}),
|
|
);
|
|
|
|
await maybeScheduleNextAiringEpisode(
|
|
env<Env, typeof c>(c, "workerd"),
|
|
c.req,
|
|
aniListId,
|
|
);
|
|
|
|
return c.json(SuccessResponse, 200);
|
|
},
|
|
);
|
|
|
|
export default app;
|