diff --git a/api/src/controllers/seed/insert/entries.ts b/api/src/controllers/seed/insert/entries.ts index e91c882a..592ff4dd 100644 --- a/api/src/controllers/seed/insert/entries.ts +++ b/api/src/controllers/seed/insert/entries.ts @@ -47,7 +47,7 @@ export const insertEntries = async ( items: (SeedEntry | SeedExtra)[], onlyExtras = false, ) => { - if (!items) return []; + if (!items.length) return []; const retEntries = await db.transaction(async (tx) => { const vals: EntryI[] = await Promise.all( diff --git a/api/src/controllers/seed/insert/seasons.ts b/api/src/controllers/seed/insert/seasons.ts index 5f43b8a0..f3075380 100644 --- a/api/src/controllers/seed/insert/seasons.ts +++ b/api/src/controllers/seed/insert/seasons.ts @@ -12,13 +12,18 @@ export const insertSeasons = async ( show: { pk: number; slug: string }, items: SeedSeason[], ) => { + if (!items.length) return []; + 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}`, + slug: + season.seasonNumber === 0 + ? `${show.slug}-specials` + : `${show.slug}-s${season.seasonNumber}`, nextRefresh: guessNextRefresh(season.startAir ?? new Date()), }; }); diff --git a/api/src/models/examples/bubble.ts b/api/src/models/examples/bubble.ts index fef87862..498c6e5c 100644 --- a/api/src/models/examples/bubble.ts +++ b/api/src/models/examples/bubble.ts @@ -12,6 +12,7 @@ export const bubbleVideo: Video = { title: "bubble", years: [2022], from: "guessit", + history: [], }, createdAt: "2024-11-23T15:01:24.968Z", updatedAt: "2024-11-23T15:01:24.968Z", @@ -33,7 +34,7 @@ export const bubble: SeedMovie = { "https://image.tmdb.org/t/p/original/a8Q2g0g7XzAF6gcB8qgn37ccb9Y.jpg", banner: null, logo: "https://image.tmdb.org/t/p/original/ihIs7fayAmZieMlMQbs6TWM77uf.png", - trailerUrl: "https://www.youtube.com/watch?v=vs7zsyIZkMM", + trailer: "https://www.youtube.com/watch?v=vs7zsyIZkMM", }, ja: { name: "バブル:2022", @@ -47,7 +48,7 @@ export const bubble: SeedMovie = { thumbnail: "https://image.tmdb.org/t/p/original/jp.jpg", banner: null, logo: null, - trailerUrl: "https://www.youtube.com/watch?v=vs7zsyIZkMM", + trailer: "https://www.youtube.com/watch?v=vs7zsyIZkMM", }, }, genres: ["animation", "adventure", "science-fiction", "fantasy"], diff --git a/api/src/models/examples/dune-1984.ts b/api/src/models/examples/dune-1984.ts index e43656d7..d64dc06e 100644 --- a/api/src/models/examples/dune-1984.ts +++ b/api/src/models/examples/dune-1984.ts @@ -12,6 +12,7 @@ export const dune1984Video: Video = { title: "dune", years: [1984], from: "guessit", + history: [], }, createdAt: "2024-12-02T11:45:12.968Z", updatedAt: "2024-12-02T11:45:12.968Z", @@ -33,7 +34,7 @@ export const dune1984: SeedMovie = { "https://image.tmdb.org/t/p/original/pCHV6BntWLO2H6wQOj4LwzAWqpa.jpg", banner: null, logo: "https://image.tmdb.org/t/p/original/olbKnk2VvFcM2STl0dJAf6kfydo.png", - trailerUrl: "https://www.youtube.com/watch?v=vczYTLQ6oiE", + trailer: "https://www.youtube.com/watch?v=vczYTLQ6oiE", }, }, genres: ["adventure", "drama", "science-fiction"], diff --git a/api/src/models/examples/dune-2021.ts b/api/src/models/examples/dune-2021.ts index 6287491d..f8e32e72 100644 --- a/api/src/models/examples/dune-2021.ts +++ b/api/src/models/examples/dune-2021.ts @@ -12,6 +12,7 @@ export const duneVideo: Video = { title: "dune", years: [2021], from: "guessit", + history: [], }, createdAt: "2024-12-02T10:10:24.968Z", updatedAt: "2024-12-02T10:10:24.968Z", @@ -33,7 +34,7 @@ export const dune: SeedMovie = { "https://image.tmdb.org/t/p/original/k2ocXnNkmvE6rJomRkExIStFq3v.jpg", banner: null, logo: "https://image.tmdb.org/t/p/original/5nDsd3u1c6kDphbtIqkHseLg7HL.png", - trailerUrl: "https://www.youtube.com/watch?v=n9xhJrPXop4", + trailer: "https://www.youtube.com/watch?v=n9xhJrPXop4", }, }, genres: ["adventure", "drama", "science-fiction", "action"], diff --git a/api/src/models/examples/made-in-abyss.ts b/api/src/models/examples/made-in-abyss.ts index 886466ac..fae77b19 100644 --- a/api/src/models/examples/made-in-abyss.ts +++ b/api/src/models/examples/made-in-abyss.ts @@ -12,6 +12,7 @@ export const madeInAbyssVideo: Video = { episodes: [{ season: 1, episode: 13 }], kind: "episode", from: "guessit", + history: [], }, createdAt: "2024-11-23T15:01:24.968Z", updatedAt: "2024-11-23T15:01:24.968Z", @@ -56,7 +57,7 @@ export const madeInAbyss = { "https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg", logo: "https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png", banner: null, - trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s", + trailer: "https://www.youtube.com/watch?v=ePOyy6Wlk4s", }, ja: { name: "メイドインアビス", @@ -90,7 +91,7 @@ export const madeInAbyss = { "https://image.tmdb.org/t/p/original/Df9XrvZFIeQfLKfu8evRmzvRsd.jpg", logo: "https://image.tmdb.org/t/p/original/7hY3Q4GhkiYPBfn4UoVg0AO4Zgk.png", banner: null, - trailerUrl: "https://www.youtube.com/watch?v=ePOyy6Wlk4s", + trailer: "https://www.youtube.com/watch?v=ePOyy6Wlk4s", }, }, genres: [ diff --git a/api/src/models/movie.ts b/api/src/models/movie.ts index c575ae5d..3d14dc4f 100644 --- a/api/src/models/movie.ts +++ b/api/src/models/movie.ts @@ -80,12 +80,19 @@ export const SeedMovie = t.Composite([ }), translations: TranslationRecord( t.Composite([ - t.Omit(MovieTranslation, ["poster", "thumbnail", "banner", "logo"]), + t.Omit(MovieTranslation, [ + "poster", + "thumbnail", + "banner", + "logo", + "trailerUrl", + ]), t.Object({ poster: t.Nullable(SeedImage), thumbnail: t.Nullable(SeedImage), banner: t.Nullable(SeedImage), logo: t.Nullable(SeedImage), + trailer: t.Nullable(SeedImage), latinName: t.Optional(Original.properties.latinName), }), ]), diff --git a/api/src/models/season.ts b/api/src/models/season.ts index 79c11976..d37619b5 100644 --- a/api/src/models/season.ts +++ b/api/src/models/season.ts @@ -8,7 +8,7 @@ import { TranslationRecord } from "./utils/language"; import { Resource } from "./utils/resource"; export const BaseSeason = t.Object({ - seasonNumber: t.Integer({ minimum: 1 }), + seasonNumber: t.Integer({ minimum: 0 }), startAir: t.Nullable(t.String({ format: "date" })), endAir: t.Nullable(t.String({ format: "date" })), diff --git a/api/src/models/serie.ts b/api/src/models/serie.ts index 46a2d153..61902a46 100644 --- a/api/src/models/serie.ts +++ b/api/src/models/serie.ts @@ -96,12 +96,19 @@ export const SeedSerie = t.Composite([ }), translations: TranslationRecord( t.Composite([ - t.Omit(SerieTranslation, ["poster", "thumbnail", "banner", "logo"]), + t.Omit(SerieTranslation, [ + "poster", + "thumbnail", + "banner", + "logo", + "trailerUrl", + ]), t.Object({ poster: t.Nullable(SeedImage), thumbnail: t.Nullable(SeedImage), banner: t.Nullable(SeedImage), logo: t.Nullable(SeedImage), + trailer: t.Nullable(SeedImage), latinName: t.Optional(Original.properties.latinName), }), ]), diff --git a/api/tests/movies/get-all-movies-with-null.test.ts b/api/tests/movies/get-all-movies-with-null.test.ts index 0b140396..3a7d53d9 100644 --- a/api/tests/movies/get-all-movies-with-null.test.ts +++ b/api/tests/movies/get-all-movies-with-null.test.ts @@ -21,7 +21,7 @@ describe("with a null value", () => { // instead we just make a new file for those /shrug // see: https://github.com/oven-sh/bun/issues/5738 beforeAll(async () => { - await createMovie({ + const [ret, body] = await createMovie({ slug: "no-air-date", translations: { en: { @@ -34,7 +34,7 @@ describe("with a null value", () => { tagline: null, tags: [], thumbnail: null, - trailerUrl: null, + trailer: null, }, }, genres: [], @@ -46,6 +46,7 @@ describe("with a null value", () => { externalId: {}, studios: [], }); + expectStatus(ret, body).toBe(201); }); it("sort by dates desc with a null value", async () => { diff --git a/api/tests/movies/seed-movies.test.ts b/api/tests/movies/seed-movies.test.ts index 242a1161..6da873b8 100644 --- a/api/tests/movies/seed-movies.test.ts +++ b/api/tests/movies/seed-movies.test.ts @@ -49,7 +49,7 @@ describe("Movie seeding", () => { thumbnail: null, banner: null, logo: null, - trailerUrl: null, + trailer: null, }, }, }); @@ -154,7 +154,7 @@ describe("Movie seeding", () => { poster: null, thumbnail: null, logo: null, - trailerUrl: null, + trailer: null, }, }, }); @@ -180,7 +180,7 @@ describe("Movie seeding", () => { poster: null, thumbnail: null, logo: null, - trailerUrl: null, + trailer: null, }, }, }); @@ -308,7 +308,7 @@ describe("Movie seeding", () => { part: null, version: 1, rendering: "oeunhtoeuth", - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, }); expectStatus(vresp, video).toBe(201); @@ -334,7 +334,7 @@ describe("Movie seeding", () => { part: null, version: 2, rendering: "oeunhtoeuth", - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, }); expectStatus(vresp, video).toBe(201); @@ -359,7 +359,7 @@ describe("Movie seeding", () => { part: 1, version: 2, rendering: "oaoeueunhtoeuth", - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, }); expectStatus(vresp, video).toBe(201); @@ -385,14 +385,14 @@ describe("Movie seeding", () => { part: null, version: 1, rendering: "oeunhtoeuthoeu", - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, }, { path: "/video/bubble4.mkv", part: null, version: 1, rendering: "aoeuaoeu", - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, }, ]); expectStatus(vresp, video).toBe(201); diff --git a/api/tests/videos/getdel.test.ts b/api/tests/videos/getdel.test.ts index 64a6b78a..a3247d27 100644 --- a/api/tests/videos/getdel.test.ts +++ b/api/tests/videos/getdel.test.ts @@ -27,6 +27,7 @@ beforeAll(async () => { title: "mia", episodes: [{ season: 1, episode: 13 }], from: "test", + history: [], }, part: null, path: "/video/mia s1e13.mkv", @@ -40,6 +41,7 @@ beforeAll(async () => { episodes: [{ season: 2, episode: 1 }], years: [2017], from: "test", + history: [], }, part: null, path: "/video/mia 2017 s2e1.mkv", @@ -48,7 +50,7 @@ beforeAll(async () => { for: [{ slug: `${madeInAbyss.slug}-s2e1` }], }, { - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, part: null, path: "/video/bubble.mkv", rendering: "sha5", @@ -110,6 +112,7 @@ describe("Video get/deletion", () => { title: "mia", episodes: [{ season: 1, episode: 13 }], from: "test", + history: [], }, part: null, path: "/video/mia s1e13 unknown test.mkv", @@ -148,6 +151,7 @@ describe("Video get/deletion", () => { title: "mia", episodes: [{ season: 1, episode: 13 }], from: "test", + history: [], }, part: null, path: "/video/mia s1e13 mismatch.mkv", diff --git a/api/tests/videos/scanner.test.ts b/api/tests/videos/scanner.test.ts index 9cc4c04c..9e0760eb 100644 --- a/api/tests/videos/scanner.test.ts +++ b/api/tests/videos/scanner.test.ts @@ -18,7 +18,7 @@ beforeAll(async () => { describe("Video seeding", () => { it("Can create a video without entry", async () => { const [resp, body] = await createVideo({ - guess: { title: "unknown", from: "test" }, + guess: { title: "unknown", from: "test", history: [] }, part: null, path: "/video/unknown s1e13.mkv", rendering: "sha", @@ -50,6 +50,7 @@ describe("Video seeding", () => { title: "mia", episodes: [{ season: 1, episode: 13 }], from: "test", + history: [], }, part: null, path: "/video/mia s1e13.mkv", @@ -82,7 +83,7 @@ describe("Video seeding", () => { it("With movie", async () => { const [resp, body] = await createVideo({ - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, part: null, path: "/video/bubble.mkv", rendering: "sha3", @@ -114,7 +115,7 @@ describe("Video seeding", () => { it("Conflicting path", async () => { const [resp, body] = await createVideo({ - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, part: null, path: "/video/bubble.mkv", rendering: "sha4", @@ -150,6 +151,7 @@ describe("Video seeding", () => { title: "mia", episodes: [{ season: 2, episode: 1 }], from: "test", + history: [], }, part: null, path: "/video/mia s2e1.mkv", @@ -192,6 +194,7 @@ describe("Video seeding", () => { title: "mia", episodes: [{ season: 0, episode: 3 }], from: "test", + history: [], }, part: null, path: "/video/mia sp3.mkv", @@ -233,6 +236,7 @@ describe("Video seeding", () => { title: "mia", episodes: [{ season: 0, episode: 3 }], from: "test", + history: [], }, part: null, path: "/video/mia 13.5.mkv", @@ -274,6 +278,7 @@ describe("Video seeding", () => { title: "mia", episodes: [{ season: 1, episode: 13 }], from: "test", + history: [], externalId: { themoviedatabase: "72636", }, @@ -318,6 +323,7 @@ describe("Video seeding", () => { guess: { title: "bubble", from: "test", + history: [], externalId: { themoviedatabase: "912598", }, @@ -359,7 +365,7 @@ describe("Video seeding", () => { it("Different path, same sha", async () => { const [resp, body] = await createVideo({ - guess: { title: "bubble", from: "test" }, + guess: { title: "bubble", from: "test", history: [] }, part: null, path: "/video/bubble invalid-sha.mkv", rendering: "sha", @@ -377,6 +383,7 @@ describe("Video seeding", () => { guess: { title: "bubble", from: "test", + history: [], externalId: { themoviedatabase: "912598", }, @@ -423,6 +430,7 @@ describe("Video seeding", () => { guess: { title: "bubble", from: "test", + history: [], externalId: { themoviedatabase: "912598", }, @@ -470,6 +478,7 @@ describe("Video seeding", () => { guess: { title: "bubble", from: "test", + history: [], externalId: { themoviedatabase: "912598", }, @@ -491,6 +500,7 @@ describe("Video seeding", () => { guess: { title: "bubble", from: "test", + history: [], externalId: { themoviedatabase: "912598", }, @@ -541,6 +551,7 @@ describe("Video seeding", () => { { season: 2, episode: 1 }, ], from: "test", + history: [], }, part: null, path: "/video/mia s1e13 & s2e1 [tmdb=72636].mkv", diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 84c7a85c..deb0c9da 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -8,7 +8,7 @@ x-transcoder: &transcoder-base - transcoder ports: - "7666:7666" - restart: on-failure + restart: unless-stopped cpus: 1 env_file: - ./.env @@ -39,7 +39,7 @@ services: # ports: # - "3000:3000" # - "8081:8081" - # restart: on-failure + # restart: unless-stopped # environment: # - KYOO_URL=${KYOO_URL:-http://api:5000/api} # labels: @@ -50,7 +50,7 @@ services: build: context: ./auth dockerfile: Dockerfile.dev - restart: on-failure + restart: unless-stopped depends_on: postgres: condition: service_healthy @@ -71,7 +71,7 @@ services: build: context: ./api dockerfile: Dockerfile.dev - restart: on-failure + restart: unless-stopped depends_on: postgres: condition: service_healthy @@ -99,7 +99,7 @@ services: scanner: build: ./scanner - restart: on-failure + restart: unless-stopped depends_on: api: condition: service_started @@ -172,7 +172,7 @@ services: traefik: image: traefik:v3.4 - restart: on-failure + restart: unless-stopped command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" @@ -185,7 +185,7 @@ services: postgres: image: postgres:15 - restart: on-failure + restart: unless-stopped env_file: - ./.env volumes: