Cleanup translation schema for series + example

This commit is contained in:
Zoe Roux 2025-01-25 00:58:00 +01:00
parent 9f929eeb7a
commit a6ac5dfb75
5 changed files with 109 additions and 99 deletions

View File

@ -1,37 +1,47 @@
import type { SeedSerie } from "../seed"; import type { SeedSerie } from "~/models/serie";
export const madeInAbyss: SeedSerie = { export const madeInAbyss = {
id: "04bcf2ac-3c09-42f6-8357-b003798f9562",
slug: "made-in-abyss", slug: "made-in-abyss",
name: "Made in Abyss", translations: {
tagline: "How far would you go… for the ones you love?", en: {
aliases: [ name: "Made in Abyss",
"Made in Abyss: The Golden City of the Scorching Sun", tagline: "How far would you go… for the ones you love?",
"Meidoinabisu", aliases: [
"Meidoinabisu: Retsujitsu no ôgonkyô", "Made in Abyss: The Golden City of the Scorching Sun",
], "Meidoinabisu",
description: "Meidoinabisu: Retsujitsu no ôgonkyô",
"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: [ description:
"android", "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.",
"amnesia", tags: [
"post-apocalyptic future", "android",
"exploration", "amnesia",
"friendship", "post-apocalyptic future",
"mecha", "exploration",
"survival", "friendship",
"curse", "mecha",
"tragedy", "survival",
"orphan", "curse",
"based on manga", "tragedy",
"robot", "orphan",
"dark fantasy", "based on manga",
"seinen", "robot",
"anime", "dark fantasy",
"drastic change of life", "seinen",
"fantasy", "anime",
"adventure", "drastic change of life",
], "fantasy",
"adventure",
],
poster:
"https://image.tmdb.org/t/p/original/4Bh9qzB1Kau4RDaVQXVFdoJ0HcE.jpg",
thumbnail:
"https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg",
logo: "https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png",
banner: null,
trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s",
},
},
genres: [ genres: [
"animation", "animation",
"drama", "drama",
@ -46,26 +56,6 @@ export const madeInAbyss: SeedSerie = {
originalLanguage: "ja", originalLanguage: "ja",
startAir: "2017-07-07", startAir: "2017-07-07",
endAir: "2022-09-28", 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: { externalId: {
themoviedatabase: { themoviedatabase: {
dataId: "72636", dataId: "72636",
@ -74,26 +64,23 @@ export const madeInAbyss: SeedSerie = {
imdb: { dataId: "tt7222086", link: "https://www.imdb.com/title/tt7222086" }, imdb: { dataId: "tt7222086", link: "https://www.imdb.com/title/tt7222086" },
tvdb: { dataId: "326109", link: null }, tvdb: { dataId: "326109", link: null },
}, },
createdAt: "2023-11-29T11:12:11.949503Z",
nextRefresh: "2025-01-07T11:42:50.948248Z",
seasons: [ seasons: [
{ {
id: "490aa312-53b9-43c2-845d-7cbf32642c98",
slug: "made-in-abyss-s1", slug: "made-in-abyss-s1",
seasonNumber: 1, seasonNumber: 1,
name: "Season 1", translations: {
description: en: {
"Within the depths of the Abyss, a girl named Riko stumbles upon a robot who looks like a young boy. Riko and her new friend descend into uncharted territory to unlock its mysteries, but what lies in wait for them in the darkness?", name: "Season 1",
description:
"Within the depths of the Abyss, a girl named Riko stumbles upon a robot who looks like a young boy. Riko and her new friend descend into uncharted territory to unlock its mysteries, but what lies in wait for them in the darkness?",
poster:
"https://image.tmdb.org/t/p/original/uVK3H8CgtrVgySFpdImvNXkN7RK.jpg",
thumbnail: null,
banner: null,
},
},
startAir: "2017-07-07", startAir: "2017-07-07",
endAir: "2017-09-29", endAir: "2017-09-29",
poster: {
id: "1c121a2b-d3a2-4ce8-e22a-79b13dde3f7d",
source:
"https://image.tmdb.org/t/p/original/uVK3H8CgtrVgySFpdImvNXkN7RK.jpg",
blurhash: "LYG9BNkrD%V?~WS5S1WA%LbubHV[",
},
thumbnail: null,
banner: null,
externalId: { externalId: {
themoviedatabase: { themoviedatabase: {
serieId: "72636", serieId: "72636",
@ -101,26 +88,23 @@ export const madeInAbyss: SeedSerie = {
link: "https://www.themoviedb.org/tv/72636/season/1", link: "https://www.themoviedb.org/tv/72636/season/1",
}, },
}, },
createdAt: "2023-11-29T11:12:13.008151Z",
nextRefresh: "2025-01-07T11:37:50.151836Z",
}, },
{ {
id: "135af9ae-a8eb-4110-a4e4-05eee49e2d76",
slug: "made-in-abyss-s2", slug: "made-in-abyss-s2",
seasonNumber: 2, seasonNumber: 2,
name: "The Golden City of the Scorching Sun", translations: {
description: en: {
"Set directly after the events of Made in Abyss: Dawn of the Deep Soul, the fifth installment of Made in Abyss covers the adventure of Reg, Riko and Nanachi in the Sixth Layer, The Capital of the Unreturned.", name: "The Golden City of the Scorching Sun",
description:
"Set directly after the events of Made in Abyss: Dawn of the Deep Soul, the fifth installment of Made in Abyss covers the adventure of Reg, Riko and Nanachi in the Sixth Layer, The Capital of the Unreturned.",
poster:
"https://image.tmdb.org/t/p/original/clC2erfUqIezhET67Gz9fcKD1L2.jpg",
thumbnail: null,
banner: null,
},
},
startAir: "2022-07-06", startAir: "2022-07-06",
endAir: "2022-09-28", endAir: "2022-09-28",
poster: {
id: "a03c57d7-4032-7d97-083a-9a6e51d5f1e7",
source:
"https://image.tmdb.org/t/p/original/clC2erfUqIezhET67Gz9fcKD1L2.jpg",
blurhash: "LpNTRGx]s9oz~WbJRPoft7RjV@a|",
},
thumbnail: null,
banner: null,
externalId: { externalId: {
themoviedatabase: { themoviedatabase: {
serieId: "72636", serieId: "72636",
@ -128,8 +112,6 @@ export const madeInAbyss: SeedSerie = {
link: "https://www.themoviedb.org/tv/72636/season/2", link: "https://www.themoviedb.org/tv/72636/season/2",
}, },
}, },
createdAt: "2023-11-29T11:12:13.630306Z",
nextRefresh: "2025-01-07T11:09:19.552971Z",
}, },
], ],
entries: [ entries: [
@ -337,4 +319,4 @@ export const madeInAbyss: SeedSerie = {
}, },
}, },
], ],
}; } satisfies SeedSerie;

View File

@ -6,6 +6,7 @@ import {
Genre, Genre,
Image, Image,
Language, Language,
Resource,
SeedImage, SeedImage,
TranslationRecord, TranslationRecord,
} from "./utils"; } from "./utils";
@ -15,8 +16,6 @@ export const MovieStatus = t.UnionEnum(["unknown", "finished", "planned"]);
export type MovieStatus = typeof MovieStatus.static; export type MovieStatus = typeof MovieStatus.static;
const BaseMovie = t.Object({ const BaseMovie = t.Object({
id: t.String({ format: "uuid" }),
slug: t.String({ format: "slug" }),
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: MovieStatus, status: MovieStatus,
@ -53,8 +52,9 @@ export const MovieTranslation = t.Object({
export type MovieTranslation = typeof MovieTranslation.static; export type MovieTranslation = typeof MovieTranslation.static;
export const Movie = t.Intersect([ export const Movie = t.Intersect([
BaseMovie, Resource,
MovieTranslation, MovieTranslation,
BaseMovie,
t.Object({ isAvailable: t.Boolean() }), t.Object({ isAvailable: t.Boolean() }),
]); ]);
export type Movie = typeof Movie.static; export type Movie = typeof Movie.static;
@ -69,8 +69,9 @@ export const FullMovie = t.Intersect([
export type FullMovie = typeof FullMovie.static; export type FullMovie = typeof FullMovie.static;
export const SeedMovie = t.Intersect([ export const SeedMovie = t.Intersect([
t.Omit(BaseMovie, ["id", "createdAt", "nextRefresh"]), t.Omit(BaseMovie, ["createdAt", "nextRefresh"]),
t.Object({ t.Object({
slug: t.String({ format: "slug", examples: ["bubble"] }),
translations: TranslationRecord( translations: TranslationRecord(
t.Intersect([ t.Intersect([
t.Omit(MovieTranslation, ["poster", "thumbnail", "banner", "logo"]), t.Omit(MovieTranslation, ["poster", "thumbnail", "banner", "logo"]),
@ -92,4 +93,3 @@ registerExamples(Movie, {
...bubble.translations.en, ...bubble.translations.en,
...bubbleImages, ...bubbleImages,
}); });
registerExamples(SeedMovie, bubble);

View File

@ -1,7 +1,7 @@
import { t } from "elysia"; import { t } from "elysia";
import { SeasonId } from "./utils/external-id"; import { SeasonId } from "./utils/external-id";
import { Image } from "./utils/image"; import { Image, SeedImage } from "./utils/image";
import { Language } from "./utils/language"; import { TranslationRecord } from "./utils/language";
import { Resource } from "./utils/resource"; import { Resource } from "./utils/resource";
export const BaseSeason = t.Object({ export const BaseSeason = t.Object({
@ -29,8 +29,18 @@ export const Season = t.Intersect([Resource, BaseSeason, SeasonTranslation]);
export type Season = typeof Season.static; export type Season = typeof Season.static;
export const SeedSeason = t.Intersect([ export const SeedSeason = t.Intersect([
BaseSeason, t.Omit(BaseSeason, ["createdAt", "nextRefresh"]),
t.Object({ t.Object({
translations: t.Record(Language(), SeasonTranslation, { minPropreties: 1 }), slug: t.String({ format: "slug" }),
translations: TranslationRecord(
t.Intersect([
t.Omit(SeasonTranslation, ["poster", "thumbnail", "banner"]),
t.Object({
poster: t.Nullable(SeedImage),
thumbnail: t.Nullable(SeedImage),
banner: t.Nullable(SeedImage),
}),
]),
),
}), }),
]); ]);

View File

@ -1,10 +1,10 @@
import { t } from "elysia"; import { t } from "elysia";
import { madeInAbyss, registerExamples } from "./examples"; import { bubbleImages, madeInAbyss, registerExamples } from "./examples";
import { SeedSeason } from "./season"; import { SeedSeason } from "./season";
import { ExternalId } from "./utils/external-id"; import { ExternalId } from "./utils/external-id";
import { Genre } from "./utils/genres"; import { Genre } from "./utils/genres";
import { Image } from "./utils/image"; import { Image, SeedImage } from "./utils/image";
import { Language } from "./utils/language"; import { Language, TranslationRecord } from "./utils/language";
import { Resource } from "./utils/resource"; import { Resource } from "./utils/resource";
export const SerieStatus = t.UnionEnum([ export const SerieStatus = t.UnionEnum([
@ -55,16 +55,34 @@ export const SerieTranslation = t.Object({
}); });
export type SerieTranslation = typeof SerieTranslation.static; export type SerieTranslation = typeof SerieTranslation.static;
export const Serie = t.Intersect([Resource, BaseSerie, SerieTranslation]); export const Serie = t.Intersect([Resource, SerieTranslation, BaseSerie]);
export type Serie = typeof Serie.static; export type Serie = typeof Serie.static;
export const SeedSerie = t.Intersect([ export const SeedSerie = t.Intersect([
BaseSerie, t.Omit(BaseSerie, ["createdAt", "nextRefresh"]),
t.Object({ t.Object({
translations: t.Record(Language(), SerieTranslation, { minProperties: 1 }), slug: t.String({ format: "slug" }),
translations: TranslationRecord(
t.Intersect([
t.Omit(SerieTranslation, ["poster", "thumbnail", "banner", "logo"]),
t.Object({
poster: t.Nullable(SeedImage),
thumbnail: t.Nullable(SeedImage),
banner: t.Nullable(SeedImage),
logo: t.Nullable(SeedImage),
}),
]),
),
seasons: t.Array(SeedSeason), seasons: t.Array(SeedSeason),
// entries: t.Array(SeedEntry), // entries: t.Array(SeedEntry),
// extras: t.Optional(t.Array(SeedExtra)), // extras: t.Optional(t.Array(SeedExtra)),
}), }),
]); ]);
export type SeedSerie = typeof SeedSerie.static; export type SeedSerie = typeof SeedSerie.static;
registerExamples(Serie, {
...madeInAbyss,
...madeInAbyss.translations.en,
...bubbleImages,
});
registerExamples(SeedSerie, madeInAbyss);

View File

@ -11,7 +11,7 @@ export const Page = <T extends TSchema>(schema: T, options?: ObjectOptions) =>
next: t.Nullable(t.String({ format: "uri" })), next: t.Nullable(t.String({ format: "uri" })),
}, },
{ {
description: `Paginated list of ${schema.title} that match filters.`, description: "Paginated list that match filters.",
...options, ...options,
}, },
); );