openapi: 3.0.0
info:
  title: AzuraCast
  description: 'AzuraCast is a standalone, turnkey web radio management tool. Radio stations hosted by AzuraCast expose a public API for viewing now playing data, making requests and more.'
  license:
    name: 'GNU Affero General Public License v3.0 or later'
    url: 'https://www.gnu.org/licenses/agpl-3.0.txt'
  version: 0.21.0
servers:
  -
    url: 'https://demo.azuracast.com/api'
    description: 'AzuraCast Public Demo Server'
paths:
  '/admin/acme-log/{path}':
    get:
      tags:
        - 'Administration: General'
      summary: 'View the logs of a manually run ACME certificate renewal.'
      operationId: adminAcmeViewLog
      parameters:
        -
          name: path
          in: path
          description: 'Log path as returned by the Run action.'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_LogContents'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/acme:
    put:
      tags:
        - 'Administration: General'
      summary: 'Generate or renew ACME certificate.'
      operationId: putAdminGenerateAcmeCert
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_TaskWithLog'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/api-keys:
    get:
      tags:
        - 'Administration: General'
      summary: 'List all current API keys across the system.'
      operationId: adminListApiKeys
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  allOf: [{ $ref: '#/components/schemas/ApiKey' }, { $ref: '#/components/schemas/HasLinks' }]
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/api-key/{id}':
    delete:
      tags:
        - 'Administration: General'
      summary: 'Delete a single API key.'
      operationId: adminDeleteApiKey
      parameters:
        -
          name: id
          in: path
          description: 'API Key ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/auditlog:
    get:
      tags:
        - 'Administration: General'
      summary: 'List all Audit Log actions that have taken place on the installation.'
      operationId: getAuditlog
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_AuditLog'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/backups/delete/{path}':
    delete:
      tags:
        - 'Administration: Backups'
      summary: 'Delete a given backup.'
      operationId: deleteBackup
      parameters:
        -
          name: path
          in: path
          description: 'Download path (base64-encoded "StorageLocationID | Path")'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/backups/download/{path}':
    get:
      tags:
        - 'Administration: Backups'
      summary: 'Download a given backup.'
      operationId: downloadBackup
      parameters:
        -
          name: path
          in: path
          description: 'Download path (base64-encoded "StorageLocationID | Path")'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/backups:
    get:
      tags:
        - 'Administration: Backups'
      summary: 'Return a list of all current backups.'
      operationId: getBackups
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Backup'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/backups/log/{path}':
    get:
      tags:
        - 'Administration: Backups'
      summary: 'View a specific backup log contents.'
      operationId: adminBackupsViewLog
      parameters:
        -
          name: path
          in: path
          description: 'Log path as returned by the Run action.'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_LogContents'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/backups/run:
    post:
      tags:
        - 'Administration: Backups'
      summary: 'Initialize a manual backup.'
      operationId: postAdminDoBackup
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_TaskWithLog'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/custom_assets/{type}':
    get:
      tags:
        - 'Administration: General'
      summary: 'Get the details of the custom asset of the specified type.'
      operationId: getAdminCustomAsset
      parameters:
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_UploadedRecordStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: General'
      summary: 'Upload a new custom asset of the specified type.'
      operationId: postAdminCustomAsset
      parameters:
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: General'
      summary: 'Removes the custom asset of the specified type.'
      operationId: deleteAdminCustomAsset
      parameters:
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/custom_fields:
    get:
      tags:
        - 'Administration: Custom Fields'
      summary: 'List all current custom fields in the system.'
      operationId: getCustomFields
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  allOf: [{ $ref: '#/components/schemas/CustomField' }, { $ref: '#/components/schemas/HasLinks' }]
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: Custom Fields'
      summary: 'Create a new custom field.'
      operationId: addCustomField
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomField'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/CustomField' }
                  - { $ref: '#/components/schemas/HasLinks' }
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/custom_field/{id}':
    get:
      tags:
        - 'Administration: Custom Fields'
      summary: 'Retrieve details for a single custom field.'
      operationId: getCustomField
      parameters:
        -
          name: id
          in: path
          description: 'Custom Field ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/CustomField' }
                  - { $ref: '#/components/schemas/HasLinks' }
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Custom Fields'
      summary: 'Update details of a single custom field.'
      operationId: editCustomField
      parameters:
        -
          name: id
          in: path
          description: 'Custom Field ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomField'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: Custom Fields'
      summary: 'Delete a single custom field.'
      operationId: deleteCustomField
      parameters:
        -
          name: id
          in: path
          description: 'Custom Field ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/debug/clear-cache:
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Clear the application cache (Redis).'
      operationId: adminDebugClearCache
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/clear-queue/{queue}':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Clear the specified message queue.'
      operationId: adminDebugClearQueue
      parameters:
        -
          name: queue
          in: path
          description: 'Message queue type.'
          required: true
          schema:
            type: string
            enum:
              - high_priority
              - normal_priority
              - low_priority
              - search_index
              - media
              - podcast_media
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/station/{station_id}/clearqueue':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Clear the upcoming song queue and generate a new one.'
      operationId: adminDebugClearStationQueue
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Debug_LogResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/debug/queues:
    get:
      tags:
        - 'Administration: Debugging'
      summary: 'List all message queues.'
      operationId: getAdminDebugQueues
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Debug_Queue'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/debug/stations:
    get:
      tags:
        - 'Administration: Debugging'
      summary: 'List all stations with their debug links.'
      operationId: getAdminDebugStations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Debug_Station'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/debug/sync-tasks:
    get:
      tags:
        - 'Administration: Debugging'
      summary: 'List all sync tasks and details about their run times.'
      operationId: getAdminDebugSyncTasks
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Debug_SyncTask'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/station/{station_id}/nextsong':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Get the next song to be played by the AutoDJ for a given station.'
      operationId: adminDebugStationNextSong
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Debug_LogResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/station/{station_id}/nowplaying':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Generate the raw Now Playing data for a given station.'
      operationId: adminDebugStationNowPlaying
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Debug_LogResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/sync/{task}':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Manually run a scheduled synchronized task by name.'
      operationId: adminDebugRunSyncTask
      parameters:
        -
          name: task
          in: path
          description: 'Synchronized task (either class name or "all").'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Debug_LogResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/debug/station/{station_id}/telnet':
    put:
      tags:
        - 'Administration: Debugging'
      summary: 'Manually run a Telnet command on a station backend.'
      operationId: putAdminDebugTelnetCommand
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Debug_LogResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/geolite:
    get:
      tags:
        - 'Administration: General'
      summary: 'Get the current MaxMindDB GeoLite Database status.'
      operationId: getGeoLite
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_GeoLiteStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: General'
      summary: 'Set the GeoLite MaxMindDB Database license key.'
      operationId: postGeoLite
      requestBody:
        content:
          application/json:
            schema:
              properties:
                geolite_license_key:
                  type: string
                  nullable: true
              type: object
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_GeoLiteStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/logs:
    get:
      tags:
        - 'Administration: General'
      summary: 'List all available log types for viewing.'
      operationId: adminListLogs
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_LogType'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/log/{key}':
    get:
      tags:
        - 'Administration: General'
      summary: 'View a specific log contents.'
      operationId: adminViewLog
      parameters:
        -
          name: key
          in: path
          description: 'Log Key from listing return.'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_LogContents'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/permissions:
    get:
      tags:
        - 'Administration: Roles'
      summary: 'Return a list of all available permissions.'
      operationId: getPermissions
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Permissions'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/relays/list:
    get:
      tags:
        - 'Administration: General'
      summary: 'Return a list of all currently active AzuraRelay instances.'
      operationId: adminGetRelays
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Relay'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/roles:
    get:
      tags:
        - 'Administration: Roles'
      summary: 'List all current roles in the system.'
      operationId: getRoles
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Role'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: Roles'
      summary: 'Create a new role.'
      operationId: addRole
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Admin_Role'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Role'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/role/{id}':
    get:
      tags:
        - 'Administration: Roles'
      summary: 'Retrieve details for a single current role.'
      operationId: getRole
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_Role'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Roles'
      summary: 'Update details of a single role.'
      operationId: editRole
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Admin_Role'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: Roles'
      summary: 'Delete a single role.'
      operationId: deleteRole
      parameters:
        -
          name: id
          in: path
          description: 'Role ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/rsas/license:
    post:
      tags:
        - 'Administration: General'
      summary: 'Upload a new Rocket Streaming Audio Server (RSAS) license key.'
      operationId: postRsasLicense
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: General'
      summary: 'Removes the Rocket Streaming Audio Server (RSAS) license.'
      operationId: deleteRsasLicense
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/rsas:
    get:
      tags:
        - 'Administration: General'
      summary: 'Get the current Rocket Streaming Audio Server (RSAS) status.'
      operationId: getRsas
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_RsasStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: General'
      summary: 'Upload a new Rocket Streaming Audio Server (RSAS) binary.'
      operationId: postRsas
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/send-test-message:
    post:
      tags:
        - 'Administration: General'
      summary: 'Send a test e-mail to confirm mail delivery settings.'
      operationId: adminSendTestEmail
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/server/stats:
    get:
      tags:
        - 'Administration: General'
      summary: 'Return a list of all CPU usage stats.'
      operationId: getServerStats
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_ServerStats'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/services:
    get:
      tags:
        - 'Administration: General'
      summary: 'List the status of essential system services.'
      operationId: getServiceDetails
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_ServiceData'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/services/restart/{service}':
    post:
      tags:
        - 'Administration: General'
      summary: 'Restart the specified service.'
      operationId: restartService
      parameters:
        -
          name: service
          in: path
          description: 'Service name.'
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomField'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/settings:
    get:
      tags:
        - 'Administration: Settings'
      summary: 'List the current values of all editable system settings.'
      operationId: getSettings
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Settings'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Settings'
      summary: 'Update settings to modify any settings provided.'
      operationId: editSettings
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Settings'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/shoutcast:
    get:
      tags:
        - 'Administration: General'
      summary: 'Get details about the Shoutcast installation.'
      operationId: getShoutcast
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_ShoutcastStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: General'
      summary: 'Upload a new Shoutcast binary.'
      operationId: postShoutcast
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/station/{id}/clone':
    post:
      tags:
        - 'Administration: Stations'
      summary: 'Clone a station, preserving certain settings.'
      operationId: postAdminStationsClone
      parameters:
        -
          name: id
          in: path
          description: 'Station ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              properties:
                name:
                  description: 'The name of the newly cloned station.'
                  type: string
                description:
                  description: 'The description of the newly cloned station.'
                  type: string
                clone:
                  description: 'Which parts of the original station to clone.'
                  type: array
                  items: { type: string, enum: [media_storage, recordings_storage, podcasts_storage, playlists, mounts, remotes, streamers, permissions, webhooks] }
              type: object
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/stations/storage-locations:
    get:
      tags:
        - 'Administration: Stations'
      summary: 'List storage locations available for assignment to a station.'
      operationId: getAdminStationStorageLocations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  $ref: '#/components/schemas/Api_Form_SimpleOptions'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/stations:
    get:
      tags:
        - 'Administration: Stations'
      summary: 'List all current stations in the system.'
      operationId: adminGetStations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Station'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: Stations'
      summary: 'Create a new station.'
      operationId: adminAddStation
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Station'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Station'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/station/{id}':
    get:
      tags:
        - 'Administration: Stations'
      summary: 'Retrieve details for a single station.'
      operationId: adminGetStation
      parameters:
        -
          name: id
          in: path
          description: ID
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Station'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Stations'
      summary: 'Update details of a single station.'
      operationId: adminEditStation
      parameters:
        -
          name: id
          in: path
          description: ID
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Station'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: Stations'
      summary: 'Delete a single station.'
      operationId: adminDeleteStation
      parameters:
        -
          name: id
          in: path
          description: ID
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/stereo_tool:
    get:
      tags:
        - 'Administration: General'
      summary: 'Get information about the Stereo Tool installation.'
      operationId: getStereoTool
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_StereoToolStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: General'
      summary: 'Upload a new Stereo Tool binary.'
      operationId: postStereoTool
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: General'
      summary: 'Removes the installed Stereo Tool binary.'
      operationId: deleteStereoTool
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/storage_locations:
    get:
      tags:
        - 'Administration: Storage Locations'
      summary: 'List all current storage locations in the system.'
      operationId: getStorageLocations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_StorageLocation'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: Storage Locations'
      summary: 'Create a new storage location.'
      operationId: addStorageLocation
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Admin_StorageLocation'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_StorageLocation'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/storage_location/{id}':
    get:
      tags:
        - 'Administration: Storage Locations'
      summary: 'Retrieve details for a single storage location.'
      operationId: getStorageLocation
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_StorageLocation'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Storage Locations'
      summary: 'Update details of a single storage location.'
      operationId: editStorageLocation
      parameters:
        -
          name: id
          in: path
          description: 'Storage Location ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Admin_StorageLocation'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: Storage Locations'
      summary: 'Delete a single storage location.'
      operationId: deleteStorageLocation
      parameters:
        -
          name: id
          in: path
          description: 'Storage Location ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/updates:
    get:
      tags:
        - 'Administration: General'
      summary: 'Show information about this installation and its update status.'
      operationId: getUpdateStatus
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Admin_UpdateDetails'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: General'
      summary: 'Attempts to trigger a web-based update.'
      operationId: putWebUpdate
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /admin/users:
    get:
      tags:
        - 'Administration: Users'
      summary: 'List all current users in the system.'
      operationId: getUsers
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Administration: Users'
      summary: 'Create a new user.'
      operationId: addUser
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/admin/user/{id}':
    get:
      tags:
        - 'Administration: Users'
      summary: 'Retrieve details for a single current user.'
      operationId: getUser
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Administration: Users'
      summary: 'Update details of a single user.'
      operationId: editUser
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Administration: Users'
      summary: 'Delete a single user.'
      operationId: deleteUser
      parameters:
        -
          name: id
          in: path
          description: 'User ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/api-keys:
    get:
      tags:
        - 'My Account'
      summary: 'List all API keys associated with your account.'
      operationId: getMyApiKeys
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  allOf: [{ $ref: '#/components/schemas/ApiKey' }, { $ref: '#/components/schemas/HasLinks' }]
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'My Account'
      summary: 'Create a new API key associated with your account.'
      operationId: addMyApiKey
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiKey'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/Api_Account_NewApiKey' }
                  - { $ref: '#/components/schemas/ApiKey' }
                  - { $ref: '#/components/schemas/HasLinks' }
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/frontend/account/api-key/{id}':
    get:
      tags:
        - 'My Account'
      summary: 'Retrieve details for a single API key.'
      operationId: getMyApiKey
      parameters:
        -
          name: id
          in: path
          description: 'API Key ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/ApiKey' }
                  - { $ref: '#/components/schemas/HasLinks' }
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'My Account'
      summary: 'Delete a single API key associated with your account.'
      operationId: deleteMyApiKey
      parameters:
        -
          name: id
          in: path
          description: 'API Key ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/two-factor:
    get:
      tags:
        - 'My Account'
      summary: 'Get the current two-factor authentication status of your account.'
      operationId: getMyTwoFactor
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Account_TwoFactorStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'My Account'
      summary: 'Register a new two-factor authentication method.'
      operationId: putAccountTwoFactor
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'My Account'
      summary: 'Remove two-factor authentication from your account.'
      operationId: deleteMyTwoFactor
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/me:
    get:
      tags:
        - 'My Account'
      summary: 'Show the details for your current logged-in account.'
      operationId: getMe
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'My Account'
      summary: 'Save changes to your logged in account.'
      operationId: putMe
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/passkeys:
    get:
      tags:
        - 'My Account'
      summary: 'List currently registered passkeys.'
      operationId: getAccountListPasskeys
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/frontend/account/passkey/{id}':
    get:
      tags:
        - 'My Account'
      summary: 'Get the details of a single passkey.'
      operationId: getAccountGetPasskey
      parameters:
        -
          name: id
          in: path
          description: 'Passkey ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'My Account'
      summary: 'Delete a specified passkey by ID.'
      operationId: deleteAccountPasskey
      parameters:
        -
          name: id
          in: path
          description: 'Passkey ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/password:
    put:
      tags:
        - 'My Account'
      summary: 'Change the password of your account.'
      operationId: changeMyPassword
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Account_ChangePassword'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/account/webauthn/register:
    get:
      tags:
        - 'My Account'
      summary: 'Get registration details for WebAuthn registration.'
      operationId: getAccountWebAuthnRegister
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'My Account'
      summary: 'Submit a new registration request for WebAuthn.'
      operationId: putAccountWebAuthnRegister
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/dashboard/charts:
    put:
      tags:
        - Miscellaneous
      summary: 'Get the measurements for the dashboard charts.'
      operationId: getDashboardCharts
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/dashboard/notifications:
    get:
      tags:
        - Miscellaneous
      summary: 'Show all notifications your current account should see.'
      operationId: getNotifications
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Notification'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  /frontend/dashboard/stations:
    get:
      tags:
        - Miscellaneous
      summary: 'List stations that can be managed by the current user account on the dashboard.'
      operationId: getDashboardStations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Dashboard'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /status:
    get:
      tags:
        - 'Public: Miscellaneous'
      summary: 'Returns an affirmative response if the API is active.'
      operationId: getStatus
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_SystemStatus'
      security: []
  /time:
    get:
      tags:
        - 'Public: Miscellaneous'
      description: "Returns the time (with formatting) in GMT and the user's local time zone, if logged in."
      operationId: getTime
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Time'
      security: []
  /internal/relays:
    get:
      tags:
        - 'Administration: General'
      description: "Returns all necessary information to relay all 'relayable' stations."
      operationId: internalGetRelayDetails
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Admin_Relay'
  /nowplaying:
    get:
      tags:
        - 'Public: Now Playing'
      description: "Returns a full summary of all stations' current state."
      operationId: getAllNowPlaying
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_NowPlaying'
      security: []
  '/nowplaying/{station_id}':
    get:
      tags:
        - 'Public: Now Playing'
      description: "Returns a full summary of the specified station's current state."
      operationId: getStationNowPlaying
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_NowPlaying'
        '404':
          $ref: '#/components/responses/RecordNotFound'
      security: []
  '/nowplaying/{station_id}/art':
    get:
      tags:
        - 'Public: Now Playing'
      summary: 'Always redirects to the current art for the given station.'
      operationId: getStationNowPlayingArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '302':
          description: 'A temporary redirect to the correct resource.'
          headers:
            location:
              description: 'The current URL of the resource.'
              schema:
                type: string
        '404':
          $ref: '#/components/responses/RecordNotFound'
      security: []
  /openapi.yml:
    get:
      tags:
        - 'Public: Miscellaneous'
      summary: 'Returns the OpenAPI specification document for this installation.'
      operationId: getOpenApiSpec
      responses:
        '200':
          description: Success
          content:
            text/x-yaml:
              schema:
                description: 'The OpenAPI specification document for this installation.'
                type: string
                format: binary
      security: []
  /prometheus:
    get:
      tags:
        - Miscellaneous
      summary: 'Returns the Prometheus measurements for this installation.'
      operationId: getPrometheus
      responses:
        '200':
          description: Success
          content:
            text/plain:
              schema:
                description: 'The Prometheus measurements for this installation.'
                type: string
                format: binary
  '/station/{station_id}/art/{media_id}':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Returns the album art for a song, or a generic image.'
      operationId: getMediaArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: media_id
          in: path
          description: 'The station media unique ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithImage'
        '302':
          description: 'Image not found; generic filler image.'
          headers:
            location:
              description: 'The current URL of the resource.'
              schema:
                type: string
      security: []
    post:
      tags:
        - 'Stations: Media'
      summary: 'Sets the album art for a track.'
      operationId: postMediaArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: media_id
          in: path
          description: 'Media ID'
          required: true
          schema:
            anyOf:
              -
                type: integer
                format: int64
              -
                type: string
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Media'
      summary: 'Removes the album art for a track.'
      operationId: deleteMediaArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: media_id
          in: path
          description: 'Media ID'
          required: true
          schema:
            anyOf:
              -
                type: integer
                format: int64
              -
                type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/bulk':
    get:
      tags:
        - 'Stations: Media'
      summary: 'Download a CSV containing details about all station media.'
      operationId: getStationBulkMediaDownload
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            text/csv:
              schema:
                description: 'A CSV file containing bulk media details.'
                type: string
                format: binary
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Media'
      summary: 'Upload a CSV containing details about all station media.'
      operationId: postStationBulkMediaUpload
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/custom_assets/{type}':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the details of the custom asset of the specified type.'
      operationId: getStationCustomAsset
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_UploadedRecordStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: General'
      summary: 'Upload a new custom asset of the specified type.'
      operationId: postStationCustomAsset
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: General'
      summary: 'Removes the custom asset of the specified type.'
      operationId: deleteStationCustomAsset
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: type
          in: path
          description: 'Asset Type'
          required: true
          schema:
            type: string
            enum:
              - album_art
              - background
              - browser_icon
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/fallback':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the custom fallback track for a station.'
      operationId: getStationFallback
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_UploadedRecordStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: General'
      summary: 'Update the custom fallback track for the station.'
      operationId: postStationFallback
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: General'
      summary: 'Removes the custom fallback track for a station.'
      operationId: deleteStationFallback
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/batch':
    put:
      tags:
        - 'Stations: Media'
      summary: 'Perform a batch action on a collection of files/directories.'
      operationId: putStationFileBatchAction
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/download':
    get:
      tags:
        - 'Stations: Media'
      summary: 'Download a file by relative path.'
      operationId: getStationFileDownload
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: file
          in: query
          description: 'The relative path of the file in the Media filesystem.'
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/upload':
    post:
      tags:
        - 'Stations: Media'
      summary: 'Upload and process a new media file.'
      operationId: postUploadFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/list':
    get:
      tags:
        - 'Stations: Media'
      summary: 'List files in the media directory by path.'
      operationId: getStationFileList
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: currentDirectory
          in: query
          required: true
          schema:
            type: string
        -
          name: searchPhrase
          in: query
          schema:
            type: string
            nullable: true
        -
          name: flushCache
          in: query
          schema:
            type: boolean
            default: false
            nullable: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_FileList'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/directories':
    get:
      tags:
        - 'Stations: Media'
      summary: 'List directories in a station media library for moving/renaming.'
      operationId: getStationFileDirectories
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/mkdir':
    post:
      tags:
        - 'Stations: Media'
      summary: 'Create a directory in a station media directory.'
      operationId: postStationFilesMkdir
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/file/{id}/play':
    get:
      tags:
        - 'Stations: Media'
      summary: 'Download or play a given file by ID.'
      operationId: getPlayFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files/rename':
    put:
      tags:
        - 'Stations: Media'
      summary: 'Rename the specified files in the station media directory.'
      operationId: postStationFilesRename
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/files':
    get:
      tags:
        - 'Stations: Media'
      summary: 'List all current uploaded files.'
      operationId: getFiles
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationMedia'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Media'
      summary: 'Upload a new file.'
      operationId: addFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_UploadFile'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationMedia'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/file/{id}':
    get:
      tags:
        - 'Stations: Media'
      summary: 'Retrieve details for a single file.'
      operationId: getFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationMedia'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Media'
      summary: 'Update details of a single file.'
      operationId: editFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_StationMedia'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Media'
      summary: 'Delete a single file.'
      operationId: deleteFile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/quota':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the current usage and quota for a given station storage location.'
      operationId: getQuota
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationQuota'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/quota/{type}':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the current usage and quota for a given station storage location.'
      operationId: getQuotaOfType
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: type
          in: path
          description: 'The storage location type (i.e. station_media, station_recordings, station_podcasts)'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationQuota'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/restart-status':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the pending restart status for a station.'
      operationId: getRestartStatus
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationRestartStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/history':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Return song playback history items for a given station.'
      operationId: getStationHistory
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: start
          in: query
          description: 'The start date for records, in PHP-supported date/time format. (https://www.php.net/manual/en/datetime.formats.php)'
          required: false
          schema:
            type: string
        -
          name: end
          in: query
          description: 'The end date for records, in PHP-supported date/time format. (https://www.php.net/manual/en/datetime.formats.php)'
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_DetailedSongHistory'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/hls_streams':
    get:
      tags:
        - 'Stations: HLS Streams'
      summary: 'List all current HLS streams.'
      operationId: getHlsStreams
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StationHlsStream'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: HLS Streams'
      summary: 'Create a new HLS stream.'
      operationId: addHlsStream
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationHlsStream'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationHlsStream'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/hls_stream/{id}':
    get:
      tags:
        - 'Stations: HLS Streams'
      summary: 'Retrieve details for a single HLS stream.'
      operationId: getHlsStream
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'HLS Stream ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationHlsStream'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: HLS Streams'
      summary: 'Update details of a single HLS stream.'
      operationId: editHlsStream
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'HLS Stream ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationHlsStream'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: HLS Streams'
      summary: 'Delete a single HLS stream.'
      operationId: deleteHlsStream
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'HLS Stream ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  /stations:
    get:
      tags:
        - 'Public: Stations'
      summary: 'Returns a list of stations.'
      operationId: getStations
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_NowPlaying_Station'
      security: []
  '/station/{station_id}':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Return information about a single station.'
      operationId: getStation
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_NowPlaying_Station'
        '404':
          $ref: '#/components/responses/RecordNotFound'
      security: []
  '/station/{station_id}/liquidsoap-config':
    get:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Get the generated and editable sections of the station Liquidsoap configuration.'
      operationId: getStationLiquidsoapConfig
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Save the editable sections of the station Liquidsoap configuration.'
      operationId: putStationLiquidsoapConfig
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/listeners':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Return detailed information about current listeners.'
      operationId: getStationListeners
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Listener'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/logs':
    get:
      tags:
        - 'Stations: General'
      summary: 'Return a list of available logs for the given station.'
      operationId: getStationLogs
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_LogType'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/log/{key}':
    get:
      tags:
        - 'Stations: General'
      summary: 'View a specific log contents for the given station.'
      operationId: getStationLog
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: key
          in: path
          description: 'Log Key from listing return.'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_LogContents'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/mount/{id}/intro':
    get:
      tags:
        - 'Stations: Mount Points'
      summary: 'Get the intro track for a mount point.'
      operationId: getMountIntro
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Mount Points'
      summary: 'Update the intro track for a mount point.'
      operationId: postMountIntro
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Mount Points'
      summary: 'Removes the intro track for a mount point.'
      operationId: deleteMountIntro
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/mounts':
    get:
      tags:
        - 'Stations: Mount Points'
      summary: 'List all current mount points.'
      operationId: getStationMounts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StationMount'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Mount Points'
      summary: 'Create a new mount point.'
      operationId: addMount
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationMount'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationMount'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/mount/{id}':
    get:
      tags:
        - 'Stations: Mount Points'
      summary: 'Retrieve details for a single mount point.'
      operationId: getMount
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationMount'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Mount Points'
      summary: 'Update details of a single mount point.'
      operationId: editMount
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationMount'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Mount Points'
      summary: 'Delete a single mount point.'
      operationId: deleteMount
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Mount Point ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/ondemand/download/{media_id}':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Download an on-demand playlist file by media unique ID.'
      operationId: getStationOnDemandDownload
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: media_id
          in: path
          description: 'The media unique ID to download.'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/ondemand':
    get:
      tags:
        - 'Public: Stations'
      summary: 'List all tracks available on-demand for this station.'
      operationId: getStationOnDemand
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationOnDemand'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/playlist/{id}/clone':
    post:
      tags:
        - 'Stations: Playlists'
      summary: 'Create a copy of the specified playlist.'
      operationId: postStationPlaylistClone
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              properties:
                name:
                  description: 'The name of the newly cloned playlist.'
                  type: string
                clone:
                  description: 'Which parts of the original playlist to clone.'
                  type: array
                  items: { type: string, enum: [schedule, media] }
              type: object
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/queue':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'Get the current playback queue for the specified playlist.'
      operationId: getStationPlaylistQueue
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationPlaylistQueue'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Playlists'
      summary: 'Reset the internal playback queue of a shuffled, song-based playlist.'
      operationId: deletePlaylistQueue
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/empty':
    delete:
      tags:
        - 'Stations: Playlists'
      summary: 'Empty the contents of a song-based playlist.'
      operationId: deleteEmptyPlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/export/{format}':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'Export a playlist contents in standard media player playlist format.'
      operationId: getExportPlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
        -
          name: format
          in: path
          description: 'Export Playlist Format'
          required: true
          schema:
            type: string
            default: pls
            enum:
              - pls
              - m3u
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/apply-to':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'Get a list of directories that the given playlist can apply to.'
      operationId: getStationPlaylistApplyTo
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Playlists'
      summary: 'Apply the specified playlist to the specified directories.'
      operationId: putStationPlaylistApplyTo
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/order':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'Get the current order of sequential tracks in the specified playlist.'
      operationId: getStationPlaylistOrder
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Playlists'
      summary: 'Set the order of sequential tracks in the specified playlist.'
      operationId: putStationPlaylistOrder
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/import':
    post:
      tags:
        - 'Stations: Playlists'
      summary: 'Import the contents of an uploaded playlist (PLS/M3U) file into the specified playlist.'
      operationId: getStationPlaylistImport
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/reshuffle':
    put:
      tags:
        - 'Stations: Playlists'
      summary: 'Re-shuffle a playlist whose playback order is "shuffled".'
      operationId: putReshufflePlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}/toggle':
    put:
      tags:
        - 'Stations: Playlists'
      summary: 'Toggle a playlist between enabled and disabled status.'
      operationId: putTogglePlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlists':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'List all current playlists.'
      operationId: getPlaylists
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StationPlaylist'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Playlists'
      summary: 'Create a new playlist.'
      operationId: addPlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationPlaylist'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationPlaylist'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/playlist/{id}':
    get:
      tags:
        - 'Stations: Playlists'
      summary: 'Retrieve details for a single playlist.'
      operationId: getPlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationPlaylist'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Playlists'
      summary: 'Update details of a single playlist.'
      operationId: editPlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationPlaylist'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Playlists'
      summary: 'Delete a single playlist relay.'
      operationId: deletePlaylist
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Playlist ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{podcast_id}/episodes':
    get:
      tags:
        - 'Stations: Podcasts'
      summary: 'List all current episodes for a given podcast ID.'
      operationId: getEpisodes
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_PodcastEpisode'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Podcasts'
      summary: 'Create a new podcast episode.'
      operationId: addEpisode
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_PodcastEpisode'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_PodcastEpisode'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{podcast_id}/episode/{id}':
    get:
      tags:
        - 'Stations: Podcasts'
      summary: 'Retrieve details for a single podcast episode.'
      operationId: getEpisode
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_PodcastEpisode'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Podcasts'
      summary: 'Update details of a single podcast episode.'
      operationId: editEpisode
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_PodcastEpisode'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Podcasts'
      summary: 'Delete a single podcast episode.'
      operationId: deleteEpisode
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{podcast_id}/art':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Gets the album art for a podcast.'
      operationId: getPodcastArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithImage'
        '302':
          description: 'A temporary redirect to the correct resource.'
          headers:
            location:
              description: 'The current URL of the resource.'
              schema:
                type: string
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
    post:
      tags:
        - 'Stations: Podcasts'
      summary: 'Sets the album art for a podcast.'
      operationId: postPodcastArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Podcasts'
      summary: 'Removes the album art for a podcast.'
      operationId: deletePodcastArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{podcast_id}/batch':
    post:
      tags:
        - 'Stations: Playlists'
      summary: 'Import the contents of an uploaded playlist (PLS/M3U) file into the specified playlist.'
      operationId: postStationPodcastBatch
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                do:
                  description: 'The action to take with the specified rows.'
                  type: string
                  enum: [list, delete, edit]
                episodes:
                  description: 'The IDs to perform batch actions on.'
                  type: array
                  items: { type: string }
              type: object
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_PodcastBatchResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Gets the album art for a podcast episode.'
      operationId: getPodcastEpisodeArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithImage'
        '302':
          description: 'A temporary redirect to the correct resource.'
          headers:
            location:
              description: 'The current URL of the resource.'
              schema:
                type: string
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
    post:
      tags:
        - 'Stations: Podcasts'
      summary: 'Sets the album art for a podcast episode.'
      operationId: postPodcastEpisodeArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Podcasts'
      summary: 'Removes the album art for a podcast episode.'
      operationId: deletePodcastEpisodeArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Status'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/public/podcast/{podcast_id}/episode/{episode_id}':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Get information for a public episode of a public podcast.'
      operationId: getStationPublicPodcastEpisode
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_PodcastEpisode'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/public/podcast/{podcast_id}/episodes':
    get:
      tags:
        - 'Public: Stations'
      summary: 'List all visible episodes for a given podcast.'
      operationId: getStationPublicPodcastEpisodes
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_PodcastEpisode'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Gets the media for a podcast episode.'
      operationId: getPodcastEpisodeMedia
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
    post:
      tags:
        - 'Stations: Podcasts'
      summary: 'Sets the media for a podcast episode.'
      operationId: postPodcastEpisodeMedia
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Podcasts'
      summary: 'Removes the media for a podcast episode.'
      operationId: deletePodcastEpisodeMedia
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
        -
          name: episode_id
          in: path
          description: 'Podcast Episode ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/public/podcast/{podcast_id}':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Get the public information for a given podcast.'
      operationId: getStationPublicPodcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Podcast'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/public/podcasts':
    get:
      tags:
        - 'Public: Stations'
      summary: 'List all visible public podcasts.'
      operationId: getStationPublicPodcasts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: podcast_id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Podcast'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/podcasts/playlists':
    get:
      tags:
        - 'Stations: Podcasts'
      summary: 'Get a list of playlists that can be associated with a podcast.'
      operationId: getStationPodcastPlaylists
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Form_SimpleOptions'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcasts':
    get:
      tags:
        - 'Stations: Podcasts'
      summary: 'List all current podcasts.'
      operationId: getPodcasts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_Podcast'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Podcasts'
      summary: 'Create a new podcast.'
      operationId: addPodcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Podcast'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Podcast'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/podcast/{id}':
    get:
      tags:
        - 'Stations: Podcasts'
      summary: 'Retrieve details for a single podcast.'
      operationId: getPodcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_Podcast'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Podcasts'
      summary: 'Update details of a single podcast.'
      operationId: editPodcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_Podcast'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Podcasts'
      summary: 'Delete a single podcast.'
      operationId: deletePodcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Podcast ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/profile':
    get:
      tags:
        - 'Stations: General'
      summary: 'Retrieve the profile of the given station.'
      operationId: getStationProfile
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationProfile'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/profile/edit':
    get:
      tags:
        - 'Stations: General'
      summary: 'Get the editable profile for the current station.'
      description: "This controller handles the specific \"Edit Profile\" function on a station's profile, which has different permissions\nand possible actions than the Admin Station Edit function."
      operationId: getStationProfileEdit
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: General'
      summary: 'Save the station profile for the current station.'
      operationId: putStationProfileEdit
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/queue':
    get:
      tags:
        - 'Stations: Queue'
      summary: 'Return information about the upcoming song playback queue.'
      operationId: getQueue
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationQueueDetailed'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/queue/{id}':
    get:
      tags:
        - 'Stations: Queue'
      summary: 'Retrieve details of a single queued item.'
      operationId: getQueueItem
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Queue Item ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationQueueDetailed'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Queue'
      summary: 'Delete a single queued item.'
      operationId: deleteQueueItem
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Queue Item ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/remotes':
    get:
      tags:
        - 'Stations: Remote Relays'
      summary: 'List all current remote relays.'
      operationId: getRelays
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationRemote'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Remote Relays'
      summary: 'Create a new remote relay.'
      operationId: addRelay
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_StationRemote'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationRemote'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/remote/{id}':
    get:
      tags:
        - 'Stations: Remote Relays'
      summary: 'Retrieve details for a single remote relay.'
      operationId: getRelay
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Remote Relay ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationRemote'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Remote Relays'
      summary: 'Update details of a single remote relay.'
      operationId: editRelay
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Remote Relay ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Api_StationRemote'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Remote Relays'
      summary: 'Delete a single remote relay.'
      operationId: deleteRelay
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Remote Relay ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/best-and-worst':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Best and Worst Performing Songs" report for a station.'
      operationId: getStationReportBestAndWorst
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/by-browser':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Listeners by Browser" report for a station.'
      operationId: getStationReportByBrowser
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/by-client':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Listeners by Client" report for a station.'
      operationId: getStationReportByClient
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/by-country':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Listeners by Country" report for a station.'
      operationId: getStationReportByCountry
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/by-listening-time':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Listeners by Listening Time" report for a station.'
      operationId: getStationReportByListeningTime
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/by-stream':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get the "Listeners by Stream" report for a station.'
      operationId: getStationReportByStream
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/overview/charts':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Get chart data for the station reports.'
      operationId: getStationReportCharts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/requests':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'List station requests.'
      operationId: getStationRequestsReport
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/requests/clear':
    post:
      tags:
        - 'Stations: Reports'
      summary: 'Clear all unplayed station requests.'
      operationId: postStationRequestsClear
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/requests/{request_id}':
    delete:
      tags:
        - 'Stations: Reports'
      summary: 'Delete an individual station request.'
      operationId: deleteStationRequest
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: request_id
          in: path
          description: 'Request ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/reports/soundexchange':
    get:
      tags:
        - 'Stations: Reports'
      summary: 'Generate a SoundExchange royalty report.'
      description: 'Produce a report in SoundExchange (the US webcaster licensing agency) format.'
      operationId: getStationSoundExchangeReport
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: start_date
          in: query
          required: false
          schema:
            type: string
            format: date
        -
          name: end_date
          in: query
          required: false
          schema:
            type: string
            format: date
      responses:
        '200':
          description: Success
          content:
            text/plain:
              schema:
                description: 'A CSV report for the given time range.'
                type: string
                format: binary
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/requests':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Return a list of requestable songs.'
      operationId: getRequestableSongs
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationRequest'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/request/{request_id}':
    post:
      tags:
        - 'Public: Stations'
      summary: 'Submit a song request.'
      operationId: submitSongRequest
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: request_id
          in: path
          description: 'The requestable song ID'
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/schedule':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Return upcoming and currently ongoing schedule entries.'
      operationId: getSchedule
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: now
          in: query
          description: 'The date/time to compare schedule items to. Defaults to the current date and time.'
          required: false
          schema:
            type: string
        -
          name: rows
          in: query
          description: 'The number of upcoming/ongoing schedule entries to return. Defaults to 5.'
          required: false
          schema:
            type: integer
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationSchedule'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
  '/station/{station_id}/status':
    get:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Retrieve the current status of all serivces associated with the radio broadcast.'
      operationId: getServiceStatus
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_StationServiceStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/restart':
    post:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Restart all services associated with the radio broadcast.'
      operationId: restartServices
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/frontend/{action}':
    post:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Perform service control actions on the radio frontend (Icecast, Shoutcast, etc.)'
      operationId: doFrontendServiceAction
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: action
          in: path
          description: 'The action to perform.'
          required: true
          schema:
            type: string
            default: restart
            enum:
              - start
              - stop
              - reload
              - restart
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/backend/{action}':
    post:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Perform service control actions on the radio backend (Liquidsoap)'
      operationId: doBackendServiceAction
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: action
          in: path
          description: 'The action to perform.'
          required: true
          schema:
            type: string
            default: restart
            enum:
              - skip
              - disconnect
              - start
              - stop
              - reload
              - restart
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/sftp-users':
    get:
      tags:
        - 'Stations: SFTP Users'
      summary: 'List all current SFTP users.'
      operationId: getSftpUsers
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SftpUser'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: SFTP Users'
      summary: 'Create a new SFTP user.'
      operationId: addSftpUser
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SftpUser'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SftpUser'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/sftp-user/{id}':
    get:
      tags:
        - 'Stations: SFTP Users'
      summary: 'Retrieve details for a single SFTP user.'
      operationId: getSftpUser
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'SFTP User ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SftpUser'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: SFTP Users'
      summary: 'Update details of a single SFTP user.'
      operationId: editSftpUser
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'SFTP User ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SftpUser'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: SFTP Users'
      summary: 'Delete a single SFTP user.'
      operationId: deleteSftpUser
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'SFTP User ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/stereo-tool-configuration':
    get:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Get the Stereo Tool configuration file for a station.'
      operationId: getStereoToolConfiguration
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_UploadedRecordStatus'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Update the Stereo Tool configuration file for a station.'
      operationId: postStereoToolConfiguration
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Broadcasting'
      summary: 'Removes the Stereo Tool configuration file for a station.'
      operationId: deleteStereoToolConfiguration
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}/art':
    get:
      tags:
        - 'Public: Stations'
      summary: 'Gets the default album art for a streamer.'
      operationId: getStreamerArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithImage'
        '302':
          description: 'A temporary redirect to the correct resource.'
          headers:
            location:
              description: 'The current URL of the resource.'
              schema:
                type: string
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
      security: []
    post:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Sets the default album art for a streamer.'
      operationId: postStreamerArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        $ref: '#/components/requestBodies/FlowFileUpload'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Removes the default album art for a streamer.'
      operationId: deleteStreamerArt
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}/broadcasts/batch':
    post:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Perform batch actions on the specified broadcasts.'
      operationId: postStationStreamerBroadcastsBatch
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              properties:
                do:
                  description: 'The action to take with the specified rows.'
                  type: string
                  enum: [delete]
                rows:
                  description: 'The IDs to perform batch actions on.'
                  type: array
                  items: { type: integer, format: int64 }
              type: object
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_GenericBatchResult'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamers/broadcasts':
    get:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'List all broadcasts associated with the station.'
      operationId: getStationAllBroadcasts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationStreamerBroadcast'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}/broadcasts':
    get:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'List all broadcasts associated with the specified streamer.'
      operationId: getStationStreamerBroadcasts
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Api_StationStreamerBroadcast'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}/broadcast/{broadcast_id}/download':
    get:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Download a single broadcast from a streamer.'
      operationId: getStationStreamerDownloadBroadcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
        -
          name: broadcast_id
          in: path
          description: 'Broadcast ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/SuccessWithDownload'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}/broadcast/{broadcast_id}':
    delete:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Remove a single broadcast from a streamer.'
      operationId: getStationStreamerDeleteBroadcast
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
        -
          name: broadcast_id
          in: path
          description: 'Broadcast ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamers':
    get:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'List all current Streamer/DJ accounts for the specified station.'
      operationId: getStreamers
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StationStreamer'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Create a new Streamer/DJ account.'
      operationId: addStreamer
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationStreamer'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationStreamer'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/streamer/{id}':
    get:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Retrieve details for a single Streamer/DJ account.'
      operationId: getStreamer
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationStreamer'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Update details of a single Streamer/DJ account.'
      operationId: editStreamer
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Streamer ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationStreamer'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Streamers/DJs'
      summary: 'Delete a single Streamer/DJ account.'
      operationId: deleteStreamer
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'StationStreamer ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/nowplaying/update':
    post:
      tags:
        - 'Stations: General'
      summary: 'Manually update the Now Playing metadata for the station.'
      operationId: postStationNowPlayingUpdate
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/waveform/{media_id}':
    get:
      tags:
        - 'Stations: Media'
      summary: 'Get waveform data for a media ID (for the Visual Cue Editor).'
      operationId: getStationMediaWaveform
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Media'
      summary: 'Save cached waveform data for a media ID (for the Visual Cue Editor).'
      operationId: postStationMediaWaveform
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Media ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/webhook/{id}/test':
    put:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Send a test dispatch of a webhook with the current Now Playing data for the station.'
      operationId: putStationWebhookTest
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_TaskWithLog'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/webhooks/{id}/test-log/{path}':
    get:
      tags:
        - 'Stations: Web Hooks'
      summary: 'View a specific webhook test dispatch log contents.'
      operationId: getWebhookTestLog
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
        -
          name: path
          in: path
          description: 'Log path as returned by the Test action.'
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Api_LogContents'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/webhook/{id}/toggle':
    put:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Toggle the enabled/disabled status of a webhook.'
      operationId: putStationWebhookToggle
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/webhooks':
    get:
      tags:
        - 'Stations: Web Hooks'
      summary: 'List all current web hooks.'
      operationId: getWebhooks
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/StationWebhook'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    post:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Create a new web hook.'
      operationId: addWebhook
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationWebhook'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationWebhook'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
  '/station/{station_id}/webhook/{id}':
    get:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Retrieve details for a single web hook.'
      operationId: getWebhook
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StationWebhook'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    put:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Update details of a single web hook.'
      operationId: editWebhook
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StationWebhook'
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
    delete:
      tags:
        - 'Stations: Web Hooks'
      summary: 'Delete a single web hook.'
      operationId: deleteWebhook
      parameters:
        -
          $ref: '#/components/parameters/StationIdRequired'
        -
          name: id
          in: path
          description: 'Web Hook ID'
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '200':
          $ref: '#/components/responses/Success'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/RecordNotFound'
        '500':
          $ref: '#/components/responses/GenericError'
