From 24d10fda5da624079bf38d8931afcdf74e4c59d3 Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Sun, 31 May 2026 15:45:28 -0400 Subject: [PATCH] fix(playout/web-ui): no-store on live HLS m3u8 so hls.js sees the live edge Definitive root cause of the black preview, proven in-browser: the live .m3u8 was served Cache-Control: no-cache, so the browser cached the playlist and served a STALE copy to hls.js's reloads (cache:'default' stuck at one MEDIA-SEQUENCE while cache:'reload' advanced). hls.js saw the live playlist as never advancing -> "live playlist MISSED" forever -> never established the timeline -> never loaded a fragment -> readyState 0 (black), even though the stream itself is clean and advancing server-side. Fix: serve live HLS (/live and /media/live) with "no-store, no-cache, must-revalidate" + Pragma no-cache so the browser never caches the playlist and every reload fetches the fresh live edge. Co-Authored-By: Claude Opus 4.8 --- services/web-ui/nginx.conf | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/services/web-ui/nginx.conf b/services/web-ui/nginx.conf index 2590563..10db848 100644 --- a/services/web-ui/nginx.conf +++ b/services/web-ui/nginx.conf @@ -61,12 +61,19 @@ server { add_header Cache-Control "no-cache, no-store, must-revalidate"; } - # Live HLS — served from /live (bind-mounted capture live volume) + # Live HLS — served from /live (bind-mounted capture live volume). + # no-store (not just no-cache): with "no-cache" the browser still caches the + # playlist and serves a STALE copy to hls.js's reloads, so hls.js sees the + # live playlist as never advancing ("MISSED" forever) and never plays — the + # monitor stays black. no-store forbids caching entirely so every reload + # fetches the fresh live edge. Segments are short-lived; not caching them is + # fine for a live preview. location /live/ { alias /live/; types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } - add_header Cache-Control "no-cache"; - add_header Access-Control-Allow-Origin *; + add_header Cache-Control "no-store, no-cache, must-revalidate" always; + add_header Pragma "no-cache" always; + add_header Access-Control-Allow-Origin * always; } # Playout HLS preview — CasparCG sidecar writes to the media volume under @@ -74,8 +81,9 @@ server { location /media/live/ { alias /media/live/; types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } - add_header Cache-Control "no-cache"; - add_header Access-Control-Allow-Origin *; + add_header Cache-Control "no-store, no-cache, must-revalidate" always; + add_header Pragma "no-cache" always; + add_header Access-Control-Allow-Origin * always; } # API proxy - forward to mam-api service