openapi: 3.1.3 info: title: DAB Music Player API description: | A comprehensive music streaming and library management API that provides access to music search, album information, user authentication, playlist management, and administrative features. THIS SOFTWARE AND API ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE OR API. By using this API or building on it, you agree that any software or service that incorporates it must also be made available under an open-source license compatible with AGPLv3. ## Authentication Most endpoints require authentication via JWT tokens stored in HTTP-only cookies. ## Base URL All API endpoints are relative to: `https://dabmusic.xyz/api` version: 1.0.1 contact: name: DAB Music Player url: https://dabmusic.xyz license: name: GNU Affero General Public License v3.0 url: https://www.gnu.org/licenses/agpl-3.0.en.html servers: - url: https://dabmusic.xyz/api description: Production server security: - cookieAuth: [] - {} paths: # Authentication Endpoints /auth/login: post: tags: - Authentication summary: User login description: Authenticate user with email and password security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LoginRequest" responses: "200": description: Login successful content: application/json: schema: $ref: "#/components/schemas/LoginResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" /auth/register: post: tags: - Authentication summary: User registration description: Register a new user account security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RegisterRequest" responses: "201": description: User created successfully content: application/json: schema: $ref: "#/components/schemas/RegisterResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /auth/logout: post: tags: - Authentication summary: User logout description: Logout current user and clear session responses: "200": description: Logged out successfully content: application/json: schema: $ref: "#/components/schemas/LogoutResponse" "500": $ref: "#/components/responses/InternalServerError" /auth/me: get: tags: - Authentication summary: Get current user description: Get information about the currently authenticated user responses: "200": description: User information retrieved content: application/json: schema: $ref: "#/components/schemas/CurrentUserResponse" "500": $ref: "#/components/responses/InternalServerError" /auth/forgot-password: post: tags: - Authentication summary: Request password reset description: Send password reset email to user security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ForgotPasswordRequest" responses: "200": description: Password reset email sent content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /auth/reset-password: post: tags: - Authentication summary: Reset password description: Reset user password using reset token security: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ResetPasswordRequest" responses: "200": description: Password reset successful content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" # Music Endpoints /search: get: tags: - Music summary: Search for music description: Search for tracks, albums, or artists. Returns separate arrays for each content type. Depending on the 'type' parameter, some arrays may be empty. security: [] parameters: - name: q in: query required: true description: Search query schema: type: string example: "The Beatles" - name: type in: query description: Type of content to search for schema: type: string enum: [track, album, artist] default: track - name: limit in: query description: Number of results to return schema: type: integer minimum: 1 maximum: 50 default: 20 responses: "200": description: Search results content: application/json: schema: $ref: "#/components/schemas/SearchResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /album: get: tags: - Music summary: Get album information description: Retrieve detailed information about an album security: [] parameters: - name: albumId in: query required: true description: Album ID schema: type: string example: "12345" responses: "200": description: Album information content: application/json: schema: $ref: "#/components/schemas/AlbumResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /album/{id}: get: tags: - Music summary: Get album by ID description: Get album details from database parameters: - name: id in: path required: true description: Album ID schema: type: string responses: "200": description: Album found content: application/json: schema: $ref: "#/components/schemas/AlbumResponse" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /discography: get: tags: - Music summary: Get artist discography description: Retrieve all albums by an artist security: [] parameters: - name: artistId in: query required: true description: Artist ID schema: type: string example: "67890" responses: "200": description: Artist discography content: application/json: schema: $ref: "#/components/schemas/DiscographyResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /download: get: tags: - Music summary: Get album download information description: Retrieve album information for download security: [] parameters: - name: albumId in: query required: true description: Album ID schema: type: string - name: quality in: query description: Audio quality schema: type: string default: "27" example: "27" responses: "200": description: Album download information content: application/json: schema: $ref: "#/components/schemas/AlbumResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /stream: get: tags: - Music summary: Stream audio track description: Get streaming URL for a track security: [] parameters: - name: trackId in: query required: true description: Track ID schema: type: string - name: quality in: query description: Audio quality schema: type: string default: "27" responses: "200": description: Stream URL content: application/json: schema: $ref: "#/components/schemas/StreamResponse" "400": $ref: "#/components/responses/BadRequest" "500": $ref: "#/components/responses/InternalServerError" /lyrics: get: tags: - Music summary: Get song lyrics description: Retrieve lyrics for a song security: [] parameters: - name: artist in: query required: true description: Artist name schema: type: string example: "The Beatles" - name: title in: query required: true description: Song title schema: type: string example: "Hey Jude" responses: "200": description: Lyrics found content: application/json: schema: $ref: "#/components/schemas/LyricsResponse" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" # User Features /favorites: get: tags: - User Features summary: Get user favorites description: Retrieve user's favorite tracks responses: "200": description: User favorites content: application/json: schema: $ref: "#/components/schemas/FavoritesResponse" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" post: tags: - User Features summary: Add track to favorites description: Add a track to user's favorites requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddToFavoritesRequest" responses: "201": description: Added to favorites content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "200": description: Already in favorites content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" delete: tags: - User Features summary: Remove track from favorites description: Remove a track from user's favorites parameters: - name: trackId in: query required: true description: Track ID to remove schema: type: string responses: "200": description: Removed from favorites content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" /libraries: get: tags: - Libraries summary: Get user libraries description: Retrieve all libraries for the current user responses: "200": description: User libraries content: application/json: schema: $ref: "#/components/schemas/LibrariesResponse" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" post: tags: - Libraries summary: Create library description: Create a new library requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateLibraryRequest" responses: "201": description: Library created content: application/json: schema: $ref: "#/components/schemas/CreateLibraryResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" /libraries/{id}: get: tags: - Libraries summary: Get library description: Get a specific library with its tracks parameters: - name: id in: path required: true description: Library ID schema: type: string - name: page in: query description: Page number for pagination schema: type: integer minimum: 1 default: 1 - name: limit in: query description: Number of tracks per page schema: type: integer minimum: 1 maximum: 100 default: 20 responses: "200": description: Library found content: application/json: schema: $ref: "#/components/schemas/LibraryDetailsResponse" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" delete: tags: - Libraries summary: Delete library description: Delete a library parameters: - name: id in: path required: true description: Library ID schema: type: string responses: "200": description: Library deleted content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" patch: tags: - Libraries summary: Update library description: Update library information parameters: - name: id in: path required: true description: Library ID schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateLibraryRequest" responses: "200": description: Library updated content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /libraries/{id}/tracks: post: tags: - Libraries summary: Add track to library description: Add a track to a library parameters: - name: id in: path required: true description: Library ID schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddTrackToLibraryRequest" responses: "201": description: Track added to library content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "200": description: Track already exists in library content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /libraries/{id}/tracks/{trackId}: delete: tags: - Libraries summary: Remove track from library description: Remove a track from a library parameters: - name: id in: path required: true description: Library ID schema: type: string - name: trackId in: path required: true description: Track ID schema: type: string responses: "200": description: Track removed from library content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": $ref: "#/components/responses/InternalServerError" /queue: get: tags: - Queue summary: Get user queue description: Retrieve user's playback queue responses: "200": description: User queue content: application/json: schema: $ref: "#/components/schemas/QueueResponse" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" post: tags: - Queue summary: Save user queue description: Save user's playback queue requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SaveQueueRequest" responses: "200": description: Queue saved content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" delete: tags: - Queue summary: Clear user queue description: Clear user's playback queue responses: "200": description: Queue cleared content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalServerError" components: securitySchemes: cookieAuth: type: apiKey in: cookie name: session description: JWT token stored in HTTP-only cookie schemas: # Base Models User: type: object properties: id: type: integer example: 1 username: type: string example: johndoe email: type: string format: email example: john@example.com created_at: type: string format: date-time Track: type: object properties: id: oneOf: - type: string - type: integer example: "12345" title: type: string example: "Hey Jude" artist: type: string example: "The Beatles" artistId: type: integer example: 67890 albumTitle: type: string example: "The Beatles 1967-1970" albumCover: type: string format: uri example: "https://example.com/cover.jpg" albumId: type: string example: "54321" releaseDate: type: string example: "1968-08-26" genre: type: string example: "Rock" duration: type: integer description: Duration in seconds example: 431 audioQuality: $ref: "#/components/schemas/AudioQuality" Album: type: object properties: id: type: string example: "54321" title: type: string example: "Abbey Road" artist: type: string example: "The Beatles" releaseDate: type: string example: "1969-09-26" genre: type: string example: "Rock" cover: type: string format: uri example: "https://example.com/cover.jpg" tracks: type: array items: $ref: "#/components/schemas/Track" trackCount: type: integer example: 17 duration: type: integer description: Total duration in seconds example: 2873 audioQuality: $ref: "#/components/schemas/AudioQuality" label: type: string example: "Apple Records" upc: type: string example: "094638241621" url: type: string format: uri streamable: type: boolean downloadable: type: boolean mediaCount: type: integer example: 1 maximumChannelCount: type: integer example: 2 parental_warning: type: boolean popularity: type: integer example: 85 Artist: type: object properties: id: type: string example: "67890" name: type: string example: "The Beatles" albumsCount: type: integer example: 13 albumsAsPrimaryArtistCount: type: integer example: 13 albumsAsPrimaryComposerCount: type: integer example: 0 slug: type: string example: "the-beatles" image: type: string format: uri example: "https://example.com/artist.jpg" biography: type: string similarArtistIds: type: array items: type: string information: type: string Library: type: object properties: id: type: string example: "lib-123" name: type: string example: "My Favorites" description: type: string example: "My favorite songs collection" isPublic: type: boolean example: false trackCount: type: integer example: 25 createdAt: type: string format: date-time AudioQuality: type: object properties: maximumBitDepth: type: integer example: 16 maximumSamplingRate: type: number example: 44.1 isHiRes: type: boolean example: false Pagination: type: object properties: page: type: integer example: 1 limit: type: integer example: 20 total: type: integer example: 100 hasMore: type: boolean example: true loaded: type: integer example: 20 ResponseError: type: object properties: error: type: string example: "Error message" message: type: string example: "Detailed error message" # Search Result with discriminator SearchResultItem: discriminator: propertyName: type mapping: track: "#/components/schemas/Track" album: "#/components/schemas/Album" artist: "#/components/schemas/Artist" oneOf: - allOf: - $ref: "#/components/schemas/Track" - type: object properties: type: type: string enum: [track] - allOf: - $ref: "#/components/schemas/Album" - type: object properties: type: type: string enum: [album] - allOf: - $ref: "#/components/schemas/Artist" - type: object properties: type: type: string enum: [artist] # Generic Message Response MessageResponse: type: object properties: message: type: string example: "Operation successful" # Auth Request/Response Models LoginRequest: type: object required: - email - password properties: email: type: string format: email example: user@example.com password: type: string format: password example: password123 LoginResponse: type: object properties: message: type: string example: Login successful user: $ref: "#/components/schemas/User" RegisterRequest: type: object required: - username - email - password properties: username: type: string example: johndoe email: type: string format: email example: john@example.com password: type: string format: password example: password123 inviteCode: type: string description: Required if invite system is enabled example: INVITE123 RegisterResponse: type: object properties: message: type: string example: User created successfully LogoutResponse: type: object properties: message: type: string example: Logged out successfully CurrentUserResponse: type: object properties: user: allOf: - $ref: "#/components/schemas/User" nullable: true ForgotPasswordRequest: type: object required: - email properties: email: type: string format: email example: user@example.com ResetPasswordRequest: type: object required: - token - password properties: token: type: string example: reset-token-123 password: type: string format: password example: newpassword123 # Music Response Models SearchResponse: type: object properties: albums: type: array items: $ref: "#/components/schemas/Album" description: Array of albums found nullable: true tracks: type: array items: $ref: "#/components/schemas/Track" description: Array of tracks found nullable: true artists: type: array items: $ref: "#/components/schemas/Artist" description: Array of artists found nullable: true pagination: $ref: "#/components/schemas/Pagination" query: type: string description: Original search query example: "The Beatles" searchType: type: string enum: [track, album, artist, all] description: Type of search performed AlbumResponse: type: object properties: album: $ref: "#/components/schemas/Album" DiscographyResponse: type: object properties: artist: $ref: "#/components/schemas/Artist" albums: type: array items: $ref: "#/components/schemas/Album" StreamResponse: type: object properties: streamUrl: type: string format: uri LyricsResponse: type: object properties: lyrics: type: string example: "Hey Jude, don't make it bad..." unsynced: type: boolean description: Whether lyrics are time-synced # User Features Models FavoritesResponse: type: object properties: favorites: type: array items: $ref: "#/components/schemas/Track" AddToFavoritesRequest: type: object required: - track properties: track: $ref: "#/components/schemas/Track" # Libraries Models LibrariesResponse: type: object properties: libraries: type: array items: $ref: "#/components/schemas/Library" CreateLibraryRequest: type: object required: - name properties: name: type: string example: "My Playlist" description: type: string example: "My favorite songs" isPublic: type: boolean default: false CreateLibraryResponse: type: object properties: message: type: string library: $ref: "#/components/schemas/Library" LibraryDetailsResponse: type: object properties: library: allOf: - $ref: "#/components/schemas/Library" - type: object properties: tracks: type: array items: $ref: "#/components/schemas/Track" pagination: $ref: "#/components/schemas/Pagination" UpdateLibraryRequest: type: object properties: name: type: string description: type: string isPublic: type: boolean AddTrackToLibraryRequest: type: object required: - track properties: track: $ref: "#/components/schemas/Track" # Queue Models QueueResponse: type: object properties: queue: type: array items: $ref: "#/components/schemas/Track" SaveQueueRequest: type: object required: - queue properties: queue: type: array items: $ref: "#/components/schemas/Track" responses: BadRequest: description: Bad request content: application/json: schema: $ref: "#/components/schemas/ResponseError" Unauthorized: description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ResponseError" NotFound: description: Resource not found content: application/json: schema: $ref: "#/components/schemas/ResponseError" InternalServerError: description: Internal server error content: application/json: schema: $ref: "#/components/schemas/ResponseError" tags: - name: Authentication description: User authentication and session management - name: Music description: Music search, streaming, and metadata - name: User Features description: User-specific features like favorites and preferences - name: Libraries description: User library and playlist management - name: Queue description: Playback queue management