mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Create movie seed route handler
This commit is contained in:
parent
1309749e46
commit
30d5d65755
19
api/src/controllers/seed/images.ts
Normal file
19
api/src/controllers/seed/images.ts
Normal 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);
|
||||||
|
};
|
79
api/src/controllers/seed/index.ts
Normal file
79
api/src/controllers/seed/index.ts
Normal 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"],
|
||||||
|
},
|
||||||
|
);
|
12
api/src/controllers/seed/refresh.ts
Normal file
12
api/src/controllers/seed/refresh.ts
Normal 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);
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
import { t } from "elysia";
|
import { t } from "elysia";
|
||||||
|
|
||||||
export const Image = t.Object({
|
export const Image = t.Object({
|
||||||
id: t.String({ format: "uuid" }),
|
id: t.String(),
|
||||||
source: t.String({ format: "uri" }),
|
source: t.String({ format: "uri" }),
|
||||||
blurhash: t.String(),
|
blurhash: t.String(),
|
||||||
});
|
});
|
||||||
|
@ -3,11 +3,19 @@
|
|||||||
"target": "ES2021",
|
"target": "ES2021",
|
||||||
"module": "ES2022",
|
"module": "ES2022",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"types": ["bun-types"],
|
"types": [
|
||||||
|
"bun-types"
|
||||||
|
],
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"noErrorTruncation": true
|
"noErrorTruncation": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"~/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user