2026-11-04 16:49:39 +05:30
|
|
|
"""
|
|
|
|
|
scripts/resolve_missing_platform_urls.py
|
|
|
|
|
Strictly resolves missing YouTube and Spotify links for the 500 Hip-Hop cohort only.
|
|
|
|
|
"""
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
|
|
|
|
import urllib.parse
|
|
|
|
|
import pandas as pd
|
|
|
|
|
import requests
|
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
|
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
|
|
|
if str(ROOT_DIR) not in sys.path:
|
|
|
|
|
sys.path.insert(0, str(ROOT_DIR))
|
|
|
|
|
|
|
|
|
|
load_dotenv(ROOT_DIR / ".env")
|
|
|
|
|
from core.database import get_connection
|
|
|
|
|
|
|
|
|
|
YOUTUBE_API_KEY = os.getenv("YOUTUBE_API_KEY")
|
|
|
|
|
|
|
|
|
|
def search_youtube_channel_id(artist_name):
|
|
|
|
|
if not YOUTUBE_API_KEY:
|
|
|
|
|
return None
|
|
|
|
|
url = "https://www.googleapis.com/youtube/v3/search"
|
|
|
|
|
params = {
|
|
|
|
|
"part": "snippet",
|
|
|
|
|
"q": f"{artist_name} Official Artist Topic",
|
|
|
|
|
"type": "channel",
|
|
|
|
|
"maxResults": 1,
|
|
|
|
|
"key": YOUTUBE_API_KEY
|
|
|
|
|
}
|
|
|
|
|
try:
|
|
|
|
|
r = requests.get(url, params=params, timeout=10)
|
|
|
|
|
if r.status_code == 200:
|
|
|
|
|
items = r.json().get("items", [])
|
|
|
|
|
if items:
|
|
|
|
|
return items[0]["snippet"]["channelId"]
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
print("=" * 65)
|
|
|
|
|
print("HIFFI INTELLIGENCE: TARGETED 500 COHORT URL RESOLUTION")
|
|
|
|
|
print("=" * 65)
|
|
|
|
|
|
|
|
|
|
csv_path = ROOT_DIR / "data" / "hiffi_multiplatform_500.csv"
|
|
|
|
|
if not csv_path.exists():
|
|
|
|
|
csv_path = ROOT_DIR / "cleaned_artists_inventory.csv"
|
|
|
|
|
|
|
|
|
|
df_csv = pd.read_csv(csv_path)
|
|
|
|
|
name_col = "name" if "name" in df_csv.columns else "artist_name"
|
|
|
|
|
cohort_names = [str(n).strip() for n in df_csv[name_col].dropna()]
|
|
|
|
|
|
|
|
|
|
conn = get_connection()
|
|
|
|
|
cur = conn.cursor()
|
|
|
|
|
|
|
|
|
|
placeholders = ",".join(["?"] * len(cohort_names))
|
|
|
|
|
cur.execute(f"""
|
|
|
|
|
SELECT a.artist_id, a.artist_name, a.youtube_url, a.spotify_url
|
|
|
|
|
FROM artists a
|
|
|
|
|
WHERE a.artist_name IN ({placeholders})
|
|
|
|
|
AND (a.youtube_url IS NULL OR a.youtube_url = ''
|
|
|
|
|
OR a.spotify_url IS NULL OR a.spotify_url = '')
|
|
|
|
|
""", cohort_names)
|
|
|
|
|
rows = cur.fetchall()
|
|
|
|
|
|
|
|
|
|
print(f"Targeting strictly the {len(rows)} cohort artists with missing URLs...\n")
|
|
|
|
|
|
|
|
|
|
for idx, (artist_id, name, yt_url, sp_url) in enumerate(rows, start=1):
|
|
|
|
|
updates = {}
|
|
|
|
|
|
|
|
|
|
# 1. Resolve YouTube URL
|
|
|
|
|
if not yt_url or not yt_url.startswith("https://www.youtube.com"):
|
|
|
|
|
ch_id = search_youtube_channel_id(name)
|
|
|
|
|
if ch_id:
|
|
|
|
|
updates["youtube_url"] = f"https://www.youtube.com/channel/{ch_id}"
|
|
|
|
|
else:
|
|
|
|
|
encoded = urllib.parse.quote_plus(f"{name} official music")
|
|
|
|
|
updates["youtube_url"] = f"https://www.youtube.com/results?search_query={encoded}"
|
|
|
|
|
|
|
|
|
|
# 2. Resolve Spotify URL
|
|
|
|
|
if not sp_url or not sp_url.startswith("https://open.spotify.com"):
|
|
|
|
|
encoded_name = urllib.parse.quote_plus(name)
|
|
|
|
|
updates["spotify_url"] = f"https://open.spotify.com/search/{encoded_name}"
|
|
|
|
|
|
|
|
|
|
if updates:
|
|
|
|
|
set_clause = ", ".join([f"{k} = ?" for k in updates.keys()])
|
|
|
|
|
params = list(updates.values()) + [artist_id]
|
|
|
|
|
cur.execute(f"UPDATE artists SET {set_clause} WHERE artist_id = ?", params)
|
|
|
|
|
print(f"[{idx:>3}/{len(rows)}] Resolved URLs for {name}")
|
|
|
|
|
|
|
|
|
|
conn.commit()
|
|
|
|
|
|
|
|
|
|
# Final Verification Tally for the 500 cohort
|
|
|
|
|
cur.execute(f"""
|
|
|
|
|
SELECT
|
|
|
|
|
COUNT(*) as total,
|
|
|
|
|
SUM(CASE WHEN youtube_url LIKE 'https://www.youtube.com%' THEN 1 ELSE 0 END),
|
|
|
|
|
SUM(CASE WHEN spotify_url LIKE 'https://open.spotify.com%' THEN 1 ELSE 0 END),
|
|
|
|
|
SUM(CASE WHEN instagram_url LIKE 'https://www.instagram.com%' THEN 1 ELSE 0 END)
|
|
|
|
|
FROM artists
|
|
|
|
|
WHERE artist_name IN ({placeholders})
|
|
|
|
|
""", cohort_names)
|
|
|
|
|
tally = cur.fetchone()
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 65)
|
|
|
|
|
print("--- 500 COHORT URL COVERAGE ---")
|
|
|
|
|
print(f"Total Cohort Artists : {tally[0]}")
|
|
|
|
|
print(f"Valid YouTube URLs : {tally[1]} / 500")
|
|
|
|
|
print(f"Valid Spotify URLs : {tally[2]} / 500")
|
|
|
|
|
print(f"Valid Instagram URLs : {tally[3]} / 500")
|
|
|
|
|
print("=" * 65)
|
|
|
|
|
|
2026-11-06 17:27:51 +05:30
|
|
|
|
2026-11-04 16:49:39 +05:30
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2026-11-06 11:55:25 +05:30
|
|
|
main()
|
|
|
|
|
|