mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Add serie model, dummy controller & example
This commit is contained in:
parent
89952185a9
commit
c5a502ec32
11
api/src/controllers/series.ts
Normal file
11
api/src/controllers/series.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Elysia, t } from "elysia";
|
||||||
|
import { Serie } from "../models/serie";
|
||||||
|
|
||||||
|
export const series = new Elysia({ prefix: "/series" })
|
||||||
|
.model({
|
||||||
|
serie: Serie,
|
||||||
|
error: t.Object({}),
|
||||||
|
})
|
||||||
|
.get("/:id", () => "hello" as unknown as Serie, {
|
||||||
|
response: { 200: "serie" },
|
||||||
|
});
|
@ -3,6 +3,7 @@ import { swagger } from "@elysiajs/swagger";
|
|||||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||||
import { Elysia } from "elysia";
|
import { Elysia } from "elysia";
|
||||||
import { movies } from "./controllers/movies";
|
import { movies } from "./controllers/movies";
|
||||||
|
import { series } from "./controllers/series";
|
||||||
import { videos } from "./controllers/videos";
|
import { videos } from "./controllers/videos";
|
||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ const app = new Elysia()
|
|||||||
.use(swagger())
|
.use(swagger())
|
||||||
.get("/", () => "Hello Elysia")
|
.get("/", () => "Hello Elysia")
|
||||||
.use(movies)
|
.use(movies)
|
||||||
|
.use(series)
|
||||||
.use(videos)
|
.use(videos)
|
||||||
.listen(3000);
|
.listen(3000);
|
||||||
|
|
||||||
|
@ -1,22 +1,4 @@
|
|||||||
import type { TSchema } from "elysia";
|
import type { CompleteVideo } from "../video";
|
||||||
import type { CompleteVideo } from "./video";
|
|
||||||
|
|
||||||
export const registerExamples = <T extends TSchema>(
|
|
||||||
schema: T,
|
|
||||||
...examples: (T["static"] | undefined)[]
|
|
||||||
) => {
|
|
||||||
for (const example of examples) {
|
|
||||||
if (!example) continue;
|
|
||||||
for (const [key, val] of Object.entries(example)) {
|
|
||||||
const prop = schema.properties[
|
|
||||||
key as keyof typeof schema.properties
|
|
||||||
] as TSchema;
|
|
||||||
if (!prop) continue;
|
|
||||||
prop.examples ??= [];
|
|
||||||
prop.examples.push(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const bubble: CompleteVideo = {
|
export const bubble: CompleteVideo = {
|
||||||
id: "0934da28-4a49-404e-920b-a150404a3b6d",
|
id: "0934da28-4a49-404e-920b-a150404a3b6d",
|
27
api/src/models/examples/index.ts
Normal file
27
api/src/models/examples/index.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { TSchema } from "elysia";
|
||||||
|
|
||||||
|
export const registerExamples = <T extends TSchema>(
|
||||||
|
schema: T,
|
||||||
|
...examples: (T["static"] | undefined)[]
|
||||||
|
) => {
|
||||||
|
if ("anyOf" in schema) {
|
||||||
|
for (const union of schema.anyOf) {
|
||||||
|
registerExamples(union, examples);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const example of examples) {
|
||||||
|
if (!example) continue;
|
||||||
|
for (const [key, val] of Object.entries(example)) {
|
||||||
|
const prop = schema.properties[
|
||||||
|
key as keyof typeof schema.properties
|
||||||
|
] as TSchema;
|
||||||
|
if (!prop) continue;
|
||||||
|
prop.examples ??= [];
|
||||||
|
prop.examples.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { bubble } from "./bubble";
|
||||||
|
export { madeInAbyss } from "./made-in-abyss";
|
79
api/src/models/examples/made-in-abyss.ts
Normal file
79
api/src/models/examples/made-in-abyss.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import type { Serie } from "../serie";
|
||||||
|
|
||||||
|
export const madeInAbyss: Serie = {
|
||||||
|
id: "04bcf2ac-3c09-42f6-8357-b003798f9562",
|
||||||
|
slug: "made-in-abyss",
|
||||||
|
name: "Made in Abyss",
|
||||||
|
tagline: "How far would you go… for the ones you love?",
|
||||||
|
aliases: [
|
||||||
|
"Made in Abyss: The Golden City of the Scorching Sun",
|
||||||
|
"Meidoinabisu",
|
||||||
|
"Meidoinabisu: Retsujitsu no ôgonkyô",
|
||||||
|
],
|
||||||
|
description:
|
||||||
|
"Located in the center of a remote island, the Abyss is the last unexplored region, a huge and treacherous fathomless hole inhabited by strange creatures where only the bravest adventurers descend in search of ancient relics. In the upper levels of the Abyss, Riko, a girl who dreams of becoming an explorer, stumbles upon a mysterious little boy.",
|
||||||
|
tags: [
|
||||||
|
"android",
|
||||||
|
"amnesia",
|
||||||
|
"post-apocalyptic future",
|
||||||
|
"exploration",
|
||||||
|
"friendship",
|
||||||
|
"mecha",
|
||||||
|
"survival",
|
||||||
|
"curse",
|
||||||
|
"tragedy",
|
||||||
|
"orphan",
|
||||||
|
"based on manga",
|
||||||
|
"robot",
|
||||||
|
"dark fantasy",
|
||||||
|
"seinen",
|
||||||
|
"anime",
|
||||||
|
"drastic change of life",
|
||||||
|
"fantasy",
|
||||||
|
"adventure",
|
||||||
|
],
|
||||||
|
genres: [
|
||||||
|
"animation",
|
||||||
|
"drama",
|
||||||
|
"action",
|
||||||
|
"adventure",
|
||||||
|
"science-fiction",
|
||||||
|
"fantasy",
|
||||||
|
],
|
||||||
|
status: "finished",
|
||||||
|
rating: 84,
|
||||||
|
runtime: 24,
|
||||||
|
originalLanguage: "ja",
|
||||||
|
startAir: "2017-07-07",
|
||||||
|
endAir: "2022-09-28",
|
||||||
|
poster: {
|
||||||
|
id: "8205a20e-d91f-804c-3a84-4e4dc6202d66",
|
||||||
|
source:
|
||||||
|
"https://image.tmdb.org/t/p/original/4Bh9qzB1Kau4RDaVQXVFdoJ0HcE.jpg",
|
||||||
|
blurhash: "LZGlS3XTD%jE~Wf,SeV@%2o|WERj",
|
||||||
|
},
|
||||||
|
thumbnail: {
|
||||||
|
id: "819d816c-88f6-9f3a-b5e7-ce3daaffbac4",
|
||||||
|
source:
|
||||||
|
"https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg",
|
||||||
|
blurhash: "LmJtk{kq~q%2bbWCxaV@.8RixuNG",
|
||||||
|
},
|
||||||
|
logo: {
|
||||||
|
id: "23cb7b06-8406-2288-8e40-08bfc16180b5",
|
||||||
|
source:
|
||||||
|
"https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png",
|
||||||
|
blurhash: "LKGaa%M{0zbI#7$%bbofGGw^wcw{",
|
||||||
|
},
|
||||||
|
banner: null,
|
||||||
|
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
|
||||||
|
externalId: {
|
||||||
|
themoviedatabase: {
|
||||||
|
dataId: "72636",
|
||||||
|
link: "https://www.themoviedb.org/tv/72636",
|
||||||
|
},
|
||||||
|
imdb: { dataId: "tt7222086", link: "https://www.imdb.com/title/tt7222086" },
|
||||||
|
tvdb: { dataId: "326109", link: null },
|
||||||
|
},
|
||||||
|
createdAt: "2023-11-29T11:12:11.949503Z",
|
||||||
|
nextRefresh: "2025-01-07T11:42:50.948248Z",
|
||||||
|
};
|
@ -1,10 +1,13 @@
|
|||||||
import { t } from "elysia";
|
import { t } from "elysia";
|
||||||
import { Genre, ShowStatus } from "./show";
|
import { Genre } from "./show";
|
||||||
import { Image } from "./image";
|
import { Image } from "./image";
|
||||||
import { ExternalId } from "./external-id";
|
import { ExternalId } from "./external-id";
|
||||||
import { bubble, registerExamples } from "./examples";
|
import { bubble, registerExamples } from "./examples";
|
||||||
import { comment } from "../utils";
|
import { comment } from "../utils";
|
||||||
|
|
||||||
|
export const MovieStatus = t.UnionEnum(["unknown", "finished", "planned"]);
|
||||||
|
export type MovieStatus = typeof MovieStatus.static;
|
||||||
|
|
||||||
export const Movie = t.Object({
|
export const Movie = t.Object({
|
||||||
id: t.String({ format: "uuid" }),
|
id: t.String({ format: "uuid" }),
|
||||||
slug: t.String(),
|
slug: t.String(),
|
||||||
@ -16,8 +19,10 @@ export const Movie = t.Object({
|
|||||||
|
|
||||||
genres: t.Array(Genre),
|
genres: t.Array(Genre),
|
||||||
rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })),
|
rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })),
|
||||||
status: ShowStatus,
|
status: MovieStatus,
|
||||||
runtime: t.Nullable(t.Number({ minimum: 0 })),
|
runtime: t.Nullable(
|
||||||
|
t.Number({ minimum: 0, description: "Runtime of the movie in minutes." }),
|
||||||
|
),
|
||||||
|
|
||||||
airDate: t.Nullable(t.String({ format: "date" })),
|
airDate: t.Nullable(t.String({ format: "date" })),
|
||||||
originalLanguage: t.Nullable(
|
originalLanguage: t.Nullable(
|
||||||
|
61
api/src/models/serie.ts
Normal file
61
api/src/models/serie.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { t } from "elysia";
|
||||||
|
import { Genre } from "./show";
|
||||||
|
import { Image } from "./image";
|
||||||
|
import { ExternalId } from "./external-id";
|
||||||
|
import { madeInAbyss , registerExamples } from "./examples";
|
||||||
|
import { comment } from "../utils";
|
||||||
|
|
||||||
|
export const SerieStatus = t.UnionEnum([
|
||||||
|
"unknown",
|
||||||
|
"finished",
|
||||||
|
"airing",
|
||||||
|
"planned",
|
||||||
|
]);
|
||||||
|
export type SerieStatus = typeof SerieStatus.static;
|
||||||
|
|
||||||
|
export const Serie = t.Object({
|
||||||
|
id: t.String({ format: "uuid" }),
|
||||||
|
slug: t.String(),
|
||||||
|
name: t.String(),
|
||||||
|
description: t.Nullable(t.String()),
|
||||||
|
tagline: t.Nullable(t.String()),
|
||||||
|
aliases: t.Array(t.String()),
|
||||||
|
tags: t.Array(t.String()),
|
||||||
|
|
||||||
|
genres: t.Array(Genre),
|
||||||
|
rating: t.Nullable(t.Number({ minimum: 0, maximum: 100 })),
|
||||||
|
status: SerieStatus,
|
||||||
|
runtime: t.Nullable(
|
||||||
|
t.Number({
|
||||||
|
minimum: 0,
|
||||||
|
description: "Average runtime of all episodes (in minutes.)",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
startAir: t.Nullable(t.String({ format: "date" })),
|
||||||
|
endAir: t.Nullable(t.String({ format: "date" })),
|
||||||
|
originalLanguage: t.Nullable(
|
||||||
|
t.String({
|
||||||
|
description: comment`
|
||||||
|
The language code this movie was made in.
|
||||||
|
This is a BCP 47 language code (the IETF Best Current Practices on Tags for Identifying Languages).
|
||||||
|
BCP 47 is also known as RFC 5646. It subsumes ISO 639 and is backward compatible with it.
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
|
poster: t.Nullable(Image),
|
||||||
|
thumbnail: t.Nullable(Image),
|
||||||
|
banner: t.Nullable(Image),
|
||||||
|
logo: t.Nullable(Image),
|
||||||
|
trailerUrl: t.Nullable(t.String()),
|
||||||
|
|
||||||
|
createdAt: t.String({ format: "date-time" }),
|
||||||
|
nextRefresh: t.String({ format: "date-time" }),
|
||||||
|
|
||||||
|
externalId: ExternalId,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Serie = typeof Serie.static;
|
||||||
|
|
||||||
|
registerExamples(Serie, madeInAbyss);
|
@ -1,13 +1,5 @@
|
|||||||
import { t } from "elysia";
|
import { t } from "elysia";
|
||||||
|
|
||||||
export const ShowStatus = t.UnionEnum([
|
|
||||||
"unknown",
|
|
||||||
"finished",
|
|
||||||
"airing",
|
|
||||||
"planned",
|
|
||||||
]);
|
|
||||||
export type ShowStatus = typeof ShowStatus.static;
|
|
||||||
|
|
||||||
export const Genre = t.UnionEnum([
|
export const Genre = t.UnionEnum([
|
||||||
"action",
|
"action",
|
||||||
"adventure",
|
"adventure",
|
||||||
|
7
api/src/seed.ts
Normal file
7
api/src/seed.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { db } from "./db";
|
||||||
|
import { videos } from "./db/schema/videos";
|
||||||
|
import { Video } from "./models/video";
|
||||||
|
|
||||||
|
const seed = async () =>{
|
||||||
|
db.insert(videos).values(Video.examples)
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user