Add Discogs to watchlist — column, backfill, matching
- Add discogs_artist_id column to watchlist_artists table (migration) - Add discogs_artist_id to WatchlistArtist dataclass - Add to get_watchlist_artists optional_columns and constructor - Add update_watchlist_discogs_id DB method - Backfill loop includes Discogs when token is configured - Add _match_to_discogs for cross-provider artist matching - Backfill maps updated: id_attr, match_fn, update_fn all include discogs
This commit is contained in:
parent
58c3e589b6
commit
82f9b84e5b
2 changed files with 54 additions and 3 deletions
|
|
@ -609,6 +609,12 @@ class WatchlistScanner:
|
|||
providers_to_backfill = ['itunes', 'deezer']
|
||||
if self.spotify_client and self.spotify_client.is_spotify_authenticated():
|
||||
providers_to_backfill.append('spotify')
|
||||
try:
|
||||
from config.settings import config_manager as _cfg
|
||||
if _cfg.get('discogs.token', ''):
|
||||
providers_to_backfill.append('discogs')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for provider in providers_to_backfill:
|
||||
try:
|
||||
|
|
@ -979,6 +985,7 @@ class WatchlistScanner:
|
|||
'spotify': 'spotify_artist_id',
|
||||
'itunes': 'itunes_artist_id',
|
||||
'deezer': 'deezer_artist_id',
|
||||
'discogs': 'discogs_artist_id',
|
||||
}.get(provider)
|
||||
|
||||
if not id_attr:
|
||||
|
|
@ -997,12 +1004,14 @@ class WatchlistScanner:
|
|||
'spotify': self._match_to_spotify,
|
||||
'itunes': self._match_to_itunes,
|
||||
'deezer': self._match_to_deezer,
|
||||
'discogs': self._match_to_discogs,
|
||||
}.get(provider)
|
||||
|
||||
update_fn = {
|
||||
'spotify': self.database.update_watchlist_spotify_id,
|
||||
'itunes': self.database.update_watchlist_itunes_id,
|
||||
'deezer': getattr(self.database, 'update_watchlist_deezer_id', None),
|
||||
'discogs': getattr(self.database, 'update_watchlist_discogs_id', None),
|
||||
}.get(provider)
|
||||
|
||||
if not match_fn or not update_fn:
|
||||
|
|
@ -1150,6 +1159,17 @@ class WatchlistScanner:
|
|||
logger.warning(f"Could not match {artist_name} to Deezer: {e}")
|
||||
return None
|
||||
|
||||
def _match_to_discogs(self, artist_name: str) -> Optional[str]:
|
||||
"""Match artist name to Discogs ID using fuzzy name comparison."""
|
||||
try:
|
||||
from core.discogs_client import DiscogsClient
|
||||
client = DiscogsClient()
|
||||
results = client.search_artists(artist_name, limit=5)
|
||||
return self._best_artist_match(results, artist_name)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not match {artist_name} to Discogs: {e}")
|
||||
return None
|
||||
|
||||
def _get_lookback_period_setting(self) -> str:
|
||||
"""
|
||||
Get the discovery lookback period setting from database.
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ class WatchlistArtist:
|
|||
image_url: Optional[str] = None
|
||||
itunes_artist_id: Optional[str] = None # Cross-provider support
|
||||
deezer_artist_id: Optional[str] = None # Cross-provider support
|
||||
discogs_artist_id: Optional[str] = None # Cross-provider support
|
||||
include_albums: bool = True
|
||||
include_eps: bool = True
|
||||
include_singles: bool = True
|
||||
|
|
@ -1272,6 +1273,10 @@ class MusicDatabase:
|
|||
cursor.execute("ALTER TABLE watchlist_artists ADD COLUMN deezer_artist_id TEXT")
|
||||
logger.info("Added deezer_artist_id column to watchlist_artists table for cross-provider support")
|
||||
|
||||
if 'discogs_artist_id' not in columns:
|
||||
cursor.execute("ALTER TABLE watchlist_artists ADD COLUMN discogs_artist_id TEXT")
|
||||
logger.info("Added discogs_artist_id column to watchlist_artists table for cross-provider support")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding itunes_artist_id column to watchlist_artists: {e}")
|
||||
# Don't raise - this is a migration, database can still function
|
||||
|
|
@ -6444,7 +6449,7 @@ class MusicDatabase:
|
|||
|
||||
# Check if artist already exists by name (case-insensitive) for this profile
|
||||
cursor.execute("""
|
||||
SELECT id, spotify_artist_id, itunes_artist_id, deezer_artist_id
|
||||
SELECT id, spotify_artist_id, itunes_artist_id, deezer_artist_id, discogs_artist_id
|
||||
FROM watchlist_artists
|
||||
WHERE LOWER(artist_name) = LOWER(?) AND profile_id = ?
|
||||
LIMIT 1
|
||||
|
|
@ -6457,7 +6462,7 @@ class MusicDatabase:
|
|||
|
||||
if existing:
|
||||
# Artist already on watchlist — update with new source ID if missing
|
||||
col_map = {'spotify': 'spotify_artist_id', 'itunes': 'itunes_artist_id', 'deezer': 'deezer_artist_id'}
|
||||
col_map = {'spotify': 'spotify_artist_id', 'itunes': 'itunes_artist_id', 'deezer': 'deezer_artist_id', 'discogs': 'discogs_artist_id'}
|
||||
col = col_map.get(source)
|
||||
if col and not existing[col]:
|
||||
cursor.execute(f"""
|
||||
|
|
@ -6486,6 +6491,13 @@ class MusicDatabase:
|
|||
VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, ?)
|
||||
""", (artist_id, artist_name, profile_id))
|
||||
logger.info(f"Added artist '{artist_name}' to watchlist (iTunes ID: {artist_id}, profile: {profile_id})")
|
||||
elif source == 'discogs':
|
||||
cursor.execute("""
|
||||
INSERT INTO watchlist_artists
|
||||
(discogs_artist_id, artist_name, date_added, updated_at, profile_id)
|
||||
VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, ?)
|
||||
""", (artist_id, artist_name, profile_id))
|
||||
logger.info(f"Added artist '{artist_name}' to watchlist (Discogs ID: {artist_id}, profile: {profile_id})")
|
||||
else:
|
||||
cursor.execute("""
|
||||
INSERT INTO watchlist_artists
|
||||
|
|
@ -6572,7 +6584,7 @@ class MusicDatabase:
|
|||
# Build SELECT query based on existing columns
|
||||
base_columns = ['id', 'spotify_artist_id', 'artist_name', 'date_added',
|
||||
'last_scan_timestamp', 'created_at', 'updated_at']
|
||||
optional_columns = ['image_url', 'itunes_artist_id', 'deezer_artist_id', 'include_albums', 'include_eps', 'include_singles',
|
||||
optional_columns = ['image_url', 'itunes_artist_id', 'deezer_artist_id', 'discogs_artist_id', 'include_albums', 'include_eps', 'include_singles',
|
||||
'include_live', 'include_remixes', 'include_acoustic', 'include_compilations',
|
||||
'include_instrumentals', 'lookback_days']
|
||||
|
||||
|
|
@ -6600,6 +6612,7 @@ class MusicDatabase:
|
|||
image_url = row['image_url'] if 'image_url' in existing_columns else None
|
||||
itunes_artist_id = row['itunes_artist_id'] if 'itunes_artist_id' in existing_columns else None
|
||||
deezer_artist_id = row['deezer_artist_id'] if 'deezer_artist_id' in existing_columns else None
|
||||
discogs_artist_id = row['discogs_artist_id'] if 'discogs_artist_id' in existing_columns else None
|
||||
include_albums = bool(row['include_albums']) if 'include_albums' in existing_columns else True
|
||||
include_eps = bool(row['include_eps']) if 'include_eps' in existing_columns else True
|
||||
include_singles = bool(row['include_singles']) if 'include_singles' in existing_columns else True
|
||||
|
|
@ -6621,6 +6634,7 @@ class MusicDatabase:
|
|||
image_url=image_url,
|
||||
itunes_artist_id=itunes_artist_id,
|
||||
deezer_artist_id=deezer_artist_id,
|
||||
discogs_artist_id=discogs_artist_id,
|
||||
include_albums=include_albums,
|
||||
include_eps=include_eps,
|
||||
include_singles=include_singles,
|
||||
|
|
@ -6889,6 +6903,23 @@ class MusicDatabase:
|
|||
logger.error(f"Error updating watchlist Deezer ID: {e}")
|
||||
return False
|
||||
|
||||
def update_watchlist_discogs_id(self, watchlist_id: int, discogs_id: str) -> bool:
|
||||
"""Update the Discogs artist ID for a watchlist artist (cross-provider support)"""
|
||||
try:
|
||||
with self._get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
UPDATE watchlist_artists
|
||||
SET discogs_artist_id = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
""", (discogs_id, watchlist_id))
|
||||
conn.commit()
|
||||
logger.info(f"Updated Discogs ID for watchlist artist {watchlist_id}: {discogs_id}")
|
||||
return cursor.rowcount > 0
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating watchlist Discogs ID: {e}")
|
||||
return False
|
||||
|
||||
def update_watchlist_artist_itunes_id(self, spotify_artist_id: str, itunes_id: str) -> bool:
|
||||
"""Update the iTunes artist ID for a watchlist artist by Spotify ID (for cross-provider caching)"""
|
||||
try:
|
||||
|
|
|
|||
Loading…
Reference in a new issue