openapi: 3.0.0
info:
  title: Koel API
  version: 5.1.0
  description: 'The API for [Koel](https://koel.dev), the music streaming application that works.'
  contact:
    name: An Phan
    url: 'https://phanan.net'
    email: me@phanan.net
  license:
    name: MIT
    url: 'https://github.com/koel/koel/blob/master/LICENSE.md'
servers:
  - url: 'https://koel.test'
    description: Local
tags:
  - name: interaction
  - name: download
paths:
  /api/user:
    post:
      summary: Create a user
      tags:
        - user
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      operationId: post-user
      security:
        - Bearer Token: [ ]
      description: Create a new user
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
                is_admin:
                  type: boolean
              required:
                - name
                - email
                - password
                - is_admin
    parameters: [ ]
  '/api/user/{userId}':
    parameters:
      - schema:
          type: integer
        name: userId
        in: path
        required: true
        description: ID of the user
    patch:
      summary: Update a user
      tags:
        - user
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      operationId: patch-user-userId
      description: Update a user
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
                  description: 'If provided, will update the user''s password'
                is_admin:
                  type: boolean
              required:
                - name
                - email
                - is_admin
    delete:
      summary: Delete a user
      tags:
        - user
      responses:
        '204':
          description: No Content
      operationId: delete-user-userId
      description: Delete a user
      security:
        - Bearer Token: [ ]
  /api/me:
    get:
      summary: Get profile
      tags:
        - authentication
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
      operationId: get-me
      security:
        - Bearer Token: [ ]
      description: Get the current user's profile
    post:
      summary: Log in
      tags:
        - authentication
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                required:
                  - token
      operationId: post-me
      description: 'Log a user in. Upon a successful login, an API token will be returned. This token should be stored for further authenticated request (either as a Bearer token or as an `api-token` parameter).'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
              required:
                - email
                - password
    put:
      summary: Update profile
      tags:
        - authentication
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                    description: New API token if the password is changed.
      operationId: put-me
      description: Update the current user's profile
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                password:
                  type: string
                  format: password
                  description: 'If provided, will update the current user''s password'
              required:
                - name
                - email
    delete:
      summary: Log out
      tags:
        - authentication
      responses:
        '204':
          description: No Content
      operationId: delete-me
      description: Log the current user out
      security:
        - Bearer Token: [ ]
    parameters: [ ]
  /api/data:
    get:
      summary: Get application data
      tags:
        - data
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  albums:
                    type: array
                    items:
                      $ref: '#/components/schemas/Album'
                  allowDownload:
                    type: boolean
                    description: Whether the current installation of Koel allows downloading
                  artists:
                    type: array
                    items:
                      $ref: '#/components/schemas/Artist'
                  cdnUrl:
                    type: string
                    format: uri
                    description: 'The CDN URL of the application, if configured'
                  currentUser:
                    $ref: '#/components/schemas/User'
                  currentVersion:
                    type: string
                    description: Version of the current installation of Koel
                  latestVersion:
                    type: string
                    description: The latest version of Koel
                  playlists:
                    type: array
                    items:
                      $ref: '#/components/schemas/Playlist'
                  recentlyPlayed:
                    type: array
                    description: An array containing the IDs of the most recently-played songs
                    items:
                      type: string
                  settings:
                    type: object
                    description: Settings for the current Koel installation. Only available if the current authenticated user is an admin.
                    properties:
                      media_path:
                        type: string
                    required:
                      - media_path
                  songs:
                    type: array
                    items:
                      $ref: '#/components/schemas/Song'
                  supportsTranscoding:
                    type: boolean
                    description: Whether the current installation of Koel supports transcoding media
                  useLastfm:
                    type: boolean
                  useYouTube:
                    type: boolean
                  useiTunes:
                    type: boolean
                  users:
                    description: Only available if the current authenticated user is an admin
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  interactions:
                    type: array
                    items:
                      $ref: '#/components/schemas/InteractionExcerpt'
                required:
                  - albums
                  - allowDownload
                  - artists
                  - cdnUrl
                  - currentUser
                  - currentVersion
                  - latestVersion
                  - playlists
                  - recentlyPlayed
                  - songs
                  - supportsTranscoding
                  - useLastfm
                  - useYouTube
                  - useiTunes
                  - interactions
      operationId: get-data
      description: 'Retrieve a set of application data catered for the current authenticated user (songs, albums, artists, playlists, interactions, and if the user is an admin, settings as well). This call should typically be made right after the user is logged in, to populate the application''s interface with relevant information.'
      security:
        - Bearer Token: [ ]
    parameters: [ ]
  /api/interaction/play:
    post:
      summary: Increase play count
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Interaction'
      operationId: post-interaction-play
      description: 'Increase a song''s play count as the currently authenticated user. This request should be made whenever a song is played. '
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                song:
                  type: string
                  description: ID of the song
              required:
                - song
      tags:
        - interaction
    parameters: [ ]
  /api/interaction/like:
    post:
      summary: Toggle like/unlike a song
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Interaction'
      operationId: post-interaction-like
      description: Toggle like ("favorite") or unlike ("unfavorite") a song. The "liked" status of the song will be reversed by this operation.
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                song:
                  type: string
                  description: ID of the song
              required:
                - song
      tags:
        - interaction
  /api/interaction/batch/like:
    post:
      summary: Like multiple songs
      tags:
        - interaction
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Interaction'
      operationId: post-interaction-batch-like
      description: 'Like several songs at once, useful for "batch" (e.g., drag-and-drop) actions'
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                songs:
                  type: array
                  description: An array of song IDs
                  items:
                    type: string
              required:
                - songs
    parameters: [ ]
  /api/interaction/batch/unlike:
    post:
      summary: Unlike multiple songs
      tags:
        - interaction
      responses:
        '204':
          description: OK
      operationId: post-interaction-batch-unlike
      description: 'Unlike several songs at once, useful for "batch" (e.g., drag-and-drop) actions'
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                songs:
                  type: array
                  description: An array of song IDs
                  items:
                    type: string
              required:
                - songs
  '/api/interaction/recently-played/{count}':
    parameters:
      - schema:
          type: integer
        name: count
        in: path
        description: The maximum number of songs to be returned (optional)
    get:
      summary: Get recently played songs
      tags:
        - interaction
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                description: An array of song IDs
                items:
                  type: string
      operationId: get-interaction-recently-played-count
      description: Get a list of songs recently played by the current authenticated user
      security:
        - Bearer Token: [ ]
  /api/playlist:
    get:
      summary: Get current user's playlists
      tags:
        - playlist
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Playlist'
      operationId: get-playlist
      description: Get all playlists owned by the current authenticated user
      security:
        - Bearer Token: [ ]
    post:
      summary: Create another playlist
      tags:
        - playlist
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Playlist'
      operationId: post-playlist
      description: Create a new playlist that's owned by the current authenticated user
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                rules:
                  type: array
                  items:
                    $ref: '#/components/schemas/SmartPlaylistRule'
                songs:
                  type: array
                  description: An array of song IDs to populate the playlist. Only used if the playlist is not a smart one (i.e. `rules` are empty).
                  items:
                    type: string
                    format: md5
              required:
                - name
  '/api/playlist/{playlistId}/songs':
    parameters:
      - schema:
          type: integer
        name: playlistId
        in: path
        required: true
        description: ID of the playlist
    patch:
      summary: Update a playlist
      tags:
        - playlist
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Playlist'
      operationId: patch-playlist-playlistId
      description: 'Update a playlist (name and, if a smart playlist, its rules)'
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                rules:
                  type: array
                  items:
                    $ref: '#/components/schemas/Playlist'
    delete:
      summary: ''
      operationId: delete-playlist-playlistId
      responses:
        '200':
          description: OK
      description: Delete a playlist
      security:
        - Bearer Token: [ ]
    get:
      summary: Get playlist's songs
      operationId: get-playlist-playlistId
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                description: An array of song IDs
                items:
                  type: string
      description: Get a playlist's songs
      security:
        - Bearer Token: [ ]
  '/api/playlist/{playlistId}/sync':
    parameters:
      - schema:
          type: integer
        name: playlistId
        in: path
        required: true
        description: ID of the playlist
    put:
      summary: ''
      operationId: put-playlist-playlistId-sync
      responses:
        '200':
          description: OK
      description: 'Populate playlist''s content. Instead of adding or removing songs individually, a playlist''s content is replaced entirely with an array of song IDs.'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                songs:
                  type: array
                  description: An array of song IDs
                  items:
                    type: string
              required:
                - songs
  /api/songs:
    put:
      summary: Update song(s) information
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  artists:
                    type: array
                    items:
                      $ref: '#/components/schemas/Artist'
                  albums:
                    type: array
                    items:
                      $ref: '#/components/schemas/Album'
                  songs:
                    type: array
                    items:
                      $ref: '#/components/schemas/Song'
                required:
                  - artists
                  - albums
                  - songs
      operationId: put-songs
      description: Update the information of a song or multiple songs
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                songs:
                  type: array
                  items:
                    type: string
                data:
                  type: object
                  properties:
                    title:
                      type: string
                    artistName:
                      type: string
                    albumName:
                      type: string
                    lyrics:
                      type: string
              required:
                - songs
                - data
  '/api/album/{albumId}/info':
    parameters:
      - schema:
          type: integer
        name: albumId
        in: path
        required: true
        description: ID of the album
    get:
      summary: Get album's extra information
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlbumExtraInformation'
      operationId: get-album-albumId-info
      description: 'Get extra information (image, description etc.) about an album. Currently this information is only available if Last.fm integration is enabled. If it''s not the case, `null` will be returned.'
      security:
        - Bearer Token: [ ]
  '/api/artist/{artistId}/info':
    parameters:
      - schema:
          type: integer
        name: artistId
        in: path
        required: true
        description: ID of the artist
    get:
      summary: Get artist's extra information
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArtistExtraInformation'
      operationId: get-artist-artistId-info
      description: 'Get extra information (image, biography etc.) about an artist. Currently this information is only available if Last.fm integration is enabled. If it''s not the case, `null` will be returned.'
      security:
        - Bearer Token: [ ]
  '/api/song/{songId}/info':
    parameters:
      - schema:
          type: string
        name: songId
        in: path
        required: true
        description: ID of the song
    get:
      summary: Get song's extra information
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  lyrics:
                    type: string
                  album_info:
                    $ref: '#/components/schemas/AlbumExtraInformation'
                  artist_info:
                    $ref: '#/components/schemas/ArtistExtraInformation'
                  youtube:
                    $ref: '#/components/schemas/YouTubeSearchResult'
                required:
                  - lyrics
                  - album_info
      operationId: get-song-songId-info
      description: 'Get a song''s extra information. The response of this request is a superset of both corresponding `album/{albumId}/info` and `artist/{artistId}/info` responses, combined with the song''s lyrics and related YouTube videos, if applicable. '
      security:
        - Bearer Token: [ ]
  '/api/album/{albumId}/cover':
    parameters:
      - schema:
          type: integer
        name: albumId
        in: path
        required: true
        description: ID of the album
    put:
      summary: Upload album's cover
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  coverUrl:
                    type: string
                    format: uri
                required:
                  - coverUrl
      operationId: put-album-albumId-cover
      description: Upload an image as an album's cover
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                cover:
                  description: 'The cover image''s content, in [Data URI format](https://en.wikipedia.org/wiki/Data_URI_scheme)'
                  type: string
              required:
                - cover
  '/api/artist/{artistId}/image':
    parameters:
      - schema:
          type: integer
        name: artistId
        in: path
        required: true
        description: ID of the artist
    put:
      summary: Upload artist's image
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  imageUrl:
                    type: string
                    format: uri
                required:
                  - imageUrl
      operationId: put-artist-artistId-image
      description: Upload an artist's image
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                image:
                  type: string
                  description: 'The image''s content, in [Data URI format](https://en.wikipedia.org/wiki/Data_URI_scheme)'
              required:
                - image
  '/api/album/{album}/thumbnail':
    parameters:
      - schema:
          type: integer
        name: album
        in: path
        required: true
        description: ID of the album
    get:
      summary: Get album's thumbnail
      tags:
        - media information
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type:
                  - object
                  - 'null'
                properties:
                  thumbnailUrl:
                    type: string
                    format: uri
                required:
                  - thumbnailUrl
      operationId: get-album-album-thumbnail
      description: Get an album's thumbnail (a 48px-wide blurry version of the album's cover). Returns the full URL to the thumbnail or NULL if the album has no cover.
      security:
        - Bearer Token: [ ]
  /api/settings:
    put:
      summary: Save the application settings
      tags:
        - settings
      responses:
        '204':
          description: No Content
      operationId: post-settings
      description: Save the application settings. Right now there's only one setting to be saved (`media_path`). The current authenticated user must be an admin.
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                media_path:
                  type: string
                  description: Absolute path to the media folder
              required:
                - media_path
  /api/os/s3/song:
    post:
      summary: Save a song from S3
      tags:
        - S3 integration
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Song'
      operationId: post-os-s3-song
      description: Create a new song or update an existing one with data sent from AWS
      security: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                bucket:
                  type: string
                key:
                  type: string
                tags:
                  type: object
                  required:
                    - duration
                    - artist
                    - album
                    - title
                  properties:
                    duration:
                      type: number
                    artist:
                      type: string
                    albumartist:
                      type: string
                    album:
                      type: string
                    cover:
                      type: object
                      properties:
                        data:
                          type: string
                          description: The base64-encoded binary content of the album cover
                        extension:
                          type: string
                      required:
                        - data
                        - extension
                    title:
                      type: string
                    track:
                      type: number
                    lyrics:
                      type: string
              required:
                - bucket
                - key
                - tags
    delete:
      summary: Remove a song from S3
      operationId: delete-os-s3-song
      responses:
        '204':
          description: No Content
      description: Remove a song whose information matches the data sent from AWS S3 (`bucket` and `key`)
      security: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                bucket:
                  type: string
                key:
                  type: string
              required:
                - bucket
                - key
  /api/upload:
    post:
      summary: Upload a song
      tags: [ ]
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SongWithAlbumAndArtist'
      operationId: post-upload
      description: Upload a song. The current authenticated user must be an admin.
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
              required:
                - file
  '/api/{songId}/scrobble':
    parameters:
      - schema:
          type: string
        name: songId
        in: path
        required: true
        description: ID of the song
    post:
      summary: Scrobble a song
      tags:
        - last.fm
      responses:
        '204':
          description: No Content
      operationId: post-api-songId-scrobble
      description: 'Create a [Last.fm scrobble entry](https://www.last.fm/api/scrobbling) for a song. Only functional if Last.fm integration has been configured and the current authenticated user has connected to Last.fm.'
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                timestamp:
                  type: integer
  /api/lastfm/session-key:
    post:
      summary: Set Last.fm session key
      tags:
        - last.fm
      responses:
        '204':
          description: No Content
      operationId: post-api-lastfm-session-key
      description: 'Set the Last.fm session key for the current authenticated user. This call should be made after the user is [connected to Last.fm](https://www.last.fm/api/authentication).'
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                key:
                  type: string
                  description: 'The Last.fm [session key](https://www.last.fm/api/show/auth.getSession)'
              required:
                - key
  /lastfm/connect:
    get:
      summary: Connect to Last.fm
      tags:
        - last.fm
      responses: { }
      operationId: get-lastfm-connect
      description: '[Connect](https://www.last.fm/api/authentication) the current user to Last.fm. This is actually NOT an API request. The application should instead redirect the current user to this route, which will send them to Last.fm for authentication. After authentication is successful, the user will be redirected back to `/lastfm/callback?token=<Last.fm token>`.'
      security:
        - api-token: [ ]
  '/play/{songId}/{transcode}/{bitrate}':
    parameters:
      - schema:
          type: string
        name: songId
        in: path
        required: true
        description: ID of the song
      - schema:
          type: boolean
        name: transcode
        in: path
        description: Whether to transcode the song (optional)
      - schema:
          type: number
        name: bitrate
        in: path
        description: Bit rate to transcode to (optional)
    get:
      summary: Play a song
      tags:
        - playback
      responses: { }
      operationId: get-play-songId-transcode-bitrate
      description: 'The GET request to play/stream a song. This is NOT an XmlHttpRequest By default Koel will serve the file as-is, unless it''s a FLAC file. If the value of `transcode` is truthy, Koel will attempt to transcode the file into `bitRate` kbps using ffmpeg.'
      security:
        - api-token: [ ]
  /download/songs:
    get:
      summary: Download songs
      tags:
        - download
      responses: { }
      operationId: get-download-songs
      description: Download a song or several songs. This is NOT an XmlHttpRequest. The response will be a download response of either the media file or a zip file containing multiple media files.
      security:
        - api-token: [ ]
      parameters:
        - schema:
            type: array
          in: query
          name: songs
          description: Array of IDs of songs to download
  '/download/album/{albumId}':
    parameters:
      - schema:
          type: integer
        name: albumId
        in: path
        required: true
        description: ID of the album
    get:
      summary: Download album
      tags:
        - download
      responses: { }
      operationId: get-download-album-albumId
      description: Download a whole album. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containing multiple media files.
      security:
        - api-token: [ ]
  '/download/artist/{artistId}':
    parameters:
      - schema:
          type: integer
        name: artistId
        in: path
        required: true
        description: ID of the artist
    get:
      summary: Download artist
      tags:
        - download
      responses: { }
      operationId: get-download-artist-artistId
      description: Download a whole artist's biography. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containing multiple media files.
      security:
        - api-token: [ ]
  '/download/playlist/{playlistId}':
    parameters:
      - schema:
          type: integer
        name: playlistId
        in: path
        required: true
        description: ID of the playlist
    get:
      summary: Download playlist
      tags:
        - download
      responses: { }
      operationId: get-download-playlist-playlistId
      description: Download a whole playlist. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containing multiple media files.
      security:
        - api-token: [ ]
  /api/search:
    get:
      summary: 'Search for songs, albums, and artists'
      tags:
        - search
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: object
                    required:
                      - songs
                      - artists
                      - albums
                    properties:
                      songs:
                        type: array
                        description: An array of max 6 best-matching songs' IDs
                        items:
                          type: string
                      artists:
                        type: array
                        description: An array of max 6 best-matching artists' IDs
                        items:
                          type: integer
                      albums:
                        type: array
                        description: An array of max 6 best-matching albums' IDs
                        items:
                          type: number
                required:
                  - results
      operationId: get-api-search
      description: 'Search for songs, albums, and artists, with a maximum of {count} results each.'
      security:
        - Bearer Token: [ ]
      parameters:
        - schema:
            type: string
          in: query
          name: q
          description: The keywords to search
          required: true
        - schema:
            type: integer
            minimum: 1
            default: 6
          in: query
          name: count
          description: 'The maximum number of results for songs, artists, and albums'
    parameters: [ ]
  /api/search/songs:
    get:
      summary: Search for songs
      tags:
        - search
      responses: { }
      operationId: get-api-search-songs
      description: Get all songs that matches a search query.
      security:
        - Bearer Token: [ ]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                songs:
                  type: array
                  description: An array of matching songs' IDs
                  items: { }
              required:
                - songs
