2026-05-09 01:11:31 +01:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# apply-26-incident-fixes.sh
|
|
|
|
|
#
|
|
|
|
|
# Re-applies the three server-state fixes from docs/26 if branding.xml /
|
|
|
|
|
# encoding.xml drift back to broken state (e.g. after a Jellyfin restore).
|
|
|
|
|
#
|
|
|
|
|
# 1. CustomCss: Cineplex hardcoded "Abspielen" → "Play"
|
|
|
|
|
# 2. CustomCss: Backdrop transparent-scope using :has() (BLACK-PASS occluded backdrop layer)
|
|
|
|
|
# 3. encoding.xml: EnableThrottling=false + EnableSegmentDeletion=false (kills HLS 499)
|
|
|
|
|
#
|
|
|
|
|
# Usage: ssh user@nullstone "$(cat bin/apply-26-incident-fixes.sh)"
|
|
|
|
|
# Idempotent: re-running is safe.
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
doc 26 INC4: black band + 4K HDR slow transcode + v2 test + methodology audit
Two regressions slipped through INC1-3:
INC4a -- BLACK BAND behind every detail-page carousel
Pre-existing 2026-05-08 home-page rule painted .emby-scroller {bg:#000
!important} UNSCOPED. Hits every carousel inside .itemDetailPage incl
admin-only More from Season N, More Like This. INC1-3 transparent-scope
list missed .emby-scroller / .verticalSection / .padded-top-focusscale.
Fixed by extending scope.
INC4b -- VIDEO 'BLACK SCREEN' on play
Not actually black-screen. CPU-only nullstone cannot sustain real-time
4K HEVC HDR tonemap+x264 transcode -- 0.5x realtime, ffmpeg takes ~6s
per 3s segment. With user resume seeks adding restart overhead, total
wait ~18s before browser readyState rises. User saw black, gave up.
Fix: disable EnableTonemapping (R&M fake HDR per doc 21) + cap
RemoteClientBitrateLimit=20Mbps on every user (1080p target, no 4K
scale). Headless v2 test confirms HEVC + AV1 episodes now hit
readyState=3/4 within wait window; 4K HDR R&M still slow (heaviest).
INC4 testing methodology audit -- bin/headless-test-v2.py
v1 only logged in as guest and never clicked Play. v2 runs both admin
and guest, walks 3 codec-tagged items per role (HEVC/AV1/H.264),
clicks Play, captures <video> state, sweeps DOM for opaque bgs over
backdrop layer. False positives: off-viewport #reactRoot + collapsed
.mainDrawer (negative coords). Allowlist refinement TODO.
Open: 4K HDR sources still slow even post-fix. Real fix path = pre-
transcode masters to 1080p H.264 SDR via separate batch, OR migrate to
10.11.8 with vaapi/qsv driver fixed.
2026-05-09 01:46:47 +01:00
|
|
|
# 3+5. encoding.xml — disable throttling + segment deletion (HLS 499)
|
|
|
|
|
# AND disable software tonemapping (CPU-only nullstone
|
|
|
|
|
# cannot sustain real-time 4K HDR tonemap+x264, ffmpeg
|
|
|
|
|
# runs at ~0.5x → 18s wait time before video starts;
|
|
|
|
|
# R&M is fake-HDR per doc 21 anyway, so no visual loss)
|
2026-05-09 01:11:31 +01:00
|
|
|
for cfg in /home/docker/jellyfin/config/config/encoding.xml \
|
|
|
|
|
/home/docker/jellyfin-dev/config/config/encoding.xml; do
|
|
|
|
|
[ -f "$cfg" ] || continue
|
|
|
|
|
cp -n "$cfg" "$cfg.bak.pre-doc26" || true
|
|
|
|
|
sed -i \
|
|
|
|
|
-e 's|<EnableThrottling>true</EnableThrottling>|<EnableThrottling>false</EnableThrottling>|' \
|
|
|
|
|
-e 's|<EnableSegmentDeletion>true</EnableSegmentDeletion>|<EnableSegmentDeletion>false</EnableSegmentDeletion>|' \
|
doc 26 INC4: black band + 4K HDR slow transcode + v2 test + methodology audit
Two regressions slipped through INC1-3:
INC4a -- BLACK BAND behind every detail-page carousel
Pre-existing 2026-05-08 home-page rule painted .emby-scroller {bg:#000
!important} UNSCOPED. Hits every carousel inside .itemDetailPage incl
admin-only More from Season N, More Like This. INC1-3 transparent-scope
list missed .emby-scroller / .verticalSection / .padded-top-focusscale.
Fixed by extending scope.
INC4b -- VIDEO 'BLACK SCREEN' on play
Not actually black-screen. CPU-only nullstone cannot sustain real-time
4K HEVC HDR tonemap+x264 transcode -- 0.5x realtime, ffmpeg takes ~6s
per 3s segment. With user resume seeks adding restart overhead, total
wait ~18s before browser readyState rises. User saw black, gave up.
Fix: disable EnableTonemapping (R&M fake HDR per doc 21) + cap
RemoteClientBitrateLimit=20Mbps on every user (1080p target, no 4K
scale). Headless v2 test confirms HEVC + AV1 episodes now hit
readyState=3/4 within wait window; 4K HDR R&M still slow (heaviest).
INC4 testing methodology audit -- bin/headless-test-v2.py
v1 only logged in as guest and never clicked Play. v2 runs both admin
and guest, walks 3 codec-tagged items per role (HEVC/AV1/H.264),
clicks Play, captures <video> state, sweeps DOM for opaque bgs over
backdrop layer. False positives: off-viewport #reactRoot + collapsed
.mainDrawer (negative coords). Allowlist refinement TODO.
Open: 4K HDR sources still slow even post-fix. Real fix path = pre-
transcode masters to 1080p H.264 SDR via separate batch, OR migrate to
10.11.8 with vaapi/qsv driver fixed.
2026-05-09 01:46:47 +01:00
|
|
|
-e 's|<EnableTonemapping>true|<EnableTonemapping>false|' \
|
|
|
|
|
-e 's|<EnableVppTonemapping>true|<EnableVppTonemapping>false|' \
|
2026-05-09 01:11:31 +01:00
|
|
|
"$cfg"
|
|
|
|
|
echo "[+] patched $cfg"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# 1+2. branding.xml CustomCss — Abspielen + backdrop transparent-scope
|
|
|
|
|
patch_branding() {
|
|
|
|
|
local cfg="$1"
|
|
|
|
|
[ -f "$cfg" ] || return 0
|
|
|
|
|
if grep -q "ARRFLIX 2026-05-09" "$cfg"; then
|
|
|
|
|
echo "[=] $cfg already has doc-26 patch"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
cp -n "$cfg" "$cfg.bak.pre-doc26" || true
|
|
|
|
|
python3 - <<PY
|
|
|
|
|
p = "$cfg"
|
|
|
|
|
s = open(p).read()
|
|
|
|
|
patch = """
|
|
|
|
|
|
|
|
|
|
/* ARRFLIX 2026-05-09 — incident fixes (see docs/26-incident-2026-05-09-...).
|
2026-05-09 01:21:01 +01:00
|
|
|
INC1: Cineplex theme hardcodes German "Abspielen" via content: ::after.
|
|
|
|
|
INC1: BLACK-PASS occludes backdrop; transparent-scope via :has().
|
|
|
|
|
INC2: pin backdrop position:fixed so it persists across scroll.
|
|
|
|
|
INC3: extend transparent-scope through detail-page sub-sections so
|
doc 26 INC4: black band + 4K HDR slow transcode + v2 test + methodology audit
Two regressions slipped through INC1-3:
INC4a -- BLACK BAND behind every detail-page carousel
Pre-existing 2026-05-08 home-page rule painted .emby-scroller {bg:#000
!important} UNSCOPED. Hits every carousel inside .itemDetailPage incl
admin-only More from Season N, More Like This. INC1-3 transparent-scope
list missed .emby-scroller / .verticalSection / .padded-top-focusscale.
Fixed by extending scope.
INC4b -- VIDEO 'BLACK SCREEN' on play
Not actually black-screen. CPU-only nullstone cannot sustain real-time
4K HEVC HDR tonemap+x264 transcode -- 0.5x realtime, ffmpeg takes ~6s
per 3s segment. With user resume seeks adding restart overhead, total
wait ~18s before browser readyState rises. User saw black, gave up.
Fix: disable EnableTonemapping (R&M fake HDR per doc 21) + cap
RemoteClientBitrateLimit=20Mbps on every user (1080p target, no 4K
scale). Headless v2 test confirms HEVC + AV1 episodes now hit
readyState=3/4 within wait window; 4K HDR R&M still slow (heaviest).
INC4 testing methodology audit -- bin/headless-test-v2.py
v1 only logged in as guest and never clicked Play. v2 runs both admin
and guest, walks 3 codec-tagged items per role (HEVC/AV1/H.264),
clicks Play, captures <video> state, sweeps DOM for opaque bgs over
backdrop layer. False positives: off-viewport #reactRoot + collapsed
.mainDrawer (negative coords). Allowlist refinement TODO.
Open: 4K HDR sources still slow even post-fix. Real fix path = pre-
transcode masters to 1080p H.264 SDR via separate batch, OR migrate to
10.11.8 with vaapi/qsv driver fixed.
2026-05-09 01:46:47 +01:00
|
|
|
section wrappers don't paint over the pinned backdrop.
|
|
|
|
|
INC4: override the 2026-05-08 .emby-scroller=#000 rule on detail page
|
|
|
|
|
(it was painting a black band behind every carousel — most visible
|
|
|
|
|
on admin-only "More from Season" / "More Like This"). */
|
2026-05-09 01:11:31 +01:00
|
|
|
.mainDetailButtons .material-icons.play_arrow::after {
|
|
|
|
|
content: "Play" !important;
|
|
|
|
|
}
|
|
|
|
|
.itemDetailPage,
|
|
|
|
|
.layout-desktop:has(.itemDetailPage),
|
|
|
|
|
.layout-mobile:has(.itemDetailPage),
|
|
|
|
|
.layout-tv:has(.itemDetailPage),
|
|
|
|
|
.mainAnimatedPages:has(.itemDetailPage),
|
|
|
|
|
.pageContainer:has(.itemDetailPage),
|
|
|
|
|
.padded-bottom-page:has(.itemDetailPage),
|
|
|
|
|
.libraryPage:has(.itemDetailPage),
|
|
|
|
|
.absolutePageTabContent:has(.itemDetailPage) {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
}
|
2026-05-09 01:21:01 +01:00
|
|
|
.layout-desktop .backdropContainer,
|
|
|
|
|
.layout-mobile .backdropContainer,
|
|
|
|
|
.layout-tv .backdropContainer,
|
|
|
|
|
.layout-desktop .backgroundContainer,
|
|
|
|
|
.layout-mobile .backgroundContainer,
|
|
|
|
|
.layout-tv .backgroundContainer {
|
|
|
|
|
position: fixed !important;
|
|
|
|
|
top: 0 !important;
|
|
|
|
|
left: 0 !important;
|
|
|
|
|
width: 100vw !important;
|
|
|
|
|
height: 100vh !important;
|
|
|
|
|
z-index: 0 !important;
|
|
|
|
|
}
|
|
|
|
|
.layout-desktop .backgroundContainer.withBackdrop::after,
|
|
|
|
|
.layout-mobile .backgroundContainer.withBackdrop::after,
|
|
|
|
|
.layout-tv .backgroundContainer.withBackdrop::after {
|
|
|
|
|
content: "";
|
|
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
|
|
|
|
background: linear-gradient(
|
|
|
|
|
180deg,
|
|
|
|
|
rgba(0,0,0,0.00) 0%,
|
|
|
|
|
rgba(0,0,0,0.00) 35%,
|
|
|
|
|
rgba(0,0,0,0.40) 70%,
|
|
|
|
|
rgba(0,0,0,0.75) 100%
|
|
|
|
|
);
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
.itemDetailPage,
|
|
|
|
|
.itemDetailPage > *,
|
|
|
|
|
.detailPageContent,
|
|
|
|
|
.detailPagePrimaryContainer,
|
|
|
|
|
.detailPageWrapperContainer,
|
|
|
|
|
.detailPageContent > *,
|
|
|
|
|
.detailVerticalSection,
|
|
|
|
|
.detailVerticalSection-extrabottompadding,
|
|
|
|
|
.detailSection,
|
|
|
|
|
.detailSectionContent,
|
|
|
|
|
.itemsContainer,
|
|
|
|
|
.scrollSlider,
|
|
|
|
|
.scrollSliderContainer,
|
|
|
|
|
.padded-bottom-page,
|
|
|
|
|
.detailPagePrimaryContent,
|
|
|
|
|
.sectionTitleContainer,
|
|
|
|
|
.detailRibbon,
|
|
|
|
|
.subtitleAudioContainer,
|
|
|
|
|
.detailPageRoot {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
}
|
doc 26 INC4: black band + 4K HDR slow transcode + v2 test + methodology audit
Two regressions slipped through INC1-3:
INC4a -- BLACK BAND behind every detail-page carousel
Pre-existing 2026-05-08 home-page rule painted .emby-scroller {bg:#000
!important} UNSCOPED. Hits every carousel inside .itemDetailPage incl
admin-only More from Season N, More Like This. INC1-3 transparent-scope
list missed .emby-scroller / .verticalSection / .padded-top-focusscale.
Fixed by extending scope.
INC4b -- VIDEO 'BLACK SCREEN' on play
Not actually black-screen. CPU-only nullstone cannot sustain real-time
4K HEVC HDR tonemap+x264 transcode -- 0.5x realtime, ffmpeg takes ~6s
per 3s segment. With user resume seeks adding restart overhead, total
wait ~18s before browser readyState rises. User saw black, gave up.
Fix: disable EnableTonemapping (R&M fake HDR per doc 21) + cap
RemoteClientBitrateLimit=20Mbps on every user (1080p target, no 4K
scale). Headless v2 test confirms HEVC + AV1 episodes now hit
readyState=3/4 within wait window; 4K HDR R&M still slow (heaviest).
INC4 testing methodology audit -- bin/headless-test-v2.py
v1 only logged in as guest and never clicked Play. v2 runs both admin
and guest, walks 3 codec-tagged items per role (HEVC/AV1/H.264),
clicks Play, captures <video> state, sweeps DOM for opaque bgs over
backdrop layer. False positives: off-viewport #reactRoot + collapsed
.mainDrawer (negative coords). Allowlist refinement TODO.
Open: 4K HDR sources still slow even post-fix. Real fix path = pre-
transcode masters to 1080p H.264 SDR via separate batch, OR migrate to
10.11.8 with vaapi/qsv driver fixed.
2026-05-09 01:46:47 +01:00
|
|
|
/* INC4: 2026-05-08 home-page "kill gray band" rule paints .emby-scroller
|
|
|
|
|
#000 unscoped — that's the OPAQUE wrapper around every carousel inside
|
|
|
|
|
.itemDetailPage. Override back to transparent on detail page only. */
|
|
|
|
|
.itemDetailPage .emby-scroller,
|
|
|
|
|
.itemDetailPage .emby-scroller-container,
|
|
|
|
|
.itemDetailPage .verticalSection,
|
|
|
|
|
.itemDetailPage .padded-top-focusscale,
|
|
|
|
|
.itemDetailPage .padded-bottom-focusscale,
|
|
|
|
|
.itemDetailPage .moreFromSeasonSection,
|
|
|
|
|
.itemDetailPage .moreFromArtistSection,
|
|
|
|
|
.itemDetailPage .scrollSliderContainer,
|
|
|
|
|
.itemDetailPage .scrollButtonContainer {
|
|
|
|
|
background-color: transparent !important;
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
}
|
2026-05-09 01:11:31 +01:00
|
|
|
"""
|
|
|
|
|
s = s.replace("</CustomCss>", patch + "</CustomCss>")
|
|
|
|
|
open(p, "w").write(s)
|
|
|
|
|
PY
|
|
|
|
|
echo "[+] patched $cfg"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
patch_branding /home/docker/jellyfin/config/config/branding.xml
|
|
|
|
|
patch_branding /home/docker/jellyfin-dev/config/config/branding.xml
|
|
|
|
|
|
|
|
|
|
# Restart so changes take effect
|
|
|
|
|
docker restart jellyfin jellyfin-dev 2>/dev/null || docker restart jellyfin
|
|
|
|
|
|
|
|
|
|
echo "[*] Done. Verify with bin/headless-test.py."
|