# Undocumented endpoints:
#  /api/v1/settings
#  /api/v1/activity
#  /api/v1/playlists
#  /api/v1/playlist-tracks
#  /api/v1/search
#  /api/v1/radios
#  /api/v1/history

openapi: "3.0.2"
info:
  description: |
    Interactive documentation for [Funkwhale](https://funkwhale.audio) API.

    The API is **not** freezed yet, but we will document breaking changes in our changelog,
    and try to avoid those as much as possible.

    Usage
    -----

    Click on an endpoint name to inspect its properties, parameters and responses.

    Use the "Try it out" button to send a real world payload to the endpoint and inspect
    the corresponding response.

    Authentication
    --------------

    To authenticate, use the `/token/` endpoint with a username and password, and copy/paste
    the resulting JWT token in the `Authorize` modal. All subsequent requests made via the interactive
    documentation will be authenticated.

    If you keep the default server (https://demo.funkwhale.audio), the default username and password
    couple is "demo" and "demo".

    Rate limiting
    -------------

    Depending on server configuration, pods running Funkwhale 0.20 and higher may rate-limit incoming
    requests to prevent abuse and improve the stability of service. Requests that are dropped because of rate-limiting
    receive a 429 HTTP response.

    The limits themselves vary depending on:

    - The client: anonymous requests are subject to lower limits than authenticated requests
    - The operation being performed: Write and delete operations, as performed with DELETE, POST, PUT and PATCH HTTP methods are subject to lower limits

    Those conditions are used to determine the scope of the request, which in turns determine the limit that is applied.
    For instance, authenticated POST requests are bound to the `authenticated-create` scope, with a default limit of
    1000 requests/hour, but anonymous POST requests are bound to the `anonymous-create` scope, with a lower limit of 1000 requests/day.

    A full list of scopes with their corresponding description, and the current usage data for the client performing the request
    is available via the `/api/v1/rate-limit` endpoint.

    Additionally, we include HTTP headers on all API response to ensure API clients can understand:

    - what scope was bound to a given request
    - what is the corresponding limit
    - how much similar requests can be sent before being limited
    - and how much time they should wait if they have been limited

    <table>
      <caption>Rate limiting headers</caption>
      <thead>
        <th>Header</th>
        <th>Example value</th>
        <th>Description value</th>
      </thead>
      <tbody>
        <tr>
          <td><code>X-RateLimit-Limit</code></td>
          <td>50</td>
          <td>The number of allowed requests whithin a given period</td>
        </tr>
        <tr>
          <td><code>X-RateLimit-Duration</code></td>
          <td>3600</td>
          <td>The time window, in seconds, during which those requests are accounted for.</td>
        </tr>
        <tr>
          <td><code>X-RateLimit-Scope</code></td>
          <td>login</td>
          <td>The name of the scope as computed for the request</td>
        </tr>
        <tr>
          <td><code>X-RateLimit-Remaining</code></td>
          <td>42</td>
          <td>How many requests can be sent with the same scope before the limit applies</td>
        </tr>
        <tr>
          <td><code>Retry-After</code> (if <code>X-RateLimit-Remaining</code> is 0)</td>
          <td>3543</td>
          <td>How many seconds to wait before a retry</td>
        </tr>
        <tr>
          <td><code>X-RateLimit-Reset</code></td>
          <td>1568126089</td>
          <td>A timestamp indicating when <code>X-RateLimit-Remaining</code> will return to its higher possible value</td>
        </tr>
        <tr>
          <td><code>X-RateLimit-ResetSeconds</code></td>
          <td>3599</td>
          <td>How many seconds to wait before <code>X-RateLimit-Remaining</code> returns to its higher possible value</td>
        </tr>
      </tbody>
    </table>


    Resources
    ---------

    For more targeted guides regarding API usage, and especially authentication, please
    refer to [https://docs.funkwhale.audio/api.html](https://docs.funkwhale.audio/api.html)

  version: "1.0.0"
  title: "Funkwhale API"

servers:
  - url: https://demo.funkwhale.audio
    description: Demo server
  - url: https://{domain}
    description: Custom server
    variables:
      domain:
        default: yourdomain
        description: Your Funkwhale Domain
      protocol:
        enum:
          - 'http'
          - 'https'
        default: 'https'

components:
  securitySchemes:
    oauth2:
      type: oauth2
      description: This API uses OAuth 2 with the Authorization Code flow. You can register an app using the /oauth/apps/ endpoint.
      flows:
        authorizationCode:
          # Swagger doesn't support relative URLs yet (cf https://github.com/swagger-api/swagger-ui/pull/5244)
          authorizationUrl: /authorize
          tokenUrl: /api/v1/oauth/token/
          refreshUrl: /api/v1/oauth/token/
          scopes:
            "read": "Read-only access to all user data"
            "write": "Write-only access on all user data"
            "read:profile": "Read-only access to profile data"
            "read:libraries": "Read-only access to library and uploads"
            "read:playlists": "Read-only access to playlists"
            "read:listenings": "Read-only access to listening history"
            "read:favorites": "Read-only access to favorites"
            "read:radios": "Read-only access to radios"
            "read:edits": "Read-only access to edits"
            "read:notifications": "Read-only access to notifications"
            "read:follows": "Read-only to follows"
            "read:filters": "Read-only to to content filters"
            "write:profile": "Write-only access to profile data"
            "write:libraries": "Write-only access to libraries"
            "write:playlists": "Write-only access to playlists"
            "write:follows": "Write-only access to follows"
            "write:favorites": "Write-only access to favorits"
            "write:notifications": "Write-only access to notifications"
            "write:radios": "Write-only access to radios"
            "write:edits": "Write-only access to edits"
            "write:filters": "Write-only access to content-filters"
            "write:listenings": "Write-only access to listening history"
    jwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "You can get a token by using the /token endpoint"

security:
  - jwt: []
  - oauth2: []

tags:
  - name: Auth and security
    description: Login, logout, rate-limit and authorization endpoints
  - name: Library and metadata
    description: Information and metadata about musical and audio entities (albums, tracks, artists, etc.)
  - name: Uploads and audio content
    description: Manipulation and uploading of audio files
    externalDocs:
      url: https://docs.funkwhale.audio/users/managing.html
  - name: Content curation
    description: Favorites, playlists, radios

paths:
  /api/v1/oauth/apps/:
    post:
      tags:
        - "Auth and security"
      description:
        Register an OAuth application
      security: []
      responses:
        201:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/OAuthApplication"
                  - $ref: "#/definitions/OAuthApplicationCreation"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                name:
                  type: "string"
                  example: "My Awesome Funkwhale Client"
                  summary: "A human readable name for your app"
                redirect_uris:
                  type: "string"
                  example: "https://myapp/oauth2/funkwhale"
                  summary: "A list of redirect uris, separated by spaces"
                scopes:
                  type: "string"
                  summary: "A list of scopes requested by your app, separated by spaces"
                  example: "read write:playlists write:favorites"
  /api/v1/token/:
    post:
      tags:
        - "Auth and security"
      summary: Get an API token
      description:
        Obtain a JWT token you can use for authenticating your next requests.
      security: []
      responses:
        '200':
          description: Successfull auth
        '400':
          description: Invalid credentials
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                username:
                  type: "string"
                  example: "demo"
                password:
                  type: "string"
                  example: "demo"

  /api/v1/auth/registration/:
    post:
      summary: Create an account
      description: |
        Register a new account on this instance. An invitation code will be required
        if sign up is disabled.
      tags:
        - "Auth and security"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                username:
                  type: "string"
                  example: "alice"
                email:
                  type: "string"
                  format: "email"
                invitation:
                  type: "string"
                  example: "INVITECODE"
                  required: false
                  description: An invitation code, required if signups are closed on the instance.
                password1:
                  type: "string"
                  example: "passw0rd"
                password2:
                  type: "string"
                  description: Must be identical to password1
                  example: "passw0rd"
      responses:
        201:
          $ref: "#/responses/201"
  /api/v1/auth/password/reset/:
    post:
      summary: Request a password reset
      description: |
        Request a password reset. An email with reset instructions will be sent to the provided email,
        if it's associated with a user account.
      tags:
        - "Auth and security"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                email:
                  type: "string"
                  format: "email"
      responses:
        200:
          $ref: "#/responses/200"
  /api/v1/users/users/me/:
    get:
      summary: Retrive profile information
      description: |
        Retrieve profile informations of the current user
      tags:
        - "Auth and security"

      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/Me"

  /api/v1/rate-limit/:
    get:
      summary: Retrive rate-limit information and current usage status
      tags:
        - "Auth and security"

      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/RateLimitStatus"

  /api/v1/artists/:
    get:
      summary: List artists
      tags:
        - "Library and metadata"
      security:
        - oauth2:
          - "read:libraries"
      parameters:
        - name: "q"
          in: "query"
          default: null
          description: "Search query used to filter artists"
          schema:
            required: false
            type: "string"
        - allOf:
            - $ref: "#/parameters/Ordering"
            - default: "-creation_date"
              schema:
                required: false
                type: "string"
                example: "creation_date"
                enum:
                  - creation_date
                  - id
                  - name
        - $ref: "#/parameters/Playable"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"

      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/Artist"
  /api/v1/artists/{id}/:
    get:
      summary: Retrieve a single artist
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/Refresh"
      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/Artist"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"
  /api/v1/artists/{id}/libraries/:
    get:
      summary: List available user libraries containing work from this artist
      security:
        - oauth2:
          - "read:libraries"
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"

      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/LibraryPage"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/albums/:
    get:
      summary: List albums
      tags:
        - "Library and metadata"

      security:
        - oauth2:
          - "read:libraries"
      parameters:
        - name: "q"
          in: "query"
          default: null
          description: "Search query used to filter albums"
          schema:
            required: false
            type: "string"
        - name: "artist"
          in: "query"
          default: null
          description: "Only include albums by the requested artist"
          schema:
            required: false
            type: "integer"
            format: "int64"
        - allOf:
            - $ref: "#/parameters/Ordering"
            - default: "-creation_date"
              schema:
                required: false
                type: "string"
                example: "creation_date"
                enum:
                  - creation_date
                  - release_date
                  - title
        - $ref: "#/parameters/Playable"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"

      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/Album"
  /api/v1/albums/{id}/:
    get:
      summary: Retrieve a single album
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/Refresh"

      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/Album"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/albums/{id}/libraries/:
    get:
      summary: List available user libraries containing tracks from this album
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"

      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/LibraryPage"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/tracks/:
    get:
      summary: List tracks
      tags:
        - "Library and metadata"

      security:
        - oauth2:
          - "read:libraries"
      parameters:
        - name: "q"
          in: "query"
          default: null
          description: "Search query used to filter tracks"
          schema:
            required: false
            type: "string"
        - name: "artist"
          in: "query"
          default: null
          description: "Only include tracks by the requested artist"
          schema:
            required: false
            type: "integer"
            format: "int64"
        - name: "favorites"
          in: "query"
          default: null
          description: "filter/exclude tracks favorited by the current user"
          schema:
            required: false
            type: "boolean"
        - name: "album"
          in: "query"
          default: null
          description: "Only include tracks from the requested album"
          schema:
            required: false
            type: "integer"
            format: "int64"
        - name: "license"
          in: "query"
          description: "Only include tracks with the given license"
          default: null
          schema:
            example: "cc-by-sa-4.0"
            required: false
            type: "string"
        - allOf:
            - $ref: "#/parameters/Ordering"
            - default: "-creation_date"
              schema:
                required: false
                type: "string"
                example: "creation_date"
                enum:
                  - creation_date
                  - release_date
                  - title
        - $ref: "#/parameters/Playable"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"

      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/Track"
  /api/v1/tracks/{id}/:
    get:
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/Refresh"
      summary: Retrieve a single track

      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/Track"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/tracks/{id}/libraries/:
    get:
      summary: List available user libraries containing given track
      parameters:
        - $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"
      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/LibraryPage"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"
  /api/v1/listen/{uuid}/:
    get:
      summary: Download the audio file matching the given track uuid
      description: |
        Given a track uuid (and not ID), return the first found audio file
        accessible by the user making the request.

        In case of a remote upload, this endpoint will fetch the audio file from the remote
        and cache it before sending the response.

      parameters:
        - name: uuid
          in: path
          required: true
          description: Track uuid
          schema:
            type: "string"
            format: "uuid"
        - name: to
          in: query
          required: false
          description: |
            If specified, the endpoint will return a transcoded version of the original
            audio file.

            Since transcoding happens on the fly, it can significantly increase response time,
            and it's recommended to request transcoding only for files that are not playable
            by the client.

            This endpoint support bytess-range requests.
          schema:
            $ref: "#/properties/transcode_options"
        - name: upload
          in: query
          required: false
          summary: An upload uuid
          description: |
            If specified, will return the audio for the given upload uuid.

            This is useful for tracks that have multiple uploads available.

          schema:
            type: string
            format: uuid

      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            '*/*':
              description: "Audio file, as binary data"
              schema:
                type: string
                format: binary
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/licenses/:
    get:
      summary: List licenses
      security:
        - oauth2:
          - "read:libraries"
      tags:
        - "Library and metadata"
      parameters:
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"
      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/License"

  /api/v1/licenses/{code}/:
    get:
      summary: Retrieve a single license
      security:
        - oauth2:
          - "read:libraries"
      parameters:
        - name: code
          in: path
          description: License code
          required: true
          schema:
            type: string
            example: cc0-1.0

      tags:
        - "Library and metadata"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/License"
        404:
          content:
            application/json:
              schema:
                $ref: "#/definitions/ResourceNotFound"

  /api/v1/libraries/:
    get:
      summary: List owned libraries
      tags:
        - "Uploads and audio content"
      parameters:
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"
      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/OwnedLibrary"
    post:
      tags:
        - "Uploads and audio content"
      description:
        Create a new library
      responses:
        201:
          $ref: "#/responses/201"
        400:
          $ref: "#/responses/400"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/definitions/OwnedLibraryCreate"

  /api/v1/libraries/{uuid}/:
    parameters:
      - name: uuid
        in: path
        required: true
        schema:
          type: "string"
          format: "uuid"
    get:
      summary: Retrieve a library
      tags:
        - "Uploads and audio content"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/OwnedLibrary"
    post:
      summary: Update a library
      tags:
        - "Uploads and audio content"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/definitions/OwnedLibraryCreate"
      responses:
        201:
          content:
            application/json:
              schema:
                $ref: "#/definitions/OwnedLibrary"
    delete:
      summary: Delete a library and all associated uploads
      description: |
        This will delete the library, all associated uploads, follows, and broadcast
        the event on the federation.
      tags:
        - "Uploads and audio content"
      responses:
        204:
          $ref: "#/responses/204"

  /api/v1/uploads/:
    get:
      summary: List owned uploads
      tags:
        - "Uploads and audio content"
      parameters:
        - name: "q"
          in: "query"
          default: null
          description: "Search query used to filter uploads"
          schema:
            required: false
            type: "string"
            example: "Dire straits"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"
      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/OwnedUpload"
    post:
      tags:
        - "Uploads and audio content"
      description:
        Upload a new file in a library. The event will be broadcasted on federation,
        according to the library visibility and followers.
      responses:
        201:
          $ref: "#/responses/201"
        400:
          $ref: "#/responses/400"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                library:
                  type: string
                  format: uuid
                  description: "The library in which the audio should be stored"
                import_reference:
                  type: string
                  example: "Import launched via API client on 04/19"
                source:
                  type: string
                  example: "upload://filename.mp3"
                audio_file:
                  type: string
                  format: binary

  /api/v1/uploads/{uuid}/:
    parameters:
      - name: uuid
        in: path
        required: true
        schema:
          type: "string"
          format: "uuid"
    get:
      summary: Retrieve an upload
      tags:
        - "Uploads and audio content"
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/definitions/OwnedUpload"
    delete:
      summary: Delete an upload
      description: |
        This will delete the upload from the server and broadcast the event
        on the federation.
      tags:
        - "Uploads and audio content"
      responses:
        204:
          $ref: "#/responses/204"

  /api/v1/favorites/tracks/:
    get:
      tags:
        - "Content curation"
      parameters:
        - name: "q"
          in: "query"
          default: null
          description: "Search query used to filter favorites"
          schema:
            required: false
            type: "string"
        - name: "user"
          in: "query"
          default: null
          description: "Limit results to favorites belonging to the given user"
          schema:
            $ref: "#/parameters/ObjectId"
        - $ref: "#/parameters/PageNumber"
        - $ref: "#/parameters/PageSize"
      responses:
        200:
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/definitions/ResultPage"
                  - type: "object"
                    properties:
                      results:
                        type: "array"
                        items:
                          $ref: "#/definitions/TrackFavorite"
    post:
      summary: Mark the given track as favorite
      tags:
        - "Content curation"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                track:
                  type: "integer"
                  format: "int64"
                  example: 98
      responses:
        201:
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  id:
                    type: "integer"
                    format: "int64"
                    example: 876
                  track:
                    type: "integer"
                    format: "int64"
                    example: 98
                  creation_date:
                    $ref: "#/properties/creation_date"
  /api/v1/favorites/tracks/remove/:
    post:
      summary: Remove the given track from favorites
      tags:
        - "Content curation"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                track:
                  type: "integer"
                  format: "int64"
                  example: 98
      responses:
        204:
          $ref: "#/responses/204"

parameters:
  ObjectId:
    name: id
    in: path
    description: Object ID
    required: true
    schema:
      type: integer
      format: int64
  Ordering:
    name: "ordering"
    in: "query"
    description: "Ordering for the results, prefix with - for DESC ordering"

  PageNumber:
    in: query
    name: page
    schema:
      type: "integer"
      format: "int64"
      example: 1
      default: 1
      minimum: 1
  PageSize:
    in: query
    name: page_size
    schema:
      type: "integer"
      format: "int64"
      example: 16
      default: 25
      minimum: 1
      maximum: 25
  Playable:
    name: "playable"
    in: "query"
    default: null
    description: "Filter/exclude resources with playable tracks"
    schema:
      required: false
      type: "boolean"
  Refresh:
    name: "refresh"
    in: "query"
    default: false
    description: "Trigger an ActivityPub fetch to refresh local data"
    schema:
      required: false
      type: "boolean"

responses:
  200:
    description: Success
  201:
    description: Successfully created
  204:
    description: Successfully deleted
  400:
    description: Bad request

properties:
  mbid:
    type: "string"
    format: "uuid"
    description: "A musicbrainz ID"
  creation_date:
    type: "string"
    format: "date-time"
  privacy_level:
    type: string
    example: "me"
    description: |
     * `me`: private
     * `instance`: accessible by local users
     * `everyone`: public (including over federation)
    enum:
      - "me"
      - "instance"
      - "everyone"
  fid:
    type: "string"
    format: "uri"
    description: "Federation ID"
    example: "https://my.instance/federation/music/libraries/3fa85f64-5717-4562-b3fc-2c963f66afa6"
  audio_mimetype:
    type: string
    example: "audio/ogg"
    enum:
      - "audio/ogg"
      - "audio/mpeg"
      - "audio/x-flac"
      - "audio/flac"
  import_status:
    type: string
    example: "finished"
    enum:
      - "pending"
      - "finished"
      - "errored"
      - "skipped"
    description: |
     * `pending`: waiting to be processed by the server
     * `finished`: successfully processed by the server
     * `errored`: couldn't be processed by the server (e.g because of a tagging issue)
     * `skipped`: processed by the server but skipped, because considered as a duplicate of an existing upload

  transcode_options:
    type: string
    enum:
      - "ogg"
      - "mp3"

definitions:
  OAuthApplication:
    type: "object"
    properties:
      client_id:
        type: "string"
        example: "VKIZWv7FwBq56UMfUtbCSIgSxzUTv1b6nMyOkJvP"
      created:
        type: "string"
        format: "date-time"
      updated:
        type: "string"
        format: "date-time"
      scopes:
        type: "string"
        description: "Coma-separated list of scopes requested by the app"

  OAuthApplicationCreation:
    type: "object"
    properties:
      client_secret:
        type: "string"
        example: "qnKDX8zjIfC0BG4tUreKlqk3tNtuCfJdGsaEt5MIWrTv0YLLhGI6SGqCjs9kn12gyXtIg4FWfZqWMEckJmolCi7a6qew4LawPWMfnLDii4mQlY1eQG4BJbwPANOrDiTZ"
      redirect_uris:
        type: "string"
        format: "uri"
        description: "Coma-separated list of redirect uris allowed for the app"


  ResultPage:
    type: "object"
    properties:
      count:
        type: "integer"
        format: "int64"
        example: 42
        description: "The total number of results (all pages included)"
      next:
        type: "string"
        format: "uri"
        description: "Link to the next page of results"
      previous:
        type: "string"
        format: "uri"
        description: "Link to the previous page of results"


  Image:
    type: "object"
    properties:
      original:
        type: "string"
        description: "URL to the original image"
        example: "https://mydomain/media/albums/covers/ec2c53aeaac6.jpg"
      small_square_crop:
        type: "string"
        description: "URL to a small, squared thumbnail of the image"
        example: "https://mydomain/media/__sized__/albums/covers/ec2c53aeaac6-crop-c0-5__0-5-50x50-70.jpg"

      medium_square_crop:
        type: "string"
        description: "URL to a medium, squared thumbnail of the image"
        example: "https://mydomain/media/__sized__/albums/covers/ec2c53aeaac6-crop-c0-5__0-5-200x200-70.jpg"

      square_crop:
        type: "string"
        description: "URL to a large, squared thumbnail of the image"
        example: "https://mydomain/media/__sized__/albums/covers/ec2c53aeaac6-crop-c0-5__0-5-400x400-70.jpg"

  Actor:
    type: object
    description: "A federation/ ActivityPub actor"
    properties:
      fid:
        type: string
        format: uri
        description: "The actor Federation ID (unique accross federation)"
      uuid:
        type: string
        format: uuid
        description: "Local ID of the library"
      creation_date:
        type: "string"
        format: "date-time"
      preferred_username:
        type: "string"
        example: "alice"
      name:
        type: string
        example: "Alice Unicorn"
      last_fetch_date:
        type: "string"
        format: "date-time"
        description: "Last time the actor profile was fetched on its origin server"
      domain:
        type: "string"
        format: "hostname"
        example: "open.audio"
      type:
        type: "string"
        example: "Person"
        enum:
          - Person
          - Application
          - Group
          - Organization
      manually_approves_followers:
        type: "boolean"
      full_username:
        type: string
        example: "alice@open.audio"

  BaseArtist:
    type: "object"
    properties:
      mbid:
        required: false
        $ref: "#/properties/mbid"
      id:
        type: "integer"
        format: "int64"
        example: 42
      fid:
        type: string
        format: uri
        description: "The artist Federation ID (unique accross federation)"
      name:
        type: "string"
        example: "System of a Down"
      creation_date:
        type: "string"
        format: "date-time"
      is_local:
        type: "boolean"
        description: "Indicates if the object was initally created locally or on another server"

  Artist:
    type: "object"
    allOf:
      - $ref: "#/definitions/BaseArtist"
      - type: "object"
        properties:
          tracks_count:
            type: "integer"
            format: "int64"
            example: 42
          albums:
            type: "array"
            items:
              $ref: "#/definitions/ArtistAlbum"

  BaseAlbum:
    type: "object"
    properties:
      mbid:
        required: false
        $ref: "#/properties/mbid"
      id:
        type: "integer"
        format: "int64"
        example: 16
      fid:
        type: string
        format: uri
        description: "The album Federation ID (unique accross federation)"
      artist:
        type: "integer"
        format: "int64"
        example: 42
      title:
        type: "string"
        example: "Toxicity"
      creation_date:
        type: "string"
        format: "date-time"
      release_date:
        type: "string"
        required: false
        format: "date"
        example: "2001-01-01"
      is_playable:
        type: "boolean"
      cover:
        $ref: "#/definitions/Image"
      is_local:
        type: "boolean"
        description: "Indicates if the object was initally created locally or on another server"

  Album:
    type: "object"
    allOf:
      - $ref: "#/definitions/BaseAlbum"
      - type: "object"
        properties:
          tracks:
            type: "array"
            items:
              $ref: "#/definitions/AlbumTrack"

  ArtistAlbum:
    type: "object"
    allOf:
      - $ref: "#/definitions/BaseAlbum"
      - type: "object"
        properties:
          tracks_count:
            type: "integer"
            format: "int64"
            example: 16
  Library:
    type: "object"
    properties:
      fid:
        type: string
        format: uri
        description: "The library Federation ID (unique accross federation)"
      uuid:
        type: string
        format: uuid
        description: "Local ID of the library"
      name:
        type: string
        example: "My awesome library"
      description:
        type: string
        nullable: true
        example: "This library contains all the stuff I love!"
      uploads_count:
        type: "integer"
        format: "int64"
        example: 687
      privacy_level:
        type: string
        example: "me"
        enum:
          - "me"
          - "instance"
          - "everyone"
      actor:
        $ref: "#/definitions/Actor"
  LibraryPage:
    allOf:
      - $ref: "#/definitions/ResultPage"
      - type: "object"
        properties:
          results:
            type: "array"
            items:
              $ref: "#/definitions/Library"

  License:
    type: "object"
    properties:
      id:
        type: string
        format: uri
        example: http://creativecommons.org/publicdomain/zero/1.0/
        description: "The license ID"
      url:
        type: string
        format: uri
        example: http://creativecommons.org/publicdomain/zero/1.0/
        description: "The license url (can be different than the ID)"
      code:
        type: string
        description: "A unique code to identify the license"
        example: cc0-1.0
      redistribute:
        type: boolean
        example: true
        description: "Does the license allow free redistribution?"
      derivative:
        type: boolean
        example: true
        description: "Does the license allow the creation of derivative work?"
      commercial:
        type: boolean
        example: true
        description: "Does the license allow commercial use?"
      attribution:
        type: boolean
        example: false
        description: "Does the license requires crediting the author?"
      copyleft:
        type: boolean
        example: false
        description: "Does the license enforce a similar license of derivative work?"

  BaseTrack:
    type: "object"
    properties:
      mbid:
        required: false
        $ref: "#/properties/mbid"
      id:
        type: "integer"
        format: "int64"
        example: 66
      fid:
        type: string
        format: uri
        description: "The track Federation ID (unique accross federation)"
      artist:
        type: "integer"
        format: "int64"
        example: 42
      album:
        type: "integer"
        format: "int64"
        example: 16
      title:
        type: "string"
        example: "Chop Suey!"
      position:
        required: false
        description: "Position of the track in the album"
        type: "number"
        minimum: 1
        example: 1
      disc_number:
        required: false
        type: "number"
        minimum: 1
        example: 1
      listen_url:
        type: "string"
        format: "uri"
        description: "URL to stream the track"
      copyright:
        type: "string"
        example: "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0: http://creativecommons.org/licenses/by-nc-nd/4.0/"
        description: "Copyright information as extracted from upload tags"
      license:
        type: "string"
        description: "Identifier of the license that is linked to the track"
        example: "cc-by-nc-nd-4.0"
      is_local:
        type: "boolean"
        description: "Indicates if the object was initally created locally or on another server"

  AlbumTrack:
    type: "object"
    allOf:
      - $ref: "#/definitions/BaseTrack"
      - type: "object"
        properties:
          artist:
            $ref: "#/definitions/BaseArtist"
          uploads:
            type: "array"
            description: "List of uploads associated with this track"
            items:
              $ref: "#/definitions/Upload"
  Track:
    type: "object"
    allOf:
      - $ref: "#/definitions/BaseTrack"
      - type: "object"
        properties:
          album:
            $ref: "#/definitions/Album"
          artist:
            $ref: "#/definitions/BaseArtist"
          uploads:
            type: "array"
            description: "List of uploads associated with this track"
            items:
              $ref: "#/definitions/Upload"
  Upload:
    type: "object"
    properties:
      uuid:
        type: string
        format: uuid
      size:
        type: "integer"
        format: "int64"
        example: 278987000
        description: "Size of the file, in bytes"
      duration:
        type: "integer"
        format: "int64"
        example: 184
        description: "Duration of the audio, in seconds"
      bitrate:
        type: "integer"
        format: "int64"
        example: 128000
        description: "Bitrate of the file, in bytes/s"
      mimetype:
        $ref: "#/properties/audio_mimetype"
      extension:
        type: string
        example: "ogg"
        description: "File extension of the upload"
      filename:
        type: "string"
        example: "Myfile.mp3"
      listen_url:
        type: "string"
        format: "uri"
        description: "URL to stream the upload"

  OwnedLibraryCreate:
    type: "object"
    properties:
      password:
        type: "name"
        example: "My new library"
      description:
        required: false
        type: "string"
        example: "Lots of interesting content"
      privacy_level:
        $ref: "#/properties/privacy_level"

  OwnedLibrary:
    type: "object"
    properties:
      uuid:
        type: string
        format: uuid
      fid:
        $ref: "#/properties/fid"
      name:
        type: "string"
        example: "My Creative Commons library"
      description:
        type: "string"
        example: "All content is under CC-BY"
      creation_date:
        $ref: "#/properties/creation_date"
      privacy_level:
        $ref: "#/properties/privacy_level"
      uploads_count:
        type: "integer"
        format: "int64"
        example: 34
      size:
        type: "integer"
        format: "int64"
        example: 678917000
        description: "Total size of uploads in the library, in bytes"

  OwnedUpload:
    type: "object"
    allOf:
      - $ref: "#/definitions/Upload"
      - type: "object"
        properties:
          import_status:
            $ref: "#/properties/import_status"
          track:
            $ref: "#/definitions/Track"
          library:
            $ref: "#/definitions/OwnedLibrary"
          source:
            type: "string"
            example: "upload://myfile.mp3"
          import_reference:
            type: "string"
            example: "Import launched via web UI on 03/18"
  TrackFavorite:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 876
      track:
        $ref: "#/definitions/Track"
      user:
        $ref: "#/definitions/User"
      creation_date:
        $ref: "#/properties/creation_date"
  User:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 23
      username:
        type: "string"
        example: "alice"
      name:
        type: "string"
        example: "Alice Kingsley"
      avatar:
        $ref: "#/definitions/Avatar"

  Me:
    type: "object"
    allOf:
      - $ref: "#/definitions/User"
      - type: "object"
        properties:
          full_username:
            type: "string"
            description: Full username, for use on federation
            example: "alice@yourdomain.com"
          email:
            type: "string"
            format: "email"
            description: Email address associated with the account
            example: "alice@email.provider"
          is_staff:
            type: "boolean"
            example: false
          is_superuser:
            type: "boolean"
            example: false
          date_joined:
            type: "string"
            format: "date-time"
          privacy_level:
            $ref: "#/properties/privacy_level"
            description: Default privacy-level associated with the user account
          quota_status:
            $ref: "#/definitions/QuotaStatus"
          permissions:
            $ref: "#/definitions/Permissions"
  Avatar:
    type: "object"
    properties:
      original:
        type: "string"
        format: "uri"
        description: "Original image URL"
        example: "http://yourinstance/media/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996.jpg"
      square_crop:
        type: "string"
        format: "uri"
        description: "400x400 thumbnail URL"
        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-400x400-70.jpg"
      small_square_crop:
        type: "string"
        format: "uri"
        description: "50x50 thumbnail URL"
        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-50x50-70.jpg"
      medium_square_crop:
        type: "string"
        format: "uri"
        description: "200x200 thumbnail URL"
        example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-200x200-70.jpg"
  QuotaStatus:
    type: "object"
    properties:
      max:
        type: "integer"
        format: "int64"
        description: Storage space allocated to this user, in MB
        example: 5000
      remaining:
        type: "integer"
        format: "int64"
        description: Remaining storage space for this user, in MB
        example: 4600
      current:
        type: "integer"
        format: "int64"
        description: Storage space used by this user, in MB
        example: 400
      skipped:
        type: "integer"
        format: "int64"
        description: Storage space occupied by uploads with "skipped" import status, in MB
        example: 30
      finished:
        type: "integer"
        format: "int64"
        description: Storage space occupied by uploads with "finished" import status, in MB
        example: 350
      pending:
        type: "integer"
        format: "int64"
        description: Storage space occupied by uploads with "pending" import status, in MB
        example: 15
      errored:
        type: "integer"
        format: "int64"
        description: Storage space occupied by uploads with "errored" import status, in MB
        example: 5
  Permissions:
    type: "object"
    properties:
      library:
        type: "boolean"
        example: false
        description: A boolean indicating if the user can manage the instance library
      moderation:
        type: "boolean"
        example: false
        description: A boolean indicating if the user has moderation permission
      settings:
        type: "boolean"
        example: false
        description: A boolean indicating if the user can manage instance settings and users
  RateLimitStatus:
    type: "object"
    properties:
      enabled:
        type: "boolean"
        example: true
        description: A boolean indicating if rate-limiting is enabled on the server
      ident:
        type: "object"
        description: Client-related data
        properties:
          type:
            type: string
            example: "anonymous"
            enum:
              - "authenticated"
              - "anonymous"
          id:
            type: string
            example: "92.143.42"
            description: An address IP or user ID identifying the client
      scopes:
        type: "array"
        items:
          type: "object"
          description: Rate-limit scope configuration and usage
          properties:
            id:
              type: string
              example: "password-reset"
            description:
              type: string
              example: "Password reset request"
            rate:
              type: string
              example: "30/day"
            limit:
              type: "integer"
              format: "int64"
              example: 30
            duration:
              type: "integer"
              format: "int64"
              example: 86400
            remaining:
              type: "integer"
              format: "int64"
              example: 28
              description: How many requests can be sent with the same scope before the limit applies
            reset:
              type: "integer"
              format: "int64"
              example: 1568126189
              description: A timestamp indicating when <code>remaining</code> will return to its higher possible value
            reset_seconds:
              type: "integer"
              format: "int64"
              example: 86267
              description: How many seconds to wait before <code>remaining</code> returns to its higher possible value
            available:
              type: "integer"
              format: "int64"
              example: 1568126089
              description: A timestamp indicating when the client can retry
            available_seconds:
              type: "integer"
              format: "int64"
              example: 54
              description: How many seconds to wait before a retry

  ResourceNotFound:
    type: "object"
    properties:
      detail:
        type: "string"
        example: "Not found."
