feat(74): per-channel On Now/Next transient overlay #569

Merged
timothy merged 10 commits from feat/74-on-now-next-overlay into main 2026-07-22 22:36:42 +02:00
Owner

Implements #74 — a per-channel "On Now / Next" transient EPG overlay burned onto the transcoded stream at each program change, reusing the existing SkiaSharp graphics engine.

What shipped

  • ChannelGraphicsElement join (5th, mirrors DecoGraphicsElement) + dual-provider migration — the first channel-level graphics-element attachment (previously only Playout/ProgramScheduleItem/BlockItem/Deco).
  • Selector base layer: GraphicsElementSelector appends channel elements at the fall-through; a deco in Override/Disable (and Merge/Override during filler without UseGraphicsElementsDuringFiller) suppresses them; HLS-Direct renders none. Eager-loaded in FFmpegProcessHandler.
  • Seeded built-in on-now-next.yml text element — materialized once (marker graphics.on_now_next_seeded, adopt-not-clobber à la #67); row created by the existing refresh.
  • REST: channel graphicsElementIds: int[] (full-replace, reconciled) + server-derived builtIn on GraphicsElementResponseModel (filename discriminator, not name).
  • SPA: Branding-tab "Show On Now / Next overlay" toggle mirroring the logo-bug switch; draft round-trips graphicsElementIds.
  • Docs + decision record graphics.channel-level-attachment.

Verification

  • .NET suite 182/182; web tests 25/25 (4 new toggle tests, incl. round-trip); decisions_validate OK; format + BOM gates clean.
  • Whole-branch adversarial review (Opus): MERGEABLE, 0 Critical/Important; 5 Minors deferred to follow-up #568.
  • Live-E2E (running instance): seed builtIn:true + channel PUT graphicsElementIds attach/detach round-trip. Visual pixel render deferred to post-merge on a content-bearing instance (see Done-when).

Design + plan: docs/superpowers/{specs,plans}/2026-07-22-on-now-next-overlay*.

fixes #74

🤖 Generated with Claude Code

Implements #74 — a per-channel "On Now / Next" transient EPG overlay burned onto the transcoded stream at each program change, reusing the existing SkiaSharp graphics engine. ## What shipped - **`ChannelGraphicsElement` join** (5th, mirrors `DecoGraphicsElement`) + dual-provider migration — the first *channel-level* graphics-element attachment (previously only Playout/ProgramScheduleItem/BlockItem/Deco). - **Selector base layer**: `GraphicsElementSelector` appends channel elements at the fall-through; a deco in Override/Disable (and Merge/Override during filler without `UseGraphicsElementsDuringFiller`) suppresses them; HLS-Direct renders none. Eager-loaded in `FFmpegProcessHandler`. - **Seeded built-in `on-now-next.yml`** text element — materialized once (marker `graphics.on_now_next_seeded`, adopt-not-clobber à la #67); row created by the existing refresh. - **REST**: channel `graphicsElementIds: int[]` (full-replace, reconciled) + server-derived `builtIn` on `GraphicsElementResponseModel` (filename discriminator, not name). - **SPA**: Branding-tab "Show On Now / Next overlay" toggle mirroring the logo-bug switch; draft round-trips `graphicsElementIds`. - **Docs + decision record** `graphics.channel-level-attachment`. ## Verification - .NET suite 182/182; web tests 25/25 (4 new toggle tests, incl. round-trip); `decisions_validate` OK; format + BOM gates clean. - Whole-branch adversarial review (Opus): **MERGEABLE**, 0 Critical/Important; 5 Minors deferred to follow-up #568. - Live-E2E (running instance): seed `builtIn:true` + channel PUT `graphicsElementIds` attach/detach round-trip. Visual pixel render deferred to post-merge on a content-bearing instance (see Done-when). Design + plan: `docs/superpowers/{specs,plans}/2026-07-22-on-now-next-overlay*`. fixes #74 🤖 Generated with [Claude Code](https://claude.com/claude-code)
timothy added 10 commits 2026-07-22 22:13:47 +02:00
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(74): tighten overlay suppression rule (Merge-during-filler also clears)
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 15s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 17s
PR Gates / Docs update reminder (pull_request) Successful in 20s
PR Gates / decisions lifecycle (pull_request) Successful in 22s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 14m25s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 16m45s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 16m51s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 21m18s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
b7d58bbf32
Folds whole-branch review finding #2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Review-verdict: MERGEABLE @ b7d58bbf

Whole-branch adversarial review (Opus) over the full branch diff: 0 Critical/Important, 5 deferrable Minors (follow-up #568). Precedence, reconcile, seed lifecycle, migration parity, and security all traced clean. Write-path live-E2E confirmed. Visual pixel render deferred to post-merge (Done-when).

Review-verdict: MERGEABLE @ b7d58bbf Whole-branch adversarial review (Opus) over the full branch diff: 0 Critical/Important, 5 deferrable Minors (follow-up #568). Precedence, reconcile, seed lifecycle, migration parity, and security all traced clean. Write-path live-E2E confirmed. Visual pixel render deferred to post-merge (Done-when).
timothy merged commit 7080f63ebe into main 2026-07-22 22:36:42 +02:00
timothy deleted branch feat/74-on-now-next-overlay 2026-07-22 22:36:42 +02:00
Sign in to join this conversation.