reorganize settings menu, add playback speed reset and instances tab
This commit is contained in:
parent
b9bbbb6820
commit
473d63c899
4 changed files with 227 additions and 113 deletions
215
index.html
215
index.html
|
|
@ -3428,6 +3428,7 @@
|
|||
<button class="settings-tab" data-tab="scrobbling">Scrobbling</button>
|
||||
<button class="settings-tab" data-tab="audio">Audio</button>
|
||||
<button class="settings-tab" data-tab="downloads">Downloads</button>
|
||||
<button class="settings-tab" data-tab="instances">Instances</button>
|
||||
<button class="settings-tab" data-tab="system">System</button>
|
||||
</div>
|
||||
<div class="settings-tab-content active" id="settings-tab-appearance">
|
||||
|
|
@ -3665,6 +3666,9 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Full-screen Visualizer</span>
|
||||
|
|
@ -3868,6 +3872,29 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Compact Artists</span>
|
||||
<span class="description">Show artist cards in a compact, horizontal layout</span>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="compact-artist-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Compact Albums</span>
|
||||
<span class="description">Show album cards in a compact, horizontal layout</span>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="compact-album-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group" id="sidebar-order-settings-group">
|
||||
<div class="sidebar-settings-section sidebar-settings-main">
|
||||
<span class="sidebar-settings-section-label">TOP SECTION</span>
|
||||
|
|
@ -4502,43 +4529,6 @@
|
|||
<option value="LOW">AAC 96kbps</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Download Quality</span>
|
||||
<span class="description">Quality for track downloads</span>
|
||||
</div>
|
||||
<select id="download-quality-setting">
|
||||
<option value="HI_RES_LOSSLESS">Hi-Res FLAC (24-bit)</option>
|
||||
<option value="LOSSLESS">FLAC (Lossless)</option>
|
||||
<option value="MP3_320">MP3 320kbps</option>
|
||||
<option value="HIGH">AAC 320kbps</option>
|
||||
<option value="LOW">AAC 96kbps</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Lossless Container</span>
|
||||
<span class="description">Container format for lossless downloads</span>
|
||||
</div>
|
||||
<select id="lossless-container-setting">
|
||||
<option value="flac">FLAC</option>
|
||||
<option value="alac">Apple Lossless</option>
|
||||
<option value="nochange">Don't change</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Cover Art Size</span>
|
||||
<span class="description">Size for downloaded/embedded cover art</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
id="cover-art-size-setting"
|
||||
class="template-input"
|
||||
style="width: 120px; text-align: right"
|
||||
placeholder="1280x1280"
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Show Quality Badges</span>
|
||||
|
|
@ -4571,6 +4561,9 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">ReplayGain Mode</span>
|
||||
|
|
@ -4624,7 +4617,7 @@
|
|||
<span class="label">Playback Speed</span>
|
||||
<span class="description">Adjust playback speed (0.01x - 100x)</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 12px">
|
||||
<div class="playback-speed-control">
|
||||
<input
|
||||
type="range"
|
||||
id="playback-speed-slider"
|
||||
|
|
@ -4632,7 +4625,7 @@
|
|||
max="4.0"
|
||||
step="0.01"
|
||||
value="1.0"
|
||||
style="width: 150px"
|
||||
class="playback-speed-slider"
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
|
|
@ -4641,18 +4634,12 @@
|
|||
max="100"
|
||||
step="0.01"
|
||||
value="1.0"
|
||||
style="
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
font-family: var(--font-family);
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
"
|
||||
class="playback-speed-number-input"
|
||||
/>
|
||||
<span style="font-family: var(--font-family)">x</span>
|
||||
<span class="playback-speed-unit">x</span>
|
||||
<button id="playback-speed-reset" class="btn-secondary" title="Reset to default">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -4924,32 +4911,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="info">
|
||||
<span class="label">Compact Artists</span>
|
||||
<span class="description">Show artist cards in a compact, horizontal layout</span>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="compact-artist-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Compact Albums</span>
|
||||
<span class="description">Show album cards in a compact, horizontal layout</span>
|
||||
</div>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="compact-album-toggle" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-tab-content" id="settings-tab-downloads">
|
||||
<div class="settings-list">
|
||||
<div class="settings-tab-content" id="settings-tab-downloads">
|
||||
<div class="settings-list">
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
|
|
@ -4985,6 +4950,43 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Download Quality</span>
|
||||
<span class="description">Quality for track downloads</span>
|
||||
</div>
|
||||
<select id="download-quality-setting">
|
||||
<option value="HI_RES_LOSSLESS">Hi-Res FLAC (24-bit)</option>
|
||||
<option value="LOSSLESS">FLAC (Lossless)</option>
|
||||
<option value="MP3_320">MP3 320kbps</option>
|
||||
<option value="HIGH">AAC 320kbps</option>
|
||||
<option value="LOW">AAC 96kbps</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Lossless Container</span>
|
||||
<span class="description">Container format for lossless downloads</span>
|
||||
</div>
|
||||
<select id="lossless-container-setting">
|
||||
<option value="flac">FLAC</option>
|
||||
<option value="alac">Apple Lossless</option>
|
||||
<option value="nochange">Don't change</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Cover Art Size</span>
|
||||
<span class="description">Size for downloaded/embedded cover art</span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
id="cover-art-size-setting"
|
||||
class="template-input"
|
||||
style="width: 120px; text-align: right"
|
||||
placeholder="1280x1280"
|
||||
/>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Filename Template</span>
|
||||
|
|
@ -5015,6 +5017,9 @@
|
|||
placeholder="{albumTitle} - {albumArtist} - monochrome.tf"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Generate M3U</span>
|
||||
|
|
@ -5067,6 +5072,9 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Relative Paths</span>
|
||||
|
|
@ -5092,6 +5100,36 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-content" id="settings-tab-instances">
|
||||
<div class="settings-list">
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">ADVANCED: Custom Database/Auth</span>
|
||||
<span class="description">Configure custom PocketBase and Firebase instances</span>
|
||||
</div>
|
||||
<button id="custom-db-btn" class="btn-secondary">Configure</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div id="api-instance-manager">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">API Instances</span>
|
||||
<span class="description">Manage and prioritize API instances.</span>
|
||||
</div>
|
||||
<button id="refresh-speed-test-btn" class="btn-secondary">
|
||||
Refresh Instance List
|
||||
</button>
|
||||
</div>
|
||||
<ul id="api-instance-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-tab-content" id="settings-tab-system">
|
||||
<div class="settings-list">
|
||||
<div class="settings-group">
|
||||
|
|
@ -5140,6 +5178,9 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Reset Local Data</span>
|
||||
|
|
@ -5160,6 +5201,9 @@
|
|||
Clear Cloud Data
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Backup & Restore</span>
|
||||
|
|
@ -5187,27 +5231,10 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">ADVANCED: Custom Database/Auth</span>
|
||||
<span class="description">Configure custom PocketBase and Firebase instances</span>
|
||||
</div>
|
||||
<button id="custom-db-btn" class="btn-secondary">Configure</button>
|
||||
</div>
|
||||
<div id="api-instance-manager">
|
||||
<div class="setting-item" style="padding-bottom: 1rem; border: none">
|
||||
<div class="info">
|
||||
<span class="label">API Instances</span>
|
||||
<span class="description">Manage and prioritize API instances.</span>
|
||||
</div>
|
||||
<button id="refresh-speed-test-btn" class="btn-secondary">
|
||||
Refresh Instance List
|
||||
</button>
|
||||
</div>
|
||||
<ul id="api-instance-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item" style="padding-bottom: 1rem; border-top: 1px solid var(--border)">
|
||||
<div class="settings-group">
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Blocked Content</span>
|
||||
<span class="description"
|
||||
|
|
|
|||
|
|
@ -901,33 +901,56 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
|||
// ========================================
|
||||
const playbackSpeedSlider = document.getElementById('playback-speed-slider');
|
||||
const playbackSpeedInput = document.getElementById('playback-speed-input');
|
||||
const playbackSpeedReset = document.getElementById('playback-speed-reset');
|
||||
|
||||
if (playbackSpeedSlider && playbackSpeedInput) {
|
||||
const currentSpeed = audioEffectsSettings.getSpeed();
|
||||
// Clamp slider to its range (0.25-4), but show actual value in input
|
||||
playbackSpeedSlider.value = Math.max(0.25, Math.min(4.0, currentSpeed));
|
||||
playbackSpeedInput.value = currentSpeed;
|
||||
|
||||
// Slider only controls 0.25-4 range
|
||||
playbackSpeedSlider.addEventListener('input', (e) => {
|
||||
const speed = parseFloat(e.target.value) || 1.0;
|
||||
playbackSpeedInput.value = speed;
|
||||
player.setPlaybackSpeed(speed);
|
||||
});
|
||||
|
||||
// Input allows full 0.01-100 range
|
||||
const handleInputChange = () => {
|
||||
const speed = parseFloat(playbackSpeedInput.value) || 1.0;
|
||||
const validSpeed = Math.max(0.01, Math.min(100, speed));
|
||||
// Helper function to update both controls
|
||||
const updatePlaybackSpeedControls = (speed) => {
|
||||
const validSpeed = Math.max(0.01, Math.min(100, parseFloat(speed) || 1.0));
|
||||
playbackSpeedInput.value = validSpeed;
|
||||
// Only update slider if value is within slider range
|
||||
if (validSpeed >= 0.25 && validSpeed <= 4.0) {
|
||||
playbackSpeedSlider.value = validSpeed;
|
||||
}
|
||||
player.setPlaybackSpeed(validSpeed);
|
||||
return validSpeed;
|
||||
};
|
||||
|
||||
playbackSpeedInput.addEventListener('change', handleInputChange);
|
||||
playbackSpeedInput.addEventListener('blur', handleInputChange);
|
||||
// Initialize with current value
|
||||
const currentSpeed = audioEffectsSettings.getSpeed();
|
||||
updatePlaybackSpeedControls(currentSpeed);
|
||||
|
||||
playbackSpeedSlider.addEventListener('input', (e) => {
|
||||
const speed = parseFloat(e.target.value);
|
||||
playbackSpeedInput.value = speed;
|
||||
audioEffectsSettings.setSpeed(speed);
|
||||
player.setPlaybackSpeed(speed);
|
||||
});
|
||||
|
||||
playbackSpeedInput.addEventListener('input', (e) => {
|
||||
const speed = parseFloat(e.target.value);
|
||||
if (!isNaN(speed) && speed >= 0.01 && speed <= 100) {
|
||||
if (speed >= 0.25 && speed <= 4.0) {
|
||||
playbackSpeedSlider.value = speed;
|
||||
}
|
||||
audioEffectsSettings.setSpeed(speed);
|
||||
player.setPlaybackSpeed(speed);
|
||||
}
|
||||
});
|
||||
|
||||
playbackSpeedInput.addEventListener('change', (e) => {
|
||||
const speed = parseFloat(e.target.value);
|
||||
const validSpeed = updatePlaybackSpeedControls(speed);
|
||||
audioEffectsSettings.setSpeed(validSpeed);
|
||||
player.setPlaybackSpeed(validSpeed);
|
||||
});
|
||||
|
||||
if (playbackSpeedReset) {
|
||||
playbackSpeedReset.addEventListener('click', () => {
|
||||
const defaultSpeed = audioEffectsSettings.resetSpeed();
|
||||
updatePlaybackSpeedControls(defaultSpeed);
|
||||
player.setPlaybackSpeed(defaultSpeed);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
|
|
|
|||
|
|
@ -1352,6 +1352,11 @@ export const audioEffectsSettings = {
|
|||
localStorage.setItem(this.SPEED_KEY, validSpeed.toString());
|
||||
},
|
||||
|
||||
resetSpeed() {
|
||||
this.setSpeed(1.0);
|
||||
return 1.0;
|
||||
},
|
||||
|
||||
// Preserve pitch when changing speed (default true)
|
||||
isPreservePitchEnabled() {
|
||||
try {
|
||||
|
|
|
|||
59
styles.css
59
styles.css
|
|
@ -2617,6 +2617,65 @@ input[type='search']::-webkit-search-cancel-button {
|
|||
width: 100px;
|
||||
}
|
||||
|
||||
.playback-speed-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.playback-speed-slider {
|
||||
appearance: none;
|
||||
width: 150px;
|
||||
height: 6px;
|
||||
background: var(--border);
|
||||
border-radius: var(--radius-full);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.playback-speed-slider::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--primary);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
.playback-speed-slider::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.playback-speed-number-input {
|
||||
width: 80px;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--input);
|
||||
color: var(--foreground);
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.playback-speed-unit {
|
||||
font-size: 0.9rem;
|
||||
color: var(--muted-foreground);
|
||||
min-width: 1rem;
|
||||
}
|
||||
|
||||
.playback-speed-number-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Hide arrows/spinners for number input */
|
||||
.playback-speed-number-input::-webkit-outer-spin-button,
|
||||
.playback-speed-number-input::-webkit-inner-spin-button {
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.template-input {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue