Create movie seed route handler

This commit is contained in:
Zoe Roux 2024-11-24 23:28:43 +01:00
parent 1309749e46
commit 30d5d65755
No known key found for this signature in database
5 changed files with 121 additions and 3 deletions

View File

@ -0,0 +1,19 @@
import type { Image } from "~/models/utils";
export const processImage = async (url: string): Promise<Image> => {
const hasher = new Bun.CryptoHasher("sha256");
hasher.update(url);
// TODO: download source, save it in multiples qualities & process blurhash
return {
id: hasher.digest().toString(),
source: url,
blurhash: "",
};
};
export const processOptImage = (url: string | null): Promise<Image | null> => {
if (!url) return Promise.resolve(null);
return processImage(url);
};

View File

@ -0,0 +1,79 @@
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"],
},
);

View File

@ -0,0 +1,12 @@
// oh i hate js dates so much.
export const guessNextRefresh = (airDate: Date | string) => {
if (typeof airDate === "string") airDate = new Date(airDate);
const diff = new Date().getTime() - airDate.getTime();
const days = diff / (24 * 60 * 60 * 1000);
const ret = new Date();
if (days <= 4) ret.setDate(ret.getDate() + 4);
else if (days <= 21) ret.setDate(ret.getDate() + 14);
else ret.setMonth(ret.getMonth() + 2);
return ret.toISOString().substring(0, 10);
};

View File

@ -1,7 +1,7 @@
import { t } from "elysia";
export const Image = t.Object({
id: t.String({ format: "uuid" }),
id: t.String(),
source: t.String({ format: "uri" }),
blurhash: t.String(),
});

View File

@ -3,11 +3,19 @@
"target": "ES2021",
"module": "ES2022",
"moduleResolution": "node",
"types": ["bun-types"],
"types": [
"bun-types"
],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"noErrorTruncation": true
"noErrorTruncation": true,
"baseUrl": ".",
"paths": {
"~/*": [
"./src/*"
]
}
}
}