• v26.11.0
    Build ErsatzTV Image / CI image pin matches docker/ci (push) Has been skipped
    Build ErsatzTV Image / Docs update reminder (push) Has been skipped
    Build ErsatzTV Image / decisions.md append-only (push) Has been skipped
    Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
    Build ErsatzTV Image / Functional E2E (curl contracts) (push) Has been skipped
    Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
    Build CI Toolchain Image / Build & push CI image (push) Successful in 21s
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 7m13s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 19m34s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 7m53s
    Stable

    timothy released this 2026-07-20 22:22:04 +02:00 | 637 commits to main since this release

    Fixes ~50% channel cold-start failures on Intel QuickSync hardware, unifies the channel logo with the on-screen bug, and hardens the Jellyfin scanner and remote-stream playback paths. 83 commits since v26.10.0.

    Upgrade note — a default changes. QsvPreferNativeDecoder ships ON, so every existing QSV FFmpeg profile switches to VA-API decoding on upgrade. This is the intended fix for #498; turn it off per-profile if you need the old strict-QSV decoder back.

    Hardware acceleration (#498)

    • QSV profiles now decode via VA-API while still encoding with QSV, mirroring Jellyfin's "Prefer OS native decoders". The strict QSV decoder failed on imperfect H.264 — measured at 3 fatal decoder-open failures across 6 channel cold-starts on an Intel i7-10700K.
    • New per-profile QsvPreferNativeDecoder field (default on) + a "Prefer native decoder" checkbox on QSV profiles, carried through the domain, FFmpeg pipeline, REST layer, and SPA.

    Channel logo / on-screen bug (#67)

    • One shared Channel Bug watermark preset drives both the channel listing logo and the on-screen bug — no more maintaining two images.
    • "Use logo as on-screen bug" toggle with a live geometry preview in the channel editor; the watermarks screen shows resolved bug geometry; new channels default to the preset.

    Jellyfin scanning

    • Support mixed-content libraries — one Jellyfin library holding more than one media kind (#489)
    • Resolve LibraryFolder from the DB so music-video scans stop throwing NullReferenceException (#488)
    • Reconcile removed music videos (#494) and music-video metadata collections (#497) on rescan

    Playback resilience

    • Probe media-server remote-stream URLs before handing them to ffmpeg; only a redirected 404 fails closed (#473)
    • Probe external-JSON remote-stream URLs the same way (#480)
    • Cascade FileNotFound from removed shows/seasons down to their descendants (#476)
    • Guard media-server library sweeps against successful-but-empty fetches — an empty 200 no longer nukes a library (#477)

    Scheduling & UI

    • Weighted distribution in the SPA — per-source weight inputs + WeightedShuffle playback order (#404)
    • Render real channel logos in the guide grid and channels list (#464)
    • Bound the schedules "Active schedule" selector so it stops overlapping the header (#463)

    Performance & instrumentation

    • Sub-split the HLS cold-start startup phase into honest buckets, with a stale-playlist guard (#472)
    • TTL-cache health-check results; ?refresh=true forces a fresh run (#431)

    CI / tooling

    • Format gate now uses dotnet format whitespace --folder: ~480s → ~0.5s (#469)
    • Sample true peak-anon memory in the test job rather than cache-inflated memory.peak (#412)
    • Deterministic functional-E2E for the playout-build lock 409 + isLocked projection (#444)

    Infrastructure

    • First release deployed to jazz (192.168.1.29) — the media transcoders moved off bumblebee on 2026-07-20 (server-management#633). docs/ci-cd.md now opens with a Hosts table and a name-reuse warning: jazz was an earlier name for the .99 host, so resolve hostnames by IP, not by name (#501, #507).

    Release process: cut on green main @ 601d855b; dotnet list package --vulnerable --include-transitive clean across 15 projects; full local test gate green (3945 passed, 0 failed); carries a dual-provider EF migration (Add_FFmpegProfile_QsvPreferNativeDecoder, SQLite + MySQL); docs/decisions.md had no superseded entries to consolidate. Prod follows the floating :prod tag — promoted via Komodo DeployStack media-servers after the immutable :26.11.0 candidate passes scripts/security-scan.sh on jazz.

    Downloads
  • v26.10.0
    Build ErsatzTV Image / Functional E2E (curl contracts) (push) Has been skipped
    Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
    Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
    Build ErsatzTV Image / CI image pin matches docker/ci (push) Has been skipped
    Build ErsatzTV Image / Docs update reminder (push) Has been skipped
    Build ErsatzTV Image / decisions.md append-only (push) Has been skipped
    Build CI Toolchain Image / Build & push CI image (push) Failing after 10m41s
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 18m20s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 18m31s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m58s
    Stable

    timothy released this 2026-07-18 21:39:25 +02:00 | 722 commits to main since this release

    First fork release of the Auto-Tune channel workflow and weighted content distribution, plus scheduling refactors, health-check remediation UX, cold-start instrumentation, and security hardening. 170 commits since v26.9.0.

    Auto-Tune (new)

    • Backend to enumerate library metadata and preview + bulk-create channels (#69, #379)
    • SPA wizard: Configure → Preview → Create (#69, #389)
    • Per-channel DetailPanel slide-over + content-source member read endpoint (#386, #384)
    • Per-channel overrides in bulk-create (#385)
    • Per-source rotation weights + query corrections (#425)

    Scheduling & distribution

    • WeightedShuffle playback order — weighted / fair-share content distribution (#70)
    • Per-playout reshuffle + shuffle-state surfacing (#71)
    • SmartCollection visual rule builder in the editor (#176)
    • ShuffleSourceBuilder extraction — removes PlaylistEnumerator's cross-engine reach-in (#380)
    • Unsupported PlaybackOrder now fails loud at build time + engine-coverage tripwire (#403)
    • Golden characterization tests for playout building; clock-boundary padding chars (#163, #77)

    Health checks & UI

    • Guided remediation for health checks (server-declared {Kind, Target}) (#164)
    • Collapsible sidebar + nav-group accordions (#396)

    Performance & instrumentation

    • HLS cold-start latency instrumentation — phase split (setup/startup/fill) + feature flags (#350)

    Security & robustness hardening

    • Paginate GET /api/v1/search/all-items to cap DoS exposure (#293)
    • XML-escape access_token in XMLTV guide output (#376)
    • Idempotent concurrent Add*ToCollection instead of a composite-PK 500 (#308)
    • Break the troubleshoot segment-wait loop on ffmpeg failure (#320)

    Fixes

    • Real per-channel playout count; flag channels that will never play (#72)
    • Library-level LastScan recorded after a successful local scan; never-scanned reports null for API/MCP parity (#264, #409)
    • Validate playlist name on rename (#327); reject Mirror channel with a playout — 422 (#401)
    • Correct Plex budget-exhausted guidance when no servers exist (#367); log scan cancellation below ERROR (#410)

    CI / infra

    • Shared CI toolchain image + runner-lane rebalance (#390); compiler-server memory + mysql caps (#406)
    • Docs-only heavy-job skip, shallow-checkout safe (#416); skip re-validating an already-green identical merge tree (#420)
    • ZAP warning vs failure exit-code handling in security-scan (#338)

    Release process: cut on green main @ df8c5202; no vulnerable transitive packages; decisions.md carried no superseded entries to consolidate. Prod follows the floating :prod tag — promotion via Komodo after the immutable :26.10.0 candidate passes security-scan.sh.

    Downloads
  • v26.9.0
    Build ErsatzTV Image / Docs update reminder (push) Has been skipped
    Build ErsatzTV Image / decisions.md append-only (push) Has been skipped
    Build ErsatzTV Image / Functional E2E (curl contracts) (push) Has been skipped
    Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
    Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m51s
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 6m15s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 7m9s
    Stable

    timothy released this 2026-07-16 22:24:15 +02:00 | 892 commits to main since this release

    Fork release continuing from v26.8.0.

    Features

    • Configurable advertised IPTV base URL for M3U/XMLTV (#340). Optional iptv.base_url setting (Settings → IPTV) that pins absolute M3U (guide/logo/stream) and XMLTV URLs to a fixed public origin instead of echoing the incoming request Host — the fix for downstream consumers (e.g. Dispatcharr → Kodi) that can't resolve an internal Docker hostname. Blank/unset preserves today's request-derived behavior byte-for-byte; backed by ConfigElement, no DB migration.

    Fixes

    • SPA left-sidebar horizontal scroll + body margin (#377, #373). Body margin reset + nav box-sizing resets.
    • Report direct streams as "on air" (#99).
    • Plex "authorized but no servers" is now a coherent, recoverable state (#345).
    • Protect local-library filesystem path details behind authentication (#371).

    Internal / CI / refactor

    • App shell + routing extraction and explicit primary-action ownership (#247); Playouts screen extraction (#245).
    • Analyzer promotion: incremental latest-All enforcement (#375).
    • Code-coverage collection + summary in CI (#15); advisory functional-E2E curl-contract harness (#299).
    • Dependency updates: Humanizer.Core 3.0.10 (#328), JetBrains.ReSharper.GlobalTools 2025.3.4.1 (#329).
    • Docs: decisions.md consolidated into topic files under docs/decisions/ (optimistic-concurrency, api-auth-security, release-ci-governance, spa-modularization).

    Images: 192.168.1.95:3000/timothy/ersatztv:26.9.0 (immutable) / :prod.

    Downloads
  • v26.8.0
    Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 9s
    Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 10s
    Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 12s
    Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 13s
    Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m37s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 10m45s
    Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
    Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
    Build ErsatzTV Image / Docs update reminder (push) Has been skipped
    Build ErsatzTV Image / decisions.md append-only (push) Has been skipped
    Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 9m49s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 10m51s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m47s
    Stable

    timothy released this 2026-07-13 19:50:39 +02:00 | 956 commits to main since this release

    Secured / versioned ChicoryTV SPA + REST API go-live release (#335). Hardens the authentication, concurrency, and HTTP-contract surface before the API and SPA are treated as a stable public interface.

    Features

    • Browser SPA session auth (#295) — session-OR-key gate enforced server-side (PR1, #295), plus the SPA session foundation: boot gate, CSRF header, login/setup/logout, machine-key screen and password change (PR2, PR #316).
    • SPA API-key entry, sending the key on all methods (#197).
    • API versioning with base-url-aware deprecation Link headers (#286); collections scan-status REST surface + authoritative SPA reconcile (#271).

    Security

    • Enforcing CSP + Permissions-Policy on the host (#319).
    • Side-effecting GETs POST-ified — troubleshoot actions and GET /api/auth/machine-key no longer mutate on GET (#301).
    • Repeatable black-box security scan in CI: authenticated ZAP + semgrep (#314).

    Fixes

    • If-Match now evaluates per RFC 7232 — a valid-but-non-matching precondition returns 412, not 400; quote-aware scanner with OWS trimming (#265, PR #322).
    • Force-write non-If-Match root writers past a concurrent Version bump so rotation survives a race; aggregate ETag rotates on Collection/Playout config siblings (#269, PR #302).
    • Content-aware stable child identity for schedule-item replace (#259, PR #276).

    Images: 192.168.1.95:3000/timothy/ersatztv:26.8.0.

    Downloads
  • v26.7.0
    Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 5m47s
    Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m29s
    Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
    Build ErsatzTV Image / Docs update reminder (push) Has been skipped
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m23s
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 5m48s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 5m8s
    Stable

    timothy released this 2026-07-11 21:37:03 +02:00 | 1063 commits to main since this release

    Blazor-removal release: ChicoryTV becomes the only UI (#91 phase b). Large release (~220 commits since v26.6.0) closing out SPA parity, media-source management, and a batch of scheduling/locking soundness fixes.

    Features

    • Media sources: SPA management screens + write REST API (#202, PR #262) — local, Plex, Jellyfin/Emby add/edit/scan flows.
    • Shared "Add-to" layer — search + media mutation surface across screens (#208/#209, PR #216).
    • Playouts: delete/reset/erase; collections custom-order & all-kind adds (#210/#211/#213, PR #214).
    • SPA playback troubleshooting screen + status/subtitles/stream-selector endpoints (#145, PR #199).
    • Playlist CRUD API + SPA editor (#153, PR #195); multi/rerun-collection editor screens (#151/#152, PR #194).
    • Schedules editor full mutation depth + channel-editor gaps (#207/#212/#126, PR #229).

    Fixes

    • Locking soundness: EntityLocker atomicity + scan-lifecycle honesty (#231/#232, PR #241); release troubleshooting + playout locks on all terminal paths (#233/#234, PR #250).
    • Scheduling: stop silently resetting fill-group state; invalidate deco edits (#251/#252, PR #258).
    • Reviewer post-merge blockers: empty-lineup bare create (#212) + dirty-guard popstate/shuffle-toggle (#230) (PR #242).
    • OpenAPI spec property naming now mirrors the runtime Newtonsoft serializer (#198, PR #201); rerun-collection existence-check per selection type (#193, PR #200).

    Internal / CI / refactor

    • Optimistic-concurrency contract rolled out across Block, Template, DecoTemplate, Playlist and schedule-items (#253, PRs #263/#268).
    • SPA modularization: ChannelsScreen extracted from App.tsx (#244, epic #243 phase 1, PR #249).
    • Husky pre-commit / pre-push / commit-msg guardrails (#273); CI build speed-ups (NuGet cache, shallow checkout) (#190/#192); CI MySQL host-port unpin to fix runner collisions (#236); docs-first rule hardened + non-blocking parity-doc reminder (#196).

    Images: 192.168.1.95:3000/timothy/ersatztv:26.7.0.

    Downloads
  • v26.6.0 — ChicoryTV SPA parity release
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m36s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m39s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m55s
    Stable

    timothy released this 2026-07-08 19:07:40 +02:00 | 1286 commits to main since this release

    First release carrying the full SPA-parity feature set beyond the phase-a cutover (v26.5.0).

    Highlights since v26.5.0

    • Full scheduling parity in the SPA (#144/#162): blocks, scheduling templates, decos + deco templates, playout create/editors, block/template copy.
    • Media: browse/search/trash + detail pages + image folder browser (#141/#161).
    • Screens: Trakt lists, FFmpeg profile/filler/watermark editors, collections (manual+smart), logs & troubleshooting, channel edit, Classic UI escape hatch (#140–#147).
    • Troubleshooting: block-playout history + sequential-YAML schedule validator (#158).
    • Fixes: library picker artwork URLs + season drill-in (#180).
    • This batch: collection-items API + real SPA listing (#155); multi/rerun collections REST API backend (#151/#152); security-registry assembly scan (#184); parallelized GET /api/search; Trakt SPA link; onboarding/convention docs + testing map + generated endpoint index (#185).

    Still pending (not in this release)

    Blazor removal (#91 phase b) remains gated on the multi/rerun + playlist SPA editors and playback troubleshooting (#145) — it lands in v26.7.0.

    Images: 192.168.1.95:3000/timothy/ersatztv:26.6.0 (immutable) / :prod. Prod's Komodo media-servers stack follows the floating :prod tag — no manual pin bump; deploy the stack once the immutable :26.6.0 candidate passes the release security scans.

    Downloads
  • v26.5.0
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m11s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m34s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m33s
    Stable

    timothy released this 2026-07-07 11:23:07 +02:00 | 1396 commits to main since this release

    SPA cutover release (#91 phase a): ChicoryTV becomes the default UI.

    Features

    • SPA cutover — root route (#91, PR #148): / and legacy Blazor routes now serve / 302-redirect to the ChicoryTV SPA at /app. The React SPA is the default UI; the legacy Blazor Server UI remains available as a Classic-UI escape hatch (its removal follows in v26.7.0, #91 phase b).

    Images: 192.168.1.95:3000/timothy/ersatztv:26.5.0.

    Downloads
  • v26.4.0
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m9s
    Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m39s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m6s
    Stable

    timothy released this 2026-07-07 10:20:30 +02:00 | 1400 commits to main since this release

    First fork release carrying application changes: the REST API foundation and the ChicoryTV React SPA foundation land side by side (~170 commits since v26.3.1).

    Features

    • ChicoryTV SPA foundation (#59 stack, #120) — new React/Vite single-page app served at /app, with the ChicoryTV rebrand (#90/#139).
    • SPA screens: Dashboard with real data sources (#109), Channels (#84), Schedule editor (#86), Playouts (#87), Libraries (#88), Guide/EPG (#85), Settings (#93), Channel Builder (#89).
    • REST API buildout — the programmatic surface the SPA (and future MCP) run on:
      • Collections (#35/#45), schedule endpoints, playout endpoints (#37/#51, #100/#101/#107/#110), FFmpeg profile endpoints, standardized error contract (#46/#47).
      • Channel state / now-playing (#97/#112), JSON channel guide (#102/#119), schedule item duration estimates (#111/#118), artwork upload (#104/#117).
      • Media sources + scan status (#103/#106/#115), health endpoints (#108/#114), filler/watermark/graphics list endpoints (#105/#113).
      • Library browse + search (#65/#130), channel templates entity + CRUD (#64/#133), composite create-channel endpoint (#63/#134).
    • Core: active-session tracking for direct-streaming modes (#99/#121); Jellyfin/Emby music-video support (#42/#55); FFmpeg 8 work (#9/#56).

    Security

    • Scriban.Signed 6.5.2 → 7.2.5 (GHSA-5wr9-m6jw-xx44) (#137).
    • Default-deny on mutating API writes; standardized write authorization.

    Internal / CI / refactor

    • Docker web-build stage fixed to a valid node:22-bookworm-slim base (#122).
    • Channel logo generator made testable (#39/#53); Renovate patch updates applied (#61).

    Images: 192.168.1.95:3000/timothy/ersatztv:26.4.0.

    Downloads
  • v26.3.1
    Build ErsatzTV Image / Build & test (.NET) (push) Successful in 2m43s
    Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m56s
    Stable

    timothy released this 2026-06-27 00:35:35 +02:00 | 1573 commits to main since this release

    First fork build: upstream ErsatzTV 26.3.0 rebuilt on our infrastructureno application changes. A patch bump because nothing functional changed.

    Internal / CI / refactor

    • New Gitea Actions build pipeline; retired upstream GitHub workflows (#4).
    • Dockerfile now references the fork's stripped, amd64-only FFmpeg base image (ersatztv-ffmpeg).
    • Hardened build pipeline per adversarial review; fixed the Serilog readiness marker for the HTTP smoke test.
    • Restore no longer fails on low/moderate/high NuGet audit advisories (criticals still block).
    • Removed external dependencies (Bugsnag, Trakt telemetry) (#2840).
    • Enshrined the fork versioning scheme; added architecture/fork-maintenance docs (#6) and the Task Completion Protocol.

    Images: 192.168.1.95:3000/timothy/ersatztv:26.3.1 (= :prod, app-identical to upstream 26.3.0).

    Downloads