From f603f92868cd9185f7c342f0b9117d3adcf06d97 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:24:15 -0700 Subject: [PATCH] Add configurable music library paths for file resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New setting in Settings > Library lets users add folder paths where their music files live. The file resolver checks these paths when looking for library files, solving Docker path mismatches and multi- folder libraries. Required for tag writing, streaming, and orphan detection when the media server reports paths that differ from what SoulSync can see. Docker users mount their music folder(s) with read-write access and add the container-side path. Default is empty — existing users see no change. --- config/settings.py | 3 +++ web_server.py | 12 ++++++++++ webui/index.html | 19 ++++++++++++++++ webui/static/script.js | 50 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/config/settings.py b/config/settings.py index a9d8740c..6820b9fc 100644 --- a/config/settings.py +++ b/config/settings.py @@ -460,6 +460,9 @@ class ConfigManager: "enabled": True, "poll_interval": 30 }, + "library": { + "music_paths": [] + }, "import": { "staging_path": "./Staging", "replace_lower_quality": False diff --git a/web_server.py b/web_server.py index 9dda191f..303db8a5 100644 --- a/web_server.py +++ b/web_server.py @@ -12913,6 +12913,18 @@ def _resolve_library_file_path(file_path): except Exception: pass + # Check user-configured music library paths (Settings > Library) + try: + music_paths = config_manager.get('library.music_paths', []) + if isinstance(music_paths, list): + for p in music_paths: + if p and isinstance(p, str): + resolved_p = docker_resolve_path(p.strip()) + if resolved_p: + library_dirs.add(resolved_p) + except Exception: + pass + path_parts = file_path.replace('\\', '/').split('/') # Try progressively shorter path suffixes against each candidate directory diff --git a/webui/index.html b/webui/index.html index eeb8afe3..8344ca8a 100644 --- a/webui/index.html +++ b/webui/index.html @@ -5693,6 +5693,25 @@ + +
+

📂 Music Library Paths

+ +
+ Tell SoulSync where your music files live. Required for tag writing, streaming, and file detection + when your media server stores files at a different path than SoulSync can see. + Docker users: mount your music folder(s) into the SoulSync container with read-write access, + then add the container-side path here (e.g. /music). +
+ +
+ +
+ +
+
+ +

🔞 Content Filter

diff --git a/webui/static/script.js b/webui/static/script.js index 11521810..22427901 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -5969,6 +5969,10 @@ async function loadSettingsData() { document.getElementById('lossy-copy-options').style.display = settings.lossy_copy?.enabled ? 'block' : 'none'; + // Populate Music Library Paths + const _musicPaths = settings.library?.music_paths || []; + renderMusicPaths(_musicPaths); + // Populate Content Filter settings document.getElementById('allow-explicit').checked = settings.content_filter?.allow_explicit !== false; @@ -6606,6 +6610,49 @@ async function toggleHydrabaseFromSettings() { } } +// ── Music Library Paths ── +function renderMusicPaths(paths) { + const container = document.getElementById('music-paths-list'); + if (!container) return; + if (!paths || paths.length === 0) { + container.innerHTML = '
No paths configured. Click "Add Path" to add your music folder(s).
'; + return; + } + container.innerHTML = paths.map((p, i) => ` +
+ + +
+ `).join(''); +} + +function addMusicPathRow() { + const container = document.getElementById('music-paths-list'); + if (!container) return; + // Clear the "no paths" message if present + const placeholder = container.querySelector('div[style*="color: rgba"]'); + if (placeholder && !container.querySelector('.music-path-row')) placeholder.remove(); + const row = document.createElement('div'); + row.className = 'form-group music-path-row'; + row.style.marginBottom = '4px'; + row.innerHTML = ` + + + `; + container.appendChild(row); + row.querySelector('input').focus(); +} + +function collectMusicPaths() { + const inputs = document.querySelectorAll('.music-path-input'); + const paths = []; + inputs.forEach(input => { + const val = input.value.trim(); + if (val) paths.push(val); + }); + return paths; +} + // ── Database Maintenance ── async function loadDbMaintenanceInfo() { try { @@ -7079,6 +7126,9 @@ async function saveSettings(quiet = false) { content_filter: { allow_explicit: document.getElementById('allow-explicit').checked }, + library: { + music_paths: collectMusicPaths() + }, import: { replace_lower_quality: document.getElementById('import-replace-lower-quality').checked },