ARRFLIX/docs/30-v6-stable-success-2026-05-09.md
s8n 148b004026 doc 30 v6-stable success + snapshot save state
Owner pronounced "near perfect". Save current state as the rollback
target. Replace older 2026-05-08-pre-elegantfin snapshot.

Snapshot md5 364cc890c58f02d07cf50b43b31a48f0 — matches both prod
and dev deployed overlay.

Doc 30 lists every file/path-of-record + rollback procedure +
remaining roadmap items.

Tag this commit v6-stable-2026-05-09 after push.
2026-05-09 12:52:44 +01:00

7.6 KiB

30 — v6-stable success — 2026-05-09

Save state. Owner pronounced "near perfect". Both servers (prod + dev) byte-identical overlay (md5 364cc890c58f02d07cf50b43b31a48f0), both branding.xml parses cleanly, both EnableTonemapping=true, both serve /Branding/Css.css 36 256 B (Cineplex theme delivered to browser), playback verified visually green on dev and prod.

Tag: v6-stable-2026-05-09. Snapshot at snapshots/2026-05-09-v6-stable/index.html (md5 matches deployed overlay). Older snapshot snapshots/2026-05-08-pre-elegantfin/ removed — replaced by this one.


What works

Surface State
Logo center ARRFLIX wordmark dead-center in header (235x85 PNG inlined as data-URL from branding.xml).
Nav left MOVIES + SERIES uppercase links inside .headerLeft. Bare #/movies.html and #/tv.html hrefs (no topParentId query).
Search right Stock .headerSearchButton pushed to flex-end via .headerRight{justify-content:flex-end}.
Login page Stock-with-Cineplex (auth-gated body.arrflix-themed). ARRFLIX top-left red, Manual Login form, Welcome footer. No user picker, no Quick Connect.
Video player .skinHeader hidden via body.arrflix-video-active — no theme bar leaking on top of <video>. Specificity (0,4,2) beats Cineplex's display:flex !important rule (0,3,2).
Favicon A-mark (red Netflix-style "A") in browser tab. Hijack JS removes stock wordmark icon links + pins data-arrflix-icon="A" href against the older lockFavicon() shim's setInterval clobber.
Streaming HDR10 sources tonemap correctly (EnableTonemapping=true flipped — see doc 21). Doc-28 INC7 transparent-<video> rule reaches browsers because branding.xml <video> literal is escaped to &lt;video&gt; so XML parser stops choking on the CustomCss block.

Files of record

File md5 Purpose
web-overrides/index.html 364cc890c58f02d07cf50b43b31a48f0 The compiled overlay. Deployed to both prod and dev (under different host filenames).
snapshots/2026-05-09-v6-stable/index.html same as above Frozen save state for rollback.
bin/inject-middle-theme.py (current) Builder. Idempotent. Reads web-overrides/assets/{arrflix-A.b64,arrflix-wordmark.b64-url}. Writes a backup *.bak.pre-middle-v6.<unix-ts> before overwriting.
web-overrides/assets/arrflix-A.png (138x180 trimmed, transparent bg) Source asset — favicon "A" mark.
web-overrides/assets/arrflix-A.b64 29 192 chars Inline-ready base64 of the A mark.
web-overrides/assets/arrflix-wordmark.b64-url 11 350 chars Inline-ready data-URL of the ARRFLIX wordmark (235x85). Extracted from branding.xml.

Server-side state (not in repo, document for rollback)

