Skip to content

Built-in API server

Crateforge has a built-in local HTTP API server. Enabling it lets you integrate with AI agents (such as dj-curator) and play and control from a phone / TV / iPad.

Screenshots to be added

Enable the API server under “AI integration / API” in settings.

  • It is OFF by default. The default port is 8787.
  • By default it listens on 127.0.0.1 (loopback only).
  • Enabling “Expose on LAN” lets you access it from a phone / TV / PC browser on the same Wi-Fi. The connection URL and a QR code are shown in settings.

It has been hardened to restart only after the server has reliably stopped (SO_REUSEADDR / SO_REUSEPORT), resolving the “can’t start because the previous server hasn’t fully shut down (address in use)” problem.

  • Access requires a token (the token shown in settings). The token can be regenerated.
  • For devices without a camera (such as Android TV), device pairing is provided. Start with POST /api/pair/start → GET /api/pair/poll (neither needs a token), and approving it in the “Approve device” UI in settings lets you connect without typing a long token by hand.

It exposes a REST API for reading and writing the library, analysis data, and playlists. The main endpoints:

  • GET /api/health — server identity + current track count
  • GET /api/tracks (?q search, ?album / ?genre partial match, offset/limit)
  • GET /api/tracks/{id} / POST /api/tracks/by-ids
  • GET /api/tracks/{id}/analysis — analysis results (null if not analyzed)
  • GET /api/tracks/{id}/similar — similar tracks
  • GET /api/stats / GET /api/genres / GET /api/albums
  • GET /api/playlists / GET /api/playlists/{id} (includes the smart criteria smartCriteria) / GET /api/playlists/{id}/tracks
  • PATCH /api/tracks/{id} — partially update name / artist / album / genre / year / bpm / rating / composer / comments, etc. name / artist / album / genre / year / composer / comments are also reflected in the actual file’s tags, while rating / disabled / playCount / skipCount are DB-only.
  • PATCH /api/tracks ({trackIds, edit}) — bulk-update multiple tracks.
  • POST /api/tracks/genre-tags/add / /remove — add or remove genre tags at the end in bulk.

Metadata writes, in addition to updating the DB, are written back to the actual file’s ID3 / Vorbis / MP4 tags, and are reflected in the GUI immediately. The write-back path is shared with editing in the desktop GUI. When an organize folder (auto-organize) is configured, the file is also moved and renamed according to the edited metadata, just like editing in the GUI, and locationPath in the response points to the new path (a failed move does not fail the edit; it is reported via relocateFailed).

BPM and Key are part of the write-back too (exactly as when editing on the desktop).

  • BPM — written as an integer to TBPM (ID3v2) / tmpo (MP4) / BPM (Vorbis Comments). The track’s own BPM takes priority, falling back to the analysis result.
  • Key — the effective key (the manual override if set, otherwise the analyzed key) is written to InitialKey (ID3v2 TKEY / MP4 initialkey / Vorbis INITIALKEY) in musical notation (Am, etc.) rather than Camelot.
  • POST /api/tracks/analyze ({trackIds, force?}) — queue BPM / Key / Energy / similarity analysis for the given tracks in the background; responds 202 with queued (how many were queued) and more. Already-analyzed tracks are skipped unless force: true. Up to 1000 IDs per request. Loopback only (403 from the LAN).
  • GET /api/analysis/status — analysis progress (analyzed / total / remaining queue pending). Poll it after queueing.

This is distinct from POST /api/analysis, the sync endpoint that imports analysis results computed on another device. Progress still shows up in the desktop GUI as usual.

  • POST /api/playlists — create a new one
  • POST /api/playlists/{id}/tracks — add tracks
  • DELETE /api/playlists/{id}/tracks/{trackId} — remove a single track

Changes made via the API are reflected immediately in the running app’s UI through the library-changed event.

This repository is also a Claude Code plugin marketplace.

/plugin marketplace add tainakanchu/crateforge
/plugin install dj-curator@crateforge
# Generate a starting point for a set from a concept
/dj-curator:build-set summer-dusk chill house, 90 min, mellow start

The policy is that the AI focuses on selecting the candidate pool, while a human finalizes the track order in the GUI. For details, see the dj-curator README.

For Google Cast playback, there is an endpoint the cast device uses to fetch the audio: GET /api/cast/media/{ticket} (supports HEAD and Range).

  • It is Cast-only and is authenticated by a short-lived Media Ticket (bound to one track, with an expiry, revocable) rather than the LAN token. An invalid, expired or revoked ticket returns 404.
  • Tickets are revoked when you change track, disconnect, or quit the app. The LAN token is never handed to the cast device.
  • Requests to this path other than GET / HEAD still require the normal token.

When you enable LAN exposure, you can open a same-origin remote web UI (http://PC-IP:PORT/) in a browser. From an iPad and the like, you can switch between “Play on PC (remote)” and “Play on this device.” On iOS, you can make it a full-screen app (PWA) with “Add to Home Screen.”

The remote has play / pause, previous/next, seek, a volume slider, and shuffle / repeat toggles, with state via GET /api/remote/state (including volume / shuffle / repeat) and operations via POST /api/remote/* (play / pause / resume / next / prev / seek / volume / shuffle / repeat, etc.).

The web UI has keyboard shortcuts close to the desktop app, and ? opens the list (Space play / pause, J / K previous / next, Shift + ← / Shift + → seek 5 seconds, S shuffle, R repeat, Ctrl + ↑ / Ctrl + ↓ volume, / and Ctrl + F search, Ctrl + L back to the library, ↑ / ↓ to move the list selection). Shuffle / repeat / volume can be controlled from the web UI while “Play on this device” is active as well.