Files
hiffi-artist-intelligence/scripts/resolve_spotify_urls.py
T

81 lines
2.9 KiB
Python
Raw Normal View History

import os
from pathlib import Path
import sqlite3
import time
import requests
PROJECT_ROOT = Path(__file__).resolve().parent.parent
DB_PATH = PROJECT_ROOT / "data" / "hiffi_catalog.db"
# MusicBrainz API requires a clear User-Agent string
MB_HEADERS = {
"User-Agent": "HIFFIArtistIntelligence/1.0.0 ( contact@hiffi.com )",
"Accept": "application/json",
}
conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()
cur.execute("""
SELECT artist_id, artist_name, spotify_url
FROM artists
WHERE spotify_url LIKE '%/search/%' AND image_verified_flag = 1
""")
rows = cur.fetchall()
print(f"Targeting {len(rows)} artists needing canonical Spotify URLs via MusicBrainz entity resolution...\n")
resolved = 0
unresolved = []
for artist_id, name, old_url in rows:
clean_name = name.strip()
try:
# Step 1: Find artist entity by exact name
search_url = "https://musicbrainz.org/ws/2/artist"
params = {"query": f'artist:"{clean_name}"', "fmt": "json", "limit": 3}
resp = requests.get(search_url, headers=MB_HEADERS, params=params, timeout=10)
found_spotify_url = None
if resp.status_code == 200:
artists_data = resp.json().get("artists", [])
for mb_artist in artists_data:
mb_id = mb_artist.get("id")
# Step 2: Fetch url-rels for the candidate artist
rel_url = f"https://musicbrainz.org/ws/2/artist/{mb_id}"
rel_resp = requests.get(rel_url, headers=MB_HEADERS, params={"inc": "url-rels", "fmt": "json"}, timeout=10)
if rel_resp.status_code == 200:
relations = rel_resp.json().get("relations", [])
for rel in relations:
target = rel.get("url", {}).get("resource", "")
if "open.spotify.com/artist/" in target:
# Strip any tracking parameters
found_spotify_url = target.split("?")[0]
break
if found_spotify_url:
break
time.sleep(1.0) # MusicBrainz rate limit compliance (1 req/sec)
if found_spotify_url:
cur.execute("""
UPDATE artists
SET spotify_url = ?
WHERE artist_id = ?
""", (found_spotify_url, artist_id))
conn.commit()
resolved += 1
print(f"[{resolved}/{len(rows)}] {clean_name} -> {found_spotify_url}")
else:
unresolved.append((artist_id, clean_name))
print(f"[NO MATCH] {clean_name}")
except Exception as e:
print(f"[ERR] {clean_name}: {e}")
# Rate limiting sleep for MusicBrainz service
time.sleep(1.1)
conn.close()
print(f"\nCompleted: {resolved}/{len(rows)} resolved.")
if unresolved:
print(f"{len(unresolved)} remaining artists flagged for targeted fallback.")