Fix all watchlist Discogs gaps

- Add discogs_artist_id to ALL watchlist WHERE clauses + bind params
- Fix artistPrimaryId to include discogs_artist_id
- Fix View Discography — add Discogs source branch
- Fix openWatchlistArtistDetailView — destructure discogs_artist_id
  from response (was causing ReferenceError)
- Discogs source/provider badges + CSS + image fetch + ID resolution
This commit is contained in:
Broque Thomas 2026-04-02 21:33:41 -07:00
parent f51a8a9ee9
commit 55f7e174d8
3 changed files with 75 additions and 28 deletions

View file

@ -6514,7 +6514,7 @@ class MusicDatabase:
return False
def remove_artist_from_watchlist(self, artist_id: str, profile_id: int = 1) -> bool:
"""Remove an artist from the watchlist (checks Spotify, iTunes, and Deezer IDs)"""
"""Remove an artist from the watchlist (checks Spotify, iTunes, Deezer, and Discogs IDs)"""
try:
with self._get_connection() as conn:
cursor = conn.cursor()
@ -6522,15 +6522,15 @@ class MusicDatabase:
# Get artist name for logging (check all ID columns)
cursor.execute("""
SELECT artist_name FROM watchlist_artists
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?) AND profile_id = ?
""", (artist_id, artist_id, artist_id, profile_id))
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?) AND profile_id = ?
""", (artist_id, artist_id, artist_id, artist_id, profile_id))
result = cursor.fetchone()
artist_name = result['artist_name'] if result else "Unknown"
cursor.execute("""
DELETE FROM watchlist_artists
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?) AND profile_id = ?
""", (artist_id, artist_id, artist_id, profile_id))
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?) AND profile_id = ?
""", (artist_id, artist_id, artist_id, artist_id, profile_id))
if cursor.rowcount > 0:
conn.commit()
@ -6545,7 +6545,7 @@ class MusicDatabase:
return False
def is_artist_in_watchlist(self, artist_id: str, profile_id: int = 1, artist_name: str = None) -> bool:
"""Check if an artist is currently in the watchlist (checks Spotify, iTunes, Deezer IDs and name)"""
"""Check if an artist is currently in the watchlist (checks Spotify, iTunes, Deezer, Discogs IDs and name)"""
try:
with self._get_connection() as conn:
cursor = conn.cursor()
@ -6554,15 +6554,15 @@ class MusicDatabase:
if artist_name:
cursor.execute("""
SELECT 1 FROM watchlist_artists
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR LOWER(artist_name) = LOWER(?)) AND profile_id = ?
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ? OR LOWER(artist_name) = LOWER(?)) AND profile_id = ?
LIMIT 1
""", (artist_id, artist_id, artist_id, artist_name, profile_id))
""", (artist_id, artist_id, artist_id, artist_id, artist_name, profile_id))
else:
cursor.execute("""
SELECT 1 FROM watchlist_artists
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?) AND profile_id = ?
WHERE (spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?) AND profile_id = ?
LIMIT 1
""", (artist_id, artist_id, artist_id, profile_id))
""", (artist_id, artist_id, artist_id, artist_id, profile_id))
result = cursor.fetchone()
return result is not None
@ -6833,8 +6833,8 @@ class MusicDatabase:
cursor.execute("""
UPDATE watchlist_artists
SET image_url = ?, updated_at = CURRENT_TIMESTAMP
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
""", (image_url, artist_id, artist_id, artist_id))
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?
""", (image_url, artist_id, artist_id, artist_id, artist_id))
conn.commit()
return cursor.rowcount > 0

View file

@ -36599,10 +36599,47 @@ def add_to_watchlist():
return jsonify({"success": False, "error": "Missing artist_id or artist_name"}), 400
database = get_database()
# Detect ID type and determine source
# Detect source from ID — check if it's a library DB ID first
is_numeric_id = artist_id.isdigit()
fallback_source = _get_metadata_fallback_source()
source = fallback_source if is_numeric_id else 'spotify'
source = None
if is_numeric_id:
# Could be a library DB ID, iTunes ID, Deezer ID, or Discogs ID
# Check if this is a library DB artist and use their actual source IDs
try:
conn = database._get_connection()
cursor = conn.cursor()
cursor.execute("""
SELECT spotify_artist_id, itunes_artist_id, deezer_id, discogs_id
FROM artists WHERE id = ? LIMIT 1
""", (artist_id,))
row = cursor.fetchone()
conn.close()
if row:
# Library artist — use the best available source ID
fallback = _get_metadata_fallback_source()
if fallback == 'discogs' and row['discogs_id']:
artist_id = row['discogs_id']
source = 'discogs'
elif fallback == 'deezer' and row['deezer_id']:
artist_id = row['deezer_id']
source = 'deezer'
elif row['spotify_artist_id']:
artist_id = row['spotify_artist_id']
source = 'spotify'
elif row['itunes_artist_id']:
artist_id = row['itunes_artist_id']
source = 'itunes'
elif row['deezer_id']:
artist_id = row['deezer_id']
source = 'deezer'
elif row['discogs_id']:
artist_id = row['discogs_id']
source = 'discogs'
except Exception:
pass
if not source:
fallback_source = _get_metadata_fallback_source()
source = fallback_source if is_numeric_id else 'spotify'
success = database.add_artist_to_watchlist(artist_id, artist_name, profile_id=get_current_profile_id(), source=source)
if success:
@ -36612,7 +36649,15 @@ def add_to_watchlist():
if is_numeric_id:
# For numeric IDs, fetch image from the configured fallback source
try:
if fallback_source == 'deezer':
if source == 'discogs':
# Discogs: fetch artist image from API
from core.discogs_client import DiscogsClient
dc = DiscogsClient()
dc_data = dc.get_artist(artist_id)
if dc_data:
image_url = dc_data.get('image_url')
print(f"🖼️ Discogs artist image: {image_url[:60] if image_url else 'None'}")
elif source == 'deezer' or fallback_source == 'deezer':
# Deezer: fetch artist image directly from API
dz_resp = requests.get(f'https://api.deezer.com/artist/{artist_id}', timeout=5)
if dz_resp.ok:
@ -37584,9 +37629,9 @@ def watchlist_artist_config(artist_id):
cur2.execute("""
SELECT banner_url, summary, style, mood, label, genres
FROM artists
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?
LIMIT 1
""", (artist_id, artist_id, artist_id))
""", (artist_id, artist_id, artist_id, artist_id))
lib_row = cur2.fetchone()
if lib_row:
artist_info['banner_url'] = lib_row[0]
@ -37679,8 +37724,8 @@ def watchlist_artist_config(artist_id):
# Check if lookback_days changed — if so, clear last_scan_timestamp to force rescan
cursor.execute("""
SELECT lookback_days FROM watchlist_artists
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
""", (artist_id, artist_id, artist_id))
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?
""", (artist_id, artist_id, artist_id, artist_id))
old_row = cursor.fetchone()
old_lookback = old_row[0] if old_row else None
lookback_changed = old_lookback != lookback_days
@ -37692,11 +37737,11 @@ def watchlist_artist_config(artist_id):
include_instrumentals = ?, lookback_days = ?,
last_scan_timestamp = CASE WHEN ? THEN NULL ELSE last_scan_timestamp END,
updated_at = CURRENT_TIMESTAMP
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?
""", (int(include_albums), int(include_eps), int(include_singles),
int(include_live), int(include_remixes), int(include_acoustic), int(include_compilations),
int(include_instrumentals), lookback_days, lookback_changed,
artist_id, artist_id, artist_id))
artist_id, artist_id, artist_id, artist_id))
conn.commit()
if cursor.rowcount == 0:
@ -37752,8 +37797,8 @@ def watchlist_artist_link_provider(artist_id):
cursor.execute("""
SELECT id, artist_name, spotify_artist_id, itunes_artist_id
FROM watchlist_artists
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ?
""", (artist_id, artist_id, artist_id))
WHERE spotify_artist_id = ? OR itunes_artist_id = ? OR deezer_artist_id = ? OR discogs_artist_id = ?
""", (artist_id, artist_id, artist_id, artist_id))
row = cursor.fetchone()
if not row:

View file

@ -38782,7 +38782,7 @@ async function showWatchlistModal() {
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>');
if (artist.discogs_artist_id) sourceBadges.push('<span class="watchlist-source-badge watchlist-source-discogs">Discogs</span>');
const artistPrimaryId = artist.spotify_artist_id || artist.itunes_artist_id || artist.deezer_artist_id;
const artistPrimaryId = artist.spotify_artist_id || artist.itunes_artist_id || artist.deezer_artist_id || artist.discogs_artist_id;
return `
<div class="watchlist-artist-card"
data-artist-name="${artist.artist_name.toLowerCase().replace(/"/g, '&quot;')}"
@ -39278,7 +39278,7 @@ async function openWatchlistArtistDetailView(artistId, artistName) {
return;
}
const { config, artist, recent_releases, spotify_artist_id, itunes_artist_id, deezer_artist_id } = data;
const { config, artist, recent_releases, spotify_artist_id, itunes_artist_id, deezer_artist_id, discogs_artist_id } = data;
// Remove existing overlay if any
const existing = document.querySelector('.watchlist-artist-detail-overlay');
@ -39407,13 +39407,15 @@ async function openWatchlistArtistDetailView(artistId, artistName) {
const activeSrc = (currentMusicSourceName || '').toLowerCase();
if (activeSrc.includes('spotify') && spotify_artist_id) {
discogId = spotify_artist_id; source = 'spotify';
} else if (activeSrc.includes('discogs') && discogs_artist_id) {
discogId = discogs_artist_id; source = 'discogs';
} else if (activeSrc.includes('deezer') && deezer_artist_id) {
discogId = deezer_artist_id; source = 'deezer';
} else if (itunes_artist_id) {
discogId = itunes_artist_id; source = 'itunes';
} else {
discogId = spotify_artist_id || deezer_artist_id || itunes_artist_id;
source = spotify_artist_id ? 'spotify' : deezer_artist_id ? 'deezer' : 'itunes';
discogId = spotify_artist_id || discogs_artist_id || deezer_artist_id || itunes_artist_id;
source = spotify_artist_id ? 'spotify' : discogs_artist_id ? 'discogs' : deezer_artist_id ? 'deezer' : 'itunes';
}
if (discogId) {
// Close watchlist modal + detail overlay