2025-01-10 12:16:32 +01:00

80 lines
2.1 KiB
TypeScript

import Elysia, { t } from "elysia";
import { Movie, SeedMovie } from "~/models/movie";
import { db } from "~/db";
import {
shows,
showTranslations,
entries,
entryTranslations,
} from "~/db/schema";
import { guessNextRefresh } from "./refresh";
import { processOptImage } from "./images";
type Show = typeof shows.$inferInsert;
type ShowTrans = typeof showTranslations.$inferInsert;
type Entry = typeof entries.$inferInsert;
export const seed = new Elysia()
.model({
movie: Movie,
"seed-movie": SeedMovie,
error: t.String(),
})
.post(
"/movies",
async ({ body }) => {
const { translations, videos, ...bMovie } = body;
const ret = await db.transaction(async (tx) => {
const movie: Show = {
kind: "movie",
startAir: bMovie.airDate,
nextRefresh: guessNextRefresh(bMovie.airDate ?? new Date()),
...bMovie,
};
const [ret] = await tx
.insert(shows)
.values(movie)
.returning({ pk: shows.pk, id: shows.id });
// even if never shown to the user, a movie still has an entry.
const movieEntry: Entry = { type: "movie", ...bMovie };
const [entry] = await tx
.insert(entries)
.values(movieEntry)
.returning({ pk: entries.pk });
const trans: ShowTrans[] = await Promise.all(
Object.entries(translations).map(async ([lang, tr]) => ({
pk: ret.pk,
// TODO: normalize lang or error if invalid
language: lang,
...tr,
poster: await processOptImage(tr.poster),
thumbnail: await processOptImage(tr.thumbnail),
logo: await processOptImage(tr.logo),
banner: await processOptImage(tr.banner),
})),
);
await tx.insert(showTranslations).values(trans);
const entryTrans = trans.map((x) => ({ ...x, pk: entry.pk }));
await tx.insert(entryTranslations).values(entryTrans);
return { ...ret, entry: entry.pk };
});
// TODO: insert entry-video links
// await db.transaction(async tx => {
// await tx.insert(videos).values(videos);
// });
return ret.id;
},
{
body: "seed-movie",
response: { 200: "movie", 400: "error" },
tags: ["movies"],
},
);