Skip to content

Instantly share code, notes, and snippets.

@cprkrn
Created April 22, 2026 20:52
Show Gist options
  • Select an option

  • Save cprkrn/3adcfff33908a2b5d40eb9e64e31218a to your computer and use it in GitHub Desktop.

Select an option

Save cprkrn/3adcfff33908a2b5d40eb9e64e31218a to your computer and use it in GitHub Desktop.
How I built my Coachella 2026 playlist with Claude Code — Beatport API, SoundCloud scraping, pyrekordbox, genre auto-sort

How I built my Coachella 2026 playlist with Claude Code

A DJ workflow: take ~9 reference playlists (Spotify + SoundCloud) → find everything on Beatport → fill the gaps with Bandcamp/vinyl → sort the rekordbox library by genre. All scripted, no clicking through 400 tracks by hand.

The stack

  • Claude Code with the Chrome extension for browser automation
  • Beatport API v4 (undocumented, but accessible with your session token)
  • SoundCloud api-v2 (hydration data + scraped client_id)
  • pyrekordbox for reading/writing the encrypted rekordbox master.db
  • Discogs API + marketplace scraping for vinyl-only tracks
  • Bandcamp for the long tail

The main tricks

1. Beatport API auth

Beatport's API doesn't have public docs but it's easy to talk to once you're logged in:

// From any beatport.com tab:
const session = await fetch('/api/auth/session').then(r => r.json());
const token = session.token.accessToken;

// Now hit the real API:
const r = await fetch('https://api.beatport.com/v4/my/playlists/?per_page=100', {
  headers: { Authorization: 'Bearer ' + token }
});

Useful endpoints:

  • GET /v4/my/playlists/ — list your playlists
  • GET /v4/my/playlists/{id}/tracks/ — track list (paginated, follow .next)
  • POST /v4/my/playlists/{id}/tracks/ with {track_id: N} — add
  • DELETE /v4/my/playlists/{id}/tracks/{playlist_track_id}/ — remove
  • GET /v4/catalog/search/?q=Artist+Title&type=tracks — search

2. SoundCloud playlist scraping

SoundCloud embeds the playlist tracklist in a global variable:

// From any soundcloud.com playlist page:
const data = window.__sc_hydration.find(h => h.hydratable === 'playlist').data;
const trackIds = data.tracks.map(t => t.id);

Then batch-fetch metadata via api-v2 (you'll need to scrape client_id from their JS bundle — /client_id:"([a-zA-Z0-9]{32})"/).

3. Reading the rekordbox library

Rekordbox 6 encrypts its SQLite db with SQLCipher. pyrekordbox handles the key for you:

from pyrekordbox import Rekordbox6Database
db = Rekordbox6Database()

tracks = list(db.get_content())
for t in tracks:
    print(t.Title, t.Artist.Name, t.Genre.Name, t.BPM)

It also supports writing — db.create_playlist(name, parent=folder), db.add_to_playlist(pl, track), db.commit(). Rekordbox must be closed for writes to stick.

4. Auto-sort by genre

Once you can read the db, sorting 250 tracks into genre playlists is a one-shot script:

from collections import defaultdict
buckets = defaultdict(list)
for t in db.get_content():
    g = t.Genre.Name if t.Genre else 'Other'
    buckets[g].append(t)

for name, tracks in buckets.items():
    pl = db.create_playlist(name, parent=genre_folder)
    for t in tracks:
        db.add_to_playlist(pl, t)
db.commit()

5. Cross-referencing saved DJ posts on Instagram

Instagram's saved-collection page exposes each post's og:title with the caption. Fetch each post URL and regex for releases / tracks names mentioned:

const html = await fetch(postUrl).then(r => r.text());
const title = html.match(/<meta property="og:title" content="([^"]+)"/)[1];

Then run the extracted artist/track pairs through the Beatport search.

The workflow

  1. Drop playlist URLs into the agent (Spotify / SoundCloud)
  2. Scrape tracklists via the methods above
  3. Fuzzy-match to Beatport with the search API (normalize punctuation, try artist+title variants)
  4. Flag ⚠️ low-confidence matches — these bite later when you actually listen
  5. Dedupe against rekordbox so you don't buy what you own
  6. Gap-fill with Bandcamp for anything still missing (Bandcamp Discover search or direct label page)
  7. Sort everything by genre in rekordbox once downloaded

Catches I hit

  • Fuzzy matching lies. Generic titles like "Good Times" or "Delight" silently match wrong tracks. Always listen before committing to a set. I ended up removing 4 wrong matches after downloading.
  • Beatport's Cloudflare blocks WebFetch — use browser-side fetch() with cookies/token instead.
  • JWTs get redacted by Claude's output filters. Store tokens in window._tok and operate same-tab instead of trying to export them.
  • Rekordbox's master.db is locked when RB is open — writes silently fail. Quit RB, then run.
  • FAT32 for DJ USB sticks — works on every Pioneer CDJ/XDJ. HFS+ does not.

What I'd build next

  • Chrome extension that wraps all this so non-coders can do it
  • Auto-fill Bandcamp wishlist from a list of unfound tracks
  • Track price-drops on Beatport for stuff you flagged but didn't buy

Bonus: which tracks ended up where

  • Beatport playlists (split by source): 5 playlists, ~300 tracks total
  • Bandcamp recoveries: 10 tracks across 9 small labels (~$20)
  • Rekordbox Genre folder: 10 auto-sorted playlists (Deep House, House, Minimal/Deep Tech, Tech House, Electronica, Indie Dance, Techno, UK Garage, Nu Disco, Other)

Built with Claude Code. The whole thing ran in one long conversation — the agent scripted Chrome, hit the APIs, wrote the pyrekordbox code, and kept track of everything in a markdown file along the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment