dc429ecd16 refactor(app): carve the player controls out of app.js (R3a) (#891)
static/js/player-controls.js (229) — the speed + mastery sliders and the four
playback-preference reads (autoplay-exit, up-next, countdown-before-song,
confirm-exit). Bodies VERBATIM. app.js 7,914 → 7,727.

The fourth slice out of the strongly-connected core, and by far the easiest: ONE
hook (handleSliderInput) and NO shared mutable state. The three groups are the same
surface — the controls under the highway — and the preference reads are the
one-line localStorage lookups half of app.js consults before deciding whether to
auto-start, show the Up Next pill, run a count-in, or confirm on exit. They travel
with the controls that set them.

Zero missed members on the first build (the no-undef pass was clean), which is the
first time that has happened in this phase.

TWO HARNESSES ARE SPLIT, and both taught something:

  * speed_reset spans BOTH files — playSong (app.js) resets the speed controls
    (module). Its presence GUARDS still read `src.includes('function setSpeed')`
    against app.js, so once the code moved they silently evaluated FALSE and the
    helpers were quietly dropped from the sandbox. A guard that disables itself is
    worse than no guard. Repointed at the file the code actually lives in.

  * Its `host.handleSliderInput` stub had to route at the sandbox's EXISTING spy,
    not a fresh `() => {}`. The test asserts the slider was actually refreshed
    (`deepEqual(__sliderInputs, ['speed-slider'])`); a fresh stub swallows the call
    and the assertion passes VACUOUSLY. Same failure mode as a no-op host default —
    the thing this whole seam design exists to prevent.

  * autoplay_exit is split too: _autoplayExitEnabled moved, but the auto-exit
    machinery around it (_clearAutoExit, holdAutoExit, _resolvePlayerOrigin) stayed.

VERIFIED. A/B against origin/main in two browsers, real song: setSpeed(0.75) ->
playbackRate 0.75; applySpeedPreset(100) -> 1; the speed slider; setMastery;
setAutoplayExit / setCountdownBeforeSong / setShowUpNext — IDENTICAL, zero page errors.

pytest 2396, node 1040/1040, ESLint 0 (no-cycle clean), tailwind clean.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 22:12:34 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-06-16 18:47:13 +02:00
2026-07-03 13:41:50 +02:00
S
Description
No description provided
AGPL-3.0
981 MiB
Languages
JavaScript 56.4%
Python 37.1%
HTML 3.2%
CSS 1.2%
TypeScript 1.1%
Other 1%