From 202be1ddd03897db1288fb23d8c3f18eb7f44727 Mon Sep 17 00:00:00 2001 From: Ash Date: Tue, 1 Sep 2026 14:43:28 +0100 Subject: [PATCH] fix(omdb): stop sending a series release's year to OMDb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A film's OMDb year IS its identity — "Ashfall" 1999 and "Ashfall" 2024 are different films, and y= is what tells OMDb which one — but a SERIES release's embedded year is not the same kind of fact. It is usually when the release's own season aired, not when the show debuted, and OMDb keys a series by the latter. "The Boys S05 Season 5 2026 1080p AMZN WEBRip..." parses year 2026 — the season's own air year. OMDb has no "The Boys" answering to y=2026, so the exact-match search comes back empty and falls back to an unrelated title that does happen to answer that year: wrong imdbId, wrong plot, wrong poster, on a title whose IMDb id and artwork torlink otherwise resolves correctly. Every season of a long-running or returning show carries a different embedded year, so this was not one show's edge case — it was every poster lookup for any series whose current season aired later than its debut. fetchTitleMetaByName now drops year for type: "series" before building either OMDb query it can send (the primary lookup and the episode-then-series-poster fallback). Shared by both front ends, so one change fixes it everywhere the terminal and the browser fetch title metadata by name. Found while verifying the show/season nesting work in a separate PR — "The Boys" and "The Boys S05" were both showing a poster that had nothing to do with the actual show. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_011QTsg7ie21bP9JpEPFMkyP --- src/recc/omdb.test.ts | 30 ++++++++++++++++++++++++++---- src/recc/omdb.ts | 15 +++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/recc/omdb.test.ts b/src/recc/omdb.test.ts index 5f555dcc..e5cd6d7a 100644 --- a/src/recc/omdb.test.ts +++ b/src/recc/omdb.test.ts @@ -66,13 +66,35 @@ describe("fetchTitleMeta (by id)", () => { }); describe("fetchTitleMetaByName", () => { - it("builds a title lookup with year and type", async () => { + it("builds a title lookup with year and type, for a film", async () => { + // A film's OMDb year IS its identity — Ashfall 1999 and Ashfall 2024 are + // different films — so unlike a series (below), it is sent unconditionally. const { impl, urls } = jsonImpl(200, { Response: "True", imdbID: "tt2", Plot: "P", Poster: "https://p.jpg" }); - const res = await fetchTitleMetaByName("Harrowgate", "KEY", { year: 2022, type: "series", fetchImpl: impl }); + const res = await fetchTitleMetaByName("Ashfall", "KEY", { year: 1999, type: "movie", fetchImpl: impl }); expect(res).toEqual({ ok: true, type: null, imdbId: "tt2", plot: "P", posterUrl: "https://p.jpg" }); const u = urls[0]!; - expect(u).toContain("t=Harrowgate"); - expect(u).toContain("y=2022"); + expect(u).toContain("t=Ashfall"); + expect(u).toContain("y=1999"); + expect(u).toContain("type=movie"); + }); + + it("drops the year for a series — it names the release's own air date, not the show's debut", async () => { + // "The Boys S05 Season 5 2026 1080p..." parses year 2026, the season's own + // air year. OMDb keys a series by when it DEBUTED (2019 here), so sending + // y=2026 finds no match and OMDb falls back to an unrelated title that + // happens to answer to that year — a real bug this protects against. + const { impl, urls } = jsonImpl(200, { Response: "True", imdbID: "tt1190634", Plot: "P", Poster: "https://p.jpg" }); + const res = await fetchTitleMetaByName("The Boys", "KEY", { year: 2026, type: "series", fetchImpl: impl }); + expect(res).toEqual({ + ok: true, + type: null, + imdbId: "tt1190634", + plot: "P", + posterUrl: "https://p.jpg", + }); + const u = urls[0]!; + expect(u).toContain("t=The+Boys"); + expect(u).not.toContain("y=2026"); expect(u).toContain("type=series"); }); diff --git a/src/recc/omdb.ts b/src/recc/omdb.ts index 723a7d5f..bb5408a2 100644 --- a/src/recc/omdb.ts +++ b/src/recc/omdb.ts @@ -96,8 +96,19 @@ export async function fetchTitleMetaByName( } = {}, ): Promise { if (!title.trim()) return { ok: false, error: "no title" }; + // A film's OMDb year IS its identity — "Ashfall" 1999 and "Ashfall" 2024 are + // different films, and `y=` is what tells OMDb which one. A SERIES release's + // year is not the same kind of fact: it is usually when the release's own + // season aired, not when the show debuted, and OMDb keys a series by the + // latter. "The Boys S05 Season 5 2026 1080p..." parses year 2026 — the + // season's air year — and OMDb has no "The Boys" answering to that year, so + // an exact-match search comes back empty and falls back to an unrelated + // title that does. Every season of a show would carry a different embedded + // year and searching wrongly narrowed on each one, so the correct fix is not + // sending y= for a series at all — the title alone is the disambiguator here. + const seriesSafeYear = opts.type !== "series" ? opts.year : undefined; const params = new URLSearchParams({ t: title.trim() }); - if (opts.year) params.set("y", String(opts.year)); + if (seriesSafeYear) params.set("y", String(seriesSafeYear)); if (opts.type) params.set("type", opts.type); const wantsEpisode = opts.season !== undefined && opts.episode !== undefined; if (opts.season !== undefined) params.set("Season", String(opts.season)); @@ -114,7 +125,7 @@ export async function fetchTitleMetaByName( // function — the terminal directly, the browser via `/api/title` — and a // fallback written twice is the copy-then-drift this codebase keeps recording. const seriesParams = new URLSearchParams({ t: title.trim() }); - if (opts.year) seriesParams.set("y", String(opts.year)); + if (seriesSafeYear) seriesParams.set("y", String(seriesSafeYear)); if (opts.type) seriesParams.set("type", opts.type); const series = await request(seriesParams, apiKey, opts, `by name ${title} (poster)`); // A failed fallback leaves the episode answer exactly as it was: no poster is