Disabled obsolete CI
This commit is contained in:
214
docs/PLAYER-API.md
Normal file
214
docs/PLAYER-API.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 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.).
|
||||
Reference in New Issue
Block a user