Add source badges (Spotify/iTunes/Deezer) to watchlist artist cards

Shows which metadata sources each artist is matched to with small
colored badges on the card. Also adds deezer_artist_id to the
watchlist API response and fixes the data-artist-id fallback chain
to include Deezer-only artists.
This commit is contained in:
Broque Thomas 2026-03-16 13:37:53 -07:00
parent 46ac46134b
commit f10beeea0a
3 changed files with 44 additions and 3 deletions

View file

@ -30128,6 +30128,7 @@ def get_watchlist_artists():
"updated_at": artist.updated_at.isoformat() if artist.updated_at else None, "updated_at": artist.updated_at.isoformat() if artist.updated_at else None,
"image_url": artist.image_url, # Cached during watchlist scans "image_url": artist.image_url, # Cached during watchlist scans
"itunes_artist_id": artist.itunes_artist_id, # For iTunes-only artists "itunes_artist_id": artist.itunes_artist_id, # For iTunes-only artists
"deezer_artist_id": getattr(artist, 'deezer_artist_id', None),
"include_albums": artist.include_albums, "include_albums": artist.include_albums,
"include_eps": artist.include_eps, "include_eps": artist.include_eps,
"include_singles": artist.include_singles, "include_singles": artist.include_singles,

View file

@ -34267,21 +34267,26 @@ async function showWatchlistModal() {
if (artist.include_remixes) pills.push('<span class="watchlist-pill watchlist-pill-filter">Remixes</span>'); if (artist.include_remixes) pills.push('<span class="watchlist-pill watchlist-pill-filter">Remixes</span>');
if (artist.include_acoustic) pills.push('<span class="watchlist-pill watchlist-pill-filter">Acoustic</span>'); if (artist.include_acoustic) pills.push('<span class="watchlist-pill watchlist-pill-filter">Acoustic</span>');
if (artist.include_compilations) pills.push('<span class="watchlist-pill watchlist-pill-filter">Compilations</span>'); if (artist.include_compilations) pills.push('<span class="watchlist-pill watchlist-pill-filter">Compilations</span>');
const sourceBadges = [];
if (artist.spotify_artist_id) sourceBadges.push('<span class="watchlist-source-badge watchlist-source-spotify">Spotify</span>');
if (artist.itunes_artist_id) sourceBadges.push('<span class="watchlist-source-badge watchlist-source-itunes">iTunes</span>');
if (artist.deezer_artist_id) sourceBadges.push('<span class="watchlist-source-badge watchlist-source-deezer">Deezer</span>');
const artistPrimaryId = artist.spotify_artist_id || artist.itunes_artist_id || artist.deezer_artist_id;
return ` return `
<div class="watchlist-artist-card" <div class="watchlist-artist-card"
data-artist-name="${artist.artist_name.toLowerCase().replace(/"/g, '&quot;')}" data-artist-name="${artist.artist_name.toLowerCase().replace(/"/g, '&quot;')}"
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}"> data-artist-id="${artistPrimaryId}">
<label class="watchlist-card-checkbox" onclick="event.stopPropagation();"> <label class="watchlist-card-checkbox" onclick="event.stopPropagation();">
<input type="checkbox" class="watchlist-select-cb" <input type="checkbox" class="watchlist-select-cb"
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}" data-artist-id="${artistPrimaryId}"
data-artist-name="${escapeHtml(artist.artist_name)}" data-artist-name="${escapeHtml(artist.artist_name)}"
onchange="updateWatchlistBatchBar()"> onchange="updateWatchlistBatchBar()">
<span class="watchlist-checkbox-custom"></span> <span class="watchlist-checkbox-custom"></span>
</label> </label>
<button class="watchlist-card-gear" <button class="watchlist-card-gear"
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}" data-artist-id="${artistPrimaryId}"
data-artist-name="${escapeHtml(artist.artist_name)}" data-artist-name="${escapeHtml(artist.artist_name)}"
onclick="event.stopPropagation();" onclick="event.stopPropagation();"
title="Artist settings"> title="Artist settings">
@ -34303,6 +34308,7 @@ async function showWatchlistModal() {
<span class="watchlist-card-name">${escapeHtml(artist.artist_name)}</span> <span class="watchlist-card-name">${escapeHtml(artist.artist_name)}</span>
<span class="watchlist-card-meta">${formatRelativeScanTime(artist.last_scan_timestamp)}</span> <span class="watchlist-card-meta">${formatRelativeScanTime(artist.last_scan_timestamp)}</span>
</div> </div>
${sourceBadges.length > 0 ? `<div class="watchlist-card-sources">${sourceBadges.join('')}</div>` : ''}
${pills.length > 0 ? `<div class="watchlist-card-pills">${pills.join('')}</div>` : ''} ${pills.length > 0 ? `<div class="watchlist-card-pills">${pills.join('')}</div>` : ''}
</div> </div>
`}).join('')} `}).join('')}

View file

@ -12063,6 +12063,40 @@ body {
} }
/* Card release-type pills */ /* Card release-type pills */
.watchlist-card-sources {
position: relative;
z-index: 2;
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 2px 16px 4px;
}
.watchlist-source-badge {
font-size: 8px;
font-weight: 700;
text-transform: uppercase;
padding: 2px 6px;
border-radius: 3px;
letter-spacing: 0.4px;
line-height: 1.3;
}
.watchlist-source-spotify {
background: rgba(30, 215, 96, 0.15);
color: #1ed760;
}
.watchlist-source-itunes {
background: rgba(252, 60, 68, 0.15);
color: #fc3c44;
}
.watchlist-source-deezer {
background: rgba(162, 101, 230, 0.15);
color: #a265e6;
}
.watchlist-card-pills { .watchlist-card-pills {
position: relative; position: relative;
z-index: 2; z-index: 2;