components:
  schemas:
    User:
      title: User
      type: object
      description: A User model
      x-examples:
        Sample User:
          id: 1
          name: Phan An
          email: me@phanan.net
          password: ''
          is_admin: true
          preferences:
            last_fm_session_key: 12OcZD8_lsuGEFvxxY0k4lJihOYBZGWa
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
        is_admin:
          type: boolean
        preferences:
          type: object
          properties:
            last_fm_session_key:
              type: string
      required:
        - id
        - name
        - email
        - is_admin
        - preferences
    Song:
      title: Song
      type: object
      description: A Song model
      x-examples:
        Sample Song:
          id: f88c7671623c6b8be881e2a04e685509
          artist_id: 3
          album_id: 3
          title: When the Lights Are Down
          disc: 1
          track: 2
          length: 221
      properties:
        id:
          type: string
          description: An md5 string
        artist_id:
          type: integer
        album_id:
          type: integer
        title:
          type: string
        disc:
          type: integer
        track:
          type: number
        length:
          type: number
          format: float
          description: The duration of the song in seconds
      required:
        - id
        - artist_id
        - album_id
        - title
        - disc
        - track
        - length
    Artist:
      title: Artist
      type: object
      description: An Artist model
      properties:
        id:
          type: integer
        name:
          type: string
      required:
        - id
        - name
      x-examples:
        Unknown Artist:
          id: 1
          name: Unknown Artist
        Various Artists:
          id: 2
          name: Various Artists
        Sample Artist:
          id: 3
          name: Kamelot
    Album:
      title: Album
      type: object
      description: An Album entity
      properties:
        id:
          type: integer
        artist_id:
          type: integer
        name:
          type: string
      required:
        - id
        - artist_id
        - name
      x-examples:
        Unknown Album:
          id: 1
          artist_id: 1
          name: Unknown Album
        Sample Album:
          id: 2
          artist_id: 3
          name: The Black Halo
    InteractionExcerpt:
      title: Interaction
      type: object
      description: 'An excerpt of the Interaction model, containing only the minimal data'
      properties:
        song_id:
          type: string
        liked:
          type: boolean
        play_count:
          type: integer
      required:
        - song_id
        - liked
        - play_count
    Playlist:
      title: Playlist
      type: object
      description: A Playlist model
      properties:
        id:
          type: integer
        name:
          type: string
        rules:
          type:
            - array
            - 'null'
          description: An array of Rule objects if the playlist is a Smart playlist
          items:
            $ref: '#/components/schemas/Playlist'
        is_smart:
          type: boolean
          description: Whether the playlist is of Smart (dynamic) type
      required:
        - id
        - name
        - rules
        - is_smart
    SmartPlaylistRule:
      title: SmartPlaylistRule
      type: object
      description: A SmartPlaylistRule model
      properties:
        id:
          type: integer
        rules:
          type: array
          description: An array of "subrules" (constraints) of the current rule
          items:
            type: object
            properties:
              id:
                type: integer
              model:
                type: string
                enum:
                  - title
                  - album.name
                  - artist.name
                  - interactions.play_count
                  - interactions.last_played_at
                  - length
                  - created_at
                  - updated_at
              operator:
                type: string
                enum:
                  - is
                  - isNot
                  - contains
                  - notContain
                  - isBetween
                  - isGreaterThan
                  - isLessThan
                  - beginsWith
                  - endsWith
                  - notInLast
              value:
                type: array
                items:
                  type: string
            required:
              - id
              - model
              - operator
              - value
      required:
        - id
        - rules
    Interaction:
      title: Interaction
      type: object
      description: An Interaction model
      properties:
        song_id:
          type: string
        liked:
          type: boolean
        play_count:
          type: integer
        song:
          $ref: '#/components/schemas/Song'
        user:
          $ref: '#/components/schemas/User'
      required:
        - song_id
        - liked
        - play_count
        - song
        - user
    AlbumExtraInformation:
      title: AlbumExtraInformation
      type: object
      description: 'Extra information about an album, currently provided by Last.fm'
      properties:
        url:
          type: string
          format: uri
          description: URL to the album's page on Last.fm
        image:
          type: string
          format: uri
          description: URL to the album's image on Last.fm
        wiki:
          type: object
          required:
            - summary
            - full
          properties:
            summary:
              type: string
            full:
              type: string
        tracks:
          type: array
          items:
            type: object
            properties:
              title:
                type: string
              length:
                type: integer
              url:
                type: string
                format: uri
            required:
              - title
              - length
              - url
        cover:
          type: string
          description: URL to the album cover by Koel
      required:
        - url
        - image
        - wiki
        - tracks
        - cover
      x-examples:
        Sample:
          url: 'https://www.last.fm/music/Queen/Innuendo'
          image: 'https://lastfm-img2.akamaized.net/i/u/300x300/b56adcd16ca6454498981a8470a3ec06.png'
          wiki:
            summary: Innuendo is a 1991 album by English rock band Queen...
            full: Innuendo is a 1991 album by English rock band Queen. It is the band's fourteenth studio album and the last to be composed entirely of new material. It is also their final studio album to be released while lead singer Freddie Mercury was still alive.
          tracks:
            - title: Innuendo
              length: 392
              url: 'https://www.last.fm/music/Queen/_/Innuendo'
            - title: I'm Going Slightly Mad
              length: 247
              url: 'https://www.last.fm/music/Queen/_/I%27m+Going+Slightly+Mad'
          cover: 'https://koel.yourdomain.net/img/covers/5a771ec82a5d72.25096250.png'
    ArtistExtraInformation:
      title: ArtistExtraInformation
      type: object
      description: 'Extra information about an artist, currently provided by Last.fm'
      properties:
        url:
          type: string
          format: uri
          description: URL to the artist's page on Last.fm
        image:
          type: string
          format: uri
          description: URL to the artist's image on Last.fm
        bio:
          type: object
          required:
            - summary
            - full
          properties:
            summary:
              type: string
            full:
              type: string
      required:
        - url
        - image
        - bio
      x-examples:
        Sample:
          url: 'https://www.last.fm/music/Queen'
          image: 'https://koel.yourdomain.net/img/artists/5a772708e7de19.84120679.png'
          bio:
            summary: Queen were an English rock band originally consisting of four members...
            full: 'Queen were an English rock band originally consisting of four members: vocalist Freddie Mercury, guitarist Brian May, bass guitarist John Deacon, and drummer Roger Taylor.'
    YouTubeSearchResult:
      title: YouTubeSearchResult
      type: object
      description: A search result object returned by YouTube
      properties:
        kind:
          type: string
        etag:
          type: string
        nextPageToken:
          type: string
        regionCode:
          type: string
        pageInfo:
          type: object
          required:
            - totalResults
            - resultsPerPage
          properties:
            totalResults:
              type: integer
            resultsPerPage:
              type: integer
        items:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              etag:
                type: string
              id:
                type: array
                items:
                  type: object
                  properties:
                    kind:
                      type: string
                    videoId:
                      type: string
                  required:
                    - kind
                    - videoId
              snippet:
                type: object
                required:
                  - publishedAt
                  - channelId
                  - title
                  - description
                  - thumbnails
                  - channelTitle
                  - liveBroadcastContent
                properties:
                  publishedAt:
                    type: string
                    format: date-time
                  channelId:
                    type: string
                  title:
                    type: string
                  description:
                    type: string
                  thumbnails:
                    type: array
                    items:
                      type: object
                      properties:
                        default:
                          type: object
                          required:
                            - url
                            - width
                            - height
                          properties:
                            url:
                              type: string
                              format: uri
                            width:
                              type: integer
                            height:
                              type: integer
                        medium:
                          type: object
                          required:
                            - url
                            - width
                            - height
                          properties:
                            url:
                              type: string
                              format: uri
                            width:
                              type: integer
                            height:
                              type: integer
                        high:
                          type: object
                          required:
                            - url
                            - width
                            - height
                          properties:
                            url:
                              type: string
                              format: uri
                            width:
                              type: integer
                            height:
                              type: integer
                      required:
                        - default
                        - medium
                        - high
                  channelTitle:
                    type: string
                  liveBroadcastContent:
                    type: string
            required:
              - kind
              - etag
              - id
              - snippet
      required:
        - kind
        - etag
        - nextPageToken
        - regionCode
        - pageInfo
        - items
      x-examples:
        Sample:
          kind: youtube#searchListResponse
          etag: '"XI7nbFXulYBIpL0ayR_gDh3eu1k/UMIztE1sQ8L9tu7igiTaSoBA9tw"'
          nextPageToken: CAoQAA
          regionCode: CH
          pageInfo:
            totalResults: 1000000
            resultsPerPage: 10
          items:
            - kind: youtube#searchResult
              etag: '"XI7nbFXulYBIpL0ayR_gDh3eu1k/bRRI2oEvvXIbCBFKv8WrLUaG-0A"'
              id:
                kind: youtube#video
                videoId: t99KH0TR-J4
              snippet:
                publishedAt: '2013-10-15T14:24:31.000Z'
                channelId: UCiMhD4jzUqG-IgPzUmmytRQ
                title: Queen - The Show Must Go On (Official Video)
                description: 'Subscribe to the Official Queen Channel Here http://bit.ly/Subscribe2Queen Taken from Innuendo, 1991. Queen - The Show Must Go On (promo video, 1991) ...'
                thumbnails:
                  default:
                    url: 'https://i.ytimg.com/vi/t99KH0TR-J4/default.jpg'
                    width: 120
                    height: 90
                  medium:
                    url: 'https://i.ytimg.com/vi/t99KH0TR-J4/mqdefault.jpg'
                    width: 320
                    height: 180
                  high:
                    url: 'https://i.ytimg.com/vi/t99KH0TR-J4/hqdefault.jpg'
                    width: 480
                    height: 360
                channelTitle: Queen Official
                liveBroadcastContent: none
    SongWithAlbumAndArtist:
      title: SongWithAlbumAndArtist
      type: object
      description: A Song model with loaded album and artist information
      x-examples: { }
      properties:
        id:
          type: string
          description: An md5 string
        artist_id:
          type: integer
        album_id:
          type: integer
        title:
          type: string
        disc:
          type: integer
        track:
          type: number
        length:
          type: number
          format: float
          description: The duration of the song in seconds
        album:
          $ref: '#/components/schemas/Album'
        artist:
          $ref: '#/components/schemas/Artist'
      required:
        - id
        - artist_id
        - album_id
        - title
        - disc
        - track
        - length
        - album
        - artist
  securitySchemes:
    Bearer Token:
      type: http
      scheme: bearer
    api-token:
      name: The API token as a query parameter
      type: apiKey
      in: query
