mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-23 17:52: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 { insertShow } from "./insert/shows";
|
||||
import { guessNextRefresh } from "./refresh";
|
||||
import { insertSeasons } from "./insert/seasons";
|
||||
|
||||
export const SeedSerieResponse = t.Object({
|
||||
id: t.String({ format: "uuid" }),
|
||||
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(
|
||||
t.Object({
|
||||
id: t.String({ format: "uuid" }),
|
||||
@ -55,12 +62,14 @@ export const seedSerie = async (
|
||||
);
|
||||
if ("status" in show) return show;
|
||||
|
||||
const retSeasons = await insertSeasons(show, seasons);
|
||||
const retEntries = await insertEntries(show, entries);
|
||||
|
||||
return {
|
||||
updated: show.updated,
|
||||
id: show.id,
|
||||
slug: show.slug,
|
||||
seasons: retSeasons,
|
||||
entries: retEntries,
|
||||
};
|
||||
};
|
||||
|
@ -2,7 +2,7 @@ import { t } from "elysia";
|
||||
import { Image } from "../utils/image";
|
||||
|
||||
export const BaseEntry = t.Object({
|
||||
airDate: t.Nullable(t.String({ format: "data" })),
|
||||
airDate: t.Nullable(t.String({ format: "date" })),
|
||||
runtime: t.Nullable(
|
||||
t.Number({ minimum: 0, description: "Runtime of the episode in minutes" }),
|
||||
),
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { SeedMovie } from "../movie";
|
||||
import type { Video } from "../video";
|
||||
import type { SeedMovie } from "~/models/movie";
|
||||
import type { Video } from "~/models/video";
|
||||
|
||||
export const bubbleVideo: Video = {
|
||||
id: "3cd436ee-01ff-4f45-ba98-62aabeb22f25",
|
||||
|
@ -1,4 +1,22 @@
|
||||
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 = {
|
||||
slug: "made-in-abyss",
|
||||
|
@ -45,6 +45,7 @@ export const SeedSeason = t.Intersect([
|
||||
),
|
||||
}),
|
||||
]);
|
||||
export type SeedSeason = typeof SeedSeason.static;
|
||||
|
||||
registerExamples(Season, {
|
||||
...madeInAbyss.seasons[0],
|
||||
|
@ -37,22 +37,24 @@ export const Video = t.Object({
|
||||
t.Object(
|
||||
{
|
||||
title: t.String(),
|
||||
year: t.Array(t.Integer(), { default: [] }),
|
||||
season: t.Array(t.Integer(), { default: [] }),
|
||||
episode: t.Array(t.Integer(), { default: [] }),
|
||||
year: t.Optional(t.Array(t.Integer(), { default: [] })),
|
||||
season: t.Optional(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)
|
||||
type: t.Optional(t.UnionEnum(["episode", "movie", "extra"])),
|
||||
|
||||
from: t.String({
|
||||
description: "Name of the tool that made the guess",
|
||||
}),
|
||||
history: t.Array(t.Omit(Self, ["history"]), {
|
||||
default: [],
|
||||
description: comment`
|
||||
When another tool refines the guess or a user manually edit it, the history of the guesses
|
||||
are kept in this \`history\` value.
|
||||
`,
|
||||
}),
|
||||
history: t.Optional(
|
||||
t.Array(t.Omit(Self, ["history"]), {
|
||||
default: [],
|
||||
description: comment`
|
||||
When another tool refines the guess or a user manually edit it, the history of the guesses
|
||||
are kept in this \`history\` value.
|
||||
`,
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
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",
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": true,
|
||||
"indentStyle": "tab",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
|
Loading…
x
Reference in New Issue
Block a user