mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add insert seasons
This commit is contained in:
parent
5d8d5721af
commit
32a1e89b27
61
api/src/controllers/seed/insert/seasons.ts
Normal file
61
api/src/controllers/seed/insert/seasons.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { db } from "~/db";
|
||||||
|
import { seasonTranslations, seasons } from "~/db/schema";
|
||||||
|
import { conflictUpdateAllExcept } from "~/db/utils";
|
||||||
|
import type { SeedSeason } from "~/models/season";
|
||||||
|
import { processOptImage } from "../images";
|
||||||
|
import { guessNextRefresh } from "../refresh";
|
||||||
|
|
||||||
|
type SeasonI = typeof seasons.$inferInsert;
|
||||||
|
type SeasonTransI = typeof seasonTranslations.$inferInsert;
|
||||||
|
|
||||||
|
export const insertSeasons = async (
|
||||||
|
show: { pk: number; slug: string },
|
||||||
|
items: SeedSeason[],
|
||||||
|
) => {
|
||||||
|
return db.transaction(async (tx) => {
|
||||||
|
const vals: SeasonI[] = items.map((x) => {
|
||||||
|
const { translations, ...season } = x;
|
||||||
|
return {
|
||||||
|
...season,
|
||||||
|
showPk: show.pk,
|
||||||
|
slug: `${show.slug}-s${season.seasonNumber}`,
|
||||||
|
nextRefresh: guessNextRefresh(season.startAir ?? new Date()),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const ret = await tx
|
||||||
|
.insert(seasons)
|
||||||
|
.values(vals)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: seasons.slug,
|
||||||
|
set: conflictUpdateAllExcept(seasons, [
|
||||||
|
"pk",
|
||||||
|
"showPk",
|
||||||
|
"id",
|
||||||
|
"slug",
|
||||||
|
"createdAt",
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
.returning({ pk: seasons.pk, id: seasons.id, slug: seasons.slug });
|
||||||
|
|
||||||
|
const trans: SeasonTransI[] = items.flatMap((seed, i) =>
|
||||||
|
Object.entries(seed.translations).map(([lang, tr]) => ({
|
||||||
|
// assumes ret is ordered like items.
|
||||||
|
pk: ret[i].pk,
|
||||||
|
language: lang,
|
||||||
|
...tr,
|
||||||
|
poster: processOptImage(tr.poster),
|
||||||
|
thumbnail: processOptImage(tr.thumbnail),
|
||||||
|
banner: processOptImage(tr.banner),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
await tx
|
||||||
|
.insert(seasonTranslations)
|
||||||
|
.values(trans)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [seasonTranslations.pk, seasonTranslations.language],
|
||||||
|
set: conflictUpdateAllExcept(seasonTranslations, ["pk", "language"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
};
|
@ -4,10 +4,17 @@ import { getYear } from "~/utils";
|
|||||||
import { insertEntries } from "./insert/entries";
|
import { insertEntries } from "./insert/entries";
|
||||||
import { insertShow } from "./insert/shows";
|
import { insertShow } from "./insert/shows";
|
||||||
import { guessNextRefresh } from "./refresh";
|
import { guessNextRefresh } from "./refresh";
|
||||||
|
import { insertSeasons } from "./insert/seasons";
|
||||||
|
|
||||||
export const SeedSerieResponse = t.Object({
|
export const SeedSerieResponse = t.Object({
|
||||||
id: t.String({ format: "uuid" }),
|
id: t.String({ format: "uuid" }),
|
||||||
slug: t.String({ format: "slug", examples: ["made-in-abyss"] }),
|
slug: t.String({ format: "slug", examples: ["made-in-abyss"] }),
|
||||||
|
seasons: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String({ format: "uuid" }),
|
||||||
|
slug: t.String({ format: "slug", examples: ["made-in-abyss-s1"] }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
entries: t.Array(
|
entries: t.Array(
|
||||||
t.Object({
|
t.Object({
|
||||||
id: t.String({ format: "uuid" }),
|
id: t.String({ format: "uuid" }),
|
||||||
@ -55,12 +62,14 @@ export const seedSerie = async (
|
|||||||
);
|
);
|
||||||
if ("status" in show) return show;
|
if ("status" in show) return show;
|
||||||
|
|
||||||
|
const retSeasons = await insertSeasons(show, seasons);
|
||||||
const retEntries = await insertEntries(show, entries);
|
const retEntries = await insertEntries(show, entries);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updated: show.updated,
|
updated: show.updated,
|
||||||
id: show.id,
|
id: show.id,
|
||||||
slug: show.slug,
|
slug: show.slug,
|
||||||
|
seasons: retSeasons,
|
||||||
entries: retEntries,
|
entries: retEntries,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ import { t } from "elysia";
|
|||||||
import { Image } from "../utils/image";
|
import { Image } from "../utils/image";
|
||||||
|
|
||||||
export const BaseEntry = t.Object({
|
export const BaseEntry = t.Object({
|
||||||
airDate: t.Nullable(t.String({ format: "data" })),
|
airDate: t.Nullable(t.String({ format: "date" })),
|
||||||
runtime: t.Nullable(
|
runtime: t.Nullable(
|
||||||
t.Number({ minimum: 0, description: "Runtime of the episode in minutes" }),
|
t.Number({ minimum: 0, description: "Runtime of the episode in minutes" }),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { SeedMovie } from "../movie";
|
import type { SeedMovie } from "~/models/movie";
|
||||||
import type { Video } from "../video";
|
import type { Video } from "~/models/video";
|
||||||
|
|
||||||
export const bubbleVideo: Video = {
|
export const bubbleVideo: Video = {
|
||||||
id: "3cd436ee-01ff-4f45-ba98-62aabeb22f25",
|
id: "3cd436ee-01ff-4f45-ba98-62aabeb22f25",
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
import type { SeedSerie } from "~/models/serie";
|
import type { SeedSerie } from "~/models/serie";
|
||||||
|
import type { Video } from "~/models/video";
|
||||||
|
|
||||||
|
export const madeInAbyssVideo: Video = {
|
||||||
|
id: "3cd436ee-01ff-4f45-ba98-654282531234",
|
||||||
|
slug: "made-in-abyss-s1e1",
|
||||||
|
path: "/video/Made in abyss S01E01.mkv",
|
||||||
|
rendering: "459429fa062adeebedcc2bb04b9965de0262bfa453369783132d261be79021bd",
|
||||||
|
part: null,
|
||||||
|
version: 1,
|
||||||
|
guess: {
|
||||||
|
title: "Made in abyss",
|
||||||
|
season: [1],
|
||||||
|
episode: [1],
|
||||||
|
type: "episode",
|
||||||
|
from: "guessit",
|
||||||
|
},
|
||||||
|
createdAt: "2024-11-23T15:01:24.968Z",
|
||||||
|
};
|
||||||
|
|
||||||
export const madeInAbyss = {
|
export const madeInAbyss = {
|
||||||
slug: "made-in-abyss",
|
slug: "made-in-abyss",
|
||||||
|
@ -45,6 +45,7 @@ export const SeedSeason = t.Intersect([
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
export type SeedSeason = typeof SeedSeason.static;
|
||||||
|
|
||||||
registerExamples(Season, {
|
registerExamples(Season, {
|
||||||
...madeInAbyss.seasons[0],
|
...madeInAbyss.seasons[0],
|
||||||
|
@ -37,22 +37,24 @@ export const Video = t.Object({
|
|||||||
t.Object(
|
t.Object(
|
||||||
{
|
{
|
||||||
title: t.String(),
|
title: t.String(),
|
||||||
year: t.Array(t.Integer(), { default: [] }),
|
year: t.Optional(t.Array(t.Integer(), { default: [] })),
|
||||||
season: t.Array(t.Integer(), { default: [] }),
|
season: t.Optional(t.Array(t.Integer(), { default: [] })),
|
||||||
episode: t.Array(t.Integer(), { default: [] }),
|
episode: t.Optional(t.Array(t.Integer(), { default: [] })),
|
||||||
// TODO: maybe replace "extra" with the `extraKind` value (aka behind-the-scene, trailer, etc)
|
// TODO: maybe replace "extra" with the `extraKind` value (aka behind-the-scene, trailer, etc)
|
||||||
type: t.Optional(t.UnionEnum(["episode", "movie", "extra"])),
|
type: t.Optional(t.UnionEnum(["episode", "movie", "extra"])),
|
||||||
|
|
||||||
from: t.String({
|
from: t.String({
|
||||||
description: "Name of the tool that made the guess",
|
description: "Name of the tool that made the guess",
|
||||||
}),
|
}),
|
||||||
history: t.Array(t.Omit(Self, ["history"]), {
|
history: t.Optional(
|
||||||
|
t.Array(t.Omit(Self, ["history"]), {
|
||||||
default: [],
|
default: [],
|
||||||
description: comment`
|
description: comment`
|
||||||
When another tool refines the guess or a user manually edit it, the history of the guesses
|
When another tool refines the guess or a user manually edit it, the history of the guesses
|
||||||
are kept in this \`history\` value.
|
are kept in this \`history\` value.
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
additionalProperties: true,
|
additionalProperties: true,
|
||||||
|
35
api/tests/series/seed-serie.test.ts
Normal file
35
api/tests/series/seed-serie.test.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { describe, expect, it } from "bun:test";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { expectStatus } from "tests/utils";
|
||||||
|
import { db } from "~/db";
|
||||||
|
import { seasons, shows, videos } from "~/db/schema";
|
||||||
|
import { madeInAbyss, madeInAbyssVideo } from "~/models/examples";
|
||||||
|
import { createSerie } from "../helpers";
|
||||||
|
|
||||||
|
describe("Serie seeding", () => {
|
||||||
|
it("Can create a serie with seasons and episodes", async () => {
|
||||||
|
// create video beforehand to test linking
|
||||||
|
await db.insert(videos).values(madeInAbyssVideo);
|
||||||
|
const [resp, body] = await createSerie(madeInAbyss);
|
||||||
|
|
||||||
|
expectStatus(resp, body).toBe(201);
|
||||||
|
expect(body.id).toBeString();
|
||||||
|
expect(body.slug).toBe("made-in-abyss");
|
||||||
|
|
||||||
|
const ret = await db.query.shows.findFirst({
|
||||||
|
where: eq(shows.id, body.id),
|
||||||
|
with: {
|
||||||
|
seasons: { orderBy: seasons.seasonNumber },
|
||||||
|
entries: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(ret).not.toBeNull();
|
||||||
|
expect(ret!.seasons).toBeArrayOfSize(2);
|
||||||
|
expect(ret!.seasons[0].slug).toBe("made-in-abyss-s1");
|
||||||
|
expect(ret!.seasons[1].slug).toBe("made-in-abyss-s2");
|
||||||
|
// expect(ret!.entries).toBeArrayOfSize(
|
||||||
|
// madeInAbyss.entries.length + madeInAbyss.extras.length,
|
||||||
|
// );
|
||||||
|
});
|
||||||
|
});
|
@ -2,6 +2,7 @@
|
|||||||
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
|
"$schema": "https://biomejs.dev/schemas/1.8.1/schema.json",
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
"formatWithErrors": true,
|
||||||
"indentStyle": "tab",
|
"indentStyle": "tab",
|
||||||
"indentWidth": 2,
|
"indentWidth": 2,
|
||||||
"lineEnding": "lf",
|
"lineEnding": "lf",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user