feat: finalize root api.py with X-Auth-Secret auth security and clean pure sales cohort
This commit is contained in:
1 parent
85e6395770
commit
78a46a8dbe
629 files changed
+123965
-755
No files matched your search
@@ -0,0 +1,81 @@
|
||||
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.")
|
||||
Reference in new issue
Block a user