From cb49904a211a893faa6dd7e12aeb816a1a08b656 Mon Sep 17 00:00:00 2001 From: tryptz <216453278+tryptz@users.noreply.github.com> Date: Mon, 6 Apr 2026 22:52:07 +0000 Subject: [PATCH] fix: address remaining PR #519 review comments - Preserve existing preamp when importing files without Preamp line - Extend import regex to accept k/kHz/Hz suffixes and +signed gains - Rename localStorage key to monochrome- prefix for backup/restore compat - Add try/catch to localStorage writes for quota/disabled storage - Validate custom preset gains array before applying - Fix delete button visibility for all preset change paths - Add overflow-x: auto for mobile EQ band scrolling - Add flex-wrap and responsive sizing for bottom controls on mobile --- js/settings.js | 101 ++++++++++++++++++++++++++++++++----------------- styles.css | 12 ++++++ 2 files changed, 78 insertions(+), 35 deletions(-) diff --git a/js/settings.js b/js/settings.js index ced2eae..fce32fc 100644 --- a/js/settings.js +++ b/js/settings.js @@ -1422,27 +1422,35 @@ export async function initializeSettings(scrobbler, player, api, ui) { try { const text = event.target.result; const lines = text.split('\n'); - let preamp = 0; + let preamp = geqPreamp; + let hasPreamp = false; const importedPoints = []; for (const line of lines) { const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i); if (preampMatch) { preamp = parseFloat(preampMatch[1]); + hasPreamp = true; continue; } // EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX const filterMatch = line.match( - /Filter\s+\d+:\s*ON\s+\w+\s+Fc\s+([\d.]+)\s*Hz\s+Gain\s+([-\d.]+)\s*dB/i + /Filter\s+\d+:\s*ON\s+\w+\s+Fc\s+([\d.]+[kK]?)\s*(?:Hz)?\s+Gain\s+([+-]?[\d.]+)\s*dB/i ); if (filterMatch) { - importedPoints.push({ freq: parseFloat(filterMatch[1]), gain: parseFloat(filterMatch[2]) }); + importedPoints.push({ + freq: parseGeqLabelFrequency(filterMatch[1]), + gain: parseFloat(filterMatch[2]), + }); continue; } // Simple two-column format: freq gain (whitespace/tab/comma separated) - const simpleMatch = line.trim().match(/^([\d.]+)[,\s\t]+([-\d.]+)/); + const simpleMatch = line.trim().match(/^([\d.]+[kK]?)\s*(?:Hz|kHz)?\s*[,\s\t]+([+-]?[\d.]+)/); if (simpleMatch) { - importedPoints.push({ freq: parseFloat(simpleMatch[1]), gain: parseFloat(simpleMatch[2]) }); + importedPoints.push({ + freq: parseGeqLabelFrequency(simpleMatch[1]), + gain: parseFloat(simpleMatch[2]), + }); } } @@ -1474,14 +1482,16 @@ export async function initializeSettings(scrobbler, player, api, ui) { }); geqGains = newGains; - geqPreamp = Math.max(-20, Math.min(20, preamp)); equalizerSettings.setGraphicEqGains(geqGains); - equalizerSettings.setGraphicEqPreamp(geqPreamp); audioContextManager.setGraphicEqAllGains(geqGains); - audioContextManager.setGraphicEqPreamp(geqPreamp); geqSyncAllSliders(); - geqPreampSliders.forEach((s) => (s.value = geqPreamp)); - geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); + if (hasPreamp) { + geqPreamp = Math.max(-20, Math.min(20, preamp)); + equalizerSettings.setGraphicEqPreamp(geqPreamp); + audioContextManager.setGraphicEqPreamp(geqPreamp); + geqPreampSliders.forEach((s) => (s.value = geqPreamp)); + geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); + } geqPresetSelects.forEach((s) => { s.value = ''; s.dispatchEvent(new Event('change')); @@ -1496,7 +1506,17 @@ export async function initializeSettings(scrobbler, player, api, ui) { } // Legacy EQ Custom Presets (Save / Delete) - const LEGACY_GEQ_CUSTOM_PRESETS_KEY = 'legacy-geq-custom-presets'; + const LEGACY_GEQ_CUSTOM_PRESETS_KEY = 'monochrome-legacy-geq-custom-presets'; + // Migrate from old key if present + try { + const oldData = localStorage.getItem('legacy-geq-custom-presets'); + if (oldData && !localStorage.getItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY)) { + localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, oldData); + localStorage.removeItem('legacy-geq-custom-presets'); + } + } catch { + /* ignore */ + } const legacyGeqSavePresetBtn = document.getElementById('legacy-geq-save-preset-btn'); const legacyGeqDeletePresetBtn = document.getElementById('legacy-geq-delete-preset-btn'); @@ -1510,7 +1530,12 @@ export async function initializeSettings(scrobbler, player, api, ui) { }; const saveLegacyGeqCustomPresets = (presets) => { - localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, JSON.stringify(presets)); + try { + localStorage.setItem(LEGACY_GEQ_CUSTOM_PRESETS_KEY, JSON.stringify(presets)); + } catch (e) { + console.error('[Legacy GEQ] Failed to save presets:', e); + alert('Failed to save preset. Storage may be full.'); + } }; /** Rebuild custom preset options in all legacy GEQ preset dropdowns */ @@ -1555,31 +1580,37 @@ export async function initializeSettings(scrobbler, player, api, ui) { geqPresetSelects.forEach((select) => { select.addEventListener('change', () => { const key = select.value; - if (!key) { - updateDeleteBtnVisibility(); - return; - } - - // Check custom presets first - const customPresets = getLegacyGeqCustomPresets(); - if (customPresets[key]) { - geqGains = [...customPresets[key].gains]; - equalizerSettings.setGraphicEqGains(geqGains); - audioContextManager.setGraphicEqAllGains(geqGains); - geqSyncAllSliders(); - if (customPresets[key].preamp !== undefined) { - geqPreamp = customPresets[key].preamp; - equalizerSettings.setGraphicEqPreamp(geqPreamp); - audioContextManager.setGraphicEqPreamp(geqPreamp); - geqPreampSliders.forEach((s) => (s.value = geqPreamp)); - geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); + if (key) { + // Check custom presets first + const customPresets = getLegacyGeqCustomPresets(); + if (customPresets[key]) { + const gains = customPresets[key]?.gains; + if (!Array.isArray(gains) || gains.length !== GEQ_FREQUENCIES.length) { + updateDeleteBtnVisibility(); + return; + } + geqGains = gains.map((g) => { + const n = Number(g); + return Number.isFinite(n) + ? Math.max(parseFloat(geqRange.min), Math.min(parseFloat(geqRange.max), n)) + : 0; + }); + equalizerSettings.setGraphicEqGains(geqGains); + audioContextManager.setGraphicEqAllGains(geqGains); + geqSyncAllSliders(); + if (customPresets[key].preamp !== undefined) { + geqPreamp = customPresets[key].preamp; + equalizerSettings.setGraphicEqPreamp(geqPreamp); + audioContextManager.setGraphicEqPreamp(geqPreamp); + geqPreampSliders.forEach((s) => (s.value = geqPreamp)); + geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`)); + } + geqPresetSelects.forEach((s) => { + if (s !== select) s.value = key; + }); } - geqPresetSelects.forEach((s) => { - if (s !== select) s.value = key; - }); - updateDeleteBtnVisibility(); - return; } + updateDeleteBtnVisibility(); }); }); diff --git a/styles.css b/styles.css index baa5e44..b3d3241 100644 --- a/styles.css +++ b/styles.css @@ -7934,6 +7934,8 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { background: rgb(0, 0, 0, 0.15); border-radius: var(--radius); min-height: 240px; + overflow-x: auto; + overscroll-behavior-x: contain; } .graphic-eq-band { @@ -7986,6 +7988,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { display: flex; align-items: center; gap: var(--spacing-md); + flex-wrap: wrap; } .graphic-eq-preamp { @@ -8033,6 +8036,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { .graphic-eq-band-value { font-size: 0.5rem; } + + .graphic-eq-bottom-row { + gap: var(--spacing-sm); + } + + .graphic-eq-preamp { + min-width: 0; + flex-basis: 100%; + } } /* ========================================