OpenTune
For the community · Audio add-ons

Your catalog.
More ways to listen.

Connect your audio service to OpenTune with three HTTPS endpoints. Search recordings, return the best available audio, and let listeners choose their source order.

Get the starter ↗Read the protocol
01 · Describe

A manifest introduces your service and its capabilities.

02 · Match

Search returns exact recordings with artists and durations.

03 · Play

A stream endpoint returns a playable URL and honest format metadata.

A small API. No extension runtime.

OpenTune uses the BitChord HTTP add-on contract. Users add your service root or manifest.json URL in Settings → Audio → Audio add-ons. No executable package is installed.

The starter is a Cloudflare Worker with a small configurable catalog, CORS support and tests. It starts with an empty catalog; add your own audio URLs and their measured metadata before deploying.

cd examples/audio-addon
node --test worker.test.mjs
npx wrangler deploy

Configure CATALOG in wrangler.toml. Keep signed audio URLs short-lived and generate them at stream resolution if your service needs that. The example catalog is intended for a small collection; use a database for a larger service.

The three endpoints

GET /manifest.json

{
  "id": "org.example.catalog",
  "name": "My audio catalog",
  "version": "1.0.0",
  "resources": ["search", "stream"],
  "allowDownloads": true,
  "checkValidLossless": false,
  "settings": [{
    "key": "quality", "default": "lossless",
    "options": [{"label": "Best available FLAC", "value": "lossless"}]
  }]
}

Use a stable, unique ID. allowDownloads: false excludes your source from file downloads. checkValidLossless: true requires a supported wired, USB or HDMI output before OpenTune queries your service. Bluetooth and unknown outputs do not qualify.

GET /search?q=title%20artist&quality=lossless

{"tracks": [{
  "id": "recording-42", "title": "Example Song",
  "artist": "Example Artist", "album": "Example Album",
  "duration": 203, "format": "flac",
  "artwork": "https://cdn.example.org/cover.jpg"
}]}

Duration is in seconds. Return the real title and credited performers, including version labels such as live or remix. OpenTune checks recording identity and duration; the first search result is not automatically accepted. No match should return {"tracks":[]}.

GET /stream/recording-42?quality=lossless

{
  "url": "https://cdn.example.org/recording-42.flac",
  "codec": "flac", "format": "flac", "manifest": "none",
  "sampleRate": 96000, "bitDepth": 24,
  "encrypted": false
}

IDs are opaque and URL-encoded as one path segment. sampleRate is in Hz; bitrate, if supplied, is in bits per second. For unencrypted segmented playback use manifest: "hls" or "dash". File downloads currently require a direct audio file.

Describe the audio you actually serve.

Lossless describes the encoding, not a promise about the original master. Do not relabel AAC or MP3 as FLAC, upsample to claim higher resolution, or advertise 24-bit/192 kHz for every track.

ffprobe -v error -select_streams a:0 \
  -show_entries stream=codec_name,sample_rate,bits_per_raw_sample \
  -of json recording.flac

OpenTune reads direct FLAC headers and uses the playback decoder's format for the quality display. HLS/DASH renditions must contain supported lossless audio; encrypted audio is unsupported. Browser codec support differs from Android.

Source priority is intentional: Lossless quality checks eligible matching lossless results for the best available quality; equal quality keeps the listener’s source order. Normal playback can start while the higher-quality lookup runs.

Make delivery reliable.

ConcernExpected behavior
TransportPublic HTTPS endpoints, including redirects and media URLs. Local/private destinations are rejected by the Android addon transport.
Browser accessEnable CORS on API responses, audio, manifests and every segment. Support OPTIONS. Public unauthenticated services can use Access-Control-Allow-Origin: *.
SeekingSupport Range requests and HTTP 206 with correct Content-Range and Content-Length for direct files.
Rate limitsReturn HTTP 429 with Retry-After. OpenTune applies a bounded cooldown and tries another enabled source.
FailuresUse a suitable HTTP status and {"error":"A safe explanation"}. Never return an HTML error document as audio.
Response sizeKeep JSON small; the Android client limits metadata responses to 2 MiB and downloads to 512 MiB.
ExpirationStream responses may be cached for five minutes. Keep URLs valid for playback and seeking beyond that window, or return a renewable stable URL.

Configured URL paths and query parameters are preserved locally. They are not safe places for credentials intended to stay secret from your users. OpenTune does not attach its Google session or other app cookies to addon requests.

Test it, then share the URL.

  1. Run the starter tests and check all three endpoints.
  2. Add your manifest in OpenTune and use Check to inspect its availability.
  3. Select Lossless quality, play a known recording, and inspect Signal path. Check a non-match, a timeout and an expired URL too.
  4. Test downloads, seeking and playback on the intended devices. Inspect the file with ffprobe instead of relying on its extension.
  5. Share the manifest URL and source code with your community. Document region limits, costs, authentication and availability.

Read the client behavior and platform limits ↗

Build with the community ↗