createYoutubeEmbed set container.style.position = 'relative' to anchor
the click-to-unmute overlay. That overrode #playerContainer's
position:fixed/inset:0 — the container fell into normal flow with
zero height (the YT iframe inside has no intrinsic size), so the new
absolute-positioned iframe rendered as 100% of 0 = black screen.
The container is already position:fixed, so absolute children anchor
to it correctly without the override. Removed the line. Bumped SW
cache to v7.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous CSS fix used 100% width/height but YT.Player can bake in
300x150 fallback pixel dimensions if the placeholder isn't laid out at
construction time. Inline pixel dimensions beat percentage CSS at
equal specificity, so the iframe stayed small.
Use absolute positioning with !important to force fullscreen over
whatever YT set inline. Bumped sw cache to v6 to invalidate the
previously-cached player HTML.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The SW was causing "unexpected error" on video/image fetches due to
range request handling, opaque response caching, and stale SW races.
Fix: SW now ONLY caches player page + socket.io JS for offline boot.
Content files are left to browser native HTTP cache (server already
sets Cache-Control: public, max-age=2592000, immutable).
Also: auto-reload player when new SW activates so deploys take effect
immediately without manual hard refresh.
Bumped cache to v5 — activate purges all old caches (including the
broken rd-content-v1 content cache).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bug 1 (SW): Rewrote service worker fetch handler:
- Skip range requests (video seeking) to avoid caching partial responses
- Skip non-GET requests entirely
- Use ignoreSearch on cache match to avoid query-param misses
- Don't cache opaque cross-origin responses
- Outer catch on Cache API failures
- Don't intercept catch-all requests (let browser handle natively)
- Bump cache version to v4 to purge broken cached responses
Bug 2 (auth): Playlist refresh register was missing device_token,
causing auth rejection every 5 minutes. Fixed by including token
in the refresh-register emit. Added diagnostic logging on both
client and server for token validation failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace raw iframe YouTube embeds with official YT IFrame Player API for proper
error handling (150/153/100/101) and unmute support
- Fix playlist not updating when single item changes by comparing full content
fingerprint (id + url + filepath + filename) instead of just content_id
- Add click-to-unmute overlay for YouTube since iframe swallows click events
- Remove hardcoded origin param from server-side YouTube URLs (caused Error 153
when player domain differs from server)
- Switch service worker to network-first for player assets so deploys take effect
without hard refresh; keep cache-first for uploaded content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Loop single-video playlists natively instead of destroying/recreating the element
- Skip caching HTTP 206 partial responses in service worker (video range requests)
- Bump service worker cache version to invalidate old cache
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ScreenTinker - open source digital signage management software.
MIT License, all features included, no license gates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>