Files
furumi-ng/docs/PLAYER-API.md
AB-UK 8d70a5133a
All checks were successful
Publish Metadata Agent Image (dev) / build-and-push-image (push) Successful in 1m17s
Publish Web Player Image (dev) / build-and-push-image (push) Successful in 1m14s
Disabled obsolete CI
2026-03-20 00:49:27 +00:00

215 lines
4.6 KiB
Markdown

# 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:**
```json
[
{
"slug": "a1b2c3d4e5f6",
"name": "Pink Floyd",
"album_count": 5,
"track_count": 42
}
]
```
Sorted alphabetically by name.
### `GET /api/artists/:slug`
Get artist details.
**Response:**
```json
{
"slug": "a1b2c3d4e5f6",
"name": "Pink Floyd"
}
```
**Errors:** `404` if not found.
### `GET /api/artists/:slug/albums`
List all albums by an artist.
**Response:**
```json
[
{
"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:**
```json
[
{
"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:**
```json
{
"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:
1. Album cover from `album_images` table (if the track belongs to an album with a cover)
2. Embedded cover art extracted from the audio file metadata (ID3/Vorbis/etc. via Symphonia)
3. `404` if 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 OK` with `Content-Length` and `Accept-Ranges: bytes`
- Partial response: `206 Partial Content` with `Content-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:**
```json
[
{
"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:
```json
{
"error": "description of the error"
}
```
With appropriate HTTP status code (`400`, `404`, `500`, etc.).