{ "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": { "description": "How long the sync has been running, as minutes and seconds, e.g. \"02:15\"", "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": { "description": "How long the sync took, as minutes and seconds, e.g. \"02:15\"", "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 ", "type": "string" } }, "required": [ "token", "expires_at", "client_type" ], "type": "object" }, "Upload": { "additionalProperties": false, "properties": { "files": { "description": "The songs received so far, sorted by name", "items": { "$ref": "#/components/schemas/UploadFile" }, "type": "array" }, "id": { "type": "string" }, "name": { "description": "Name of the new soundtrack, also its folder name", "type": "string" }, "started": { "format": "date-time", "type": "string" }, "total_size": { "description": "Size of all songs received so far, in bytes", "format": "int64", "type": "integer" } }, "required": [ "id", "name", "started", "files", "total_size" ], "type": "object" }, "UploadFile": { "additionalProperties": false, "properties": { "name": { "type": "string" }, "size": { "format": "int64", "type": "integer" } }, "required": [ "name", "size" ], "type": "object" }, "UploadRequest": { "additionalProperties": false, "properties": { "name": { "description": "Name of the new soundtrack, also its folder name in the music folder", "maxLength": 200, "minLength": 1, "type": "string" } }, "required": [ "name" ], "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 `.\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/linux-package": { "get": { "description": "Redirects to the download URL of the latest MusicPlayer release for Linux (package with installer).", "operationId": "download-client-linux-package", "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 (package with installer)", "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/uploads": { "post": { "description": "Starts adding a new soundtrack. Send its songs with PUT /soundtracks/uploads/{id}/files/{file}, then POST /soundtracks/uploads/{id}/finish. The name must be usable as a folder name, and no soundtrack, folder or other upload may have it, ignoring case. Unfinished uploads are removed after a day.", "operationId": "start-upload", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Upload" } } }, "description": "Created" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Bad Request" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Unauthorized" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Conflict" }, "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" }, "503": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Service Unavailable" } }, "security": [ { "bearer": [] } ], "summary": "Start uploading a soundtrack", "tags": [ "uploads" ] } }, "/api/v1/soundtracks/uploads/{id}": { "delete": { "description": "Deletes an unfinished upload and its songs.", "operationId": "cancel-upload", "parameters": [ { "description": "ID of the upload, from POST /soundtracks/uploads", "in": "path", "name": "id", "required": true, "schema": { "description": "ID of the upload, from POST /soundtracks/uploads", "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" }, "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": "Cancel an upload", "tags": [ "uploads" ] }, "get": { "description": "Returns an unfinished upload with the songs received so far, for example to resume it.", "operationId": "get-upload", "parameters": [ { "description": "ID of the upload, from POST /soundtracks/uploads", "in": "path", "name": "id", "required": true, "schema": { "description": "ID of the upload, from POST /soundtracks/uploads", "format": "uuid", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Upload" } } }, "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" }, "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": "Get an upload", "tags": [ "uploads" ] } }, "/api/v1/soundtracks/uploads/{id}/files/{file}": { "put": { "description": "Stores one song of the upload, replacing a song of the same name, so a failed song can be sent again. Only MP3 files are accepted. The size limits are set on the server with UPLOAD_MAX_FILE_MB and UPLOAD_MAX_TOTAL_MB.", "operationId": "upload-song", "parameters": [ { "description": "ID of the upload, from POST /soundtracks/uploads", "in": "path", "name": "id", "required": true, "schema": { "description": "ID of the upload, from POST /soundtracks/uploads", "format": "uuid", "type": "string" } }, { "description": "File name of the song, e.g. \"01 Title.mp3\". Plain names only: put songs from disc folders in one folder, e.g. \"1-01 Title.mp3\".", "in": "path", "name": "file", "required": true, "schema": { "description": "File name of the song, e.g. \"01 Title.mp3\". Plain names only: put songs from disc folders in one folder, e.g. \"1-01 Title.mp3\".", "type": "string" } } ], "requestBody": { "content": { "audio/mpeg": { "schema": { "contentMediaType": "application/octet-stream", "format": "binary", "type": "string" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadFile" } } }, "description": "OK" }, "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" }, "413": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Request Entity Too Large" }, "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": "Upload a song", "tags": [ "uploads" ] } }, "/api/v1/soundtracks/uploads/{id}/finish": { "post": { "description": "Moves the songs into a new folder in the music folder, adds the soundtrack to the library and returns it. Refused when a soundtrack with the same songs exists.", "operationId": "finish-upload", "parameters": [ { "description": "ID of the upload, from POST /soundtracks/uploads", "in": "path", "name": "id", "required": true, "schema": { "description": "ID of the upload, from POST /soundtracks/uploads", "format": "uuid", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SoundtrackWithSongList" } } }, "description": "OK" }, "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" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/APIError" } } }, "description": "Conflict" }, "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": "Finish an upload", "tags": [ "uploads" ] } }, "/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" ] } } } }