Path State
/opt/docker/jellyfin/web-overrides/index.html (prod) md5 364cc890. owned root:root. Bind-mounted /jellyfin/jellyfin-web/index.html:ro.
/opt/docker/jellyfin/web-overrides/index.html.bak.pre-favfix.1778318089 rollback target — pre-v6+favfix prod overlay.
/opt/docker/jellyfin-dev/web-overrides/index-dev.html (dev) md5 364cc890. owned user:user. Same content as prod.
/opt/docker/jellyfin-dev/web-overrides/index-dev.html.bak.pre-middle-v6 rollback target — pre-v6 dev overlay.
/home/docker/jellyfin/config/config/branding.xml XML-valid (<video> escaped). 36 607 B. CustomCss reaches browsers via /Branding/Css.css.
/home/docker/jellyfin/config/config/branding.xml.bak.pre-middle-v6.1778295444 rollback target — pre-escape.
/home/docker/jellyfin/config/config/encoding.xml EnableTonemapping=true, TonemappingAlgorithm=bt2390, HardwareAccelerationType=none.
/home/docker/jellyfin/config/config/encoding.xml.bak.pre-tonemap.1778318089 rollback target — pre-flip.
/home/docker/jellyfin-dev/config/config/branding.xml Same content as prod.
/home/docker/jellyfin-dev/config/config/branding.xml.bak.dev-pre-resync rollback target — pre-resync (dev's older minimal branding).
/home/docker/jellyfin-dev/config/config/encoding.xml EnableTonemapping=true.
Container: jellyfin jellyfin/jellyfin:10.10.3, healthy, restart unless-stopped.
Container: jellyfin-dev same image.

Accounts

Prod

  • s8n — admin. Hidden. Password is private.
  • marco, house, guest, aloy, pet, 5, 64bitpotato, yummyhunny, Jayden, IX, ferghal — non-admin, hidden.
  • Loseious — non-admin, hidden, EnablePlaybackRemuxing=true. Created 2026-05-09. Password is private.

Dev

  • test / 123 — admin, hidden. Single-account theme test sandbox.

Roadmap closed in this iteration

Item Status
Streaming on prod (doc 28) closed — branding.xml XML escape was the missing delivery layer. INC7 transparent-<video> rule now reaches browsers.
Theme parity dev↔prod overlay md5 identical.
Favicon = A-mark hijack JS pins our data-arrflix-icon="A" links against lockFavicon clobber.
Tonemap HDR10 (doc 21) EnableTonemapping=false → true on both servers. ffmpeg gains zscale → tonemap → format stage on next transcode of HDR10 source.
Quick Connect off + manual login both prod and dev (QuickConnectAvailable=false in system.xml). All non-admin users IsHidden=true so no picker.
Video page header leak body.arrflix-video-active toggle hides .skinHeader during playback; specificity (0,4,2) beats Cineplex (0,3,2).
Duplicate "Movies" h3 on library pages body.arrflix-themed .skinHeader .headerLeft > h3.pageTitle:not(.pageTitleWithLogo){display:none!important}.

Roadmap open (deferred — non-blocking)

Item Note
compose-dev/docker-compose.yml in repo lacks the overlay bind-mount The host has it; repo is drift.
Locale-en-only chunk JS files (94 of them) bind-mounted on prod, absent on dev Dev users get stock locale strings. Cosmetic only.
xmllint --noout branding.xml in CI Silent XML parse failure cost a multi-hour debug cycle.
bin/headless-test-v2.py darkPct assertion INC7 lesson — element state alone (currentTime, readyState) doesn't catch CSS-overlay-over-video.
Movies/TV stuck-spinner from cached ?topParentId=movies URL Stock Jellyfin viewContainer.tryRestoreView quirk. Not a v6 regression.
Splashscreen blurred-poster login bg Owner reference image #2 had it. Currently neither prod nor dev renders it.

Lesson

The whole BLACK-PASS / INC7 / Traefik-SW chain in doc 26 + 28 was correctly diagnosed but the delivery layer was broken since 2026-05-08 by a single unescaped <video> literal in a CSS comment. xmllint --noout would have caught it instantly. Add it to CI. Silent XML parse failures with zero UI feedback are the worst class of bug — Jellyfin returned HTTP 200 with empty body for /Branding/Css.css, no banner, no admin alert.

Rollback

If anything regresses, restore in this order:

# Overlay rollback (prod)
docker run --rm --userns=host -v /opt/docker/jellyfin/web-overrides:/d:rw alpine \
  sh -c 'cp /d/index.html.bak.pre-favfix.1778318089 /d/index.html && chown root:root /d/index.html'

# Branding rollback (prod) — only if XML escape causes new issues
docker run --rm --userns=host -v /home/docker/jellyfin/config/config:/d:rw alpine \
  cp /d/branding.xml.bak.pre-middle-v6.1778295444 /d/branding.xml

# Tonemap rollback (prod)
docker run --rm --userns=host -v /home/docker/jellyfin/config/config:/d:rw alpine \
  cp /d/encoding.xml.bak.pre-tonemap.1778318089 /d/encoding.xml

docker restart jellyfin

Or git-side rollback to the previous commit 52a7df6 (pre-favfix v6) and re-deploy.