A self-hosted song search and download API powered by MusicBrainz, YouTube, and Supabase. Search for songs by title/artist, download them as MP3s, and serve them with local caching for fast playback.
- Docker & Docker Compose
- A Supabase project with:
- A
songstable (see Database Setup) - A
song-filesstorage bucket
- A
cp .env.example .env
# Edit .env with your keys (see Configuration below)
docker compose up -d --buildThe API will be available at http://localhost:6493. A web UI is served at the root (/).
| Variable | Default | Description |
|---|---|---|
MASTER_API_KEY |
(required) | Admin API key for managing sub-keys |
SUPABASE_URL |
(required) | Your Supabase project URL |
SUPABASE_SERVICE_KEY |
(required) | Supabase service role key |
SONGS_DIR |
/songs |
Local directory for song storage |
RATE_LIMIT |
60/minute |
Global rate limit per IP |
SEARCH_CACHE_MAX_SIZE |
500 |
Max entries in the in-memory search cache (LRU) |
SONG_CACHE_MAX_MB |
2048 |
Max local disk cache for MP3 files in MB |
All endpoints (except /api/health) require an API key via the X-API-Key header.
curl -H "X-API-Key: YOUR_KEY" http://localhost:6493/api/search ...Key types:
| Type | Format | Access |
|---|---|---|
| Master key | Set in .env |
Full access + admin |
| Regular key | mxd_live_... |
Search, download, playback |
Regular keys are created/revoked via the admin endpoints.
POST /api/search?fast=false
Search MusicBrainz for songs. Returns matching recordings and, when the query matches an artist, the artist with their top songs.
Request body:
{
"query": "green day welcome to paradise"
}Or search with explicit fields:
{
"title": "Welcome to Paradise",
"artist": "Green Day"
}Query parameters:
| Param | Type | Default | Description |
|---|---|---|---|
fast |
bool | false |
Use fast mode (fewer MB requests, best for typeahead) |
Response:
{
"results": [
{
"musicbrainz_id": "c2d8ca4f-503a-452b-ae1e-9646022eaf50",
"title": "Welcome to Paradise",
"artist": "Green Day",
"album": "Dookie",
"album_art_url": "https://coverartarchive.org/release/.../front-250",
"youtube_query": "Welcome to Paradise - Green Day",
"score": 100
}
],
"artists": [
{
"musicbrainz_id": "084308bd-1654-436f-ba03-df6697104e19",
"name": "Green Day",
"type": "Group",
"country": "US",
"tags": ["rock", "punk", "alternative rock"],
"top_songs": [
{
"musicbrainz_id": "6af5abdb-...",
"title": "Longview",
"artist": "Green Day",
"album": "Dookie",
"album_art_url": "https://...",
"youtube_query": "Longview - Green Day",
"score": 100
}
]
}
]
}POST /api/download
Downloads the song from YouTube, uploads to Supabase Storage, and caches locally.
Request body:
{
"musicbrainz_id": "c2d8ca4f-503a-452b-ae1e-9646022eaf50"
}Response:
{
"id": "uuid",
"musicbrainz_id": "c2d8ca4f-...",
"title": "Welcome to Paradise",
"artist": "Green Day",
"album": "Dookie",
"album_art_url": "https://...",
"file_path": "/api/cache/c2d8ca4f-...",
"duration_seconds": 227,
"genres": ["punk rock", "pop punk"],
"youtube_video_id": "...",
"youtube_title": "...",
"downloaded_at": "2026-03-18T...",
"status": "downloaded"
}The file_path will be a local cache URL (/api/cache/{id}) if cached, or a Supabase signed URL otherwise.
GET /api/songs/{musicbrainz_id}
Retrieve metadata and a playback URL for a previously downloaded song.
GET /api/cache/{file_key}?key=YOUR_API_KEY
Serves the MP3 directly from local disk. The key query parameter is an alternative to the X-API-Key header (useful for <audio> elements that can't set headers).
GET /api/cache-stats
{
"cached_songs": 12,
"used_mb": 54.3,
"max_mb": 2048.0
}GET /api/health
No authentication required.
{
"status": "healthy",
"songs_count": 12,
"storage_used_mb": 54.0,
"yt_dlp_version": "2026.03.17"
}List keys:
GET /api/admin/keys
Create a key:
POST /api/admin/keys
{ "name": "my-app" }Revoke a key:
DELETE /api/admin/keys
{ "key": "mxd_live_..." }All admin endpoints require the master API key.
Create a songs table in your Supabase project:
CREATE TABLE songs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
musicbrainz_id TEXT UNIQUE,
title TEXT NOT NULL,
artist TEXT NOT NULL,
album TEXT,
album_art_url TEXT,
file_key TEXT NOT NULL UNIQUE,
duration_seconds INTEGER,
youtube_video_id TEXT,
youtube_title TEXT,
genres TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_songs_mbid ON songs(musicbrainz_id);Create a song-files storage bucket (public or private, the API uses signed URLs).
Client -> FastAPI -> MusicBrainz (search/metadata)
-> YouTube (download via yt-dlp)
-> Supabase Storage (persistent MP3 storage)
-> Local disk cache (fast playback)
- Search cache: In-memory LRU with 1-hour TTL. Configurable max size.
- Song cache: On-disk LRU. MP3s served directly, bypassing Supabase for cached songs. Configurable max size in MB.
- Smart search: Tries title/artist field splits in both directions to find the best match. Parallel MusicBrainz queries.
- Artist detection: When a query matches an artist, returns the artist card with their top songs ranked by popularity.