4.6 KiB
Furumi Web Player API
Base URL: http://<host>:<port>/api
All endpoints require authentication when --token is set (via cookie furumi_token=<token> or query param ?token=<token>).
All entity references use slugs — 12-character hex identifiers (not sequential IDs).
Artists
GET /api/artists
List all artists that have at least one track.
Response:
[
{
"slug": "a1b2c3d4e5f6",
"name": "Pink Floyd",
"album_count": 5,
"track_count": 42
}
]
Sorted alphabetically by name.
GET /api/artists/:slug
Get artist details.
Response:
{
"slug": "a1b2c3d4e5f6",
"name": "Pink Floyd"
}
Errors: 404 if not found.
GET /api/artists/:slug/albums
List all albums by an artist.
Response:
[
{
"slug": "b2c3d4e5f6a7",
"name": "Wish You Were Here",
"year": 1975,
"track_count": 5,
"has_cover": true
}
]
Sorted by year (nulls last), then name.
GET /api/artists/:slug/tracks
List all tracks by an artist across all albums.
Response: same as album tracks (see below).
Sorted by album year, album name, track number, title.
Albums
GET /api/albums/:slug
List all tracks in an album.
Response:
[
{
"slug": "c3d4e5f6a7b8",
"title": "Have a Cigar",
"track_number": 3,
"duration_secs": 312.5,
"artist_name": "Pink Floyd",
"album_name": "Wish You Were Here",
"album_slug": "b2c3d4e5f6a7",
"genre": "Progressive Rock"
}
]
Sorted by track number (nulls last), then title. Fields album_name, album_slug may be null for tracks without an album.
GET /api/albums/:slug/cover
Serve the album cover image from the album_images table.
Response: Binary image data with appropriate Content-Type (image/jpeg, image/png, etc.) and Cache-Control: public, max-age=86400.
Errors: 404 if no cover exists.
Tracks
GET /api/tracks/:slug
Get full track details.
Response:
{
"slug": "c3d4e5f6a7b8",
"title": "Have a Cigar",
"track_number": 3,
"duration_secs": 312.5,
"genre": "Progressive Rock",
"storage_path": "/music/storage/Pink Floyd/Wish You Were Here/03 - Have a Cigar.flac",
"artist_name": "Pink Floyd",
"artist_slug": "a1b2c3d4e5f6",
"album_name": "Wish You Were Here",
"album_slug": "b2c3d4e5f6a7",
"album_year": 1975
}
Errors: 404 if not found.
GET /api/tracks/:slug/cover
Serve cover art for a specific track. Resolution order:
- Album cover from
album_imagestable (if the track belongs to an album with a cover) - Embedded cover art extracted from the audio file metadata (ID3/Vorbis/etc. via Symphonia)
404if no cover art is available
Response: Binary image data with Content-Type and Cache-Control: public, max-age=86400.
Errors: 404 if no cover art found.
Streaming
GET /api/stream/:slug
Stream the audio file for a track.
Supports HTTP Range requests for seeking:
- Full response:
200 OKwithContent-LengthandAccept-Ranges: bytes - Partial response:
206 Partial ContentwithContent-Range - Invalid range:
416 Range Not Satisfiable
Content-Type is determined by the file extension (e.g. audio/flac, audio/mpeg).
Errors: 404 if track or file not found.
Search
GET /api/search?q=<query>&limit=<n>
Search across artists, albums, and tracks by name (case-insensitive substring match).
| Parameter | Required | Default | Description |
|---|---|---|---|
q |
yes | — | Search query |
limit |
no | 20 | Max results |
Response:
[
{
"result_type": "artist",
"slug": "a1b2c3d4e5f6",
"name": "Pink Floyd",
"detail": null
},
{
"result_type": "album",
"slug": "b2c3d4e5f6a7",
"name": "Wish You Were Here",
"detail": "Pink Floyd"
},
{
"result_type": "track",
"slug": "c3d4e5f6a7b8",
"name": "Have a Cigar",
"detail": "Pink Floyd"
}
]
detail contains the artist name for albums and tracks, null for artists.
Sorted by result type (artist → album → track), then by name.
Authentication
When --token / FURUMI_PLAYER_TOKEN is set:
- Cookie:
furumi_token=<token>— set after login - Query parameter:
?token=<token>— redirects to player and sets cookie
When token is empty, authentication is disabled and all endpoints are public.
Unauthenticated requests receive 401 Unauthorized with a login form.
Error format
All errors return JSON:
{
"error": "description of the error"
}
With appropriate HTTP status code (400, 404, 500, etc.).