discovery: add Settings -> Discovery -> Adventurousness slider + align config key
A 0..1 range slider (Safe <-> Adventurous) in Settings -> Discovery with a live value readout. It auto-saves via the settings page existing range-input listener, persists to config under discover.adventurousness (matching the /api/settings "discover" section), and re-populates on load. The listening-recs route reads that key (fixed from discovery. -> discover. to match the settings section). Drag it up and "Based On Your Listening" leans harder toward obscure picks on the next load. 64 script-integrity tests green.
This commit is contained in:
parent
ce8faf0ecc
commit
29f84b5601
3 changed files with 39 additions and 1 deletions
|
|
@ -29608,7 +29608,7 @@ def get_discover_listening_recommendations():
|
|||
# don't carry it inline, so this works on existing data), then push globally-popular picks
|
||||
# down per the user's dial. level 0 -> unchanged. Fail-soft: any hiccup leaves the order.
|
||||
try:
|
||||
level = float(config_manager.get('discovery.adventurousness', 0.3) or 0)
|
||||
level = float(config_manager.get('discover.adventurousness', 0.3) or 0)
|
||||
except (TypeError, ValueError):
|
||||
level = 0.0
|
||||
if level > 0 and stored:
|
||||
|
|
|
|||
|
|
@ -6201,6 +6201,30 @@
|
|||
</div>
|
||||
</div><!-- end Listening Stats body -->
|
||||
|
||||
<!-- Discovery (collapsible tile) -->
|
||||
<div class="settings-section-header collapsed" data-stg="library" onclick="this.classList.toggle('collapsed'); const b=this.nextElementSibling; b.classList.toggle('collapsed'); b.style.display=b.classList.contains('collapsed')?'none':''">
|
||||
<span class="settings-section-arrow">▼</span>
|
||||
<h3>Discovery</h3>
|
||||
<span class="settings-section-hint">How adventurous your recommendations are</span>
|
||||
</div>
|
||||
<div class="settings-section-body collapsed" data-stg="library" style="display:none">
|
||||
<div class="settings-group" data-stg="library">
|
||||
<div class="form-group">
|
||||
<label>Adventurousness</label>
|
||||
<div style="display:flex; align-items:center; gap:12px; margin-top:8px">
|
||||
<span style="font-size:12px; color:#999">Safe</span>
|
||||
<input type="range" id="discover-adventurousness" min="0" max="1" step="0.05" value="0.3" style="flex:1"
|
||||
oninput="var v=document.getElementById('discover-adventurousness-val'); if(v) v.textContent=parseFloat(this.value).toFixed(2)">
|
||||
<span style="font-size:12px; color:#999">Adventurous</span>
|
||||
<span id="discover-adventurousness-val" style="min-width:36px; text-align:right; font-weight:700; color:var(--accent)">0.30</span>
|
||||
</div>
|
||||
<div class="help-text setting-help-body" style="margin-top:10px">
|
||||
Higher pushes globally-popular artists down so more obscure, non-obvious picks surface; lower keeps recommendations safe and close to what you already know. Affects <strong>Based On Your Listening</strong>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- end Discovery body -->
|
||||
|
||||
<!-- Security & Access (collapsible tile) -->
|
||||
<div class="settings-section-header collapsed" data-stg="advanced" onclick="this.classList.toggle('collapsed'); const b=this.nextElementSibling; b.classList.toggle('collapsed'); b.style.display=b.classList.contains('collapsed')?'none':''">
|
||||
<span class="settings-section-arrow">▼</span>
|
||||
|
|
|
|||
|
|
@ -1480,6 +1480,13 @@ async function loadSettingsData() {
|
|||
// Populate Listening Stats settings
|
||||
document.getElementById('listening-stats-enabled').checked = settings.listening_stats?.enabled === true;
|
||||
document.getElementById('listening-stats-interval').value = settings.listening_stats?.poll_interval || 30;
|
||||
const _advEl = document.getElementById('discover-adventurousness');
|
||||
if (_advEl) {
|
||||
const _adv = settings.discover?.adventurousness;
|
||||
_advEl.value = (typeof _adv === 'number') ? _adv : 0.3;
|
||||
const _advVal = document.getElementById('discover-adventurousness-val');
|
||||
if (_advVal) _advVal.textContent = parseFloat(_advEl.value).toFixed(2);
|
||||
}
|
||||
document.getElementById('lossy-copy-options').style.display =
|
||||
settings.lossy_copy?.enabled ? 'block' : 'none';
|
||||
|
||||
|
|
@ -3495,6 +3502,13 @@ async function saveSettings(quiet = false) {
|
|||
enabled: document.getElementById('listening-stats-enabled').checked,
|
||||
poll_interval: parseInt(document.getElementById('listening-stats-interval').value) || 30,
|
||||
},
|
||||
discover: {
|
||||
// Adventurousness dial (0 safe .. 1 obscure) — drives the Discover popularity penalty.
|
||||
// Use the slider's value directly (0 is valid; don't `|| 0.3` it away).
|
||||
adventurousness: document.getElementById('discover-adventurousness')
|
||||
? parseFloat(document.getElementById('discover-adventurousness').value)
|
||||
: 0.3,
|
||||
},
|
||||
m3u_export: {
|
||||
enabled: document.getElementById('m3u-export-enabled').checked,
|
||||
entry_base_path: document.getElementById('m3u-entry-base-path').value || ''
|
||||
|
|
|
|||
Loading…
Reference in a new issue