Enable Lidarr as production-ready download source

Fixed 5 critical gaps in the download orchestrator where lidarr was
missing from client loops: get_all_downloads, get_download_status,
cancel_download fallback, clear_all_completed_downloads, and
cancel_all_downloads. Without these, lidarr downloads were invisible
to the UI, couldn't be cancelled, and accumulated in memory.

Also: error messages now visible in download list (appended to
filename on error state), removed "(Development)" label from UI.
pull/339/head
Broque Thomas 4 weeks ago
parent 9370d462ff
commit 6ca3f3b070

@ -365,7 +365,7 @@ class DownloadOrchestrator:
"""
# Get downloads from all available sources
all_downloads = []
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl]:
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl, self.lidarr]:
if client:
try:
all_downloads.extend(await client.get_all_downloads())
@ -384,7 +384,7 @@ class DownloadOrchestrator:
DownloadStatus object or None if not found
"""
# Try each source until we find the download
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl]:
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl, self.lidarr]:
if not client:
continue
try:
@ -418,7 +418,7 @@ class DownloadOrchestrator:
return await self.soulseek.cancel_download(download_id, username, remove) if self.soulseek else False
# Otherwise, try all available sources
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl]:
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl, self.lidarr]:
if not client:
continue
try:
@ -453,7 +453,7 @@ class DownloadOrchestrator:
True if successful
"""
results = []
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl]:
for client in [self.soulseek, self.youtube, self.tidal, self.qobuz, self.hifi, self.deezer_dl, self.lidarr]:
if client:
try:
results.append(await client.clear_all_completed_downloads())
@ -524,7 +524,7 @@ class DownloadOrchestrator:
async def cancel_all_downloads(self) -> bool:
"""Cancel and remove all downloads from all sources."""
ok = True
for client in [self.soulseek, self.tidal, self.qobuz, self.hifi, self.deezer_dl]:
for client in [self.soulseek, self.tidal, self.qobuz, self.hifi, self.deezer_dl, self.lidarr]:
if client:
try:
await client.cancel_all_downloads() if hasattr(client, 'cancel_all_downloads') else await client.clear_all_completed_downloads()

@ -450,9 +450,13 @@ class LidarrDownloadClient:
return self._to_status(dl) if dl else None
def _to_status(self, dl: Dict) -> DownloadStatus:
filename = dl['filename']
# Append error info to filename for UI visibility when errored
if dl['state'] == 'Errored' and dl.get('error'):
filename = f"{filename}{dl['error']}"
return DownloadStatus(
id=dl['id'],
filename=dl['filename'],
filename=filename,
username='lidarr',
state=dl['state'],
progress=dl['progress'],

@ -22614,6 +22614,7 @@ def get_version_info():
"• Reject Qobuz 30-second sample/preview downloads",
"• Fix library page crash on All filter — non-string soul_id broke card rendering",
"• Auto Wing It fallback for failed discovery — unmatched tracks download via Soulseek with raw metadata",
"• Lidarr download source now production-ready — full orchestrator integration",
"• Fix M3U showing all tracks as missing — regenerate with real paths after post-processing",
"• Fix AcoustID retag not writing corrected tags to audio file",
"• Fix wishlist albums cycle stuck at 1 concurrent worker instead of configured value",

@ -4497,7 +4497,7 @@
<option value="qobuz">Qobuz Only</option>
<option value="hifi">HiFi Only (Free Lossless)</option>
<option value="deezer_dl">Deezer Only</option>
<option value="lidarr">Lidarr Only (Development)</option>
<option value="lidarr">Lidarr Only</option>
<option value="hybrid">Hybrid (Primary + Fallback)</option>
</select>
<div class="setting-help-text">

@ -3603,6 +3603,7 @@ const WHATS_NEW = {
// --- April 19, 2026 ---
{ date: 'April 19, 2026' },
{ title: 'Fix Wishlist Albums Cycle Stuck at 1 Concurrent', desc: 'Auto-wishlist processing during the "albums" cycle was limited to 1 concurrent download even with higher configured settings. The max_concurrent=1 restriction is only needed for Soulseek folder-based album grabs, not individual wishlist track downloads. Albums cycle now uses the configured concurrency like singles' },
{ title: 'Lidarr Download Source Now Production-Ready', desc: 'Lidarr is now a fully functional download source with complete orchestrator integration. Downloads appear in the UI, status polling works, cancellation works, and cleanup on shutdown works. Error messages are now visible in the download list. Removed "(Development)" label' },
{ title: 'Fix M3U Showing All Tracks as Missing', desc: 'M3U playlist files were generated before post-processing finished, so file paths pointed to download locations instead of final library paths. M3U is now regenerated from the backend after all post-processing completes, resolving real library paths from the DB' },
{ title: 'Fix AcoustID Retag Not Writing to File', desc: 'The AcoustID mismatch "Retag" fix action was only updating the database record without writing corrected tags to the actual audio file. Now writes title and artist tags to the file using Mutagen after updating the DB' },
{ title: 'Fix Downloads Badge Dropping to 300', desc: 'Downloads nav badge showed the correct count from WebSocket but dropped to max 300 after opening the Downloads page because it recounted from a truncated local array. Badge now stays accurate from the server-side count' },

Loading…
Cancel
Save