components:
  schemas:
    Api_Account_ChangePassword:
      required:
        - current_password
        - new_password
      properties:
        current_password:
          description: 'The current account password.'
          type: string
          writeOnly: true
        new_password:
          description: 'The new account password.'
          type: string
          writeOnly: true
      type: object
    Api_Account_NewApiKey:
      required:
        - key
      properties:
        key:
          description: 'The newly generated API key.'
          type: string
          readOnly: true
      type: object
    Api_Account_TwoFactorStatus:
      required:
        - two_factor_enabled
      properties:
        two_factor_enabled:
          description: 'The current two-factor status for this account.'
          type: boolean
          readOnly: true
      type: object
    Api_Admin_AuditLog:
      required:
        - id
        - timestamp
        - operation
        - operation_text
        - class
        - identifier
        - target_class
        - target
        - user
        - changes
      properties:
        id:
          type: integer
        timestamp:
          type: string
          format: date-time
        operation:
          type: integer
          enum:
            - 1
            - 2
            - 3
        operation_text:
          type: string
        class:
          type: string
        identifier:
          type: string
        target_class:
          type: string
          nullable: true
        target:
          type: string
          nullable: true
        user:
          type: string
          nullable: true
        changes:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_AuditLogChangeset'
      type: object
    Api_Admin_AuditLogChangeset:
      required:
        - field
        - from
        - to
      properties:
        field:
          type: string
        from:
          type: string
        to:
          type: string
      type: object
    Api_Admin_Backup:
      required:
        - path
        - basename
        - pathEncoded
        - timestamp
        - size
        - storageLocationId
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            path:
              type: string
            basename:
              type: string
            pathEncoded:
              type: string
            timestamp:
              type: integer
            size:
              type: integer
            storageLocationId:
              type: integer
          type: object
    Api_Admin_Debug_Queue:
      required:
        - name
        - count
        - url
      properties:
        name:
          type: string
          enum:
            - high_priority
            - normal_priority
            - low_priority
            - search_index
            - media
            - podcast_media
        count:
          type: integer
        url:
          type: string
      type: object
    Api_Admin_Debug_Station:
      required:
        - id
        - name
        - clearQueueUrl
        - getNextSongUrl
        - getNowPlayingUrl
      properties:
        id:
          type: integer
        name:
          type: string
        clearQueueUrl:
          type: string
        getNextSongUrl:
          type: string
        getNowPlayingUrl:
          type: string
      type: object
    Api_Admin_Debug_LogEntry:
      required:
        - datetime
        - channel
        - level
        - message
        - context
        - extra
        - formatted
      properties:
        datetime:
          type: string
          format: date-time
        channel:
          type: string
        level:
          type: integer
          enum:
            - 100
            - 200
            - 250
            - 300
            - 400
            - 500
            - 550
            - 600
        message:
          type: string
        context:
          type: array
          items:
            type: '{}'
        extra:
          type: array
          items:
            type: '{}'
        formatted:
          type: '{}'
          nullable: true
      type: object
    Api_Admin_Debug_LogResult:
      required:
        - logs
      properties:
        logs:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_Debug_LogEntry'
      type: object
    Api_Admin_Debug_SyncTask:
      required:
        - task
        - pattern
        - time
        - nextRun
        - url
      properties:
        task:
          type: string
        pattern:
          type: string
          nullable: true
        time:
          type: integer
        nextRun:
          type: integer
        url:
          type: string
      type: object
    Api_Admin_GeoLiteStatus:
      required:
        - version
        - key
      properties:
        version:
          type: string
          nullable: true
        key:
          type: string
          nullable: true
      type: object
    Api_Admin_Permission:
      required:
        - id
        - name
      properties:
        id:
          type: string
        name:
          type: string
      type: object
    Api_Admin_Permissions:
      required:
        - global
        - station
      properties:
        global:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_Permission'
        station:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_Permission'
      type: object
    Api_Admin_Relay:
      properties:
        id:
          description: 'Station ID'
          type: integer
          example: 1
        name:
          description: 'Station name'
          type: string
          example: 'AzuraTest Radio'
          nullable: true
        shortcode:
          description: 'Station "short code", used for URL and folder paths'
          type: string
          example: azuratest_radio
          nullable: true
        description:
          description: 'Station description'
          type: string
          example: 'An AzuraCast station!'
          nullable: true
        url:
          description: 'Station homepage URL'
          type: string
          example: 'https://www.azuracast.com/'
          nullable: true
        genre:
          description: 'The genre of the station'
          type: string
          example: Variety
          nullable: true
        type:
          description: 'Which broadcasting software (frontend) the station uses'
          type: string
          example: shoutcast2
          nullable: true
        port:
          description: 'The port used by this station to serve its broadcasts.'
          type: integer
          example: 8000
          nullable: true
        relay_pw:
          description: 'The relay password for the frontend (if applicable).'
          type: string
          example: p4ssw0rd
        admin_pw:
          description: 'The administrator password for the frontend (if applicable).'
          type: string
          example: p4ssw0rd
        mounts:
          type: array
          items:
            $ref: '#/components/schemas/Api_NowPlaying_StationMount'
      type: object
    Api_Admin_Role:
      required:
        - name
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: integer
              readOnly: true
            name:
              type: string
              example: 'Super Administrator'
            permissions:
              $ref: '#/components/schemas/Api_Admin_RolePermissions'
            is_super_admin:
              description: 'Whether this role is the protected "Super Administrator" role.'
              type: boolean
              readOnly: true
          type: object
    Api_Admin_RolePermissions:
      properties:
        global:
          type: array
          items:
            $ref: '#/components/schemas/GlobalPermissions'
        station:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_RoleStationPermission'
      type: object
    Api_Admin_RoleStationPermission:
      required:
        - id
        - permissions
      properties:
        id:
          description: 'The station ID.'
          type: integer
        permissions:
          type: array
          items:
            $ref: '#/components/schemas/StationPermissions'
      type: object
    Api_Admin_RsasStatus:
      required:
        - version
        - hasLicense
      properties:
        version:
          type: string
          nullable: true
        hasLicense:
          type: boolean
      type: object
    Api_Admin_ServerStats_CpuStats:
      required:
        - total
        - cores
        - load
      properties:
        total:
          $ref: '#/components/schemas/Api_Admin_ServerStats_CpuStatsSection'
        cores:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_ServerStats_CpuStatsSection'
        load:
          type: array
          items:
            type: integer
            format: int64
      type: object
    Api_Admin_ServerStats_CpuStatsSection:
      required:
        - name
        - usage
        - idle
        - io_wait
        - steal
      properties:
        name:
          type: string
        usage:
          type: string
        idle:
          type: string
        io_wait:
          type: string
        steal:
          type: string
      type: object
    Api_Admin_ServerStats_MemoryStats:
      required:
        - total_bytes
        - total_readable
        - free_bytes
        - free_readable
        - buffers_bytes
        - buffers_readable
        - cached_bytes
        - cached_readable
        - sReclaimable_bytes
        - sReclaimable_readable
        - shmem_bytes
        - shmem_readable
        - used_bytes
        - used_readable
      properties:
        total_bytes:
          type: string
        total_readable:
          type: string
        free_bytes:
          type: string
        free_readable:
          type: string
        buffers_bytes:
          type: string
        buffers_readable:
          type: string
        cached_bytes:
          type: string
        cached_readable:
          type: string
        sReclaimable_bytes:
          type: string
        sReclaimable_readable:
          type: string
        shmem_bytes:
          type: string
        shmem_readable:
          type: string
        used_bytes:
          type: string
        used_readable:
          type: string
      type: object
    Api_Admin_ServerStats_NetworkInterfaceReceived:
      required:
        - speed_bytes
        - speed_readable
        - packets
        - errs
        - drop
        - fifo
        - frame
        - compressed
        - multicast
      properties:
        speed_bytes:
          type: string
        speed_readable:
          type: string
        packets:
          type: string
        errs:
          type: string
        drop:
          type: string
        fifo:
          type: string
        frame:
          type: string
        compressed:
          type: string
        multicast:
          type: string
      type: object
    Api_Admin_ServerStats_NetworkInterfaceStats:
      required:
        - interface_name
        - received
        - transmitted
      properties:
        interface_name:
          type: string
        received:
          $ref: '#/components/schemas/Api_Admin_ServerStats_NetworkInterfaceReceived'
        transmitted:
          $ref: '#/components/schemas/Api_Admin_ServerStats_NetworkInterfaceTransmitted'
      type: object
    Api_Admin_ServerStats_NetworkInterfaceTransmitted:
      required:
        - speed_bytes
        - speed_readable
        - packets
        - errs
        - drop
        - fifo
        - frame
        - carrier
        - compressed
      properties:
        speed_bytes:
          type: string
        speed_readable:
          type: string
        packets:
          type: string
        errs:
          type: string
        drop:
          type: string
        fifo:
          type: string
        frame:
          type: string
        carrier:
          type: string
        compressed:
          type: string
      type: object
    Api_Admin_ServerStats:
      required:
        - cpu
        - memory
        - swap
        - disk
        - network
      properties:
        cpu:
          $ref: '#/components/schemas/Api_Admin_ServerStats_CpuStats'
        memory:
          $ref: '#/components/schemas/Api_Admin_ServerStats_MemoryStats'
        swap:
          $ref: '#/components/schemas/Api_Admin_ServerStats_StorageStats'
        disk:
          $ref: '#/components/schemas/Api_Admin_ServerStats_StorageStats'
        network:
          type: array
          items:
            $ref: '#/components/schemas/Api_Admin_ServerStats_NetworkInterfaceStats'
      type: object
    Api_Admin_ServerStats_StorageStats:
      required:
        - total_bytes
        - total_readable
        - free_bytes
        - free_readable
        - used_bytes
        - used_readable
      properties:
        total_bytes:
          type: string
        total_readable:
          type: string
        free_bytes:
          type: string
        free_readable:
          type: string
        used_bytes:
          type: string
        used_readable:
          type: string
      type: object
    Api_Admin_ServiceData:
      required:
        - name
        - description
        - running
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            name:
              type: string
            description:
              type: string
            running:
              type: boolean
          type: object
    Api_Admin_ShoutcastStatus:
      required:
        - version
      properties:
        version:
          type: string
          nullable: true
      type: object
    Api_Admin_StereoToolStatus:
      required:
        - version
      properties:
        version:
          type: string
          nullable: true
      type: object
    Api_Admin_StorageLocation:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: integer
              example: 1
            type:
              description: 'The type of storage location.'
              type: string
              example: station_media
            adapter:
              description: 'The storage adapter to use for this location.'
              type: string
              example: local
            path:
              description: 'The local path, if the local adapter is used, or path prefix for S3/remote adapters.'
              type: string
              example: /var/azuracast/stations/azuratest_radio/media
              nullable: true
            s3CredentialKey:
              description: 'The credential key for S3 adapters.'
              type: string
              example: your-key-here
              nullable: true
            s3CredentialSecret:
              description: 'The credential secret for S3 adapters.'
              type: string
              example: your-secret-here
              nullable: true
            s3Region:
              description: 'The region for S3 adapters.'
              type: string
              example: your-region
              nullable: true
            s3Version:
              description: 'The API version for S3 adapters.'
              type: string
              example: latest
              nullable: true
            s3Bucket:
              description: 'The S3 bucket name for S3 adapters.'
              type: string
              example: your-bucket-name
              nullable: true
            s3Endpoint:
              description: 'The optional custom S3 endpoint S3 adapters.'
              type: string
              example: 'https://your-region.digitaloceanspaces.com'
              nullable: true
            dropboxAppKey:
              description: 'The optional Dropbox App Key.'
              type: string
              example: ''
              nullable: true
            dropboxAppSecret:
              description: 'The optional Dropbox App Secret.'
              type: string
              example: ''
              nullable: true
            dropboxAuthToken:
              description: 'The optional Dropbox Auth Token.'
              type: string
              example: ''
              nullable: true
            sftpHost:
              description: 'The host for SFTP adapters'
              type: string
              example: 127.0.0.1
              nullable: true
            sftpUsername:
              description: 'The username for SFTP adapters'
              type: string
              example: root
              nullable: true
            sftpPassword:
              description: 'The password for SFTP adapters'
              type: string
              example: abc123
              nullable: true
            sftpPort:
              description: 'The port for SFTP adapters'
              type: integer
              example: 20
              nullable: true
            sftpPrivateKey:
              description: 'The private key for SFTP adapters'
              type: string
              nullable: true
            sftpPrivateKeyPassPhrase:
              description: 'The private key pass phrase for SFTP adapters'
              type: string
              nullable: true
            storageQuota:
              type: string
              example: '50 GB'
              nullable: true
            storageQuotaBytes:
              type: string
              example: '120000'
              nullable: true
            storageUsed:
              type: string
              example: '1 GB'
              nullable: true
            storageUsedBytes:
              type: string
              example: '60000'
              nullable: true
            storageAvailable:
              type: string
              example: '1 GB'
              nullable: true
            storageAvailableBytes:
              type: string
              example: '120000'
              nullable: true
            storageUsedPercent:
              type: integer
              example: '75'
              nullable: true
            isFull:
              type: boolean
              example: 'true'
            uri:
              description: 'The URI associated with the storage location.'
              type: string
              example: /var/azuracast/www
            stations:
              description: 'The stations using this storage location, if any.'
              type: array
              items:
                type: string
                example: 'AzuraTest Radio'
              nullable: true
          type: object
    Api_Admin_UpdateDetails:
      properties:
        current_release:
          description: 'The stable-equivalent branch your installation currently appears to be on.'
          type: string
          example: 0.20.3
        latest_release:
          description: 'The current latest stable release of the software.'
          type: string
          example: 0.20.4
        needs_rolling_update:
          description: 'If you are on the Rolling Release, whether your installation needs to be updated.'
          type: boolean
        needs_release_update:
          description: 'Whether a newer stable release is available than the version you are currently using.'
          type: boolean
        rolling_updates_available:
          description: 'If you are on the Rolling Release, the number of updates released since your version.'
          type: integer
        can_switch_to_stable:
          description: 'Whether you can seamlessly move from the Rolling Release channel to Stable without issues.'
          type: boolean
      type: object
    Api_BatchResult:
      required:
        - success
        - errors
      properties:
        success:
          type: boolean
        errors:
          type: array
          items:
            type: string
      type: object
    Api_Dashboard:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_NowPlaying'
        -
          $ref: '#/components/schemas/HasLinks'
    Api_DetailedSongHistory:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_NowPlaying_SongHistory'
        -
          properties:
            listeners_start:
              description: 'Number of listeners when the song playback started.'
              type: integer
              example: 94
            listeners_end:
              description: 'Number of listeners when song playback ended.'
              type: integer
              example: 105
            delta_total:
              description: "The sum total change of listeners between the song's start and ending."
              type: integer
              example: 11
            is_visible:
              description: 'Whether the entry is visible on public playlists.'
              type: boolean
              example: true
          type: object
    Api_Error:
      required:
        - code
        - type
        - message
        - formatted_message
        - extra_data
        - success
      properties:
        code:
          description: 'The numeric code of the error.'
          type: integer
          example: 500
        type:
          description: 'The programmatic class of error.'
          type: string
          example: NotLoggedInException
        message:
          description: 'The text description of the error.'
          type: string
          example: 'Error description.'
        formatted_message:
          description: 'The HTML-formatted text description of the error.'
          type: string
          example: '<b>Error description.</b><br>Detailed error text.'
          nullable: true
        extra_data:
          description: 'Stack traces and other supplemental data.'
          type: array
          items: {  }
        success:
          description: 'Used for API calls that expect an \Entity\Api\Status type response.'
          type: boolean
          example: false
      type: object
    Api_FileList:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            path:
              type: string
            path_short:
              type: string
            text:
              type: string
            type:
              $ref: '#/components/schemas/FileTypes'
            timestamp:
              type: integer
            size:
              type: integer
              nullable: true
            media:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_StationMedia'
              nullable: true
            dir:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_FileListDir'
              nullable: true
          type: object
    Api_FileListDir:
      properties:
        playlists:
          type: array
          items: {  }
      type: object
    Api_Form_Option:
      required:
        - value
        - text
      properties:
        value: {  }
        text:
          type: string
        description:
          type: string
          nullable: true
      type: object
    Api_Form_OptionGroup:
      required:
        - options
        - label
      properties:
        options:
          type: array
          items:
            $ref: '#/components/schemas/Api_Form_Option'
        label:
          type: string
      type: object
    Api_GenericForm:
      type: object
      additionalProperties:
        type: '{}'
    Api_Form_NestedOptions:
      type: array
      items:
        anyOf:
          -
            $ref: '#/components/schemas/Api_Form_Option'
          -
            $ref: '#/components/schemas/Api_Form_OptionGroup'
    Api_Form_SimpleOptions:
      type: array
      items:
        $ref: '#/components/schemas/Api_Form_Option'
    Api_GenericBatchResult:
      required:
        - records
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_BatchResult'
        -
          properties:
            records:
              type: array
              items:
                required:
                  - id
                  - title
                properties:
                  id: { type: integer, format: int64 }
                  title: { type: string }
                type: object
          type: object
    HashMap:
      description: 'A hash-map array represented as an object.'
      type: object
    Api_Listener:
      properties:
        ip:
          description: "The listener's IP address"
          type: string
          example: 127.0.0.1
        user_agent:
          description: "The listener's HTTP User-Agent"
          type: string
          example: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36'
        hash:
          description: 'A unique identifier for this listener/user agent (used for unique calculations).'
          type: string
          example: ''
        mount_is_local:
          description: 'Whether the user is connected to a local mount point or a remote one.'
          type: boolean
          example: false
        mount_name:
          description: 'The display name of the mount point.'
          type: string
          example: /radio.mp3
        connected_on:
          description: 'UNIX timestamp that the user first connected.'
          type: integer
          example: 1609480800
        connected_until:
          description: 'UNIX timestamp that the user disconnected (or the latest timestamp if they are still connected).'
          type: integer
          example: 1609480800
        connected_time:
          description: 'Number of seconds that the user has been connected.'
          type: integer
          example: 30
        device:
          $ref: '#/components/schemas/Api_ListenerDevice'
        location:
          $ref: '#/components/schemas/Api_ListenerLocation'
      type: object
    Api_ListenerDevice:
      properties:
        is_browser:
          description: 'If the listener device is likely a browser.'
          type: boolean
          example: true
        is_mobile:
          description: 'If the listener device is likely a mobile device.'
          type: boolean
          example: true
        is_bot:
          description: 'If the listener device is likely a crawler.'
          type: boolean
          example: true
        client:
          description: 'Summary of the listener client.'
          type: string
          example: 'Firefox 121.0, Windows'
          nullable: true
        browser_family:
          description: 'Summary of the listener browser family.'
          type: string
          example: Firefox
          nullable: true
        os_family:
          description: 'Summary of the listener OS family.'
          type: string
          example: Windows
          nullable: true
      type: object
    Api_ListenerLocation:
      properties:
        city:
          description: 'The approximate city of the listener.'
          type: string
          example: Austin
          nullable: true
        region:
          description: 'The approximate region/state of the listener.'
          type: string
          example: Texas
          nullable: true
        country:
          description: 'The approximate country of the listener.'
          type: string
          example: 'United States'
          nullable: true
        description:
          description: 'A description of the location.'
          type: string
          example: 'Austin, Texas, US'
        lat:
          description: Latitude.
          type: number
          format: float
          example: '30.000000'
          nullable: true
        lon:
          description: Latitude.
          type: number
          format: float
          example: '-97.000000'
          nullable: true
      type: object
    Api_LogContents:
      required:
        - contents
        - eof
        - position
      properties:
        contents:
          type: string
          readOnly: true
        eof:
          description: 'Whether the log file has ended at this point or has additional data.'
          type: boolean
          readOnly: true
        position:
          type: integer
          readOnly: true
          nullable: true
      type: object
    Api_LogType:
      required:
        - key
        - name
        - path
        - tail
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            key:
              type: string
              readOnly: true
            name:
              type: string
              readOnly: true
            path:
              type: string
              readOnly: true
            tail:
              type: boolean
              readOnly: true
          type: object
    Api_Notification:
      required:
        - title
        - body
        - type
        - actionLabel
        - actionUrl
      properties:
        title:
          type: string
        body:
          type: string
        type:
          $ref: '#/components/schemas/FlashLevels'
        actionLabel:
          type: string
          nullable: true
        actionUrl:
          type: string
          nullable: true
      type: object
    Api_NowPlaying_CurrentSong:
      required:
        - elapsed
        - remaining
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_NowPlaying_SongHistory'
        -
          properties:
            elapsed:
              description: "Elapsed time of the song's playback since it started."
              type: integer
              example: 25
            remaining:
              description: 'Remaining time in the song, in seconds.'
              type: integer
              example: 155
          type: object
    Api_NowPlaying_Listeners:
      required:
        - total
        - unique
        - current
      properties:
        total:
          description: 'Total non-unique current listeners'
          type: integer
          example: 20
        unique:
          description: 'Total unique current listeners'
          type: integer
          example: 15
        current:
          description: 'Total non-unique current listeners (Legacy field, may be retired in the future.)'
          type: integer
          example: 20
      type: object
    Api_NowPlaying_Live:
      required:
        - is_live
        - streamer_name
        - broadcast_start
        - art
      properties:
        is_live:
          description: 'Whether the stream is known to currently have a live DJ.'
          type: boolean
          example: false
        streamer_name:
          description: 'The current active streamer/DJ, if one is available.'
          type: string
          example: 'DJ Jazzy Jeff'
        broadcast_start:
          description: 'The start timestamp of the current broadcast, if one is available.'
          type: integer
          example: '1591548318'
          nullable: true
        art:
          description: 'URL to the streamer artwork (if available).'
          type: string
          example: 'https://picsum.photos/1200/1200'
          nullable: true
      type: object
    Api_NowPlaying:
      required:
        - station
        - listeners
        - live
        - now_playing
        - playing_next
        - song_history
        - is_online
        - cache
      properties:
        station:
          $ref: '#/components/schemas/Api_NowPlaying_Station'
        listeners:
          $ref: '#/components/schemas/Api_NowPlaying_Listeners'
        live:
          $ref: '#/components/schemas/Api_NowPlaying_Live'
        now_playing:
          oneOf:
            -
              $ref: '#/components/schemas/Api_NowPlaying_CurrentSong'
          nullable: true
        playing_next:
          oneOf:
            -
              $ref: '#/components/schemas/Api_NowPlaying_StationQueue'
          nullable: true
        song_history:
          type: array
          items:
            $ref: '#/components/schemas/Api_NowPlaying_SongHistory'
        is_online:
          description: 'Whether the stream is currently online.'
          type: boolean
          example: true
        cache:
          description: 'Debugging information about where the now playing data comes from.'
          type: string
          enum:
            - hit
            - database
            - station
          nullable: true
      type: object
    Api_NowPlaying_SongHistory:
      required:
        - sh_id
        - played_at
        - duration
        - playlist
        - streamer
        - is_request
        - song
      properties:
        sh_id:
          description: 'Song history unique identifier'
          type: integer
        played_at:
          description: 'UNIX timestamp when playback started.'
          type: integer
          example: 1609480800
        duration:
          description: 'Duration of the song in seconds'
          type: integer
          example: 180
        playlist:
          description: 'Indicates the playlist that the song was played from, if available, or empty string if not.'
          type: string
          example: 'Top 100'
          nullable: true
        streamer:
          description: 'Indicates the current streamer that was connected, if available, or empty string if not.'
          type: string
          example: 'Test DJ'
          nullable: true
        is_request:
          description: 'Indicates whether the song is a listener request.'
          type: boolean
        song:
          $ref: '#/components/schemas/Api_Song'
      type: object
    Api_NowPlaying_Station:
      required:
        - id
        - name
        - shortcode
        - description
        - frontend
        - backend
        - timezone
        - listen_url
        - url
        - public_player_url
        - playlist_pls_url
        - playlist_m3u_url
        - is_public
        - mounts
        - remotes
        - hls_enabled
        - hls_is_default
        - hls_url
        - hls_listeners
      properties:
        id:
          description: 'Station ID'
          type: integer
          example: 1
        name:
          description: 'Station name'
          type: string
          example: 'AzuraTest Radio'
        shortcode:
          description: 'Station "short code", used for URL and folder paths'
          type: string
          example: azuratest_radio
        description:
          description: 'Station description'
          type: string
          example: 'An AzuraCast station!'
        frontend:
          description: 'Which broadcasting software (frontend) the station uses'
          type: string
          example: shoutcast2
        backend:
          description: 'Which AutoDJ software (backend) the station uses'
          type: string
          example: liquidsoap
        timezone:
          description: "The station's IANA time zone"
          type: string
          example: America/Chicago
        listen_url:
          description: 'The full URL to listen to the default mount of the station'
          type: string
          example: 'http://localhost:8000/radio.mp3'
        url:
          description: 'The public URL of the station.'
          type: string
          example: 'https://example.com/'
          nullable: true
        public_player_url:
          description: 'The public player URL for the station.'
          type: string
          example: 'https://example.com/public/example_station'
        playlist_pls_url:
          description: 'The playlist download URL in PLS format.'
          type: string
          example: 'https://example.com/public/example_station/playlist.pls'
        playlist_m3u_url:
          description: 'The playlist download URL in M3U format.'
          type: string
          example: 'https://example.com/public/example_station/playlist.m3u'
        is_public:
          description: 'If the station is public (i.e. should be shown in listings of all stations)'
          type: boolean
          example: true
        mounts:
          type: array
          items:
            $ref: '#/components/schemas/Api_NowPlaying_StationMount'
        remotes:
          type: array
          items:
            $ref: '#/components/schemas/Api_NowPlaying_StationRemote'
        hls_enabled:
          description: 'If the station has HLS streaming enabled.'
          type: boolean
          example: true
        hls_is_default:
          description: 'If the HLS stream should be the default one for the station.'
          type: boolean
          example: true
        hls_url:
          description: 'The full URL to listen to the HLS stream for the station.'
          type: string
          example: 'https://example.com/hls/azuratest_radio/live.m3u8'
          nullable: true
        hls_listeners:
          description: 'HLS Listeners'
          type: integer
          example: 1
      type: object
    Api_NowPlaying_StationMount:
      required:
        - path
        - is_default
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_NowPlaying_StationRemote'
        -
          properties:
            path:
              description: 'The relative path that corresponds to this mount point'
              type: string
              example: /radio.mp3
            is_default:
              description: 'If the mount is the default mount for the parent station'
              type: boolean
              example: true
          type: object
    Api_NowPlaying_StationQueue:
      required:
        - cued_at
        - played_at
        - duration
        - playlist
        - is_request
        - song
      properties:
        cued_at:
          description: 'UNIX timestamp when the AutoDJ is expected to queue the song for playback.'
          type: integer
          example: 1609480800
        played_at:
          description: 'UNIX timestamp when playback is expected to start.'
          type: integer
          example: 1609480800
          nullable: true
        duration:
          description: 'Duration of the song in seconds'
          type: number
          format: float
          example: 180
        playlist:
          description: 'Indicates the playlist that the song was played from, if available, or empty string if not.'
          type: string
          example: 'Top 100'
          nullable: true
        is_request:
          description: 'Indicates whether the song is a listener request.'
          type: boolean
        song:
          $ref: '#/components/schemas/Api_Song'
      type: object
    Api_NowPlaying_StationRemote:
      required:
        - id
        - name
        - url
        - bitrate
        - format
        - listeners
      properties:
        id:
          description: 'Mount/Remote ID number.'
          type: integer
          example: 1
        name:
          description: 'Mount point name/URL'
          type: string
          example: /radio.mp3
        url:
          description: 'Full listening URL specific to this mount'
          type: string
          example: 'http://localhost:8000/radio.mp3'
        bitrate:
          description: 'Bitrate (kbps) of the broadcasted audio (if known)'
          type: integer
          example: 128
          nullable: true
        format:
          description: 'Audio encoding format of broadcasted audio (if known)'
          type: string
          example: mp3
          nullable: true
        listeners:
          $ref: '#/components/schemas/Api_NowPlaying_Listeners'
      type: object
    Api_Podcast:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: string
            storage_location_id:
              type: integer
            source:
              type: string
            playlist_id:
              type: integer
              nullable: true
            playlist_auto_publish:
              type: boolean
            title:
              type: string
            link:
              type: string
              nullable: true
            description:
              type: string
            description_short:
              type: string
            is_enabled:
              type: boolean
            branding_config:
              description: 'An array containing podcast-specific branding configuration'
              type: array
              items: {  }
            language:
              type: string
            language_name:
              type: string
            author:
              type: string
            email:
              type: string
            has_custom_art:
              type: boolean
            art:
              type: string
            art_updated_at:
              type: integer
            is_published:
              type: boolean
            episodes:
              type: integer
            categories:
              type: array
              items:
                $ref: '#/components/schemas/Api_PodcastCategory'
          type: object
    Api_PodcastBatchResult:
      required:
        - episodes
        - records
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_BatchResult'
        -
          properties:
            episodes:
              type: array
              items:
                required:
                  - id
                  - title
                properties:
                  id: { type: string }
                  title: { type: string }
                type: object
            records:
              type: array
              items:
                $ref: '#/components/schemas/Api_PodcastEpisode'
              nullable: true
          type: object
    Api_PodcastCategory:
      properties:
        category:
          type: string
        text:
          type: string
        title:
          type: string
        subtitle:
          type: string
          nullable: true
      type: object
    Api_PodcastEpisode:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: string
            title:
              type: string
            link:
              type: string
              nullable: true
            description:
              type: string
            description_short:
              type: string
            explicit:
              type: boolean
            season_number:
              type: integer
              nullable: true
            episode_number:
              type: integer
              nullable: true
            created_at:
              type: integer
            publish_at:
              type: integer
            is_published:
              type: boolean
            has_media:
              type: boolean
            playlist_media_id:
              type: string
              nullable: true
            playlist_media:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_Song'
              nullable: true
            media:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_PodcastMedia'
              nullable: true
            has_custom_art:
              type: boolean
            art:
              type: string
              nullable: true
            art_updated_at:
              type: integer
          type: object
    Api_PodcastMedia:
      properties:
        id:
          type: string
          nullable: true
        original_name:
          type: string
          nullable: true
        length:
          type: number
          format: float
        length_text:
          type: string
          nullable: true
        path:
          type: string
          nullable: true
      type: object
    Api_ResolvableUrl:
      type: string
    Api_Song:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_HasSongFields'
        -
          properties:
            id:
              description: "The song's 32-character unique identifier hash"
              type: string
              example: 9f33bbc912c19603e51be8e0987d076b
            art:
              description: 'URL to the album artwork (if available).'
              type: string
              example: 'https://picsum.photos/1200/1200'
            custom_fields:
              type: array
              items:
                type: string
                example: custom_field_value
          type: object
    Api_StationMedia:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_HasSongFields'
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              description: "The media's identifier."
              type: integer
              example: 1
            unique_id:
              description: 'A unique identifier associated with this record.'
              type: string
              example: 69b536afc7ebbf16457b8645
            song_id:
              description: "The media file's 32-character unique song identifier hash"
              type: string
              example: 9f33bbc912c19603e51be8e0987d076b
            art:
              description: 'URL to the album art.'
              type: string
              example: 'https://picsum.photos/1200/1200'
            path:
              description: 'The relative path of the media file.'
              type: string
              example: test.mp3
            mtime:
              description: 'The UNIX timestamp when the database was last modified.'
              type: integer
              example: 1609480800
            uploaded_at:
              description: 'The UNIX timestamp when the item was first imported into the database.'
              type: integer
              example: 1609480800
            art_updated_at:
              description: 'The latest time (UNIX timestamp) when album art was updated.'
              type: integer
              example: 1609480800
            length:
              description: 'The song duration in seconds.'
              type: number
              format: float
              example: 240
            length_text:
              description: 'The formatted song duration (in mm:ss format)'
              type: string
              example: '4:00'
            custom_fields:
              $ref: '#/components/schemas/HashMap'
            extra_metadata:
              $ref: '#/components/schemas/HashMap'
            playlists:
              type: array
              items:
                oneOf:
                  - { $ref: '#/components/schemas/Api_StationMediaPlaylist' }
                  - { type: integer, writeOnly: true }
          type: object
    Api_StationMediaPlaylist:
      properties:
        id:
          description: 'The playlist identifier.'
          type: integer
          example: 1
        name:
          type: string
          readOnly: true
        short_name:
          type: string
          readOnly: true
        count:
          type: integer
          readOnly: true
      type: object
    Api_StationOnDemand:
      properties:
        track_id:
          description: 'Track ID unique identifier'
          type: string
          example: 1
        download_url:
          description: 'URL to download/play track.'
          type: string
          example: /api/station/1/ondemand/download/1
        media:
          $ref: '#/components/schemas/Api_Song'
        playlist:
          type: string
      type: object
    Api_StationPlaylistQueue:
      properties:
        spm_id:
          description: 'ID of the StationPlaylistMedia record associating this track with the playlist'
          type: integer
          example: 1
          nullable: true
        media_id:
          description: 'ID of the StationPlaylistMedia record associating this track with the playlist'
          type: integer
          example: 1
        song_id:
          description: "The song's 32-character unique identifier hash"
          type: string
          example: 9f33bbc912c19603e51be8e0987d076b
        artist:
          description: 'The song artist.'
          type: string
          example: 'Chet Porter'
        title:
          description: 'The song title.'
          type: string
          example: 'Aluko River'
      type: object
    Api_StationProfile:
      required:
        - station
        - services
        - schedule
      properties:
        station:
          $ref: '#/components/schemas/Api_NowPlaying_Station'
        services:
          $ref: '#/components/schemas/Api_StationServiceStatus'
        schedule:
          type: array
          items:
            $ref: '#/components/schemas/Api_StationSchedule'
      type: object
    Api_StationQueueDetailed:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/Api_NowPlaying_StationQueue'
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            sent_to_autodj:
              description: 'Indicates whether the song has been sent to the AutoDJ.'
              type: boolean
            is_played:
              description: 'Indicates whether the song has already been marked as played.'
              type: boolean
            autodj_custom_uri:
              description: 'Custom AutoDJ playback URI, if it exists.'
              type: string
              example: ''
              nullable: true
            log:
              description: 'Log entries on how the specific queue item was picked by the AutoDJ.'
              type: array
              items: {  }
              nullable: true
          type: object
    Api_StationQuota:
      properties:
        used:
          type: string
        used_bytes:
          type: string
        used_percent:
          type: integer
        available:
          type: string
        available_bytes:
          type: string
        quota:
          type: string
          nullable: true
        quota_bytes:
          type: string
          nullable: true
        is_full:
          type: boolean
        num_files:
          type: integer
          nullable: true
      type: object
    Api_StationRemote:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: integer
              nullable: true
            display_name:
              type: string
              example: '128kbps MP3'
              nullable: true
            is_visible_on_public_pages:
              type: boolean
              example: true
            type:
              type: string
              example: icecast
            is_editable:
              type: boolean
              example: 'true'
            enable_autodj:
              type: boolean
              example: false
            autodj_format:
              type: string
              example: mp3
              nullable: true
            autodj_bitrate:
              type: integer
              example: 128
              nullable: true
            custom_listen_url:
              type: string
              example: 'https://custom-listen-url.example.com/stream.mp3'
              nullable: true
            url:
              type: string
              example: 'https://custom-url.example.com'
            mount:
              type: string
              example: /stream.mp3
              nullable: true
            admin_password:
              type: string
              example: password
              nullable: true
            source_port:
              type: integer
              example: 8000
              nullable: true
            source_mount:
              type: string
              example: /
              nullable: true
            source_username:
              type: string
              example: source
              nullable: true
            source_password:
              type: string
              example: password
              nullable: true
            is_public:
              type: boolean
              example: false
            listeners_unique:
              description: 'The most recent number of unique listeners.'
              type: integer
              example: 10
            listeners_total:
              description: 'The most recent number of total (non-unique) listeners.'
              type: integer
              example: 12
          type: object
    Api_StationRequest:
      properties:
        request_id:
          description: 'Requestable ID unique identifier'
          type: string
          example: 1
        request_url:
          description: 'URL to directly submit request'
          type: string
          example: /api/station/1/request/1
        song:
          $ref: '#/components/schemas/Api_Song'
      type: object
    Api_StationRestartStatus:
      properties:
        has_started:
          type: boolean
        needs_restart:
          type: boolean
      type: object
    Api_StationSchedule:
      properties:
        id:
          description: 'Unique identifier for this schedule entry.'
          type: integer
          example: 1
        type:
          description: 'The type of this schedule entry.'
          type: string
          enum:
            - playlist
            - streamer
          example: playlist
        name:
          description: "Either the playlist or streamer's display name."
          type: string
          example: 'Example Schedule Entry'
        title:
          description: 'The name of the event.'
          type: string
          example: 'Example Schedule Entry'
        description:
          description: 'The full name of the type and name combined.'
          type: string
          example: 'Playlist: Example Schedule Entry'
        start_timestamp:
          description: 'The start time of the schedule entry, in UNIX format.'
          type: integer
          example: 1609480800
        start:
          description: 'The start time of the schedule entry, in ISO 8601 format.'
          type: string
          example: '020-02-19T03:00:00-06:00'
        end_timestamp:
          description: 'The end time of the schedule entry, in UNIX format.'
          type: integer
          example: 1609480800
        end:
          description: 'The start time of the schedule entry, in ISO 8601 format.'
          type: string
          example: '020-02-19T05:00:00-06:00'
        is_now:
          description: 'Whether the event is currently ongoing.'
          type: boolean
          example: true
      type: object
    Api_StationServiceStatus:
      required:
        - backend_running
        - frontend_running
        - station_has_started
        - station_needs_restart
      properties:
        backend_running:
          type: boolean
          example: true
        frontend_running:
          type: boolean
          example: true
        station_has_started:
          type: boolean
          example: true
        station_needs_restart:
          type: boolean
          example: true
      type: object
    Api_StationStreamer:
      required:
        - id
        - streamer_username
        - display_name
      properties:
        id:
          type: integer
        streamer_username:
          type: string
        display_name:
          type: string
      type: object
    Api_StationStreamerBroadcast:
      required:
        - id
        - timestampStart
        - timestampEnd
        - streamer
        - recording
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasLinks'
        -
          properties:
            id:
              type: integer
            timestampStart:
              type: string
              format: date-time
            timestampEnd:
              type: string
              format: date-time
              nullable: true
            streamer:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_StationStreamer'
              nullable: true
            recording:
              oneOf:
                -
                  $ref: '#/components/schemas/Api_StationStreamerBroadcastRecording'
              nullable: true
          type: object
    Api_StationStreamerBroadcastRecording:
      required:
        - path
        - size
        - downloadUrl
      properties:
        path:
          type: string
        size:
          type: integer
        downloadUrl:
          type: string
      type: object
    Api_Status:
      required:
        - success
        - message
        - formatted_message
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: 'Changes saved successfully.'
        formatted_message:
          type: string
          example: '<b>Changes saved successfully.</b>'
      type: object
    Api_SystemStatus:
      required:
        - online
        - timestamp
      properties:
        online:
          description: 'Whether the service is online or not (should always be true)'
          type: boolean
          example: true
        timestamp:
          description: 'The current UNIX timestamp'
          type: integer
          example: 1609480800
      type: object
    Api_TaskWithLog:
      required:
        - logUrl
      properties:
        logUrl:
          description: 'The URL to view logs of the ongoing background task.'
          type: string
          format: uri
      type: object
    Api_Time:
      required:
        - timestamp
        - utc_datetime
        - utc_date
        - utc_time
        - utc_json
      properties:
        timestamp:
          description: 'The current UNIX timestamp'
          type: integer
          example: 1497652397
        utc_datetime:
          type: string
          example: '2017-06-16 10:33:17'
        utc_date:
          type: string
          example: 'June 16, 2017'
        utc_time:
          type: string
          example: '10:33pm'
        utc_json:
          type: string
          example: '2012-12-25T16:30:00.000000Z'
      type: object
    HasLinks:
      properties:
        links:
          type: object
          readOnly: true
          additionalProperties:
            type: string
      type: object
    Api_HasSongFields:
      properties:
        text:
          description: 'The song title, usually "Artist - Title"'
          type: string
          example: 'Chet Porter - Aluko River'
        artist:
          description: 'The song artist.'
          type: string
          example: 'Chet Porter'
          nullable: true
        title:
          description: 'The song title.'
          type: string
          example: 'Aluko River'
          nullable: true
        album:
          description: 'The song album.'
          type: string
          example: 'Moving Castle'
          nullable: true
        genre:
          description: 'The song genre.'
          type: string
          example: Rock
          nullable: true
        isrc:
          description: 'The International Standard Recording Code (ISRC) of the file.'
          type: string
          example: US28E1600021
          nullable: true
        lyrics:
          description: 'Lyrics to the song.'
          type: string
          example: ''
          nullable: true
      type: object
    Api_UploadFile:
      required:
        - path
        - file
      properties:
        path:
          description: 'The destination path of the uploaded file.'
          type: string
          example: relative/path/to/file.mp3
        file:
          description: 'The base64-encoded contents of the file to upload.'
          type: string
          example: ''
      type: object
    Api_UploadedRecordStatus:
      required:
        - hasRecord
        - url
      properties:
        hasRecord:
          type: boolean
        url:
          type: string
          nullable: true
      type: object
    ApiKey:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasSplitTokenFields'
        -
          properties:
            user:
              $ref: '#/components/schemas/User'
            comment:
              type: string
          type: object
    CustomField:
      required:
        - name
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              type: string
            short_name:
              description: 'The programmatic name for the field. Can be auto-generated from the full name.'
              type: string
            auto_assign:
              description: 'An ID3v2 field to automatically assign to this value, if it exists in the media file.'
              type: string
              nullable: true
          type: object
    AnalyticsLevel:
      type: string
      enum:
        - all
        - no_ip
        - none
      x-enumNames:
        - All
        - NoIp
        - None
    FileTypes:
      type: string
      enum:
        - directory
        - media
        - cover_art
        - unprocessable_file
        - other
      x-enumNames:
        - Directory
        - Media
        - CoverArt
        - UnprocessableFile
        - Other
    IpSources:
      type: string
      enum:
        - local
        - xff
        - cloudflare
      x-enumNames:
        - Local
        - XForwardedFor
        - Cloudflare
    PlaylistOrders:
      type: string
      enum:
        - random
        - shuffle
        - sequential
      x-enumNames:
        - Random
        - Shuffle
        - Sequential
    PlaylistRemoteTypes:
      type: string
      enum:
        - stream
        - playlist
        - other
      x-enumNames:
        - Stream
        - Playlist
        - Other
    PlaylistSources:
      type: string
      enum:
        - songs
        - remote_url
      x-enumNames:
        - Songs
        - RemoteUrl
    PlaylistTypes:
      type: string
      enum:
        - default
        - once_per_x_songs
        - once_per_x_minutes
        - once_per_hour
        - custom
      x-enumNames:
        - Standard
        - OncePerXSongs
        - OncePerXMinutes
        - OncePerHour
        - Advanced
    PodcastSources:
      type: string
      enum:
        - manual
        - playlist
      x-enumNames:
        - Manual
        - Playlist
    StationBackendPerformanceModes:
      type: string
      enum:
        - less_memory
        - less_cpu
        - balanced
        - disabled
      x-enumNames:
        - LessMemory
        - LessCpu
        - Balanced
        - Disabled
    Relay:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            base_url:
              type: string
              example: 'https://custom-url.example.com'
            name:
              type: string
              example: Relay
              nullable: true
            is_visible_on_public_pages:
              type: boolean
              example: true
            created_at:
              type: string
              format: date-time
              example: '2025-01-31T21:31:58+00:00'
            updated_at:
              type: string
              format: date-time
              example: '2025-01-31T21:31:58+00:00'
          type: object
    Settings:
      properties:
        app_unique_identifier:
          type: string
        base_url:
          description: 'Site Base URL'
          type: string
          example: 'https://your.azuracast.site'
          nullable: true
        instance_name:
          description: 'AzuraCast Instance Name'
          type: string
          example: 'My AzuraCast Instance'
          nullable: true
        prefer_browser_url:
          description: 'Prefer Browser URL (If Available)'
          type: boolean
          example: 'false'
        use_radio_proxy:
          description: 'Use Web Proxy for Radio'
          type: boolean
          example: 'false'
        history_keep_days:
          description: 'Days of Playback History to Keep'
          type: integer
        always_use_ssl:
          description: 'Always Use HTTPS'
          type: boolean
          example: 'false'
        api_access_control:
          description: "API 'Access-Control-Allow-Origin' header"
          type: string
          example: '*'
          nullable: true
        enable_static_nowplaying:
          description: 'Whether to use high-performance static JSON for Now Playing data updates.'
          type: boolean
          example: 'false'
        analytics:
          oneOf:
            -
              $ref: '#/components/schemas/AnalyticsLevel'
          nullable: true
          description: 'Listener Analytics Collection'
        check_for_updates:
          description: 'Check for Updates and Announcements'
          type: boolean
          example: 'true'
        update_results:
          description: 'Results of the latest update check.'
          type: array
          items: {  }
          example: ''
          nullable: true
        update_last_run:
          description: 'The UNIX timestamp when updates were last checked.'
          type: integer
          example: 1609480800
        public_theme:
          oneOf:
            -
              $ref: '#/components/schemas/SupportedThemes'
          nullable: true
          description: 'Base Theme for Public Pages'
          example: light
        hide_album_art:
          description: 'Hide Album Art on Public Pages'
          type: boolean
          example: 'false'
        homepage_redirect_url:
          description: 'Homepage Redirect URL'
          type: string
          example: 'https://example.com/'
          nullable: true
        default_album_art_url:
          description: 'Default Album Art URL'
          type: string
          example: 'https://example.com/image.jpg'
          nullable: true
        use_external_album_art_when_processing_media:
          description: 'Attempt to fetch album art from external sources when processing media.'
          type: boolean
          example: 'false'
        use_external_album_art_in_apis:
          description: 'Attempt to fetch album art from external sources in API requests.'
          type: boolean
          example: 'false'
        last_fm_api_key:
          description: 'An API key to connect to Last.fm services, if provided.'
          type: string
          example: SAMPLE-API-KEY
          nullable: true
        hide_product_name:
          description: 'Hide AzuraCast Branding on Public Pages'
          type: boolean
          example: 'false'
        public_custom_css:
          description: 'Custom CSS for Public Pages'
          type: string
          example: ''
          nullable: true
        public_custom_js:
          description: 'Custom JS for Public Pages'
          type: string
          example: ''
          nullable: true
        internal_custom_css:
          description: 'Custom CSS for Internal Pages'
          type: string
          example: ''
          nullable: true
        backup_enabled:
          description: 'Whether backup is enabled.'
          type: boolean
          example: 'false'
        backup_time_code:
          description: 'The timecode (i.e. 400 for 4:00AM) when automated backups should run.'
          type: string
          example: 400
          nullable: true
        backup_exclude_media:
          description: 'Whether to exclude media in automated backups.'
          type: boolean
          example: 'false'
        backup_keep_copies:
          description: 'Number of backups to keep, or infinite if zero/null.'
          type: integer
          example: 2
        backup_storage_location:
          description: 'The storage location ID for automated backups.'
          type: integer
          example: 1
          nullable: true
        backup_format:
          description: 'The output format for the automated backup.'
          type: string
          example: zip
          nullable: true
        backup_last_run:
          description: 'The UNIX timestamp when automated backup was last run.'
          type: integer
          example: 1609480800
        backup_last_output:
          description: 'The output of the latest automated backup task.'
          type: string
          example: ''
          nullable: true
        setup_complete_time:
          description: 'The UNIX timestamp when setup was last completed.'
          type: integer
          example: 1609480800
        sync_disabled:
          description: 'Temporarily disable all sync tasks.'
          type: boolean
          example: 'false'
        sync_last_run:
          description: 'The last run timestamp for the unified sync task.'
          type: integer
          example: 1609480800
        external_ip:
          description: "This installation's external IP."
          type: string
          example: 192.168.1.1
          nullable: true
        geolite_license_key:
          description: 'The license key for the Maxmind Geolite download.'
          type: string
          example: ''
          nullable: true
        geolite_last_run:
          description: 'The UNIX timestamp when the Maxmind Geolite was last downloaded.'
          type: integer
          example: 1609480800
        enable_advanced_features:
          description: "Whether to enable 'advanced' functionality in the system that is intended for power users."
          type: boolean
          example: false
        mail_enabled:
          description: 'Enable e-mail delivery across the application.'
          type: boolean
          example: 'true'
        mail_sender_name:
          description: 'The name of the sender of system e-mails.'
          type: string
          example: AzuraCast
          nullable: true
        mail_sender_email:
          description: 'The e-mail address of the sender of system e-mails.'
          type: string
          example: example@example.com
          nullable: true
        mail_smtp_host:
          description: 'The host to send outbound SMTP mail.'
          type: string
          example: smtp.example.com
          nullable: true
        mail_smtp_port:
          description: 'The port for sending outbound SMTP mail.'
          type: integer
          example: 465
        mail_smtp_username:
          description: 'The username when connecting to SMTP mail.'
          type: string
          example: username
          nullable: true
        mail_smtp_password:
          description: 'The password when connecting to SMTP mail.'
          type: string
          example: password
          nullable: true
        mail_smtp_secure:
          description: 'Whether to use a secure (TLS) connection when sending SMTP mail.'
          type: boolean
          example: 'true'
        avatar_service:
          description: 'The external avatar service to use when fetching avatars.'
          type: string
          example: libravatar
          nullable: true
        avatar_default_url:
          description: 'The default avatar URL.'
          type: string
          example: ''
          nullable: true
        acme_email:
          description: 'ACME (LetsEncrypt) e-mail address.'
          type: string
          example: ''
          nullable: true
        acme_domains:
          description: 'ACME (LetsEncrypt) domain name(s).'
          type: string
          example: ''
          nullable: true
        ip_source:
          oneOf:
            -
              $ref: '#/components/schemas/IpSources'
          nullable: true
          description: 'IP Address Source'
      type: object
    SftpUser:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            username:
              type: string
            password:
              type: string
            publicKeys:
              type: string
              nullable: true
          type: object
    Station:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              description: 'The full display name of the station.'
              type: string
              example: 'AzuraTest Radio'
            short_name:
              description: 'The URL-friendly name for the station, typically auto-generated from the full station name.'
              type: string
              example: azuratest_radio
            is_enabled:
              description: "If set to 'false', prevents the station from broadcasting but leaves it in the database."
              type: boolean
              example: true
            frontend_type:
              $ref: '#/components/schemas/FrontendAdapters'
            frontend_config:
              description: 'An array containing station-specific frontend configuration'
              type: object
            backend_type:
              $ref: '#/components/schemas/BackendAdapters'
            backend_config:
              description: 'An array containing station-specific backend configuration'
              type: object
            description:
              type: string
              example: 'A sample radio station.'
              nullable: true
            url:
              type: string
              example: 'https://demo.azuracast.com/'
              nullable: true
            genre:
              type: string
              example: Various
              nullable: true
            radio_base_dir:
              type: string
              example: /var/azuracast/stations/azuratest_radio
              nullable: true
            enable_requests:
              description: 'Whether listeners can request songs to play on this station.'
              type: boolean
              example: true
            request_delay:
              type: integer
              example: 5
              nullable: true
            request_threshold:
              type: integer
              example: 15
              nullable: true
            disconnect_deactivate_streamer:
              type: integer
              example: 0
              nullable: true
            enable_streamers:
              description: 'Whether streamers are allowed to broadcast to this station at all.'
              type: boolean
              example: false
            is_streamer_live:
              description: 'Whether a streamer is currently active on the station.'
              type: boolean
              example: false
            enable_public_page:
              description: 'Whether this station is visible as a public page and in a now-playing API response.'
              type: boolean
              example: true
            enable_on_demand:
              description: "Whether this station has a public 'on-demand' streaming and download page."
              type: boolean
              example: true
            enable_on_demand_download:
              description: "Whether the 'on-demand' page offers download capability."
              type: boolean
              example: true
            enable_hls:
              description: 'Whether HLS streaming is enabled.'
              type: boolean
              example: true
            api_history_items:
              description: "The number of 'last played' history items to show for a station in API responses."
              type: integer
              example: 5
            timezone:
              description: 'The time zone that station operations should take place in.'
              type: string
              example: UTC
              nullable: true
            max_bitrate:
              description: 'The maximum bitrate at which a station may broadcast, in Kbps. 0 for unlimited'
              type: integer
              example: 128
            max_mounts:
              description: 'The maximum number of mount points the station can have, 0 for unlimited'
              type: integer
              example: 3
            max_hls_streams:
              description: 'The maximum number of HLS streams the station can have, 0 for unlimited'
              type: integer
              example: 3
            branding_config:
              description: 'An array containing station-specific branding configuration'
              type: object
          type: object
    StationHlsStream:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              type: string
              example: aac_lofi
            format:
              example: aac
              nullable: true
            bitrate:
              type: integer
              example: 128
              nullable: true
          type: object
    StationMount:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              type: string
              example: /radio.mp3
            display_name:
              type: string
              example: '128kbps MP3'
              nullable: true
            is_visible_on_public_pages:
              type: boolean
              example: true
            is_default:
              type: boolean
              example: false
            is_public:
              type: boolean
              example: false
            fallback_mount:
              type: string
              example: /error.mp3
              nullable: true
            relay_url:
              type: string
              example: 'https://radio.example.com:8000/radio.mp3'
              nullable: true
            authhash:
              type: string
              example: ''
              nullable: true
            max_listener_duration:
              type: integer
              example: 43200
            enable_autodj:
              type: boolean
              example: true
            autodj_format:
              example: mp3
              nullable: true
            autodj_bitrate:
              type: integer
              example: 128
              nullable: true
            custom_listen_url:
              type: string
              example: 'https://custom-listen-url.example.com/stream.mp3'
              nullable: true
            frontend_config:
              type: array
              items: {  }
            listeners_unique:
              description: 'The most recent number of unique listeners.'
              type: integer
              example: 10
            listeners_total:
              description: 'The most recent number of total (non-unique) listeners.'
              type: integer
              example: 12
          type: object
    StationPlaylist:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              type: string
              example: 'Test Playlist'
            type:
              $ref: '#/components/schemas/PlaylistTypes'
            source:
              $ref: '#/components/schemas/PlaylistSources'
            order:
              $ref: '#/components/schemas/PlaylistOrders'
            remote_url:
              type: string
              example: 'https://remote-url.example.com/stream.mp3'
              nullable: true
            remote_type:
              oneOf:
                -
                  $ref: '#/components/schemas/PlaylistRemoteTypes'
              nullable: true
              example: stream
            remote_buffer:
              description: 'The total time (in seconds) that Liquidsoap should buffer remote URL streams.'
              type: integer
              example: 0
            is_enabled:
              type: boolean
              example: true
            is_jingle:
              description: 'If yes, do not send jingle metadata to AutoDJ or trigger web hooks.'
              type: boolean
              example: false
            play_per_songs:
              type: integer
              example: 5
            play_per_minutes:
              type: integer
              example: 120
            play_per_hour_minute:
              type: integer
              example: 15
            weight:
              type: integer
              example: 3
            include_in_requests:
              type: boolean
              example: true
            include_in_on_demand:
              description: "Whether this playlist's media is included in 'on demand' download/streaming if enabled."
              type: boolean
              example: true
            backend_options:
              type: string
              example: 'interrupt,loop_once,single_track,merge'
              nullable: true
            avoid_duplicates:
              type: boolean
              example: true
            schedule_items:
              description: StationSchedule>
              type: array
              items: {  }
            podcasts:
              description: Podcast>
              type: array
              items: {  }
          type: object
    StationSchedule:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            start_time:
              type: integer
              example: 900
            end_time:
              type: integer
              example: 2200
            days:
              description: 'Array of ISO-8601 days (1 for Monday, 7 for Sunday)'
              type: string
              example: '0,1,2,3'
              nullable: true
            loop_once:
              type: boolean
              example: false
          type: object
    StationStreamer:
      description: 'Station streamers (DJ accounts) allowed to broadcast to a station.'
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            streamer_username:
              type: string
              example: dj_test
            streamer_password:
              type: string
              example: ''
            display_name:
              type: string
              example: 'Test DJ'
              nullable: true
            comments:
              type: string
              example: 'This is a test DJ account.'
              nullable: true
            is_active:
              type: boolean
              example: true
            enforce_schedule:
              type: boolean
              example: false
            reactivate_at:
              type: integer
              example: 1609480800
              nullable: true
            schedule_items:
              description: StationSchedule>
              type: array
              items: {  }
          type: object
    StationStreamerBroadcast:
      description: 'Each individual broadcast associated with a streamer.'
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
    StationWebhook:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            name:
              description: 'The nickname of the webhook connector.'
              type: string
              example: 'Twitter Post'
              nullable: true
            type:
              $ref: '#/components/schemas/WebhookTypes'
            is_enabled:
              type: boolean
              example: true
            triggers:
              description: 'List of events that should trigger the webhook notification.'
              type: array
              items: {  }
            config:
              description: 'Detailed webhook configuration (if applicable)'
              type: array
              items: {  }
            metadata:
              description: 'Internal details used by the webhook to preserve state.'
              type: array
              items: {  }
          type: object
    HasAutoIncrementId:
      required:
        - id
      properties:
        id:
          type: integer
          readOnly: true
      type: object
    HasSongFields:
      properties:
        song_id:
          type: string
        text:
          type: string
          nullable: true
        artist:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
      type: object
    HasSplitTokenFields:
      properties:
        id:
          type: string
          readOnly: true
        verifier:
          type: string
          readOnly: true
      type: object
    HasUniqueId:
      required:
        - id
      properties:
        id:
          type: string
          readOnly: true
      type: object
    User:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/HasAutoIncrementId'
        -
          properties:
            email:
              type: string
              example: demo@azuracast.com
            new_password:
              type: string
              example: ''
              nullable: true
            name:
              type: string
              example: 'Demo Account'
              nullable: true
            locale:
              type: string
              example: en_US
              nullable: true
            show_24_hour_time:
              type: boolean
              example: true
              nullable: true
            two_factor_secret:
              type: string
              example: A1B2C3D4
              nullable: true
            created_at:
              type: integer
              example: 1609480800
            updated_at:
              type: integer
              example: 1609480800
            roles:
              description: Role>
              type: array
              items: {  }
          type: object
    FlashLevels:
      type: string
      enum:
        - success
        - warning
        - danger
        - info
      x-enumNames:
        - Success
        - Warning
        - Error
        - Info
    GlobalPermissions:
      type: string
      enum:
        - 'administer all'
        - 'view administration'
        - 'view system logs'
        - 'administer settings'
        - 'administer api keys'
        - 'administer stations'
        - 'administer custom fields'
        - 'administer backups'
        - 'administer storage locations'
      x-enumNames:
        - All
        - View
        - Logs
        - Settings
        - ApiKeys
        - Stations
        - CustomFields
        - Backups
        - StorageLocations
    ReleaseChannel:
      type: string
      enum:
        - latest
        - stable
      x-enumNames:
        - RollingRelease
        - Stable
    StationPermissions:
      type: string
      enum:
        - 'administer all'
        - 'view station management'
        - 'view station reports'
        - 'view station logs'
        - 'manage station profile'
        - 'manage station broadcasting'
        - 'manage station streamers'
        - 'manage station mounts'
        - 'manage station remotes'
        - 'manage station media'
        - 'manage station automation'
        - 'manage station web hooks'
        - 'manage station podcasts'
      x-enumNames:
        - All
        - View
        - Reports
        - Logs
        - Profile
        - Broadcasting
        - Streamers
        - MountPoints
        - RemoteRelays
        - Media
        - Automation
        - WebHooks
        - Podcasts
    SupportedLocales:
      type: string
      enum:
        - en_US.UTF-8
        - cs_CZ.UTF-8
        - nl_NL.UTF-8
        - fr_FR.UTF-8
        - de_DE.UTF-8
        - el_GR.UTF-8
        - it_IT.UTF-8
        - ja_JP.UTF-8
        - ko_KR.UTF-8
        - nb_NO.UTF-8
        - pl_PL.UTF-8
        - pt_PT.UTF-8
        - pt_BR.UTF-8
        - ru_RU.UTF-8
        - zh_CN.UTF-8
        - es_ES.UTF-8
        - sv_SE.UTF-8
        - tr_TR.UTF-8
        - uk_UA.UTF-8
      x-enumNames:
        - English
        - Czech
        - Dutch
        - French
        - German
        - Greek
        - Italian
        - Japanese
        - Korean
        - Norwegian
        - Polish
        - Portuguese
        - PortugueseBrazilian
        - Russian
        - SimplifiedChinese
        - Spanish
        - Swedish
        - Turkish
        - Ukrainian
    SupportedThemes:
      type: string
      enum:
        - browser
        - light
        - dark
      x-enumNames:
        - Browser
        - Light
        - Dark
    AudioProcessingMethods:
      type: string
      enum:
        - none
        - nrj
        - master_me
        - stereo_tool
      x-enumNames:
        - None
        - Liquidsoap
        - MasterMe
        - StereoTool
    BackendAdapters:
      type: string
      enum:
        - liquidsoap
        - none
      x-enumNames:
        - Liquidsoap
        - None
    FrontendAdapters:
      type: string
      enum:
        - icecast
        - shoutcast2
        - rsas
        - remote
      x-enumNames:
        - Icecast
        - Shoutcast
        - Rsas
        - Remote
    MasterMePresets:
      type: string
      enum:
        - music_general
        - speech_general
        - ebu_r128
        - apple_podcasts
        - youtube
      x-enumNames:
        - MusicGeneral
        - SpeechGeneral
        - EbuR128
        - ApplePodcasts
        - YouTube
    RemoteAdapters:
      type: string
      enum:
        - shoutcast1
        - shoutcast2
        - icecast
        - azurarelay
      x-enumNames:
        - Shoutcast1
        - Shoutcast2
        - Icecast
        - AzuraRelay
    WebhookTriggers:
      type: string
      enum:
        - song_changed
        - song_changed_live
        - listener_gained
        - listener_lost
        - live_connect
        - live_disconnect
        - station_offline
        - station_online
      x-enumNames:
        - SongChanged
        - SongChangedLive
        - ListenerGained
        - ListenerLost
        - LiveConnect
        - LiveDisconnect
        - StationOffline
        - StationOnline
    WebhookTypes:
      type: string
      enum:
        - generic
        - email
        - tunein
        - radiode
        - radioreg
        - getmeradio
        - discord
        - telegram
        - groupme
        - mastodon
        - bluesky
        - google_analytics_v4
        - matomo_analytics
        - twitter
        - google_analytics
      x-enumNames:
        - Generic
        - Email
        - TuneIn
        - RadioDe
        - RadioReg
        - GetMeRadio
        - Discord
        - Telegram
        - GroupMe
        - Mastodon
        - Bluesky
        - GoogleAnalyticsV4
        - MatomoAnalytics
        - Twitter
        - GoogleAnalyticsV3
  responses:
    SuccessWithImage:
      description: 'A successful response with a binary image download.'
      content:
        'image/*':
          schema:
            description: 'An image (album art, background, etc) in binary format.'
            type: string
            format: binary
    SuccessWithDownload:
      description: 'A successful response with a binary file download.'
      content:
        application/octet-stream:
          schema:
            description: 'A media (music, podcast, etc) download in binary format.'
            type: string
            format: binary
    Success:
      description: Success
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Api_Status'
    AccessDenied:
      description: 'Access denied.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Api_Error'
    RecordNotFound:
      description: 'Record not found.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Api_Error'
    GenericError:
      description: 'A generic exception has occurred.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Api_Error'
  parameters:
    StationIdRequired:
      name: station_id
      in: path
      required: true
      schema:
        anyOf:
          -
            type: integer
            format: int64
          -
            type: string
            format: string
  requestBodies:
    FlowFileUpload:
      content:
        multipart/form-data:
          schema:
            properties:
              file:
                description: 'The body of the file to upload.'
                type: string
                format: binary
            type: object
  securitySchemes:
    ApiKey:
      type: apiKey
      name: X-API-Key
      in: header
