diff --git a/web_server.py b/web_server.py index fb43fca4..838b3959 100644 --- a/web_server.py +++ b/web_server.py @@ -21611,6 +21611,35 @@ def hifi_reorder_instances(): return jsonify({'success': False, 'error': str(e)}), 500 +@app.route('/api/hifi/instances/reset', methods=['POST']) +@admin_only +def hifi_reset_instances(): + """Restore any built-in default HiFi instances that were removed. + + Non-destructive (#Sokhi): keeps user-added instances and the existing + order/enabled state, and only re-adds the provided defaults that are + currently missing — so you can recover ones you removed by accident without + wiping the working instance you just found.""" + try: + from database.music_database import get_database + from core.hifi_client import DEFAULT_INSTANCES + db = get_database() + existing = {(i.get('url') or '').rstrip('/') for i in db.get_all_hifi_instances()} + priority = len(existing) + restored = [] + for url in DEFAULT_INSTANCES: + u = url.rstrip('/') + if u not in existing and db.add_hifi_instance(u, priority): + restored.append(u) + priority += 1 + if download_orchestrator: + download_orchestrator.reload_instances('hifi') + return jsonify({'success': True, 'restored': len(restored), 'urls': restored}) + except Exception as e: + logger.error(f"Error resetting HiFi instances: {e}") + return jsonify({'success': False, 'error': str(e)}), 500 + + @app.route('/api/hifi/instances/list', methods=['GET']) @admin_only def hifi_list_instances(): diff --git a/webui/index.html b/webui/index.html index 5da85124..a93dd265 100644 --- a/webui/index.html +++ b/webui/index.html @@ -4876,7 +4876,10 @@ - +
+ + +
diff --git a/webui/static/settings.js b/webui/static/settings.js index 5091fb40..af4bb3f7 100644 --- a/webui/static/settings.js +++ b/webui/static/settings.js @@ -4220,6 +4220,30 @@ async function addHiFiInstance() { } } +async function restoreDefaultHiFiInstances() { + const btn = document.getElementById('hifi-instances-restore-btn'); + const orig = btn ? btn.textContent : ''; + if (btn) { btn.disabled = true; btn.textContent = 'Restoring…'; } + try { + const resp = await fetch('/api/hifi/instances/reset', { method: 'POST' }); + const data = await resp.json(); + if (data.success) { + loadHiFiInstances(); + const n = data.restored || 0; + if (typeof showToast === 'function') { + showToast(n ? `Restored ${n} default instance${n === 1 ? '' : 's'}` + : 'All default instances are already present', 'success'); + } + } else { + alert(data.error || 'Failed to restore defaults'); + } + } catch (e) { + alert(`Error: ${e.message}`); + } finally { + if (btn) { btn.disabled = false; btn.textContent = orig || 'Restore Defaults'; } + } +} + async function removeHiFiInstance(url) { try { const resp = await fetch(`/api/hifi/instances?url=${encodeURIComponent(url)}`, { diff --git a/webui/static/style.css b/webui/static/style.css index 2a645aef..d3a2d09c 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -62637,8 +62637,19 @@ body[data-artist-source="source"] #artist-detail-page #library-artist-enhance-bt .hifi-instance-toggle { flex-shrink: 0; cursor: pointer; - font-size: 0.9em; - transition: color 0.15s; + font-size: 0.95em; + transition: color 0.15s, background 0.15s; + /* Bigger tap target — the bare glyph was hard to hit/register (#Sokhi). */ + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 30px; + height: 30px; + border-radius: 6px; + user-select: none; +} +.hifi-instance-toggle:hover { + background: rgba(255, 255, 255, 0.07); } .hifi-instance-toggle.on { color: #4caf50; @@ -62656,11 +62667,20 @@ body[data-artist-source="source"] #artist-detail-page #library-artist-enhance-bt flex-shrink: 0; color: #f44336; cursor: pointer; - font-size: 0.9em; - transition: color 0.15s; + font-size: 0.95em; + transition: color 0.15s, background 0.15s; + /* Bigger tap target — the bare ✖ was hard to hit/register (#Sokhi). */ + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 30px; + height: 30px; + border-radius: 6px; + user-select: none; } .hifi-instance-remove:hover { color: #ef5350; + background: rgba(244, 67, 54, 0.15); } /* ==========================================================================