#!/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 # 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) 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|true|false|' \ -e 's|true|false|' \ -e 's|true|false|' \ -e 's|true|false|' \ "$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 - < *, .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; } /* 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; } /* INC5: kill grey scrollbar groove at page bottom (Chrome native scrollbar default = grey track; appears as ~15px strip at viewport bottom). Style all scrollbars to ARRFLIX palette. */ *::-webkit-scrollbar { background: #000000 !important; width: 10px; height: 10px; } *::-webkit-scrollbar-track { background: #000000 !important; } *::-webkit-scrollbar-thumb { background: #2a2a2a !important; border-radius: 5px; } *::-webkit-scrollbar-thumb:hover { background: #3a3a3a !important; } *::-webkit-scrollbar-corner { background: #000000 !important; } * { scrollbar-color: #2a2a2a #000000; } html, body { scrollbar-color: #2a2a2a #000000; } """ s = s.replace("", patch + "") 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."