mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Handle extra seeding
This commit is contained in:
parent
32a1e89b27
commit
4424e9b40a
@ -7,13 +7,26 @@ import {
|
|||||||
videos,
|
videos,
|
||||||
} from "~/db/schema";
|
} from "~/db/schema";
|
||||||
import { conflictUpdateAllExcept, values } from "~/db/utils";
|
import { conflictUpdateAllExcept, values } from "~/db/utils";
|
||||||
import type { SeedEntry } from "~/models/entry";
|
import type { SeedEntry as SEntry, SeedExtra as SExtra } from "~/models/entry";
|
||||||
import { processOptImage } from "../images";
|
import { processOptImage } from "../images";
|
||||||
import { guessNextRefresh } from "../refresh";
|
import { guessNextRefresh } from "../refresh";
|
||||||
|
|
||||||
|
type SeedEntry = SEntry & {
|
||||||
|
video?: undefined;
|
||||||
|
};
|
||||||
|
type SeedExtra = Omit<SExtra, "kind"> & {
|
||||||
|
videos?: undefined;
|
||||||
|
translations?: undefined;
|
||||||
|
kind: "extra";
|
||||||
|
extraKind: SExtra["kind"];
|
||||||
|
};
|
||||||
|
|
||||||
type EntryI = typeof entries.$inferInsert;
|
type EntryI = typeof entries.$inferInsert;
|
||||||
|
|
||||||
const generateSlug = (showSlug: string, entry: SeedEntry): string => {
|
const generateSlug = (
|
||||||
|
showSlug: string,
|
||||||
|
entry: SeedEntry | SeedExtra,
|
||||||
|
): string => {
|
||||||
switch (entry.kind) {
|
switch (entry.kind) {
|
||||||
case "episode":
|
case "episode":
|
||||||
return `${showSlug}-s${entry.seasonNumber}e${entry.episodeNumber}`;
|
return `${showSlug}-s${entry.seasonNumber}e${entry.episodeNumber}`;
|
||||||
@ -22,22 +35,29 @@ const generateSlug = (showSlug: string, entry: SeedEntry): string => {
|
|||||||
case "movie":
|
case "movie":
|
||||||
if (entry.slug) return entry.slug;
|
if (entry.slug) return entry.slug;
|
||||||
return entry.order === 1 ? showSlug : `${showSlug}-${entry.order}`;
|
return entry.order === 1 ? showSlug : `${showSlug}-${entry.order}`;
|
||||||
|
case "extra":
|
||||||
|
return entry.slug;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const insertEntries = async (
|
export const insertEntries = async (
|
||||||
show: { pk: number; slug: string },
|
show: { pk: number; slug: string },
|
||||||
items: SeedEntry[],
|
items: (SeedEntry | SeedExtra)[],
|
||||||
) => {
|
) => {
|
||||||
|
if (!items) return [];
|
||||||
|
|
||||||
const retEntries = await db.transaction(async (tx) => {
|
const retEntries = await db.transaction(async (tx) => {
|
||||||
const vals: EntryI[] = items.map((seed) => {
|
const vals: EntryI[] = items.map((seed) => {
|
||||||
const { translations, videos, ...entry } = seed;
|
const { translations, videos, video, ...entry } = seed;
|
||||||
return {
|
return {
|
||||||
...entry,
|
...entry,
|
||||||
showPk: show.pk,
|
showPk: show.pk,
|
||||||
slug: generateSlug(show.slug, seed),
|
slug: generateSlug(show.slug, seed),
|
||||||
thumbnail: processOptImage(seed.thumbnail),
|
thumbnail: processOptImage(seed.thumbnail),
|
||||||
nextRefresh: guessNextRefresh(entry.airDate ?? new Date()),
|
nextRefresh:
|
||||||
|
entry.kind !== "extra"
|
||||||
|
? guessNextRefresh(entry.airDate ?? new Date())
|
||||||
|
: guessNextRefresh(new Date()),
|
||||||
episodeNumber:
|
episodeNumber:
|
||||||
entry.kind === "episode"
|
entry.kind === "episode"
|
||||||
? entry.episodeNumber
|
? entry.episodeNumber
|
||||||
@ -61,14 +81,25 @@ export const insertEntries = async (
|
|||||||
})
|
})
|
||||||
.returning({ pk: entries.pk, id: entries.id, slug: entries.slug });
|
.returning({ pk: entries.pk, id: entries.id, slug: entries.slug });
|
||||||
|
|
||||||
const trans = items.flatMap((seed, i) =>
|
const trans = items.flatMap((seed, i) => {
|
||||||
Object.entries(seed.translations).map(([lang, tr]) => ({
|
if (seed.kind === "extra") {
|
||||||
|
return {
|
||||||
|
pk: ret[i].pk,
|
||||||
|
// yeah we hardcode the language to extra because if we want to support
|
||||||
|
// translations one day it won't be awkward
|
||||||
|
language: "extra",
|
||||||
|
name: seed.name,
|
||||||
|
description: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.entries(seed.translations).map(([lang, tr]) => ({
|
||||||
// assumes ret is ordered like items.
|
// assumes ret is ordered like items.
|
||||||
pk: ret[i].pk,
|
pk: ret[i].pk,
|
||||||
language: lang,
|
language: lang,
|
||||||
...tr,
|
...tr,
|
||||||
})),
|
}));
|
||||||
);
|
});
|
||||||
await tx
|
await tx
|
||||||
.insert(entryTranslations)
|
.insert(entryTranslations)
|
||||||
.values(trans)
|
.values(trans)
|
||||||
@ -80,15 +111,22 @@ export const insertEntries = async (
|
|||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
const vids = items.flatMap(
|
const vids = items.flatMap((seed, i) => {
|
||||||
(seed, i) =>
|
if (seed.kind === "extra") {
|
||||||
seed.videos?.map((x, j) => ({
|
return {
|
||||||
videoId: x,
|
videoId: seed.video,
|
||||||
entryPk: retEntries[i].pk,
|
entryPk: retEntries[i].pk,
|
||||||
// The first video should not have a rendering.
|
needRendering: false,
|
||||||
needRendering: j && seed.videos!.length > 1,
|
};
|
||||||
})) ?? [],
|
}
|
||||||
);
|
if (!seed.videos) return [];
|
||||||
|
return seed.videos.map((x, j) => ({
|
||||||
|
videoId: x,
|
||||||
|
entryPk: retEntries[i].pk,
|
||||||
|
// The first video should not have a rendering.
|
||||||
|
needRendering: j && seed.videos!.length > 1,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
if (vids.length === 0)
|
if (vids.length === 0)
|
||||||
return retEntries.map((x) => ({ id: x.id, slug: x.slug, videos: [] }));
|
return retEntries.map((x) => ({ id: x.id, slug: x.slug, videos: [] }));
|
||||||
|
@ -2,9 +2,9 @@ import { t } from "elysia";
|
|||||||
import type { SeedSerie } from "~/models/serie";
|
import type { SeedSerie } from "~/models/serie";
|
||||||
import { getYear } from "~/utils";
|
import { getYear } from "~/utils";
|
||||||
import { insertEntries } from "./insert/entries";
|
import { insertEntries } from "./insert/entries";
|
||||||
|
import { insertSeasons } from "./insert/seasons";
|
||||||
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" }),
|
||||||
@ -29,6 +29,12 @@ export const SeedSerieResponse = t.Object({
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
extras: t.Array(
|
||||||
|
t.Object({
|
||||||
|
id: t.String({ format: "uuid" }),
|
||||||
|
slug: t.String({ format: "slug", examples: ["made-in-abyss-s1e1"] }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
});
|
});
|
||||||
export type SeedSerieResponse = typeof SeedSerieResponse.static;
|
export type SeedSerieResponse = typeof SeedSerieResponse.static;
|
||||||
|
|
||||||
@ -49,7 +55,7 @@ export const seedSerie = async (
|
|||||||
seed.slug = `random-${getYear(seed.startAir)}`;
|
seed.slug = `random-${getYear(seed.startAir)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { translations, seasons, entries, ...serie } = seed;
|
const { translations, seasons, entries, extras, ...serie } = seed;
|
||||||
const nextRefresh = guessNextRefresh(serie.startAir ?? new Date());
|
const nextRefresh = guessNextRefresh(serie.startAir ?? new Date());
|
||||||
|
|
||||||
const show = await insertShow(
|
const show = await insertShow(
|
||||||
@ -64,6 +70,10 @@ export const seedSerie = async (
|
|||||||
|
|
||||||
const retSeasons = await insertSeasons(show, seasons);
|
const retSeasons = await insertSeasons(show, seasons);
|
||||||
const retEntries = await insertEntries(show, entries);
|
const retEntries = await insertEntries(show, entries);
|
||||||
|
const retExtras = await insertEntries(
|
||||||
|
show,
|
||||||
|
(extras ?? []).map((x) => ({ ...x, kind: "extra", extraKind: x.kind })),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updated: show.updated,
|
updated: show.updated,
|
||||||
@ -71,5 +81,6 @@ export const seedSerie = async (
|
|||||||
slug: show.slug,
|
slug: show.slug,
|
||||||
seasons: retSeasons,
|
seasons: retSeasons,
|
||||||
entries: retEntries,
|
entries: retEntries,
|
||||||
|
extras: retExtras,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -36,8 +36,9 @@ export type Extra = typeof Extra.static;
|
|||||||
export const SeedExtra = t.Intersect([
|
export const SeedExtra = t.Intersect([
|
||||||
t.Omit(BaseExtra, ["thumbnail", "createdAt"]),
|
t.Omit(BaseExtra, ["thumbnail", "createdAt"]),
|
||||||
t.Object({
|
t.Object({
|
||||||
|
slug: t.String({ format: "slug" }),
|
||||||
thumbnail: t.Nullable(SeedImage),
|
thumbnail: t.Nullable(SeedImage),
|
||||||
videos: t.Optional(t.Array(t.String({ format: "uuid" }))),
|
video: t.String({ format: "uuid" }),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
export type SeedExtra = typeof SeedExtra.static;
|
export type SeedExtra = typeof SeedExtra.static;
|
||||||
|
@ -237,9 +237,11 @@ export const madeInAbyss = {
|
|||||||
extras: [
|
extras: [
|
||||||
{
|
{
|
||||||
kind: "behind-the-scene",
|
kind: "behind-the-scene",
|
||||||
|
slug: "made-in-abyss-making-of",
|
||||||
name: "The Making of MADE IN ABYSS 01",
|
name: "The Making of MADE IN ABYSS 01",
|
||||||
runtime: 17,
|
runtime: 17,
|
||||||
thumbnail: null,
|
thumbnail: null,
|
||||||
|
video: "3cd436ee-01ff-4f45-ba98-654282531234",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} satisfies SeedSerie;
|
} satisfies SeedSerie;
|
||||||
|
@ -28,8 +28,8 @@ describe("Serie seeding", () => {
|
|||||||
expect(ret!.seasons).toBeArrayOfSize(2);
|
expect(ret!.seasons).toBeArrayOfSize(2);
|
||||||
expect(ret!.seasons[0].slug).toBe("made-in-abyss-s1");
|
expect(ret!.seasons[0].slug).toBe("made-in-abyss-s1");
|
||||||
expect(ret!.seasons[1].slug).toBe("made-in-abyss-s2");
|
expect(ret!.seasons[1].slug).toBe("made-in-abyss-s2");
|
||||||
// expect(ret!.entries).toBeArrayOfSize(
|
expect(ret!.entries).toBeArrayOfSize(
|
||||||
// madeInAbyss.entries.length + madeInAbyss.extras.length,
|
madeInAbyss.entries.length + madeInAbyss.extras.length,
|
||||||
// );
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user