what am i doing bro
This commit is contained in:
parent
8479ed0ea3
commit
1bdecc293f
2 changed files with 218 additions and 57 deletions
|
|
@ -1,20 +1,23 @@
|
|||
# Editors Picks — album IDs (one per line)
|
||||
# Optional: add a label for this set with "# label: ..."
|
||||
# Lines starting with # are ignored.
|
||||
# Editors Picks
|
||||
# One item per line. Format: type:id
|
||||
# Supported types: album, artist, track, playlist, userplaylist, podcast
|
||||
# Bare numbers (no prefix) are treated as albums for backwards compatibility.
|
||||
# Optional: set a label for this archived set with "# label: ..."
|
||||
# label: Spring 2026
|
||||
|
||||
324660713
|
||||
15427733
|
||||
464178301
|
||||
75115890
|
||||
410197513
|
||||
418729278
|
||||
504004321
|
||||
510893864
|
||||
325723583
|
||||
336178142
|
||||
106369871
|
||||
423471869
|
||||
250986538
|
||||
509761344
|
||||
15621057
|
||||
album:324660713
|
||||
album:15427733
|
||||
album:464178301
|
||||
album:75115890
|
||||
album:410197513
|
||||
album:418729278
|
||||
album:504004321
|
||||
album:510893864
|
||||
album:325723583
|
||||
album:336178142
|
||||
album:106369871
|
||||
album:423471869
|
||||
album:250986538
|
||||
album:509761344
|
||||
album:15621057
|
||||
album:103897783
|
||||
|
|
@ -1,67 +1,225 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
INPUT_FILE = "editors-picks-input.txt"
|
||||
COUNTRY = "US"
|
||||
|
||||
TOKEN = "eyJraWQiOiJ2OU1GbFhqWSIsImFsZyI6IkVTMjU2In0.eyJ0eXBlIjoibzJfYWNjZXNzIiwic2NvcGUiOiIiLCJnVmVyIjowLCJzVmVyIjowLCJjaWQiOjEzNTU3LCJhdCI6IklOVEVSTkFMIiwiZXhwIjoxNzc1MTI4ODUzLCJpc3MiOiJodHRwczovL2F1dGgudGlkYWwuY29tL3YxIn0.qRoN8BRLM3R5WAXM3kS2hkWyaGk5tWF0FaHWJmkrWNvI48hKyS9lhVOTSnP1XkFEfdXv6aTzGUNUewyp-O_d3w"
|
||||
# Tidal internal token — replace when expired
|
||||
TIDAL_TOKEN = "eyJraWQiOiJ2OU1GbFhqWSIsImFsZyI6IkVTMjU2In0.eyJ0eXBlIjoibzJfYWNjZXNzIiwic2NvcGUiOiIiLCJnVmVyIjowLCJzVmVyIjowLCJjaWQiOjEzNTU3LCJhdCI6IklOVEVSTkFMIiwiZXhwIjoxNzc1MjQ2NzQ2LCJpc3MiOiJodHRwczovL2F1dGgudGlkYWwuY29tL3YxIn0.ksUE4yhQ39IG7oHWk8DyJ91dwIoDVWGzvTAnpeDJ5p-_Gp0F_yO858xDO11AINBaahQCq0jlbqWqIaTqCTOjqg"
|
||||
|
||||
HEADERS = {
|
||||
TIDAL_HEADERS = {
|
||||
"accept": "*/*",
|
||||
"authorization": f"Bearer {TOKEN}",
|
||||
"authorization": f"Bearer {TIDAL_TOKEN}",
|
||||
}
|
||||
|
||||
def read_album_ids(path):
|
||||
ids = []
|
||||
# PodcastIndex credentials
|
||||
PODCAST_API_KEY = "YU5HMSDYBQQVYDF6QN4P"
|
||||
PODCAST_API_SECRET = "8hCvpjSL7T$S7^5ftnf5MhqQwYUYVjM^fmUL3Ld$"
|
||||
PODCASTINDEX_BASE = "https://api.podcastindex.org/api/1.0"
|
||||
|
||||
|
||||
# ── Tidal helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
def tidal_get(path, params=None):
|
||||
if params is None:
|
||||
params = {}
|
||||
params.setdefault("countryCode", COUNTRY)
|
||||
url = f"https://api.tidal.com/v1/{path}?{urllib.parse.urlencode(params)}"
|
||||
req = urllib.request.Request(url, headers=TIDAL_HEADERS)
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
return json.loads(resp.read().decode())
|
||||
except Exception as e:
|
||||
print(f"Error fetching {url}: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def fetch_album(album_id):
|
||||
return tidal_get(f"albums/{album_id}")
|
||||
|
||||
|
||||
def fetch_artist(artist_id):
|
||||
return tidal_get(f"artists/{artist_id}")
|
||||
|
||||
|
||||
def fetch_track(track_id):
|
||||
return tidal_get(f"tracks/{track_id}")
|
||||
|
||||
|
||||
def fetch_playlist(uuid):
|
||||
return tidal_get(f"playlists/{uuid}")
|
||||
|
||||
|
||||
# ── PodcastIndex helper ───────────────────────────────────────────────────────
|
||||
|
||||
def podcast_get(endpoint):
|
||||
api_time = str(int(time.time()))
|
||||
raw = PODCAST_API_KEY + PODCAST_API_SECRET + api_time
|
||||
auth_hash = hashlib.sha1(raw.encode()).hexdigest()
|
||||
headers = {
|
||||
"User-Agent": "MonochromeMusic/1.0",
|
||||
"X-Auth-Key": PODCAST_API_KEY,
|
||||
"X-Auth-Date": api_time,
|
||||
"Authorization": auth_hash,
|
||||
}
|
||||
url = f"{PODCASTINDEX_BASE}{endpoint}"
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
return json.loads(resp.read().decode())
|
||||
except Exception as e:
|
||||
print(f"Error fetching {url}: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def fetch_podcast(feed_id):
|
||||
return podcast_get(f"/podcasts/byfeedid?id={feed_id}&pretty")
|
||||
|
||||
|
||||
# ── Transformers ──────────────────────────────────────────────────────────────
|
||||
|
||||
def transform_album(d):
|
||||
return {
|
||||
"type": "album",
|
||||
"id": d.get("id"),
|
||||
"title": d.get("title"),
|
||||
"artist": {
|
||||
"id": d.get("artist", {}).get("id"),
|
||||
"name": d.get("artist", {}).get("name"),
|
||||
},
|
||||
"releaseDate": d.get("releaseDate"),
|
||||
"cover": d.get("cover"),
|
||||
"explicit": d.get("explicit"),
|
||||
"audioQuality": d.get("audioQuality"),
|
||||
"mediaMetadata": d.get("mediaMetadata"),
|
||||
}
|
||||
|
||||
|
||||
def transform_artist(d):
|
||||
return {
|
||||
"type": "artist",
|
||||
"id": d.get("id"),
|
||||
"name": d.get("name"),
|
||||
"picture": d.get("picture"),
|
||||
}
|
||||
|
||||
|
||||
def transform_track(d):
|
||||
album = d.get("album") or {}
|
||||
return {
|
||||
"type": "track",
|
||||
"id": d.get("id"),
|
||||
"title": d.get("title"),
|
||||
"artist": {
|
||||
"id": d.get("artist", {}).get("id"),
|
||||
"name": d.get("artist", {}).get("name"),
|
||||
},
|
||||
"album": {
|
||||
"id": album.get("id"),
|
||||
"title": album.get("title"),
|
||||
"cover": album.get("cover"),
|
||||
},
|
||||
"duration": d.get("duration"),
|
||||
"explicit": d.get("explicit"),
|
||||
"audioQuality": d.get("audioQuality"),
|
||||
"mediaMetadata": d.get("mediaMetadata"),
|
||||
}
|
||||
|
||||
|
||||
def transform_playlist(d):
|
||||
# Tidal editorial playlist → rendered as album card with playlist href
|
||||
cover = d.get("squareImage") or d.get("image") or d.get("cover")
|
||||
return {
|
||||
"type": "playlist",
|
||||
"id": d.get("uuid"),
|
||||
"title": d.get("title"),
|
||||
"cover": cover,
|
||||
"numberOfTracks": d.get("numberOfTracks", 0),
|
||||
}
|
||||
|
||||
|
||||
def transform_userplaylist(d):
|
||||
# User playlist → rendered with createUserPlaylistCardHTML
|
||||
cover = d.get("squareImage") or d.get("image") or d.get("cover")
|
||||
creator = d.get("creator") or {}
|
||||
return {
|
||||
"type": "user-playlist",
|
||||
"id": d.get("uuid"),
|
||||
"name": d.get("title"),
|
||||
"cover": cover,
|
||||
"numberOfTracks": d.get("numberOfTracks", 0),
|
||||
"username": creator.get("name"),
|
||||
}
|
||||
|
||||
|
||||
def transform_podcast(d):
|
||||
feed = d.get("feed") or {}
|
||||
return {
|
||||
"type": "podcast",
|
||||
"id": str(feed.get("id", "")),
|
||||
"title": feed.get("title"),
|
||||
"author": feed.get("author") or feed.get("ownerName"),
|
||||
"image": feed.get("image") or feed.get("artwork"),
|
||||
"episodeCount": feed.get("episodeCount", 0),
|
||||
}
|
||||
|
||||
|
||||
# ── Input parser ──────────────────────────────────────────────────────────────
|
||||
|
||||
def read_items(path):
|
||||
"""
|
||||
Parses editors-picks-input.txt.
|
||||
Each non-comment line is either:
|
||||
- a bare number → album:<number> (backwards-compatible)
|
||||
- type:value → e.g. artist:123, track:456, playlist:uuid, podcast:789
|
||||
Supported types: album, artist, track, playlist, userplaylist, podcast
|
||||
"""
|
||||
items = []
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
try:
|
||||
ids.append(int(line))
|
||||
except ValueError:
|
||||
print(f"Skipping invalid ID: {line!r}", file=sys.stderr)
|
||||
return ids
|
||||
if ":" in line:
|
||||
item_type, _, value = line.partition(":")
|
||||
items.append((item_type.strip().lower(), value.strip()))
|
||||
else:
|
||||
# bare number → album
|
||||
items.append(("album", line))
|
||||
return items
|
||||
|
||||
def fetch_album(album_id):
|
||||
url = f"https://api.tidal.com/v1/albums/{album_id}?countryCode=US"
|
||||
req = urllib.request.Request(url, headers=HEADERS)
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
return json.loads(resp.read().decode())
|
||||
except Exception as e:
|
||||
print(f"Error fetching {album_id}: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
def transform_album(api_data):
|
||||
return {
|
||||
"type": "album",
|
||||
"id": api_data.get("id"),
|
||||
"title": api_data.get("title"),
|
||||
"artist": {
|
||||
"id": api_data.get("artist", {}).get("id"),
|
||||
"name": api_data.get("artist", {}).get("name"),
|
||||
},
|
||||
"releaseDate": api_data.get("releaseDate"),
|
||||
"cover": api_data.get("cover"),
|
||||
"explicit": api_data.get("explicit"),
|
||||
"audioQuality": api_data.get("audioQuality"),
|
||||
"mediaMetadata": api_data.get("mediaMetadata"),
|
||||
}
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
albums = read_album_ids(INPUT_FILE)
|
||||
FETCHERS = {
|
||||
"album": (fetch_album, transform_album),
|
||||
"artist": (fetch_artist, transform_artist),
|
||||
"track": (fetch_track, transform_track),
|
||||
"playlist": (fetch_playlist, transform_playlist),
|
||||
"userplaylist":(fetch_playlist, transform_userplaylist),
|
||||
"podcast": (fetch_podcast, transform_podcast),
|
||||
}
|
||||
|
||||
items = read_items(INPUT_FILE)
|
||||
picks = []
|
||||
for album_id in albums:
|
||||
data = fetch_album(album_id)
|
||||
|
||||
for item_type, item_id in items:
|
||||
if item_type not in FETCHERS:
|
||||
print(f"Unknown type '{item_type}' for id {item_id!r} — skipping", file=sys.stderr)
|
||||
continue
|
||||
fetch_fn, transform_fn = FETCHERS[item_type]
|
||||
data = fetch_fn(item_id)
|
||||
if data:
|
||||
picks.append(transform_album(data))
|
||||
picks.append(transform_fn(data))
|
||||
|
||||
with open("public/editors-picks.json", "w") as f:
|
||||
json.dump(picks, f, indent=4)
|
||||
|
||||
print(f"Written {len(picks)} albums to public/editors-picks.json")
|
||||
print(f"Written {len(picks)} items to public/editors-picks.json")
|
||||
|
|
|
|||
Loading…
Reference in a new issue