diff --git a/api/src/db/schema/videos.ts b/api/src/db/schema/videos.ts index 877f3c9d..a7c60d42 100644 --- a/api/src/db/schema/videos.ts +++ b/api/src/db/schema/videos.ts @@ -9,6 +9,7 @@ import { uuid, varchar, } from "drizzle-orm/pg-core"; +import type { Guess } from "~/models/video"; import { entries } from "./entries"; import { schema } from "./utils"; @@ -21,7 +22,7 @@ export const videos = schema.table( rendering: text().notNull(), part: integer(), version: integer().notNull().default(1), - guess: jsonb().notNull().default({}), + guess: jsonb().$type().notNull(), createdAt: timestamp({ withTimezone: true, mode: "string" }) .notNull() diff --git a/api/src/models/video.ts b/api/src/models/video.ts index 6822cbb2..96da6f0f 100644 --- a/api/src/models/video.ts +++ b/api/src/models/video.ts @@ -3,6 +3,42 @@ import { type Prettify, comment } from "~/utils"; import { bubbleVideo, registerExamples } from "./examples"; import { DbMetadata, Resource } from "./utils"; +export const Guess = t.Recursive((Self) => + t.Object( + { + title: t.String(), + 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) + kind: t.Optional(t.UnionEnum(["episode", "movie", "extra"])), + + from: t.String({ + description: "Name of the tool that made the guess", + }), + 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, + description: comment` + Metadata guessed from the filename. Kyoo can use those informations to bypass + the scanner/metadata fetching and just register videos to movies/entries that already + exists. If Kyoo can't find a matching movie/entry, this information will be sent to + the scanner. + `, + }, + ), +); +export type Guess = typeof Guess.static; + export const SeedVideo = t.Object({ path: t.String(), rendering: t.String({ @@ -29,42 +65,7 @@ export const SeedVideo = t.Object({ "Kyoo will prefer playing back the highest `version` number if there are multiples rendering.", }), - guess: t.Optional( - t.Recursive((Self) => - t.Object( - { - title: t.String(), - 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) - kind: t.Optional(t.UnionEnum(["episode", "movie", "extra"])), - - from: t.String({ - description: "Name of the tool that made the guess", - }), - 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, - description: comment` - Metadata guessed from the filename. Kyoo can use those informations to bypass - the scanner/metadata fetching and just register videos to movies/entries that already - exists. If Kyoo can't find a matching movie/entry, this information will be sent to - the scanner. - `, - }, - ), - ), - ), + guess: t.Optional(Guess), }); export type SeedVideo = typeof SeedVideo.static;