Add Deezer support to watchlist config modal and linked provider section
- Query/update watchlist artists by deezer_artist_id in config endpoint - Return deezer_artist_id in config response and recent albums response - Add Deezer provider badge (purple) to linked provider section - Detect Deezer vs iTunes for provider linking using fallback source setting - Show "X fans" instead of "Pop: 0" for Deezer artist search results - Include followers count in match/search artist response - Add deezer_artist_id matching to library enrichment and recent releases queries
This commit is contained in:
parent
7d0df2b9ed
commit
53ef9fa913
3 changed files with 42 additions and 19 deletions
|
|
@ -12153,7 +12153,8 @@ def search_match():
|
||||||
"name": artist.name,
|
"name": artist.name,
|
||||||
"image_url": getattr(artist, 'image_url', None),
|
"image_url": getattr(artist, 'image_url', None),
|
||||||
"genres": getattr(artist, 'genres', []),
|
"genres": getattr(artist, 'genres', []),
|
||||||
"popularity": getattr(artist, 'popularity', 0)
|
"popularity": getattr(artist, 'popularity', 0),
|
||||||
|
"followers": getattr(artist, 'followers', 0)
|
||||||
},
|
},
|
||||||
"confidence": confidence
|
"confidence": confidence
|
||||||
})
|
})
|
||||||
|
|
@ -31095,10 +31096,10 @@ def watchlist_artist_config(artist_id):
|
||||||
SELECT include_albums, include_eps, include_singles,
|
SELECT include_albums, include_eps, include_singles,
|
||||||
include_live, include_remixes, include_acoustic, include_compilations,
|
include_live, include_remixes, include_acoustic, include_compilations,
|
||||||
artist_name, image_url, spotify_artist_id, itunes_artist_id,
|
artist_name, image_url, spotify_artist_id, itunes_artist_id,
|
||||||
last_scan_timestamp, date_added, include_instrumentals
|
last_scan_timestamp, date_added, include_instrumentals, deezer_artist_id
|
||||||
FROM watchlist_artists
|
FROM watchlist_artists
|
||||||
WHERE spotify_artist_id = ? OR itunes_artist_id = ?
|
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
|
||||||
""", (artist_id, artist_id))
|
""", (artist_id, artist_id, artist_id))
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
@ -31109,6 +31110,7 @@ def watchlist_artist_config(artist_id):
|
||||||
is_itunes_artist = artist_id.isdigit()
|
is_itunes_artist = artist_id.isdigit()
|
||||||
spotify_id = result[9] # spotify_artist_id from query
|
spotify_id = result[9] # spotify_artist_id from query
|
||||||
itunes_id = result[10] # itunes_artist_id from query
|
itunes_id = result[10] # itunes_artist_id from query
|
||||||
|
deezer_id = result[14] # deezer_artist_id from query
|
||||||
|
|
||||||
# Get artist info from Spotify (only for Spotify artists)
|
# Get artist info from Spotify (only for Spotify artists)
|
||||||
artist_info = None
|
artist_info = None
|
||||||
|
|
@ -31145,9 +31147,9 @@ def watchlist_artist_config(artist_id):
|
||||||
cur2.execute("""
|
cur2.execute("""
|
||||||
SELECT banner_url, summary, style, mood, label, genres
|
SELECT banner_url, summary, style, mood, label, genres
|
||||||
FROM artists
|
FROM artists
|
||||||
WHERE spotify_artist_id = ? OR itunes_artist_id = ?
|
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
""", (artist_id, artist_id))
|
""", (artist_id, artist_id, artist_id))
|
||||||
lib_row = cur2.fetchone()
|
lib_row = cur2.fetchone()
|
||||||
if lib_row:
|
if lib_row:
|
||||||
artist_info['banner_url'] = lib_row[0]
|
artist_info['banner_url'] = lib_row[0]
|
||||||
|
|
@ -31167,10 +31169,10 @@ def watchlist_artist_config(artist_id):
|
||||||
SELECT rr.album_name, rr.release_date, rr.album_cover_url, rr.track_count
|
SELECT rr.album_name, rr.release_date, rr.album_cover_url, rr.track_count
|
||||||
FROM recent_releases rr
|
FROM recent_releases rr
|
||||||
JOIN watchlist_artists wa ON rr.watchlist_artist_id = wa.id
|
JOIN watchlist_artists wa ON rr.watchlist_artist_id = wa.id
|
||||||
WHERE wa.spotify_artist_id = ? OR wa.itunes_artist_id = ?
|
WHERE wa.spotify_artist_id = ? OR wa.itunes_artist_id = ? OR wa.deezer_artist_id = ?
|
||||||
ORDER BY rr.release_date DESC
|
ORDER BY rr.release_date DESC
|
||||||
LIMIT 6
|
LIMIT 6
|
||||||
""", (artist_id, artist_id))
|
""", (artist_id, artist_id, artist_id))
|
||||||
releases = [
|
releases = [
|
||||||
{
|
{
|
||||||
'album_name': r[0],
|
'album_name': r[0],
|
||||||
|
|
@ -31205,6 +31207,7 @@ def watchlist_artist_config(artist_id):
|
||||||
"recent_releases": releases,
|
"recent_releases": releases,
|
||||||
"spotify_artist_id": spotify_id,
|
"spotify_artist_id": spotify_id,
|
||||||
"itunes_artist_id": itunes_id,
|
"itunes_artist_id": itunes_id,
|
||||||
|
"deezer_artist_id": deezer_id,
|
||||||
"watchlist_name": result[7], # Original stored watchlist artist name
|
"watchlist_name": result[7], # Original stored watchlist artist name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -31235,11 +31238,11 @@ def watchlist_artist_config(artist_id):
|
||||||
include_live = ?, include_remixes = ?, include_acoustic = ?, include_compilations = ?,
|
include_live = ?, include_remixes = ?, include_acoustic = ?, include_compilations = ?,
|
||||||
include_instrumentals = ?,
|
include_instrumentals = ?,
|
||||||
updated_at = CURRENT_TIMESTAMP
|
updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE spotify_artist_id = ? OR itunes_artist_id = ?
|
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
|
||||||
""", (int(include_albums), int(include_eps), int(include_singles),
|
""", (int(include_albums), int(include_eps), int(include_singles),
|
||||||
int(include_live), int(include_remixes), int(include_acoustic), int(include_compilations),
|
int(include_live), int(include_remixes), int(include_acoustic), int(include_compilations),
|
||||||
int(include_instrumentals),
|
int(include_instrumentals),
|
||||||
artist_id, artist_id))
|
artist_id, artist_id, artist_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
|
|
|
||||||
|
|
@ -34453,9 +34453,9 @@ function closeWatchlistModal() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the linked provider section in the watchlist config modal.
|
* Populate the linked provider section in the watchlist config modal.
|
||||||
* Shows which Spotify/iTunes artist is linked and allows changing it.
|
* Shows which Spotify/iTunes/Deezer artist is linked and allows changing it.
|
||||||
*/
|
*/
|
||||||
function _populateLinkedProviderSection(artistId, artistName, spotifyId, itunesId, artistInfo) {
|
function _populateLinkedProviderSection(artistId, artistName, spotifyId, itunesId, artistInfo, deezerId) {
|
||||||
const section = document.getElementById('watchlist-linked-provider-section');
|
const section = document.getElementById('watchlist-linked-provider-section');
|
||||||
const content = document.getElementById('watchlist-linked-provider-content');
|
const content = document.getElementById('watchlist-linked-provider-content');
|
||||||
if (!section || !content) return;
|
if (!section || !content) return;
|
||||||
|
|
@ -34463,8 +34463,9 @@ function _populateLinkedProviderSection(artistId, artistName, spotifyId, itunesI
|
||||||
// Determine which providers are linked
|
// Determine which providers are linked
|
||||||
const hasSpotify = !!spotifyId;
|
const hasSpotify = !!spotifyId;
|
||||||
const hasItunes = !!itunesId;
|
const hasItunes = !!itunesId;
|
||||||
|
const hasDeezer = !!deezerId;
|
||||||
|
|
||||||
if (!hasSpotify && !hasItunes) {
|
if (!hasSpotify && !hasItunes && !hasDeezer) {
|
||||||
section.style.display = 'none';
|
section.style.display = 'none';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -34496,6 +34497,9 @@ function _populateLinkedProviderSection(artistId, artistName, spotifyId, itunesI
|
||||||
if (hasItunes) {
|
if (hasItunes) {
|
||||||
html += `<span class="watchlist-provider-badge itunes">iTunes</span>`;
|
html += `<span class="watchlist-provider-badge itunes">iTunes</span>`;
|
||||||
}
|
}
|
||||||
|
if (hasDeezer) {
|
||||||
|
html += `<span class="watchlist-provider-badge deezer">Deezer</span>`;
|
||||||
|
}
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
|
|
||||||
// Show mismatch warning if linked name differs from watchlist name
|
// Show mismatch warning if linked name differs from watchlist name
|
||||||
|
|
@ -34570,12 +34574,14 @@ async function _searchLinkedProviderArtists(currentArtistId, watchlistName) {
|
||||||
const img = a.image_url || '';
|
const img = a.image_url || '';
|
||||||
const genres = (a.genres || []).slice(0, 2).join(', ');
|
const genres = (a.genres || []).slice(0, 2).join(', ');
|
||||||
const pop = a.popularity || 0;
|
const pop = a.popularity || 0;
|
||||||
|
const followers = a.followers || 0;
|
||||||
|
const popMeta = pop > 0 ? `Pop: ${pop}` : followers > 0 ? `${followers.toLocaleString()} fans` : '';
|
||||||
html += `<div class="watchlist-linked-search-result" data-id="${a.id}" data-name="${escapeHtml(a.name)}">
|
html += `<div class="watchlist-linked-search-result" data-id="${a.id}" data-name="${escapeHtml(a.name)}">
|
||||||
${img ? `<img src="${img}" alt="" class="watchlist-linked-result-img">` :
|
${img ? `<img src="${img}" alt="" class="watchlist-linked-result-img">` :
|
||||||
`<div class="watchlist-linked-result-img-placeholder">🎵</div>`}
|
`<div class="watchlist-linked-result-img-placeholder">🎵</div>`}
|
||||||
<div class="watchlist-linked-result-info">
|
<div class="watchlist-linked-result-info">
|
||||||
<div class="watchlist-linked-result-name">${escapeHtml(a.name)}</div>
|
<div class="watchlist-linked-result-name">${escapeHtml(a.name)}</div>
|
||||||
<div class="watchlist-linked-result-meta">${genres ? escapeHtml(genres) + ' · ' : ''}Pop: ${pop}</div>
|
<div class="watchlist-linked-result-meta">${genres ? escapeHtml(genres) : ''}${genres && popMeta ? ' · ' : ''}${popMeta}</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="watchlist-linked-select-btn">Select</button>
|
<button class="watchlist-linked-select-btn">Select</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
@ -34603,8 +34609,16 @@ async function _searchLinkedProviderArtists(currentArtistId, watchlistName) {
|
||||||
* Link a watchlist artist to a new provider artist.
|
* Link a watchlist artist to a new provider artist.
|
||||||
*/
|
*/
|
||||||
async function _linkProviderArtist(currentArtistId, newProviderId, newProviderName) {
|
async function _linkProviderArtist(currentArtistId, newProviderId, newProviderName) {
|
||||||
// Determine provider type from ID format
|
// Determine provider from active metadata source
|
||||||
const provider = /^\d+$/.test(newProviderId) ? 'itunes' : 'spotify';
|
// Spotify IDs are alphanumeric (e.g. "4Z8W4fKeB5YxbusRsdQVPb"), iTunes/Deezer are numeric
|
||||||
|
let provider;
|
||||||
|
if (/^\d+$/.test(newProviderId)) {
|
||||||
|
// Numeric ID — check configured fallback source to distinguish iTunes from Deezer
|
||||||
|
const fallbackSrc = document.getElementById('metadata-fallback-source')?.value || 'itunes';
|
||||||
|
provider = fallbackSrc === 'deezer' ? 'deezer' : 'itunes';
|
||||||
|
} else {
|
||||||
|
provider = 'spotify';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/watchlist/artist/${currentArtistId}/link-provider`, {
|
const response = await fetch(`/api/watchlist/artist/${currentArtistId}/link-provider`, {
|
||||||
|
|
@ -34652,10 +34666,10 @@ async function openWatchlistArtistConfigModal(artistId, artistName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { config, artist, spotify_artist_id, itunes_artist_id, watchlist_name } = data;
|
const { config, artist, spotify_artist_id, itunes_artist_id, deezer_artist_id, watchlist_name } = data;
|
||||||
|
|
||||||
// Populate linked provider section (use DB watchlist_name for mismatch comparison)
|
// Populate linked provider section (use DB watchlist_name for mismatch comparison)
|
||||||
_populateLinkedProviderSection(artistId, watchlist_name || artistName, spotify_artist_id, itunes_artist_id, artist);
|
_populateLinkedProviderSection(artistId, watchlist_name || artistName, spotify_artist_id, itunes_artist_id, artist, deezer_artist_id);
|
||||||
|
|
||||||
// Check if global override is active
|
// Check if global override is active
|
||||||
let globalOverrideActive = false;
|
let globalOverrideActive = false;
|
||||||
|
|
|
||||||
|
|
@ -14095,6 +14095,12 @@ body {
|
||||||
border: 1px solid rgba(252, 60, 68, 0.3);
|
border: 1px solid rgba(252, 60, 68, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.watchlist-provider-badge.deezer {
|
||||||
|
background: rgba(162, 56, 255, 0.15);
|
||||||
|
color: #a238ff;
|
||||||
|
border: 1px solid rgba(162, 56, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
.watchlist-linked-mismatch-warning {
|
.watchlist-linked-mismatch-warning {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue