Conversation
…resh Two independent bugs reported together in code-charity#4353: 1. Cinema Mode (both the toggle button and the keyboard shortcut) darkened the page by appending a position:fixed, full-viewport overlay div and trying to out-rank it by raising z-index on player-full-bleed-container / player-container / ytd-player. YouTube's player DOM nesting has changed enough that this no longer works - the elevated z-index ends up compared against the overlay in a different effective stacking order - so the overlay covered the whole page, video and controls included, with no way back short of a refresh. Replaced it with a box-shadow "spotlight" drawn directly on #ytd-player (0 0 0 9999px rgba(0,0,0,1)), which tracks the real player size in both the default and theater layouts and is painted as part of the player's own, already-correctly-stacked box - no z-index or stacking-context guesswork needed. All three call sites (manual button, auto-enable/disable on pause, keyboard shortcut) now share one ImprovedTube.cinemaModeSetVisible() helper and one ImprovedTube.cinemaModeActive flag instead of three copies of the same broken logic. 2. Reverse Playlist: toggling it on persisted correctly (playlist_reversed_active in storage, button showed active after a refresh), but the actual playlist order and next-video wiring silently stayed unreversed. playlistReverseUpdate()'s player-sync step accessed ImprovedTube.elements.ytd_player without checking it was populated - that reference is set by a separate, async DOM walk and isn't guaranteed to be ready yet on a fresh page load, so the call threw and silently aborted the rest of the callback, including the direct playlist_panel.data patch that makes the panel actually re-render. Added a fallback DOM query for ytd_player and a bounded retry (5 attempts, 200ms apart) instead of the previous unguarded one-shot attempt. Both fixes verified live against real YouTube pages (DOM/stacking inspection, real playlist data through the actual reverse logic, before/after screenshots), not just via the unit tests. Fixes code-charity#4353 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Snzt7njUYkxw4oxYJsENbQ
|
Amazing, thankyou. Hopefully this gets merged. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fixes #4353 — two independent bugs reported together.
1. Cinema Mode blacks out the entire page
Both
player_cinema_mode_button(manual toggle) and theshortcutCinemaModekeyboard shortcut worked by appending aposition: fixed, full-viewport, fully opaque overlay div, then trying to visually raise the player above it by settingz-index: 10000+position: relativeon three separate elements (player-full-bleed-container,player-container,ytd-player).This no longer works on current YouTube. I inspected the live DOM:
player-container's ancestor chain and the overlay's parent (full-bleed-container) chain both converge back up atytd-watch-flexywith no intervening stacking context — so in principle the higher z-index should win — but empirically (confirmed viaelementFromPointon the real page) the fixed overlay always ends up on top. The player DOM nesting has drifted enough since this code was written that the z-index elevation no longer reaches the right stacking context, and the result is a full black screen with audio still playing but no video or controls, exactly as reported — and no way back short of a refresh.2. Reverse Playlist doesn't survive a refresh
Toggling reverse-playlist on persists correctly (
playlist_reversed_activein storage, and the button correctly shows "active" after a refresh), but the actual playlist order and next-video wiring silently stay unreversed. Root cause:playlistReverseUpdate()'s player-sync step callsImprovedTube.elements.ytd_player.updatePlayerComponents(...)with no check thatytd_playeris actually populated. That reference is set by a separate, async DOM walk (childHandlervia aMutationObserver) and isn't guaranteed to be ready 100ms afteryt-page-data-updatedfires on a fresh page load — so the call throws and silently aborts the rest of the callback, including the directplaylist_panel.data = playlistpatch a few lines later that's needed to make the panel actually re-render (playlist.contentsitself had already been reversed earlier in the function — it just never reached the UI or the player's own next-video order).Fix
Cinema Mode: replaced the overlay + z-index approach with a box-shadow "spotlight" drawn directly on
#ytd-player:box-shadow: 0 0 0 9999px rgba(0,0,0,1). This tracks the real player size correctly in both the default and theater layouts (verified: 1048×590 vs 1512×658), and since it's painted as part of the player element's own box, it's automatically correctly stacked above the page — no z-index or stacking-context reasoning needed at all. All three call sites (manual button, the auto-enable/auto-disable-on-pause pair, and the keyboard shortcut) now share oneImprovedTube.cinemaModeSetVisible()helper and oneImprovedTube.cinemaModeActiveflag instead of three separate copies of the old broken logic.Reverse Playlist: added a fallback DOM query (
ImprovedTube.elements.ytd_player || document.querySelector('ytd-player')) so a not-yet-cached reference doesn't crash the callback, and replaced the previous unguarded one-shotsetTimeout(..., 100)with a bounded retry (up to 5 attempts, 200ms apart) so a still-initializing player on a fresh page load gets picked up shortly after instead of being silently missed forever.Testing
tests/unit/cinema-mode-and-reverse-playlist.test.js(7 tests) matching this repo's existing test convention.npm test: 123/123 passing (26 suites).npm run lint: clean.youtube.com/watchpage (confirmed viaelementFromPointthat the overlay wins despite the lower z-index), then confirmed the new box-shadow approach correctly darkens everything except the player in both layouts, with before/after screenshots, and that player controls stay fully interactive (loading spinner, scrubber, pause/play, etc. all hit-testable).playlistReverseUpdate()against a real 9-video NASA playlist's live data, deliberately leavingImprovedTube.elements.ytd_playeruncached to reproduce the race — confirmed no throw, confirmedplaylist.contentsorder actually reverses, and confirmed the playlist panel's rendered.datareflects the reversed order.🤖 Generated with Claude Code
https://claude.ai/code/session_01Snzt7njUYkxw4oxYJsENbQ