From 9c15d0012838a76e9eb32eb7ea7f33c08506565c Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Mon, 20 Apr 2026 22:18:20 -0700 Subject: [PATCH] Enrich downloads page cards with artwork, artist, album, and source badges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The downloads page previously showed only title and source per download. Now shows album artwork thumbnail, artist name, album name, source badge, and quality badge (after post-processing). All metadata comes from the existing matched_downloads_context — no extra API calls needed. Falls back gracefully to title-only display when context metadata is not available (e.g. orphaned Soulseek transfers with no task mapping). --- web_server.py | 18 +++++++++++ webui/static/script.js | 24 +++++++++++++-- webui/static/style.css | 68 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/web_server.py b/web_server.py index 12665afb..a5791e3d 100644 --- a/web_server.py +++ b/web_server.py @@ -10119,6 +10119,24 @@ def get_download_status(): print(f"Could not fetch YouTube/Tidal downloads for status: {streaming_error}") traceback.print_exc() + # Enrich transfers with metadata from download context (artist, album, artwork) + with matched_context_lock: + for transfer in all_transfers: + ctx_key = _make_context_key(transfer.get('username', ''), transfer.get('filename', '')) + ctx = matched_downloads_context.get(ctx_key) + if ctx: + _sp_artist = ctx.get('spotify_artist') or {} + _sp_album = ctx.get('spotify_album') or {} + _sp_track = ctx.get('track_info') or {} + _sp_images = _sp_album.get('images') or [] + transfer['_meta'] = { + 'artist': _sp_artist.get('name', ''), + 'album': _sp_album.get('name', ''), + 'artwork_url': _sp_images[0].get('url', '') if _sp_images and isinstance(_sp_images[0], dict) else '', + 'track_number': _sp_track.get('track_number'), + 'quality': ctx.get('_audio_quality', ''), + } + return jsonify({"transfers": all_transfers}) except Exception as e: diff --git a/webui/static/script.js b/webui/static/script.js index 96b406f1..afd8232c 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -17261,11 +17261,31 @@ function renderQueue(containerId, downloads, isActiveQueue) { `; } + // Enrich with metadata from backend context (artist, album, artwork) + const meta = item._meta || {}; + const sourceLabels = { youtube: 'YouTube', tidal: 'Tidal', qobuz: 'Qobuz', hifi: 'HiFi', deezer_dl: 'Deezer', lidarr: 'Lidarr' }; + const sourceBadge = sourceLabels[item.username] || item.username; + html += `
-
+
+ ${meta.artwork_url + ? `` + : '
'} +
+
${title}
-
from ${item.username}
+ ${meta.artist || meta.album ? ` +
+ ${meta.artist ? `${escapeHtml(meta.artist)}` : ''} + ${meta.artist && meta.album ? '·' : ''} + ${meta.album ? `${escapeHtml(meta.album)}` : ''} +
+ ` : ''} +
+ ${sourceBadge} + ${meta.quality ? `${escapeHtml(meta.quality)}` : ''} +
${actionButtonHTML} diff --git a/webui/static/style.css b/webui/static/style.css index 0a68e3e4..0865189e 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -6874,6 +6874,9 @@ body.helper-mode-active #dashboard-activity-feed:hover { margin: 6px 0; padding: 12px; transition: all 0.2s ease; + display: flex; + align-items: center; + gap: 12px; } .download-item:hover { @@ -6883,6 +6886,35 @@ body.helper-mode-active #dashboard-activity-feed:hover { border-color: rgba(var(--accent-rgb), 0.6); } +.download-item__art { + width: 44px; + height: 44px; + border-radius: 6px; + overflow: hidden; + flex-shrink: 0; +} +.download-item__art img { + width: 100%; + height: 100%; + object-fit: cover; +} +.download-item__art-placeholder { + width: 100%; + height: 100%; + background: rgba(255,255,255,0.05); + display: flex; + align-items: center; + justify-content: center; + color: rgba(255,255,255,0.25); + font-size: 18px; + border-radius: 6px; +} + +.download-item__info { + flex: 1; + min-width: 0; +} + .download-item__header { display: flex; justify-content: space-between; @@ -6894,12 +6926,45 @@ body.helper-mode-active #dashboard-activity-feed:hover { font-size: 13px; font-weight: 600; color: #ffffff; - max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.download-item__meta { + display: flex; + align-items: center; + gap: 0; + font-size: 0.82em; + color: rgba(255,255,255,0.5); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-top: 1px; +} +.download-item__sep { + margin: 0 5px; + opacity: 0.4; +} +.download-item__album { + opacity: 0.7; +} + +.download-item__badges { + display: flex; + gap: 6px; + margin-top: 3px; +} +.download-item__source, +.download-item__quality { + font-size: 0.7em; + padding: 1px 7px; + border-radius: 4px; + background: rgba(255,255,255,0.07); + color: rgba(255,255,255,0.45); + font-weight: 500; +} + .download-item__uploader { font-size: 10px; padding-left: 15px; @@ -6912,6 +6977,7 @@ body.helper-mode-active #dashboard-activity-feed:hover { justify-content: center; flex-direction: row; gap: 15px; + flex-shrink: 0; } /* Progress Bar Styles */