"""Shared Spotify Client-Credentials token fetch for the pipeline scripts. The scripts (spotify-retag.py, spotify-genre.py, fix-track-metadata.py) each run as `python /app/pipeline/lib/.py`, so this directory is on sys.path and they can `from _spotify_auth import get_token`. Each still sources its own credentials (env vars vs a rendered .env file); only the token request itself, which was copy-pasted four ways, lives here. """ import base64 import json import urllib.parse import urllib.request _TOKEN_URL = "https://accounts.spotify.com/api/token" _cache: dict[tuple[str, str], str] = {} def get_token(client_id: str, client_secret: str) -> str: """Return a client-credentials access token, cached per (id, secret) for the life of the process.""" key = (client_id, client_secret) if key in _cache: return _cache[key] creds = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode() req = urllib.request.Request( _TOKEN_URL, data=urllib.parse.urlencode({"grant_type": "client_credentials"}).encode(), headers={ "Authorization": f"Basic {creds}", "Content-Type": "application/x-www-form-urlencoded", }, ) with urllib.request.urlopen(req, timeout=15) as r: _cache[key] = json.loads(r.read())["access_token"] return _cache[key]