security:
  -
    ApiKey: []
tags:
  -
    name: 'Public: Now Playing'
    description: 'Endpoints that provide full summaries of the current state of stations.'
  -
    name: 'Public: Stations'
  -
    name: 'Public: Miscellaneous'
  -
    name: 'Stations: General'
  -
    name: 'Stations: Broadcasting'
  -
    name: 'Stations: HLS Streams'
  -
    name: 'Stations: Media'
  -
    name: 'Stations: Mount Points'
  -
    name: 'Stations: Playlists'
  -
    name: 'Stations: Podcasts'
  -
    name: 'Stations: Queue'
  -
    name: 'Stations: Remote Relays'
  -
    name: 'Stations: Reports'
  -
    name: 'Stations: SFTP Users'
  -
    name: 'Stations: Streamers/DJs'
  -
    name: 'Stations: Web Hooks'
  -
    name: 'Administration: General'
  -
    name: 'Administration: Debugging'
  -
    name: 'Administration: Backups'
  -
    name: 'Administration: Custom Fields'
  -
    name: 'Administration: Users'
  -
    name: 'Administration: Roles'
  -
    name: 'Administration: Settings'
  -
    name: 'Administration: Stations'
  -
    name: 'Administration: Storage Locations'
  -
    name: 'My Account'
  -
    name: Miscellaneous
externalDocs:
  description: 'AzuraCast on GitHub'
  url: 'https://github.com/AzuraCast/AzuraCast'
x-tagGroups:
  -
    name: 'Public Endpoints'
    tags:
      - 'Public: Now Playing'
      - 'Public: Stations'
      - 'Public: Miscellaneous'
  -
    name: 'Station Management'
    tags:
      - 'Stations: General'
      - 'Stations: Broadcasting'
      - 'Stations: Song Requests'
      - 'Stations: HLS Streams'
      - 'Stations: Media'
      - 'Stations: Mount Points'
      - 'Stations: Playlists'
      - 'Stations: Podcasts'
      - 'Stations: Queue'
      - 'Stations: Remote Relays'
      - 'Stations: Reports'
      - 'Stations: SFTP Users'
      - 'Stations: Streamers/DJs'
      - 'Stations: Web Hooks'
  -
    name: Administration
    tags:
      - 'Administration: General'
      - 'Administration: Debugging'
      - 'Administration: Backups'
      - 'Administration: Custom Fields'
      - 'Administration: Users'
      - 'Administration: Roles'
      - 'Administration: Settings'
      - 'Administration: Stations'
      - 'Administration: Storage Locations'