Skip to content

release: 0.3.1 — queue-overlay fix, Shorts save-trigger fallback - #23

Closed
Kotmin wants to merge 33 commits into
mainfrom
dev
Closed

release: 0.3.1 — queue-overlay fix, Shorts save-trigger fallback#23
Kotmin wants to merge 33 commits into
mainfrom
dev

Conversation

@Kotmin

@Kotmin Kotmin commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fixes the queue-overlay "Add to queue" no-op (YouTube moved role="menuitem" off the popup item wrapper onto its inner button/link)
  • Adds a best-effort Shorts save-to-playlist trigger fallback for the playlist picker
  • Bumps all three extension editions to 0.3.1 (patch, per CONTRIBUTING.md semver policy)

Test plan

  • bash scripts/check.sh — syntax/manifest checks pass
  • bash scripts/test.sh — 338/338 unit tests pass
  • Queue-overlay fix manually verified live in Firefox (K) and via e2e harness (TC-17)
  • CI on this PR (ci-dev checks apply to dev pushes; this PR itself triggers no additional workflow until merge)
  • Post-merge: release-firefox.yml and release-chrome.yml on main — will monitor

Kotmin added 30 commits August 10, 2026 13:20
Trimmed to the relevant yt-sheet-view-model fragment (dropped the 19MB
full-page asset save) and redacted real playlist names before committing
to this public repo. Confirms the newer sheet-based popup renders all
playlists directly in the DOM with no continuation tokens, and the
create-new control lives in the sheet footer rather than the list.
Diffing an unselected vs. selected playlist row across the two captures
found aria-pressed on the row's inner button as the real locale-
independent selection signal, replacing the earlier assumption that only
locale-text aria-label was available. Also documents the create-new-
playlist footer button's structural (non-text) selector path.
Chords previously matched key case-insensitively with no shift distinction.
Introduces a separate shiftChords map matched via evt.shiftKey so
Shift+P (playlist picker, issue #16) stays unambiguous from plain p
(queue overlay) regardless of layout-dependent key casing.
Case/space-insensitive substring match plus edit-distance-2 typo
tolerance against the whole playlist name, per issue #16's resolved
match algorithm (deliberately not a full fzf-style scorer).
Scrapes/toggles the native yt-sheet-view-model "Save to playlist" sheet
off-screen (issue #16), same DOM-driving trick queue-overlay.js uses for
"Add to queue". Row/state/footer selectors are verified against the
captured DOM in docs/probes/save-to-playlist-dom-findings.md. How the
watch page's own action row opens this sheet was never captured in the
probes, so the caller supplies the trigger element rather than the
driver guessing a selector for it (flagged in docs/ai/questions-for-K.md).
browser.storage.local-backed, 5 min TTL per issue #16's resolved
default. Caches the playlist name catalog only, not per-video
membership, since aria-pressed state reflects the currently-open
video and would be wrong to serve to a different one from cache.
Pure reducer module (playlist-overlay-state.js, fully unit tested) drives
query typing, up/down highlight, space-checkbox toggling capped at 5,
enter-confirm resolution (checked set, implicit single-select, or
create-new), and the nested create-new sub-dialog per issue #16's
resolved UX. playlist-overlay.js is the DOM painter consuming that state,
left untested at the unit level same as jump-overlay.js's createJumpOverlay.
Ctrl+A,Shift+P now opens the playlist overlay: gated behind a
best-effort isLoggedIn signal, loads the catalog from the shared
cache or a live native-popup scrape, drives query/highlight/checkbox/
enter through the existing overlay-state reducer, and adds to
playlists sequentially (idempotent per row, since the native button
is a toggle) with a progress badge reused from jump-overlay's
BADGE_STYLE. Create-new is wired through driveCreateNewPlaylist.

findSaveToPlaylistTrigger stays an explicit null stub — the watch
page's native Save button was never captured in DOM probes, so the
whole feature self-heals to a silent no-op rather than driving a
fabricated selector. Tracked as the blocking open question for M7.
Extends keyboard-quickstart.md and keyboard-shortcuts.md with the
Ctrl+A,Shift+P playlist picker (behavior, config shape, shiftChords
merge semantics, verification coverage). Adds an Unreleased changelog
entry.

Files four open questions in questions-for-K.md surfaced while
building issue #16: the still-uncaptured native Save-trigger button
(blocking — feature currently no-ops on the live site), the
best-effort login-detection selector, the best-effort create-new
post-click UI assumption, and the name-collision limitation of
keying playlists by name with no stable id available.
Live DOM probe of the watch page's action row found the real trigger:
Save is the sole yt-button-view-model-wrapped child of
#flexible-item-buttons, distinct from Download's wrapper. Replaces the
null stub that kept Ctrl+A, Shift+P inert, resolving Q13.
The logged-out path silently no-op'd, giving no feedback that the
chord was even recognized. Reuses the existing badge pattern to tell
the user to sign in instead.
The sheet was genuinely visible on screen for the whole add/remove
sequence, not just briefly. Hides it via inline style as soon as rows
are found, instead of relying solely on the unverified Escape-close
to make it disappear afterward.
The picker never showed which playlists the video was already in
(loadPlaylistCatalog dropped the scraped selected flag, and the
cache-hit path skipped scraping entirely). Now always scrapes fresh,
pre-checks membership, and unchecking a pre-checked row on confirm
removes the video from that playlist instead of only ever adding.
hideOpenSheet's !important overrides were never undone, so YouTube's
reused sheet DOM node stayed permanently hidden after the first
drive, breaking the native Save button on subsequent opens.
Escape wasn't reliably closing YouTube's Save-to-playlist sheet,
leaving it open on screen at the end of a drive sequence. Close now
polls for the sheet actually disappearing and re-clicks the trigger
button as a fallback instead of trusting Escape blindly.
Toggle every row in a single open/close session instead of N
open+verify-close round trips, and skip re-clicking an already-open
trigger (which was toggling it shut and returning stale rows on a
same-cycle reopen). Also stop unhiding the sheet before confirming
close, so the verification wait is no longer visible on screen.
…scroll

Space sometimes leaks through to YouTube's own play/pause, so the
playlist overlay's toggle key is now sourced from
shortcuts.config.json (playlistKeys.toggle) instead of hardcoded.
Adds ArrowRight/ArrowLeft as a non-conflicting check/uncheck
alternative, also configurable. The highlighted row now scrolls into
view as the selector moves past the panel's visible area.

Issue #16.
…ield

Create-new never worked live: the native "Create new playlist" click
opens a separate yt-dialog-view-model with a <textarea> title field,
not the <input>/[contenteditable] the driver looked for inside the
original sheet, so nothing was ever typed and the empty dialog was
left sitting open. Submits via the dialog's own primary button
instead of an Enter keydown, since Enter just inserts a newline in a
textarea. Leaves the visibility dropdown untouched (defaults to
Private already).

Issue #16.
Creating a playlist worked but left the native dialog visibly open.
Submitting is async so a click doesn't guarantee it closes itself in
time; verifies the close the same way as the save-to-playlist sheet
(poll, then fall back to Escape) rather than trusting the click.

Issue #16.
Escape didn't close the create-playlist dialog either (reported live
after the previous fix), same unreliability already seen with the
save-to-playlist sheet. Falls back to clicking the dialog's own
Cancel button instead of a synthetic keydown.

Issue #16.
createNewPlaylistOnSite closed the save-to-playlist sheet then
addVideoToPlaylists immediately reopened it to check the new playlist,
since the new entry always lands in toAdd. That close/reopen race left
the sheet visibly stuck open. Only close here on failure now; success
leaves it hidden-but-open for the immediate reopen to reuse.
content.js's IIFE closure held loadPlaylistCatalog/addVideoToPlaylists/
createNewPlaylistOnSite/handlePlaylistKey with zero test coverage - every
behavior fix in this area (30ef16b, 7cf4888, 7e9fc6a, a41f324, ...) only
got verified by a live YouTube re-test. Moved into
src/ui/playlist-controller.js as a doc/win-injectable factory, same
pattern as playlist-popup-driver.js and queue-overlay.js; content.js now
just constructs it and forwards events. Behavior is unchanged.

20 new tests pin down the sequences that took multiple live-debug rounds
to get right: idempotent per-row toggling, one open/close per add batch,
and the close-only-on-failure fix from 30ef16b so a create-then-add
reopen doesn't race a redundant close.
…attern

README's shortcut table never got the queue (Ctrl+A p) or playlist
picker (Ctrl+A Shift+P) chords that docs/keyboard-quickstart.md already
documented since they shipped. CONTRIBUTING's Tests section now points
new DOM-driving code at src/ (doc/win-injectable factory) instead of
content.js's closure, per the gap playlist-controller.js just fixed.
Formalizes the default: minor bump for features/shortcuts/layout
changes, patch bump for fixes. Referenced when scoping release PRs.
Playlist picker (issue #16) is fully live and covered by unit tests;
per the versioning policy this is a minor bump.
Move Configuration to the top of the keyboard-shortcuts spec so the
customization options are found before the command reference. Add
prefix-change, chord-remap, and non-QWERTY remap examples, and note
the default chords are chosen to avoid colliding with YouTube's own
single-key shortcuts.
Point Edge and Arc at the Chrome Web Store listing directly (both are
Chromium-based, confirmed via Microsoft/Arc docs) instead of a bare
dash, and note Edge needs 'Allow extensions from other stores' enabled
first while Arc installs without extra setup.
Drop the inline parenthetical from the Listing column and mark Edge
and Arc as Unofficial* in Status instead, with the Chromium-install
caveat explained once below the table.
YouTube moved role="menuitem" off yt-list-item-view-model onto its
inner button/anchor (wrapper is now role="presentation"), so the
queue popup opened but the "Add to queue" item was never found,
silently no-opping. Select the descendant instead of the wrapper.
Kotmin added 3 commits August 16, 2026 16:36
…trigger

findSaveToPlaylistTrigger only looked for the /watch page's action-row
button, so Ctrl+A Shift+P silently no-op'd on the Shorts standalone player
(issue #20). A captured Shorts-page JSON snapshot confirms YouTube offers
"Save to playlist" there via the header "..." menu, so add
ytd-reel-player-header-renderer ytd-menu-renderer button as a fallback,
derived from JSON renderer names and this codebase's established naming
convention but not yet confirmed against a live DOM.
Patch release covering the queue-overlay menuitem-selector fix and
the Shorts save-to-playlist trigger fallback.
@Kotmin

Kotmin commented Aug 16, 2026

Copy link
Copy Markdown
Owner Author

Superseded — main had diverged from dev via a past history-replay ("promote dev to main"), so this dev-head PR would 3-way conflict despite identical content. Replaced with a cleanly rebased branch: same commits, same resulting tree, linear on top of main's actual tip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant