#!/usr/bin/env python3 """ Resolves a Spotify URL to track metadata using spotdl (TzurSoffer fork). Usage: python3 spotify_resolve.py Outputs JSON to stdout. """ import sys import json import os import tempfile import subprocess def main(): if len(sys.argv) < 2: print(json.dumps({"error": "No URL provided"})) sys.exit(1) url = sys.argv[1] tmp = tempfile.mktemp(suffix=".spotdl") try: result = subprocess.run( ["spotdl", "save", url, "--save-file", tmp, "--log-level", "ERROR"], capture_output=True, text=True, timeout=60 ) if result.returncode != 0: err = result.stderr.strip() or result.stdout.strip() or "spotdl failed" print(json.dumps({"error": err})) sys.exit(1) if not os.path.exists(tmp): print(json.dumps({"error": "spotdl produced no output file"})) sys.exit(1) with open(tmp, "r", encoding="utf-8") as f: songs = json.load(f) if not songs: print(json.dumps({"error": "No tracks found"})) sys.exit(1) # Transform spotdl Song format to NovaSonic format def fmt_track(s): artists = s.get("artists") or [] artist_str = ", ".join(artists) if artists else s.get("artist", "") date = s.get("date") or (str(s["year"]) if s.get("year") else "") return { "trackName": s.get("name", ""), "artistName": artist_str, "collectionName": s.get("album_name", ""), "artworkUrl100": s.get("cover_url", ""), "releaseDate": date, "trackNumber": s.get("track_number"), "trackExplicitness": "explicit" if s.get("explicit") else "notExplicit", "durationMs": int(s["duration"] * 1000) if s.get("duration") else None, } tracks = [fmt_track(s) for s in songs] first = songs[0] artists0 = first.get("artists") or [] artist0 = ", ".join(artists0) if artists0 else first.get("artist", "") # Determine type from URL if "/track/" in url: out = { "type": "track", "name": first.get("name", ""), "artist": artist0, "artworkUrl": first.get("cover_url", ""), "tracks": tracks, } elif "/album/" in url: out = { "type": "album", "name": first.get("album_name", ""), "artist": first.get("album_artist", artist0), "artworkUrl": first.get("cover_url", ""), "tracks": tracks, } else: out = { "type": "playlist", "name": first.get("list_name", ""), "artist": first.get("album_artist", ""), "artworkUrl": first.get("cover_url", ""), "skippedLocal": 0, "tracks": tracks, } print(json.dumps(out, ensure_ascii=False)) finally: try: os.unlink(tmp) except Exception: pass if __name__ == "__main__": main()