Add SoulSync Standalone toggle to Settings page
Fourth server option on the Connections tab with SoulSync logo and 'Standalone' label. Config panel shows Transfer folder path and Verify Folder button. Test connection counts audio files in the Transfer folder. Settings save/load properly detects soulsync toggle.
This commit is contained in:
parent
43dedeb2ee
commit
c009acdbb6
4 changed files with 85 additions and 1 deletions
|
|
@ -4342,6 +4342,20 @@ def run_service_test(service, test_config):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, f"Navidrome connection error: {str(e)}"
|
return False, f"Navidrome connection error: {str(e)}"
|
||||||
|
elif service == "soulsync":
|
||||||
|
transfer_path = docker_resolve_path(config_manager.get('soulseek.transfer_path', './Transfer'))
|
||||||
|
if os.path.isdir(transfer_path):
|
||||||
|
# Count audio files
|
||||||
|
count = 0
|
||||||
|
for root, dirs, files in os.walk(transfer_path):
|
||||||
|
for f in files:
|
||||||
|
if os.path.splitext(f)[1].lower() in ('.mp3', '.flac', '.ogg', '.opus', '.m4a', '.aac', '.wav'):
|
||||||
|
count += 1
|
||||||
|
if count > 100:
|
||||||
|
break # Don't count everything, just confirm files exist
|
||||||
|
return True, f"SoulSync standalone ready! Transfer folder: {transfer_path} ({count}+ audio files)"
|
||||||
|
else:
|
||||||
|
return False, f"Transfer folder not found: {transfer_path}"
|
||||||
elif service == "soulseek":
|
elif service == "soulseek":
|
||||||
if soulseek_client is None:
|
if soulseek_client is None:
|
||||||
return False, "Download orchestrator failed to initialize. Check server logs for startup errors."
|
return False, "Download orchestrator failed to initialize. Check server logs for startup errors."
|
||||||
|
|
|
||||||
|
|
@ -4307,6 +4307,12 @@
|
||||||
class="server-logo">
|
class="server-logo">
|
||||||
Navidrome
|
Navidrome
|
||||||
</button>
|
</button>
|
||||||
|
<button class="server-toggle-btn" id="soulsync-toggle"
|
||||||
|
onclick="toggleServer('soulsync')">
|
||||||
|
<img src="/static/trans2.png" alt="SoulSync"
|
||||||
|
class="server-logo">
|
||||||
|
Standalone
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Plex Settings -->
|
<!-- Plex Settings -->
|
||||||
|
|
@ -4407,6 +4413,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="server-config-container hidden" id="soulsync-container">
|
||||||
|
<div class="soulsync-standalone-info">
|
||||||
|
<img src="/static/trans2.png" alt="SoulSync" class="soulsync-standalone-logo">
|
||||||
|
<div class="soulsync-standalone-text">
|
||||||
|
<h4>Standalone Mode</h4>
|
||||||
|
<p>SoulSync manages your library directly without an external media server. Downloads and imports are added to the library automatically.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Library Folder (Transfer Path):</label>
|
||||||
|
<input type="text" id="soulsync-transfer-path" disabled placeholder="Set in Paths section below">
|
||||||
|
<small>Files in this folder are your library. Configure the path in the Paths section.</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button class="test-button" onclick="testConnection('soulsync')">Verify Folder</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Server Test Button -->
|
<!-- Server Test Button -->
|
||||||
<div class="server-test-section">
|
<div class="server-test-section">
|
||||||
<button class="test-button server-test-btn" onclick="testConnection('server')">Test
|
<button class="test-button server-test-btn" onclick="testConnection('server')">Test
|
||||||
|
|
|
||||||
|
|
@ -6349,12 +6349,14 @@ function toggleServer(serverType) {
|
||||||
document.getElementById('plex-toggle').classList.remove('active');
|
document.getElementById('plex-toggle').classList.remove('active');
|
||||||
document.getElementById('jellyfin-toggle').classList.remove('active');
|
document.getElementById('jellyfin-toggle').classList.remove('active');
|
||||||
document.getElementById('navidrome-toggle').classList.remove('active');
|
document.getElementById('navidrome-toggle').classList.remove('active');
|
||||||
document.getElementById(`${serverType}-toggle`).classList.add('active');
|
document.getElementById('soulsync-toggle')?.classList.remove('active');
|
||||||
|
document.getElementById(`${serverType}-toggle`)?.classList.add('active');
|
||||||
|
|
||||||
// Show/hide server containers
|
// Show/hide server containers
|
||||||
document.getElementById('plex-container').classList.toggle('hidden', serverType !== 'plex');
|
document.getElementById('plex-container').classList.toggle('hidden', serverType !== 'plex');
|
||||||
document.getElementById('jellyfin-container').classList.toggle('hidden', serverType !== 'jellyfin');
|
document.getElementById('jellyfin-container').classList.toggle('hidden', serverType !== 'jellyfin');
|
||||||
document.getElementById('navidrome-container').classList.toggle('hidden', serverType !== 'navidrome');
|
document.getElementById('navidrome-container').classList.toggle('hidden', serverType !== 'navidrome');
|
||||||
|
document.getElementById('soulsync-container')?.classList.toggle('hidden', serverType !== 'soulsync');
|
||||||
|
|
||||||
// Load Plex music libraries when switching to Plex
|
// Load Plex music libraries when switching to Plex
|
||||||
if (serverType === 'plex') {
|
if (serverType === 'plex') {
|
||||||
|
|
@ -6371,6 +6373,15 @@ function toggleServer(serverType) {
|
||||||
loadNavidromeMusicFolders();
|
loadNavidromeMusicFolders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show Transfer path for SoulSync standalone
|
||||||
|
if (serverType === 'soulsync') {
|
||||||
|
const transferInput = document.getElementById('soulsync-transfer-path');
|
||||||
|
const transferPathEl = document.getElementById('transfer-path');
|
||||||
|
if (transferInput && transferPathEl) {
|
||||||
|
transferInput.value = transferPathEl.value || './Transfer';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Auto-save after server toggle change
|
// Auto-save after server toggle change
|
||||||
debouncedAutoSaveSettings();
|
debouncedAutoSaveSettings();
|
||||||
}
|
}
|
||||||
|
|
@ -7185,6 +7196,8 @@ async function saveSettings(quiet = false) {
|
||||||
activeServer = 'jellyfin';
|
activeServer = 'jellyfin';
|
||||||
} else if (document.getElementById('navidrome-toggle').classList.contains('active')) {
|
} else if (document.getElementById('navidrome-toggle').classList.contains('active')) {
|
||||||
activeServer = 'navidrome';
|
activeServer = 'navidrome';
|
||||||
|
} else if (document.getElementById('soulsync-toggle')?.classList.contains('active')) {
|
||||||
|
activeServer = 'soulsync';
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
|
|
|
||||||
|
|
@ -3164,6 +3164,39 @@ body.helper-mode-active #dashboard-activity-feed:hover {
|
||||||
rgba(var(--accent-light-rgb), 0.18) 100%);
|
rgba(var(--accent-light-rgb), 0.18) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SoulSync standalone info section */
|
||||||
|
.soulsync-standalone-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 14px;
|
||||||
|
background: rgba(var(--accent-rgb), 0.04);
|
||||||
|
border: 1px solid rgba(var(--accent-rgb), 0.1);
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soulsync-standalone-logo {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.soulsync-standalone-text h4 {
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.soulsync-standalone-text p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.server-toggle-btn.active .server-logo {
|
.server-toggle-btn.active .server-logo {
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue