Add configurable Soulseek search timeout and buffer

Introduces 'search_timeout' and 'search_timeout_buffer' options to Soulseek settings in the config, backend, and web UI. The backend now uses these values to control search duration and polling, allowing users to fine-tune how long searches run and how long to wait for late results.
pull/97/head
Broque Thomas 4 months ago
parent a2bdb93498
commit 5d29131530

@ -30,7 +30,9 @@
"slskd_url": "http://host.docker.internal:5030",
"api_key": "SoulseekAPIKey",
"download_path": "/app/downloads",
"transfer_path": "/app/Transfer"
"transfer_path": "/app/Transfer",
"search_timeout": 60,
"search_timeout_buffer": 15
},
"logging": {
"path": "logs/app.log",

@ -602,17 +602,22 @@ class SoulseekClient:
return None
async def search(self, query: str, timeout: int = 60, progress_callback=None) -> tuple[List[TrackResult], List[AlbumResult]]:
async def search(self, query: str, timeout: int = None, progress_callback=None) -> tuple[List[TrackResult], List[AlbumResult]]:
if not self.base_url:
logger.error("Soulseek client not configured")
return [], []
# Get timeout from config if not specified
if timeout is None:
from config.settings import config_manager
timeout = config_manager.get('soulseek.search_timeout', 60)
# Apply rate limiting before search
await self._wait_for_rate_limit()
try:
logger.info(f"Starting search for: '{query}'")
logger.info(f"Starting search for: '{query}' (slskd timeout: {timeout}s)")
search_data = {
'searchText': query,
'timeout': timeout * 1000, # slskd expects milliseconds
@ -645,13 +650,24 @@ class SoulseekClient:
# Track this search as active
self.active_searches[search_id] = True
# Get timeout buffer from config
from config.settings import config_manager
timeout_buffer = config_manager.get('soulseek.search_timeout_buffer', 15)
# Poll for results - process and emit results immediately when found
all_responses = []
all_tracks = []
all_albums = []
poll_interval = 1 # Check every 1.5 seconds for more responsive updates
max_polls = int(timeout / poll_interval) # 20 attempts over 30 seconds
poll_interval = 1 # Check every 1 second for responsive updates
# IMPORTANT: Poll for LONGER than slskd searches to catch all results
# slskd timeout: how long slskd searches for
# polling timeout: how long WE wait for slskd to finish (with buffer)
polling_timeout = timeout + timeout_buffer
max_polls = int(polling_timeout / poll_interval)
logger.info(f"Polling for up to {polling_timeout}s (slskd timeout: {timeout}s + buffer: {timeout_buffer}s)")
for poll_count in range(max_polls):
# Check if search was cancelled

@ -2273,6 +2273,16 @@
<label>API Key:</label>
<input type="password" id="soulseek-api-key" placeholder="Slskd API Key">
</div>
<div class="form-group">
<label>Search Timeout (seconds):</label>
<input type="number" id="soulseek-search-timeout" placeholder="60" min="15" max="300" value="60">
<small style="color: #888; display: block; margin-top: 5px;">How long to search for tracks (15-300 seconds)</small>
</div>
<div class="form-group">
<label>Search Timeout Buffer (seconds):</label>
<input type="number" id="soulseek-search-timeout-buffer" placeholder="15" min="5" max="60" value="15">
<small style="color: #888; display: block; margin-top: 5px;">Extra time to wait for late results (5-60 seconds)</small>
</div>
</div>
<!-- ListenBrainz Settings -->

@ -1629,6 +1629,8 @@ async function loadSettingsData() {
// Populate Soulseek settings
document.getElementById('soulseek-url').value = settings.soulseek?.slskd_url || '';
document.getElementById('soulseek-api-key').value = settings.soulseek?.api_key || '';
document.getElementById('soulseek-search-timeout').value = settings.soulseek?.search_timeout || 60;
document.getElementById('soulseek-search-timeout-buffer').value = settings.soulseek?.search_timeout_buffer || 15;
// Populate ListenBrainz settings
document.getElementById('listenbrainz-token').value = settings.listenbrainz?.token || '';
@ -2004,7 +2006,9 @@ async function saveSettings() {
slskd_url: document.getElementById('soulseek-url').value,
api_key: document.getElementById('soulseek-api-key').value,
download_path: document.getElementById('download-path').value,
transfer_path: document.getElementById('transfer-path').value
transfer_path: document.getElementById('transfer-path').value,
search_timeout: parseInt(document.getElementById('soulseek-search-timeout').value) || 60,
search_timeout_buffer: parseInt(document.getElementById('soulseek-search-timeout-buffer').value) || 15
},
listenbrainz: {
token: document.getElementById('listenbrainz-token').value

Loading…
Cancel
Save