From a0f74dfc3915fe2e5578324b96bc7a925a24712b Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 25 Apr 2026 02:24:01 +0300 Subject: [PATCH] fix(visualizer): full-width spectrum + device pick auto-starts capture Spectrum width - grid-auto-flow: column with implicit columns wasn't reliably stretching to fill the parent. Switch to explicit grid-template-columns: repeat(var(--spectrum-bars), minmax(0, 1fr)) with the bar count exposed as a CSS variable from JS so the column count and the actual bar count stay in sync. - !important on display/grid-template-columns/width to defeat any legacy descendant rules. Device selection - Picking a device in the audio-device dropdown is an explicit signal that the user wants capture. Auto-enable the visualizer if it isn't already on, then call applyVisualizerMode so the WS subscription happens and the badge flips from 'Available' to 'Active'. Was only doing this when visualizer was already on, which is why the user kept seeing 'Available, not capturing'. --- media_server/static/css/styles.css | 13 ++++++------- media_server/static/js/app.js | 3 +++ media_server/static/js/player.js | 7 ++++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/media_server/static/css/styles.css b/media_server/static/css/styles.css index 8ad31cb..3fa38d6 100644 --- a/media_server/static/css/styles.css +++ b/media_server/static/css/styles.css @@ -6867,21 +6867,20 @@ body.visualizer-active .now-playing .spectrogram-canvas { /* ─── Spectrum bars (JS-injected; real audio from backend FFT) ── */ .now-playing .spectrum { - /* Grid with explicit equal-width columns guarantees each bar - claims its share of the full container width, regardless of - the bar count. */ - display: grid; + /* Explicit equal-width columns. The CSS variable --spectrum-bars + is set by JS so adding/removing bars stays in sync. */ + display: grid !important; + grid-template-columns: repeat(var(--spectrum-bars, 40), minmax(0, 1fr)) !important; grid-auto-flow: column; - grid-auto-columns: 1fr; align-items: end; column-gap: 4px; height: 70px; margin: 36px 0 24px; - width: 100%; + width: 100% !important; box-sizing: border-box; min-width: 0; } -.now-playing .spectrum span { +.now-playing .spectrum > span { display: block; width: 100%; min-width: 0; diff --git a/media_server/static/js/app.js b/media_server/static/js/app.js index 1b82c81..d9e31ce 100644 --- a/media_server/static/js/app.js +++ b/media_server/static/js/app.js @@ -172,6 +172,9 @@ window.addEventListener('DOMContentLoaded', async () => { const spectrumRoot = document.getElementById('player-spectrum'); if (spectrumRoot && !spectrumRoot.children.length) { const SPECTRUM_BARS = 40; + // Sync the grid column count to the bar count so the row truly + // fills the column even if the bar count changes later. + spectrumRoot.style.setProperty('--spectrum-bars', SPECTRUM_BARS); const frag = document.createDocumentFragment(); for (let i = 0; i < SPECTRUM_BARS; i++) { const s = document.createElement('span'); diff --git a/media_server/static/js/player.js b/media_server/static/js/player.js index 910b194..80ad74f 100644 --- a/media_server/static/js/player.js +++ b/media_server/static/js/player.js @@ -618,7 +618,12 @@ export async function onAudioDeviceChanged() { const result = await resp.json(); updateAudioDeviceStatus({ available: result.success, ...result }); await checkVisualizerAvailability(); - if (visualizerEnabled) applyVisualizerMode(); + // Picking a device is an explicit signal the user wants + // capture: auto-enable the visualizer if it isn't already on. + if (!visualizerEnabled && visualizerAvailable) { + setVisualizerEnabled(true); + } + applyVisualizerMode(); showToast(t('settings.audio.device_changed'), 'success'); } else { showToast(t('settings.audio.device_change_failed'), 'error');