From d1aeadacee4f7f1387f6f2da518ea177be0e4c2d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Fri, 3 Apr 2026 19:26:21 +0200 Subject: [PATCH] Rename `criticalToStory` to `content` enum --- api/drizzle/0031_critical.sql | 3 --- api/drizzle/0031_entry-content.sql | 4 ++++ api/drizzle/meta/0031_snapshot.json | 14 ++++++++++---- api/drizzle/meta/_journal.json | 4 ++-- api/src/controllers/profiles/history.ts | 2 +- api/src/controllers/seed/movies.ts | 1 + api/src/controllers/videos.ts | 2 +- api/src/db/schema/entries.ts | 10 ++++++++-- api/src/models/entry/base-entry.ts | 9 ++++++++- api/src/models/entry/extra.ts | 2 +- api/src/models/examples/made-in-abyss.ts | 7 +++++++ front/src/models/entry.ts | 2 +- scanner/scanner/models/entry.py | 10 +++++++++- scanner/scanner/providers/themoviedatabase.py | 4 ++-- scanner/scanner/providers/thetvdb.py | 10 +++++++--- 15 files changed, 62 insertions(+), 22 deletions(-) delete mode 100644 api/drizzle/0031_critical.sql create mode 100644 api/drizzle/0031_entry-content.sql diff --git a/api/drizzle/0031_critical.sql b/api/drizzle/0031_critical.sql deleted file mode 100644 index 95469536..00000000 --- a/api/drizzle/0031_critical.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE "kyoo"."entries" ADD COLUMN "critical_to_story" boolean;--> statement-breakpoint -UPDATE "kyoo"."entries" SET "critical_to_story" = true;--> statement-breakpoint -ALTER TABLE "kyoo"."entries" ALTER COLUMN "critical_to_story" SET NOT NULl;--> statement-breakpoint diff --git a/api/drizzle/0031_entry-content.sql b/api/drizzle/0031_entry-content.sql new file mode 100644 index 00000000..9236cb5f --- /dev/null +++ b/api/drizzle/0031_entry-content.sql @@ -0,0 +1,4 @@ +CREATE TYPE "kyoo"."entry_content" AS ENUM('story', 'recap', 'filler', 'ova');--> statement-breakpoint +ALTER TABLE "kyoo"."entries" ADD COLUMN "content" "kyoo"."entry_content";--> statement-breakpoint +UPDATE "kyoo"."entries" SET content = 'story';-->statement-breakpoint +ALTER TABLE "kyoo"."entries" ALTER COLUMN "content" SET NOT NULl;--> statement-breakpoint diff --git a/api/drizzle/meta/0031_snapshot.json b/api/drizzle/meta/0031_snapshot.json index ce4f959b..265515ea 100644 --- a/api/drizzle/meta/0031_snapshot.json +++ b/api/drizzle/meta/0031_snapshot.json @@ -1,5 +1,5 @@ { - "id": "bb9072e3-4c3a-44a0-8dae-f21259a5172b", + "id": "13b1ed8d-f166-4d39-ba67-39e8c4cfd786", "prevId": "34fcf5bf-c0a7-4730-a705-0e7fe759d126", "version": "7", "dialect": "postgresql", @@ -93,9 +93,10 @@ "primaryKey": false, "notNull": false }, - "critical_to_story": { - "name": "critical_to_story", - "type": "boolean", + "content": { + "name": "content", + "type": "entry_content", + "typeSchema": "kyoo", "primaryKey": false, "notNull": true }, @@ -1939,6 +1940,11 @@ } }, "enums": { + "kyoo.entry_content": { + "name": "entry_content", + "schema": "kyoo", + "values": ["story", "recap", "filler", "ova"] + }, "kyoo.entry_type": { "name": "entry_type", "schema": "kyoo", diff --git a/api/drizzle/meta/_journal.json b/api/drizzle/meta/_journal.json index cb73196e..8f855cf1 100644 --- a/api/drizzle/meta/_journal.json +++ b/api/drizzle/meta/_journal.json @@ -222,8 +222,8 @@ { "idx": 31, "version": "7", - "when": 1775236194683, - "tag": "0031_critical", + "when": 1775238108619, + "tag": "0031_entry-content", "breakpoints": true } ] diff --git a/api/src/controllers/profiles/history.ts b/api/src/controllers/profiles/history.ts index 9222e324..83207fb8 100644 --- a/api/src/controllers/profiles/history.ts +++ b/api/src/controllers/profiles/history.ts @@ -198,7 +198,7 @@ async function updateWatchlist( and( eq(nextEntry.showPk, entries.showPk), ne(nextEntry.kind, "extra"), - nextEntry.criticalToStory, + eq(nextEntry.content, "story"), gt(nextEntry.order, entries.order), ), ) diff --git a/api/src/controllers/seed/movies.ts b/api/src/controllers/seed/movies.ts index cf95c312..60b759f6 100644 --- a/api/src/controllers/seed/movies.ts +++ b/api/src/controllers/seed/movies.ts @@ -96,6 +96,7 @@ export const seedMovie = async ( { ...movie, kind: "movie", + content: "story", order: 1, thumbnail: (movie.originalLanguage ? translations[movie.originalLanguage] diff --git a/api/src/controllers/videos.ts b/api/src/controllers/videos.ts index 063312a6..e7a877ec 100644 --- a/api/src/controllers/videos.ts +++ b/api/src/controllers/videos.ts @@ -277,7 +277,7 @@ function getNextVideoEntry({ eq(vids.part, sql`${videos.part} ${sql.raw(prev ? "-" : "+")} 1`), ), ), - entries.criticalToStory, + eq(entries.content, "story"), ), ) .orderBy( diff --git a/api/src/db/schema/entries.ts b/api/src/db/schema/entries.ts index 8bd5e6ab..1a20562e 100644 --- a/api/src/db/schema/entries.ts +++ b/api/src/db/schema/entries.ts @@ -1,6 +1,5 @@ import { relations, sql } from "drizzle-orm"; import { - boolean, check, date, index, @@ -25,6 +24,13 @@ export const entryType = schema.enum("entry_type", [ "extra", ]); +export const entryContent = schema.enum("entry_content", [ + "story", + "recap", + "filler", + "ova", +]); + export const entry_extid = () => jsonb() .$type< @@ -69,7 +75,7 @@ export const entries = schema.table( airDate: date(), runtime: integer(), thumbnail: image(), - criticalToStory: boolean().notNull(), + content: entryContent().notNull(), externalId: entry_extid(), diff --git a/api/src/models/entry/base-entry.ts b/api/src/models/entry/base-entry.ts index f66944b5..435cb10d 100644 --- a/api/src/models/entry/base-entry.ts +++ b/api/src/models/entry/base-entry.ts @@ -1,6 +1,13 @@ import { t } from "elysia"; import { Image } from "../utils/image"; +export const EntryContent = t.Union([ + t.Literal("story"), + t.Literal("recap"), + t.Literal("filler"), + t.Literal("ova"), +]); + export const BaseEntry = () => t.Object({ airDate: t.Nullable(t.String({ format: "date" })), @@ -11,7 +18,7 @@ export const BaseEntry = () => }), ), thumbnail: t.Nullable(Image), - criticalToStory: t.Boolean(), + content: EntryContent, }); export const EntryTranslation = () => diff --git a/api/src/models/entry/extra.ts b/api/src/models/entry/extra.ts index ed951ab1..d0446408 100644 --- a/api/src/models/entry/extra.ts +++ b/api/src/models/entry/extra.ts @@ -22,7 +22,7 @@ export const BaseExtra = t.Composite( kind: ExtraType, name: t.String(), }), - t.Omit(BaseEntry(), ["nextRefresh", "airDate"]), + t.Omit(BaseEntry(), ["nextRefresh", "airDate", "content"]), ], { description: comment` diff --git a/api/src/models/examples/made-in-abyss.ts b/api/src/models/examples/made-in-abyss.ts index da3b55fa..72c9f3d0 100644 --- a/api/src/models/examples/made-in-abyss.ts +++ b/api/src/models/examples/made-in-abyss.ts @@ -175,6 +175,7 @@ export const madeInAbyss = { entries: [ { kind: "episode", + content: "story", order: 13, seasonNumber: 1, episodeNumber: 13, @@ -203,6 +204,7 @@ export const madeInAbyss = { }, { kind: "special", + content: "ova", // between s1e13 & movie (which has 13.5 for the `order field`) order: 13.25, number: 3, @@ -230,6 +232,7 @@ export const madeInAbyss = { }, { kind: "movie", + content: "story", slug: "made-in-abyss-dawn-of-the-deep-soul", order: 13.5, translations: { @@ -257,6 +260,7 @@ export const madeInAbyss = { }, { kind: "episode", + content: "story", order: 14, seasonNumber: 2, episodeNumber: 1, @@ -284,6 +288,7 @@ export const madeInAbyss = { }, { kind: "episode", + content: "story", order: 15, seasonNumber: 2, episodeNumber: 2, @@ -311,6 +316,7 @@ export const madeInAbyss = { }, { kind: "episode", + content: "story", order: 16, seasonNumber: 2, episodeNumber: 3, @@ -338,6 +344,7 @@ export const madeInAbyss = { }, { kind: "episode", + content: "story", order: 17, seasonNumber: 2, episodeNumber: 4, diff --git a/front/src/models/entry.ts b/front/src/models/entry.ts index a8f47788..6f0c2c24 100644 --- a/front/src/models/entry.ts +++ b/front/src/models/entry.ts @@ -14,7 +14,7 @@ const Base = z.object({ runtime: z.number().nullable(), thumbnail: KImage.nullable(), - criticalToStory: z.boolean(), + content: z.enum(["story", "recap", "filler", "ova"]), createdAt: zdate(), updatedAt: zdate(), diff --git a/scanner/scanner/models/entry.py b/scanner/scanner/models/entry.py index 84902e26..96a8787e 100644 --- a/scanner/scanner/models/entry.py +++ b/scanner/scanner/models/entry.py @@ -1,6 +1,7 @@ from __future__ import annotations from datetime import date +from enum import Enum from typing import Any, Literal from pydantic import Field @@ -9,13 +10,20 @@ from ..utils import Language, Model from .metadataid import EpisodeId, MetadataId +class EntryContent(str, Enum): + STORY = "story" + RECAP = "recap" + FILLER = "filler" + OVA = "ova" + + class Entry(Model): kind: Literal["episode", "movie", "special"] order: float runtime: int | None air_date: date | None thumbnail: str | None - criticalToStory: bool + content: EntryContent # Movie-specific fields slug: str | None diff --git a/scanner/scanner/providers/themoviedatabase.py b/scanner/scanner/providers/themoviedatabase.py index 5ded09b0..8c470020 100644 --- a/scanner/scanner/providers/themoviedatabase.py +++ b/scanner/scanner/providers/themoviedatabase.py @@ -11,7 +11,7 @@ from aiohttp import ClientResponseError, ClientSession from langcodes import Language from ..models.collection import Collection, CollectionTranslation -from ..models.entry import Entry, EntryTranslation +from ..models.entry import Entry, EntryContent, EntryTranslation from ..models.genre import Genre from ..models.metadataid import EpisodeId, MetadataId, SeasonId from ..models.movie import Movie, MovieStatus, MovieTranslation, SearchMovie @@ -556,7 +556,7 @@ class TheMovieDatabase(Provider): if episode["air_date"] else None, thumbnail=self._map_image(episode["still_path"]), - criticalToStory=True, + content=EntryContent.STORY, slug=None, season_number=episode["season_number"], episode_number=episode["episode_number"], diff --git a/scanner/scanner/providers/thetvdb.py b/scanner/scanner/providers/thetvdb.py index 3590fa63..54351e0e 100644 --- a/scanner/scanner/providers/thetvdb.py +++ b/scanner/scanner/providers/thetvdb.py @@ -11,7 +11,7 @@ from langcodes.data_dicts import LANGUAGE_REPLACEMENTS from ..cache import cache from ..models.collection import Collection, CollectionTranslation -from ..models.entry import Entry, EntryTranslation +from ..models.entry import Entry, EntryContent, EntryTranslation from ..models.genre import Genre from ..models.metadataid import EpisodeId, MetadataId, SeasonId from ..models.movie import Movie, MovieStatus, MovieTranslation, SearchMovie @@ -541,8 +541,12 @@ class TVDB(Provider): thumbnail=f"https://artworks.thetvdb.com{entry['image']}" if entry["image"] else None, - # Mark specials as non-critical, waiting for https://github.com/thetvdb/v4-api/issues/350 - criticalToStory=entry["seasonNumber"] != 0 or entry["isMovie"], + # Mark specials as ova, waiting for https://github.com/thetvdb/v4-api/issues/350 + content=( + EntryContent.STORY + if entry["seasonNumber"] != 0 or entry["isMovie"] + else EntryContent.OVA + ), slug=None, season_number=entry["seasonNumber"], episode_number=entry["number"],