Files
MusicPlayer/server/openapi.json
T
SansanandClaude Opus 5.5 ef6ac8f1fd
Build / test (push) Successful in 1m43s
Build / build (push) Successful in 1m14s
Show soundtrack covers and edit alternative names (#49)
Covers: statistics cards show the soundtrack's cover on the left, and the
statistics popup shows it large. Until it arrives, and without a cover, the
soundtrack's initials stand in. Covers load only for cards on or near the
screen, three at a time, and are cached in covers/ next to the settings
(CoverCache), downloaded again only when cover_modified changes. The index and
file handling are shared with CharacterCache in a new FileCache.

Alternative names: the popup shows them and has an editor (add, remove, save)
that sends PUT /soundtracks/{uuid}/alternative-names. The statistics search and
the Search popup find soundtracks by them; Search shows the matching name after
the real one. Search now loads /soundtracks, falling back to the plain list.

The API types are regenerated from the server's spec, with a SoundtrackCover
theme style in every theme.

Closes #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:06:30 +02:00

4283 lines
114 KiB
JSON

{
"components": {
"schemas": {
"APIError": {
"additionalProperties": false,
"properties": {
"error": {
"description": "What went wrong",
"examples": [
"Not Found"
],
"type": "string"
}
},
"required": [
"error"
],
"type": "object"
},
"AlternativeNames": {
"additionalProperties": false,
"properties": {
"names": {
"description": "The new list of alternative names. Replaces the old list; send [] to remove them all.",
"items": {
"type": "string"
},
"maxItems": 50,
"type": "array"
}
},
"required": [
"names"
],
"type": "object"
},
"CharacterDetails": {
"additionalProperties": false,
"properties": {
"modified": {
"description": "When the image was last changed, in Unix seconds",
"format": "int64",
"type": "integer"
},
"name": {
"description": "File name of the character image",
"type": "string"
}
},
"required": [
"name",
"modified"
],
"type": "object"
},
"CoverSource": {
"additionalProperties": false,
"properties": {
"id": {
"description": "The game's ID on SteamGridDB, or the anime's ID on AniList",
"maxLength": 50,
"minLength": 1,
"type": "string"
},
"source": {
"description": "Where the cover comes from",
"enum": [
"steamgriddb",
"anilist"
],
"type": "string"
}
},
"required": [
"source",
"id"
],
"type": "object"
},
"ProgressResponse": {
"additionalProperties": false,
"properties": {
"progress": {
"type": "string"
},
"time_spent": {
"type": "string"
}
},
"required": [
"progress",
"time_spent"
],
"type": "object"
},
"Song": {
"additionalProperties": false,
"properties": {
"file_name": {
"type": "string"
},
"name": {
"type": "string"
},
"soundtrack_name": {
"type": "string"
},
"soundtrack_uuid": {
"type": "string"
},
"times_played": {
"format": "int32",
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"required": [
"uuid",
"name",
"times_played",
"soundtrack_uuid",
"soundtrack_name"
],
"type": "object"
},
"SongInfo": {
"additionalProperties": false,
"properties": {
"CurrentlyPlaying": {
"type": "boolean"
},
"Song": {
"type": "string"
},
"SongNo": {
"format": "int64",
"type": "integer"
},
"SongPlayed": {
"format": "int32",
"type": "integer"
},
"SongUuid": {
"type": "string"
},
"Soundtrack": {
"type": "string"
},
"SoundtrackPlayed": {
"format": "int32",
"type": "integer"
},
"SoundtrackUuid": {
"type": "string"
}
},
"required": [
"SoundtrackUuid",
"Soundtrack",
"SoundtrackPlayed",
"SongUuid",
"Song",
"SongPlayed",
"CurrentlyPlaying",
"SongNo"
],
"type": "object"
},
"SongInfoForStats": {
"additionalProperties": false,
"properties": {
"file_name": {
"type": "string"
},
"path": {
"type": "string"
},
"song_name": {
"type": "string"
},
"song_uuid": {
"type": "string"
},
"soundtrack_id": {
"format": "int32",
"type": "integer"
},
"soundtrack_name": {
"type": "string"
},
"soundtrack_uuid": {
"type": "string"
},
"times_played": {
"format": "int32",
"type": "integer"
}
},
"required": [
"soundtrack_id",
"soundtrack_uuid",
"song_uuid",
"soundtrack_name",
"song_name",
"path",
"times_played"
],
"type": "object"
},
"Soundtrack": {
"additionalProperties": false,
"properties": {
"added": {
"format": "date-time",
"type": "string"
},
"alternative_names": {
"description": "Other names the soundtrack is known by",
"items": {
"type": "string"
},
"type": "array"
},
"cover_modified": {
"description": "When the cover last changed, in Unix seconds. Missing when there is no cover.",
"format": "int64",
"type": "integer"
},
"last_played": {
"format": "date-time",
"type": "string"
},
"name": {
"type": "string"
},
"times_played": {
"format": "int32",
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"required": [
"uuid",
"name",
"alternative_names",
"times_played",
"added"
],
"type": "object"
},
"SoundtrackWithSongList": {
"additionalProperties": false,
"properties": {
"added": {
"format": "date-time",
"type": "string"
},
"alternative_names": {
"description": "Other names the soundtrack is known by",
"items": {
"type": "string"
},
"type": "array"
},
"cover_modified": {
"description": "When the cover last changed, in Unix seconds. Missing when there is no cover.",
"format": "int64",
"type": "integer"
},
"last_played": {
"format": "date-time",
"type": "string"
},
"name": {
"type": "string"
},
"songs": {
"items": {
"$ref": "#/components/schemas/Song"
},
"type": "array"
},
"times_played": {
"format": "int32",
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"required": [
"songs",
"uuid",
"name",
"alternative_names",
"times_played",
"added"
],
"type": "object"
},
"SoundtrackWithSongs": {
"additionalProperties": false,
"properties": {
"alternative_names": {
"description": "Other names the soundtrack is known by",
"items": {
"type": "string"
},
"type": "array"
},
"cover_modified": {
"description": "When the cover last changed, in Unix seconds. Missing when there is no cover.",
"format": "int64",
"type": "integer"
},
"songs": {
"items": {
"$ref": "#/components/schemas/SongInfoForStats"
},
"type": "array"
},
"soundtrack_id": {
"format": "int32",
"type": "integer"
},
"soundtrack_last_played": {
"format": "date-time",
"type": "string"
},
"soundtrack_name": {
"type": "string"
},
"soundtrack_played": {
"format": "int32",
"type": "integer"
},
"soundtrack_uuid": {
"type": "string"
}
},
"required": [
"soundtrack_id",
"soundtrack_uuid",
"soundtrack_name",
"alternative_names",
"soundtrack_played",
"songs"
],
"type": "object"
},
"StatisticsSummary": {
"additionalProperties": false,
"properties": {
"avg_soundtrack_plays": {
"format": "double",
"type": "number"
},
"max_soundtrack_plays": {
"format": "int64",
"type": "integer"
},
"min_soundtrack_plays": {
"format": "int64",
"type": "integer"
},
"never_played_soundtracks": {
"format": "int64",
"type": "integer"
},
"played_soundtracks": {
"format": "int64",
"type": "integer"
},
"total_soundtrack_plays": {
"format": "int64",
"type": "integer"
},
"total_soundtracks": {
"format": "int64",
"type": "integer"
}
},
"required": [
"total_soundtracks",
"played_soundtracks",
"never_played_soundtracks",
"total_soundtrack_plays",
"avg_soundtrack_plays",
"max_soundtrack_plays",
"min_soundtrack_plays"
],
"type": "object"
},
"StatusMessage": {
"additionalProperties": false,
"properties": {
"status": {
"type": "string"
}
},
"required": [
"status"
],
"type": "object"
},
"SyncResponse": {
"additionalProperties": false,
"properties": {
"catched_errors": {
"items": {
"type": "string"
},
"type": "array"
},
"soundtracks_added": {
"items": {
"type": "string"
},
"type": "array"
},
"soundtracks_changed_content": {
"items": {
"type": "string"
},
"type": "array"
},
"soundtracks_changed_title": {
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"soundtracks_re_added": {
"items": {
"type": "string"
},
"type": "array"
},
"soundtracks_removed": {
"items": {
"type": "string"
},
"type": "array"
},
"total_time": {
"type": "string"
}
},
"required": [
"soundtracks_added",
"soundtracks_re_added",
"soundtracks_changed_title",
"soundtracks_changed_content",
"soundtracks_removed",
"catched_errors",
"total_time"
],
"type": "object"
},
"TokenRequest": {
"additionalProperties": false,
"properties": {
"client_type": {
"default": "web",
"description": "Kind of client, for example web, godot or api",
"type": "string"
},
"password": {
"description": "API password, required when the server has one configured",
"type": "string"
}
},
"type": "object"
},
"TokenResponse": {
"additionalProperties": false,
"properties": {
"client_type": {
"type": "string"
},
"expires_at": {
"format": "date-time",
"type": "string"
},
"token": {
"description": "Send as Authorization: Bearer <token>",
"type": "string"
}
},
"required": [
"token",
"expires_at",
"client_type"
],
"type": "object"
},
"VersionData": {
"additionalProperties": false,
"properties": {
"changelog": {
"examples": [
[
"Initial release",
"Bug fixes"
]
],
"items": {
"type": "string"
},
"type": "array"
},
"version": {
"examples": [
"1.0.0"
],
"type": "string"
}
},
"required": [
"version",
"changelog"
],
"type": "object"
}
},
"securitySchemes": {
"bearer": {
"description": "Token from POST /api/v1/token",
"scheme": "bearer",
"type": "http"
}
}
},
"info": {
"description": "API for the MusicServer application.\n\nGet a token with `POST /api/v1/token` and send it as `Authorization: Bearer <token>`.\n\nEvery client has its own play queue. The music endpoints return its ID in the `X-Queue-Id` header; send it back in the same header to keep using that queue. Without it, or when the queue has ended (after a reset or a sync), a new queue is started.",
"title": "MusicServer API",
"version": "5.0.0"
},
"openapi": "3.1.0",
"paths": {
"/api/v1/character": {
"get": {
"description": "Returns a character image.",
"operationId": "get-character",
"parameters": [
{
"description": "File name of the character image, from the character list",
"explode": false,
"in": "query",
"name": "name",
"required": true,
"schema": {
"description": "File name of the character image, from the character list",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"image/jpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/png": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The image"
},
"206": {
"content": {
"image/jpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/png": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Character image",
"tags": [
"characters"
]
}
},
"/api/v1/character/details": {
"get": {
"description": "Returns every character image with the time it was last changed, so clients can cache images and download only the changed ones.",
"operationId": "list-character-details",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/CharacterDetails"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "List characters with change times",
"tags": [
"characters"
]
}
},
"/api/v1/character/list": {
"get": {
"description": "Returns the file names of all character images.",
"operationId": "list-characters",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "List characters",
"tags": [
"characters"
]
}
},
"/api/v1/download": {
"get": {
"description": "Returns the name of the latest MusicPlayer release.",
"operationId": "get-latest-client-version",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"502": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Gateway"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Latest client version",
"tags": [
"download"
]
}
},
"/api/v1/download/linux": {
"get": {
"description": "Redirects to the download URL of the latest MusicPlayer release for Linux.",
"operationId": "download-client-linux",
"responses": {
"302": {
"description": "Found",
"headers": {
"Location": {
"schema": {
"description": "Download URL of the asset",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"502": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Gateway"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Download the latest client for Linux",
"tags": [
"download"
]
}
},
"/api/v1/download/list": {
"get": {
"description": "Returns the file names of the latest MusicPlayer release.",
"operationId": "list-client-assets",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"502": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Gateway"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Latest client assets",
"tags": [
"download"
]
}
},
"/api/v1/download/windows": {
"get": {
"description": "Redirects to the download URL of the latest MusicPlayer release for Windows.",
"operationId": "download-client-windows",
"responses": {
"302": {
"description": "Found",
"headers": {
"Location": {
"schema": {
"description": "Download URL of the asset",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"502": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Gateway"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Download the latest client for Windows",
"tags": [
"download"
]
}
},
"/api/v1/health": {
"get": {
"description": "Returns {\"status\": \"up\"} when the server and database work, otherwise status \"down\" and an error.",
"operationId": "get-health",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"additionalProperties": {
"type": "string"
},
"type": "object"
}
}
},
"description": "OK"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Error"
}
},
"summary": "Health check",
"tags": [
"server"
]
}
},
"/api/v1/music": {
"get": {
"description": "Jumps to the song at the given queue position (clamped to the queue) and returns it.",
"operationId": "get-queue-song",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
},
{
"description": "Position of the song in the queue (SongNo)",
"explode": false,
"in": "query",
"name": "song",
"required": true,
"schema": {
"description": "Position of the song in the queue (SongNo)",
"format": "int64",
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Play a song from the queue",
"tags": [
"music"
]
}
},
"/api/v1/music/addPlayed": {
"get": {
"description": "Increments the play counters of the current song and its soundtrack.",
"operationId": "mark-current-played",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Mark the current song as played",
"tags": [
"music"
]
}
},
"/api/v1/music/addQue": {
"get": {
"description": "Adds the song returned by the last random song request to the end of the queue.",
"operationId": "add-latest-to-queue",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Add the last random song to the queue",
"tags": [
"music"
]
}
},
"/api/v1/music/all": {
"get": {
"description": "Returns the names of all soundtracks in random order.",
"operationId": "get-soundtrack-names-random",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Soundtrack names, random order",
"tags": [
"music"
]
}
},
"/api/v1/music/all/order": {
"get": {
"description": "Returns the names of all soundtracks in alphabetical order.",
"operationId": "get-soundtrack-names",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Soundtrack names, sorted",
"tags": [
"music"
]
}
},
"/api/v1/music/all/random": {
"get": {
"description": "Same as /music/all.",
"operationId": "get-soundtrack-names-random-alias",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"type": "string"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Soundtrack names, random order",
"tags": [
"music"
]
}
},
"/api/v1/music/info": {
"get": {
"description": "Returns the current song in the queue.",
"operationId": "get-song-info",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongInfo"
}
}
},
"description": "OK",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Current song",
"tags": [
"music"
]
}
},
"/api/v1/music/list": {
"get": {
"description": "Returns all songs in the queue.",
"operationId": "get-played-songs",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SongInfo"
},
"type": "array"
}
}
},
"description": "OK",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Queue",
"tags": [
"music"
]
}
},
"/api/v1/music/next": {
"get": {
"description": "Moves to the next song in the queue and returns it. Stays on the last song at the end.",
"operationId": "get-next-song",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Next song in the queue",
"tags": [
"music"
]
}
},
"/api/v1/music/played": {
"put": {
"description": "Increments the play counters of the song at the given queue position. Positions outside the queue are ignored.",
"operationId": "mark-song-played",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
},
{
"description": "Position of the song in the queue (SongNo)",
"explode": false,
"in": "query",
"name": "song",
"required": true,
"schema": {
"description": "Position of the song in the queue (SongNo)",
"format": "int64",
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "OK",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Mark a queued song as played",
"tags": [
"music"
]
}
},
"/api/v1/music/previous": {
"get": {
"description": "Moves to the previous song in the queue and returns it. Stays on the first song at the start.",
"operationId": "get-previous-song",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Previous song in the queue",
"tags": [
"music"
]
}
},
"/api/v1/music/rand": {
"get": {
"description": "Picks a random song from a random soundtrack. Add it to the queue with /music/addQue.",
"operationId": "get-random-song",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Random song",
"tags": [
"music"
]
}
},
"/api/v1/music/rand/classic": {
"get": {
"description": "Picks a random song where every song has the same chance, regardless of soundtrack.",
"operationId": "get-random-song-classic",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Random song, every song equal",
"tags": [
"music"
]
}
},
"/api/v1/music/rand/low": {
"get": {
"description": "Picks a random song, favouring soundtracks that have been played less than average.",
"operationId": "get-random-song-low-chance",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request",
"headers": {
"X-Queue-Id": {
"description": "ID of the client's play queue. Send it with the following requests.",
"schema": {
"format": "uuid",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Random song, favouring rarely played",
"tags": [
"music"
]
}
},
"/api/v1/music/reset": {
"get": {
"description": "Ends the queue, starts a new one and reloads the soundtrack list. The new queue's ID is returned in the X-Queue-Id header; send it with the following requests.",
"operationId": "reset-queue",
"parameters": [
{
"description": "ID of the client's play queue, from an earlier response. Omit it to start a new queue.",
"in": "header",
"name": "X-Queue-Id",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"headers": {
"X-Queue-Id": {
"schema": {
"description": "ID of the new queue",
"type": "string"
}
}
}
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Reset the queue",
"tags": [
"music"
]
}
},
"/api/v1/music/soundTest": {
"get": {
"description": "Returns a random song for checking the volume.",
"operationId": "get-sound-test-song",
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)"
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Sound check song",
"tags": [
"music"
]
}
},
"/api/v1/songs/{uuid}": {
"get": {
"description": "Returns information about a song.",
"operationId": "get-song",
"parameters": [
{
"description": "UUID of the soundtrack or song",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack or song",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Song"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Get song",
"tags": [
"library"
]
}
},
"/api/v1/songs/{uuid}/file": {
"get": {
"description": "Returns the audio file of a song.",
"operationId": "get-song-file",
"parameters": [
{
"description": "UUID of the soundtrack or song",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack or song",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The song (MP3)"
},
"206": {
"content": {
"audio/mpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Stream song",
"tags": [
"library"
]
}
},
"/api/v1/soundtracks": {
"get": {
"description": "Returns all soundtracks, sorted by name.",
"operationId": "list-soundtracks",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/Soundtrack"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "List soundtracks",
"tags": [
"library"
]
}
},
"/api/v1/soundtracks/{uuid}": {
"get": {
"description": "Returns a soundtrack with its songs, sorted by name.",
"operationId": "get-soundtrack",
"parameters": [
{
"description": "UUID of the soundtrack or song",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack or song",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SoundtrackWithSongList"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Get soundtrack",
"tags": [
"library"
]
}
},
"/api/v1/soundtracks/{uuid}/alternative-names": {
"put": {
"description": "Replaces the soundtrack's alternative names, which search and the cover search also use. Names are trimmed, and empty names, duplicates and the soundtrack's own name (ignoring case) are dropped.",
"operationId": "set-alternative-names",
"parameters": [
{
"description": "UUID of the soundtrack",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack",
"format": "uuid",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AlternativeNames"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Soundtrack"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Set alternative names",
"tags": [
"library"
]
}
},
"/api/v1/soundtracks/{uuid}/cover": {
"delete": {
"description": "Deletes the soundtrack's cover, including one set by hand, so the automatic search looks for a new one.",
"operationId": "delete-soundtrack-cover",
"parameters": [
{
"description": "UUID of the soundtrack or song",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack or song",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"204": {
"description": "No Content"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"503": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Service Unavailable"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Remove the cover",
"tags": [
"covers"
]
},
"get": {
"description": "Returns the soundtrack's cover image. cover_modified in the soundtrack responses tells when it last changed.",
"operationId": "get-soundtrack-cover",
"parameters": [
{
"description": "UUID of the soundtrack or song",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack or song",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"image/jpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/png": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/webp": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "The cover image"
},
"206": {
"content": {
"image/jpeg": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/png": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
},
"image/webp": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"description": "Part of the file, for a Range request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Soundtrack cover",
"tags": [
"covers"
]
},
"put": {
"description": "Stores the image as the soundtrack's cover. The automatic search never replaces it; delete it to go back to automatic.",
"operationId": "upload-soundtrack-cover",
"parameters": [
{
"description": "UUID of the soundtrack",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack",
"format": "uuid",
"type": "string"
}
}
],
"requestBody": {
"content": {
"image/*": {
"schema": {
"contentMediaType": "application/octet-stream",
"format": "binary",
"type": "string"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "No Content"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"503": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Service Unavailable"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Upload a cover",
"tags": [
"covers"
]
}
},
"/api/v1/soundtracks/{uuid}/cover/source": {
"put": {
"description": "Downloads the cover of the given SteamGridDB game or AniList anime and stores it as the soundtrack's cover. The automatic search never replaces it. SteamGridDB needs STEAMGRIDDB_API_KEY on the server.",
"operationId": "set-soundtrack-cover-source",
"parameters": [
{
"description": "UUID of the soundtrack",
"in": "path",
"name": "uuid",
"required": true,
"schema": {
"description": "UUID of the soundtrack",
"format": "uuid",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CoverSource"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "No Content"
},
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Request"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"404": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Not Found"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
},
"502": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Bad Gateway"
},
"503": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Service Unavailable"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Pick a cover",
"tags": [
"covers"
]
}
},
"/api/v1/statistics/songs/least-played": {
"get": {
"description": "Returns the least played songs with their soundtrack.",
"operationId": "get-least-played-songs",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SongInfoForStats"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Least played songs",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/songs/most-played": {
"get": {
"description": "Returns the most played songs with their soundtrack.",
"operationId": "get-most-played-songs",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SongInfoForStats"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Most played songs",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks": {
"get": {
"description": "Returns every soundtrack with its songs and play counts, sorted by name.",
"operationId": "get-all-soundtrack-statistics",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "All soundtracks with statistics",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks/last-played": {
"get": {
"description": "Returns the most recently played soundtracks with their songs.",
"operationId": "get-last-played-soundtracks",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Recently played soundtracks",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks/least-played": {
"get": {
"description": "Returns the least played soundtracks with their songs.",
"operationId": "get-least-played-soundtracks",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Least played soundtracks",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks/most-played": {
"get": {
"description": "Returns the most played soundtracks with their songs.",
"operationId": "get-most-played-soundtracks",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Most played soundtracks",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks/never-played": {
"get": {
"description": "Returns all soundtracks that have never been played, with their songs.",
"operationId": "get-never-played-soundtracks",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Never played soundtracks",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/soundtracks/oldest-played": {
"get": {
"description": "Returns the soundtracks played longest ago (played at least once) with their songs.",
"operationId": "get-oldest-played-soundtracks",
"parameters": [
{
"description": "Number of results. Values above 100 are capped to 100.",
"explode": false,
"in": "query",
"name": "limit",
"schema": {
"default": 10,
"description": "Number of results. Values above 100 are capped to 100.",
"format": "int64",
"minimum": 1,
"type": "integer"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/SoundtrackWithSongs"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Least recently played soundtracks",
"tags": [
"statistics"
]
}
},
"/api/v1/statistics/summary": {
"get": {
"description": "Returns overall play statistics.",
"operationId": "get-statistics-summary",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StatisticsSummary"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Statistics summary",
"tags": [
"statistics"
]
}
},
"/api/v1/sync": {
"post": {
"description": "Starts syncing the music folder in the background, skipping soundtracks that have not changed. Poll /sync/progress for the result.",
"operationId": "start-sync",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Sync changed soundtracks",
"tags": [
"sync"
]
}
},
"/api/v1/sync/full": {
"post": {
"description": "Starts a full sync in the background that re-reads every soundtrack and removes songs whose files are gone. Poll /sync/progress for the result.",
"operationId": "start-full-sync",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"423": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Locked"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Sync all soundtracks",
"tags": [
"sync"
]
}
},
"/api/v1/sync/progress": {
"get": {
"description": "While a sync is running, returns its progress. Otherwise returns the result of the last sync.",
"operationId": "get-sync-progress",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/ProgressResponse"
},
{
"$ref": "#/components/schemas/SyncResponse"
}
]
}
}
},
"description": "Progress of the running sync, or the result of the last sync"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Sync progress or result",
"tags": [
"sync"
]
}
},
"/api/v1/token": {
"delete": {
"description": "Deletes the token used for this request.",
"operationId": "delete-token",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StatusMessage"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Invalidate session token",
"tags": [
"auth"
]
},
"post": {
"description": "Returns a token for the other /api/v1 endpoints, valid for 24 hours. Requires the API password when the server has one. Limited to 10 requests per minute per client.",
"operationId": "create-token",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TokenRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TokenResponse"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unprocessable Entity"
},
"429": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Too Many Requests"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"summary": "Create session token",
"tags": [
"auth"
]
}
},
"/api/v1/token/cleanup": {
"post": {
"description": "Deletes all expired session tokens.",
"operationId": "cleanup-tokens",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StatusMessage"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Remove expired tokens",
"tags": [
"auth"
]
}
},
"/api/v1/version": {
"get": {
"description": "Returns the server version and its changelog.",
"operationId": "get-version",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VersionData"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Latest server version",
"tags": [
"server"
]
}
},
"/api/v1/version/history": {
"get": {
"description": "Returns all server versions with their changelogs, newest first.",
"operationId": "get-version-history",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/VersionData"
},
"type": "array"
}
}
},
"description": "OK"
},
"401": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Unauthorized"
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/APIError"
}
}
},
"description": "Internal Server Error"
}
},
"security": [
{
"bearer": []
}
],
"summary": "Version history",
"tags": [
"server"
]
}
}
}
}