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
This commit is contained in:
parent
452b810efd
commit
cb49904a21
2 changed files with 78 additions and 35 deletions
101
js/settings.js
101
js/settings.js
|
|
@ -1422,27 +1422,35 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
||||||
try {
|
try {
|
||||||
const text = event.target.result;
|
const text = event.target.result;
|
||||||
const lines = text.split('\n');
|
const lines = text.split('\n');
|
||||||
let preamp = 0;
|
let preamp = geqPreamp;
|
||||||
|
let hasPreamp = false;
|
||||||
const importedPoints = [];
|
const importedPoints = [];
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i);
|
const preampMatch = line.match(/Preamp:\s*([-\d.]+)\s*dB/i);
|
||||||
if (preampMatch) {
|
if (preampMatch) {
|
||||||
preamp = parseFloat(preampMatch[1]);
|
preamp = parseFloat(preampMatch[1]);
|
||||||
|
hasPreamp = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX
|
// EqualizerAPO format: Filter N: ON PK Fc XXXX Hz Gain X.X dB Q X.XX
|
||||||
const filterMatch = line.match(
|
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) {
|
if (filterMatch) {
|
||||||
importedPoints.push({ freq: parseFloat(filterMatch[1]), gain: parseFloat(filterMatch[2]) });
|
importedPoints.push({
|
||||||
|
freq: parseGeqLabelFrequency(filterMatch[1]),
|
||||||
|
gain: parseFloat(filterMatch[2]),
|
||||||
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Simple two-column format: freq gain (whitespace/tab/comma separated)
|
// 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) {
|
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;
|
geqGains = newGains;
|
||||||
geqPreamp = Math.max(-20, Math.min(20, preamp));
|
|
||||||
equalizerSettings.setGraphicEqGains(geqGains);
|
equalizerSettings.setGraphicEqGains(geqGains);
|
||||||
equalizerSettings.setGraphicEqPreamp(geqPreamp);
|
|
||||||
audioContextManager.setGraphicEqAllGains(geqGains);
|
audioContextManager.setGraphicEqAllGains(geqGains);
|
||||||
audioContextManager.setGraphicEqPreamp(geqPreamp);
|
|
||||||
geqSyncAllSliders();
|
geqSyncAllSliders();
|
||||||
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
|
if (hasPreamp) {
|
||||||
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
|
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) => {
|
geqPresetSelects.forEach((s) => {
|
||||||
s.value = '';
|
s.value = '';
|
||||||
s.dispatchEvent(new Event('change'));
|
s.dispatchEvent(new Event('change'));
|
||||||
|
|
@ -1496,7 +1506,17 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy EQ Custom Presets (Save / Delete)
|
// 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 legacyGeqSavePresetBtn = document.getElementById('legacy-geq-save-preset-btn');
|
||||||
const legacyGeqDeletePresetBtn = document.getElementById('legacy-geq-delete-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) => {
|
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 */
|
/** 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) => {
|
geqPresetSelects.forEach((select) => {
|
||||||
select.addEventListener('change', () => {
|
select.addEventListener('change', () => {
|
||||||
const key = select.value;
|
const key = select.value;
|
||||||
if (!key) {
|
if (key) {
|
||||||
updateDeleteBtnVisibility();
|
// Check custom presets first
|
||||||
return;
|
const customPresets = getLegacyGeqCustomPresets();
|
||||||
}
|
if (customPresets[key]) {
|
||||||
|
const gains = customPresets[key]?.gains;
|
||||||
// Check custom presets first
|
if (!Array.isArray(gains) || gains.length !== GEQ_FREQUENCIES.length) {
|
||||||
const customPresets = getLegacyGeqCustomPresets();
|
updateDeleteBtnVisibility();
|
||||||
if (customPresets[key]) {
|
return;
|
||||||
geqGains = [...customPresets[key].gains];
|
}
|
||||||
equalizerSettings.setGraphicEqGains(geqGains);
|
geqGains = gains.map((g) => {
|
||||||
audioContextManager.setGraphicEqAllGains(geqGains);
|
const n = Number(g);
|
||||||
geqSyncAllSliders();
|
return Number.isFinite(n)
|
||||||
if (customPresets[key].preamp !== undefined) {
|
? Math.max(parseFloat(geqRange.min), Math.min(parseFloat(geqRange.max), n))
|
||||||
geqPreamp = customPresets[key].preamp;
|
: 0;
|
||||||
equalizerSettings.setGraphicEqPreamp(geqPreamp);
|
});
|
||||||
audioContextManager.setGraphicEqPreamp(geqPreamp);
|
equalizerSettings.setGraphicEqGains(geqGains);
|
||||||
geqPreampSliders.forEach((s) => (s.value = geqPreamp));
|
audioContextManager.setGraphicEqAllGains(geqGains);
|
||||||
geqPreampValues.forEach((v) => (v.textContent = `${geqPreamp.toFixed(1)} dB`));
|
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
12
styles.css
12
styles.css
|
|
@ -7934,6 +7934,8 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
||||||
background: rgb(0, 0, 0, 0.15);
|
background: rgb(0, 0, 0, 0.15);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
min-height: 240px;
|
min-height: 240px;
|
||||||
|
overflow-x: auto;
|
||||||
|
overscroll-behavior-x: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graphic-eq-band {
|
.graphic-eq-band {
|
||||||
|
|
@ -7986,6 +7988,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-md);
|
gap: var(--spacing-md);
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graphic-eq-preamp {
|
.graphic-eq-preamp {
|
||||||
|
|
@ -8033,6 +8036,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
||||||
.graphic-eq-band-value {
|
.graphic-eq-band-value {
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.graphic-eq-bottom-row {
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.graphic-eq-preamp {
|
||||||
|
min-width: 0;
|
||||||
|
flex-basis: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue