The first public release. What it does: https://weavesignal.top; what changed: CHANGELOG.md.
13624 lines
351 KiB
JSON
13624 lines
351 KiB
JSON
{
|
|
"openapi": "3.1.0",
|
|
"info": {
|
|
"title": "WeaveSignal control plane API",
|
|
"description": "The station's HTTP API, `/api/v1` (ADR-0195). Within `/api/v1` changes are additive only. Bodies are JSON. The narrative (authorisation, errors, stability) is in the product documentation's *Control plane routes* page.",
|
|
"license": {
|
|
"name": "AGPL-3.0-only",
|
|
"identifier": "AGPL-3.0-only"
|
|
},
|
|
"version": "1"
|
|
},
|
|
"paths": {
|
|
"/api/v1/call-in": {
|
|
"post": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "Call the studio",
|
|
"description": "A listener's call from the player page, with their consent to record (the words from `GET /api/v1/player`) and the answered challenge. Answers with a pass and a room token for the caller's booth. 409 (`field` `consent`) when the words have changed since the page loaded; 429 over the per-address limit.",
|
|
"operationId": "public_call_in",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CallInRequest"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The pass and the token.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Joined"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"description": "Too many calls from this address just now.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "The token could not be signed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/call-in/challenge": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "A challenge to answer before calling",
|
|
"description": "A proof-of-work challenge (ADR-0006); harder while the station is busy. Never cached.",
|
|
"operationId": "public_call_in_challenge",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The challenge.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Challenge"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/cards/preview": {
|
|
"post": {
|
|
"tags": [
|
|
"cards"
|
|
],
|
|
"summary": "Preview a card",
|
|
"description": "A card from the fields in the body (`station` filled in when left out), as a PNG; nothing is kept.",
|
|
"operationId": "shows_preview",
|
|
"parameters": [
|
|
{
|
|
"name": "output",
|
|
"in": "query",
|
|
"description": "`link` (the default), `post` or `square`",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardFields"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The card.",
|
|
"content": {
|
|
"image/png": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/cards/words": {
|
|
"post": {
|
|
"tags": [
|
|
"cards"
|
|
],
|
|
"summary": "The words of a card",
|
|
"description": "The same fields, checked as the preview checks them (a refused name is refused here too): the alt text, the page the card links to, the level and the station fields. Nothing is drawn.",
|
|
"operationId": "shows_card_words",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardFields"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The card's words.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardWords"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/carts": {
|
|
"get": {
|
|
"tags": [
|
|
"carts"
|
|
],
|
|
"summary": "The banks and carts",
|
|
"description": "Each cart with FILE MISSING. Fetch it again when the studio view's `carts.version` moves.",
|
|
"operationId": "carts_catalogue",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The catalogue.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Catalogue"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"carts:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/carts/banks/{bank}/slots/{slot}": {
|
|
"put": {
|
|
"tags": [
|
|
"carts"
|
|
],
|
|
"summary": "Put an audio file in a slot",
|
|
"description": "An audio file as the body, the cart's words in the query. The media worker reads it in its sandbox, brings it to the station's loudness and makes it the cart in that slot.",
|
|
"operationId": "import_cart",
|
|
"parameters": [
|
|
{
|
|
"name": "bank",
|
|
"in": "path",
|
|
"description": "The bank's number",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "slot",
|
|
"in": "path",
|
|
"description": "The slot in the bank",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "label",
|
|
"in": "query",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "detail",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "mode",
|
|
"in": "query",
|
|
"required": true,
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CartMode"
|
|
}
|
|
},
|
|
{
|
|
"name": "ramp_ms",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "origin",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "licence",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"description": "The audio file (any format the media worker reads), at most `carts.max_upload_mb`.",
|
|
"content": {
|
|
"application/octet-stream": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The cart.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Cart"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"413": {
|
|
"description": "The file is larger than `carts.max_upload_mb`.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The cart wall failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"carts:write"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"carts"
|
|
],
|
|
"summary": "Empty a slot",
|
|
"operationId": "delete_cart",
|
|
"parameters": [
|
|
{
|
|
"name": "bank",
|
|
"in": "path",
|
|
"description": "The bank's number",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "slot",
|
|
"in": "path",
|
|
"description": "The slot in the bank",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new catalogue.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Catalogue"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The cart wall failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"carts:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/carts/banks/{number}": {
|
|
"put": {
|
|
"tags": [
|
|
"carts"
|
|
],
|
|
"summary": "Make or rename a bank",
|
|
"operationId": "put_bank",
|
|
"parameters": [
|
|
{
|
|
"name": "number",
|
|
"in": "path",
|
|
"description": "The bank's number",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/BankRequest"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new catalogue.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Catalogue"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The cart wall failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"carts:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/carts/commands": {
|
|
"post": {
|
|
"tags": [
|
|
"carts"
|
|
],
|
|
"summary": "Fire, stop or cue a cart",
|
|
"description": "`toggle`, `fire`, `stop`, `cue` a cart; `stop_last`; `fade_all`; `clear_cue`. Carts sound in the desk (ADR-0117). Answers with the new studio view.",
|
|
"operationId": "cart_command",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CartCommand"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new studio view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The cart wall failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"502": {
|
|
"description": "The desk refused the command.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"carts:fire"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/chat/modes": {
|
|
"post": {
|
|
"tags": [
|
|
"chat"
|
|
],
|
|
"summary": "A chat mode",
|
|
"description": "A chat mode (`slow`, `hold_new`, `links_trusted`) on or off, or influx (five settings at once, the earlier ones back when turned off, ADR-0068). The studio's modes; the chat service reads them. Answers with the new studio view.",
|
|
"operationId": "chat_modes",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ChatCommand"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new studio view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"chat:moderate"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/desk/commands": {
|
|
"post": {
|
|
"tags": [
|
|
"desk"
|
|
],
|
|
"summary": "A desk switch",
|
|
"description": "The same requests as the desk's control socket, without `status`: `on_air`, `mute`, `cue`, `talk`, `talk_to`, or `dump` the profanity delay. Answers with the new studio view. A caller cannot go on air or in cue without their consent to record on file (409).",
|
|
"operationId": "desk_command",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DeskCommand"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new studio view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"desk:control"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/invites": {
|
|
"post": {
|
|
"tags": [
|
|
"join"
|
|
],
|
|
"summary": "An invite link",
|
|
"description": "A link for a guest, a remote DJ or a presenter. A caller joins another way (422).",
|
|
"operationId": "public_invite",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/InviteRequest"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The invite.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Invite"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/library/tracks": {
|
|
"get": {
|
|
"tags": [
|
|
"library"
|
|
],
|
|
"summary": "The music library",
|
|
"operationId": "list_tracks",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The tracks.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/TracksBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"playout:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"library"
|
|
],
|
|
"summary": "Add a track to the library",
|
|
"description": "An audio file as the body, the track's words in the query: the media worker normalises it into the library.",
|
|
"operationId": "import_track",
|
|
"parameters": [
|
|
{
|
|
"name": "title",
|
|
"in": "query",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "artist",
|
|
"in": "query",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "category",
|
|
"in": "query",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "album",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "label",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "isrc",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"description": "The audio file, at most `playout.library_max_upload_mb`.",
|
|
"content": {
|
|
"application/octet-stream": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The track.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Track"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"413": {
|
|
"description": "The file is larger than `playout.library_max_upload_mb`.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The media worker or the library failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"library:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/library/tracks/{id}": {
|
|
"delete": {
|
|
"tags": [
|
|
"library"
|
|
],
|
|
"summary": "Remove a track",
|
|
"operationId": "delete_track",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The track",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Removed."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"library:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/logger": {
|
|
"get": {
|
|
"tags": [
|
|
"reports"
|
|
],
|
|
"summary": "The legal logger's recordings",
|
|
"description": "The recordings, and the hours of the last day with none while the logger was on.",
|
|
"operationId": "reports_logger",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The logger.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/LoggerBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"playout:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/now-playing": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "What is playing now",
|
|
"description": "What listeners are told is playing, offset by the listener delay. Never what comes next for a US statutory webcaster.",
|
|
"operationId": "now_playing",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Now playing.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NowPlaying"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/now-playing/events": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "What is playing now, as events",
|
|
"description": "Server-sent events: a `now_playing` event whose data is the same JSON as `GET /api/v1/now-playing`, at once and on every change.",
|
|
"operationId": "now_playing_events",
|
|
"responses": {
|
|
"200": {
|
|
"description": "An event stream (`text/event-stream`).",
|
|
"content": {
|
|
"text/event-stream": {
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/openapi.json": {
|
|
"get": {
|
|
"tags": [
|
|
"station"
|
|
],
|
|
"summary": "The API's description",
|
|
"description": "This document: the API as OpenAPI 3.1, generated from the handlers. Needs no bearer; the description is not secret.",
|
|
"operationId": "openapi_json",
|
|
"responses": {
|
|
"200": {
|
|
"description": "This document, OpenAPI 3.1.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/pass": {
|
|
"get": {
|
|
"tags": [
|
|
"join"
|
|
],
|
|
"summary": "What a pass is",
|
|
"description": "The pass is the bearer: from an invite's link or a call-in. Says who it is for and whether the studio has ended it.",
|
|
"operationId": "public_pass_info",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The pass.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PassInfo"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"410": {
|
|
"description": "This link has expired. Ask the station for a new one.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"pass": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/pass/events": {
|
|
"get": {
|
|
"tags": [
|
|
"join"
|
|
],
|
|
"summary": "A person's state, as events",
|
|
"description": "Server-sent events: a `me` event whose data is the person's state as JSON, at once and when it changes; a keep-alive every 10 seconds.",
|
|
"operationId": "public_pass_events",
|
|
"responses": {
|
|
"200": {
|
|
"description": "An event stream (`text/event-stream`).",
|
|
"content": {
|
|
"text/event-stream": {
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"410": {
|
|
"description": "This link has expired. Ask the station for a new one.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"pass": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/pass/leave": {
|
|
"post": {
|
|
"tags": [
|
|
"join"
|
|
],
|
|
"summary": "Hang up",
|
|
"description": "A caller's call ends: out of the queue and the room, no held place. For anyone else it does nothing.",
|
|
"operationId": "public_pass_leave",
|
|
"responses": {
|
|
"204": {
|
|
"description": "Done."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"410": {
|
|
"description": "This link has expired. Ask the station for a new one.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"pass": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/pass/token": {
|
|
"post": {
|
|
"tags": [
|
|
"join"
|
|
],
|
|
"summary": "A room token for a pass",
|
|
"description": "Signs a token for the person's room: a caller's booth, or the studio. 410 when the studio has ended the pass or no longer has the call on file.",
|
|
"operationId": "public_pass_token",
|
|
"responses": {
|
|
"201": {
|
|
"description": "The pass and the token.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Joined"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"410": {
|
|
"description": "This link has expired, or the studio has ended it.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"description": "The token could not be signed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"pass": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/passes/end": {
|
|
"post": {
|
|
"tags": [
|
|
"room"
|
|
],
|
|
"summary": "End anyone's pass",
|
|
"description": "Off air and out of the cue, the pass refused from now on (across a restart), then out of the room (ADR-0119). Someone not in the room yet (a leaked link nobody has used) is ended all the same.",
|
|
"operationId": "end_pass",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EndPassRequest"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new studio view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"502": {
|
|
"description": "Their pass is ended and they are off air, but LiveKit did not remove them.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"screener:control"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/people": {
|
|
"get": {
|
|
"tags": [
|
|
"people"
|
|
],
|
|
"summary": "Remembered people",
|
|
"description": "Admin only. The remembered guests and hosts, by name.",
|
|
"operationId": "shows_list_people",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The people.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/PersonView"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/people/{id}/erase": {
|
|
"post": {
|
|
"tags": [
|
|
"people"
|
|
],
|
|
"summary": "Erase a person",
|
|
"description": "Admin only. At their request (ADR-0122): their record, their name in every list and in what aired, the cards drawn again, the corrections log redacted.",
|
|
"operationId": "shows_erase_person",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The person",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "What was erased.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Erased"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/player": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "The player page's facts",
|
|
"description": "The station, the show, the stream, whether the presenter is live, whether call-in is open (and the consent words), and the HLS addresses while the desk has video on.",
|
|
"operationId": "public_player",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The facts.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PlayerInfo"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/playout": {
|
|
"get": {
|
|
"tags": [
|
|
"playout"
|
|
],
|
|
"summary": "The playout layer",
|
|
"description": "Mode, what is on air, dead air, whether the default loop plays (ADR-0130), automation's queue, listeners, the logger and now playing.",
|
|
"operationId": "playout_status",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The playout layer's state.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Status"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"playout:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/playout/settings": {
|
|
"get": {
|
|
"tags": [
|
|
"playout"
|
|
],
|
|
"summary": "Playout's settings",
|
|
"description": "Time zone, separations, US statutory licence, mode, logger days, default clock.",
|
|
"operationId": "get_settings",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The settings.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PlayoutSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"playout"
|
|
],
|
|
"summary": "Change playout's settings",
|
|
"description": "Admin only. Reading the settings is any staff member's; changing them, the US statutory licence among them, is an admin's. A zone change reaches the schedule's screens at once, and `mode` (`live` or `auto`) the studio's view and the desk.",
|
|
"operationId": "put_settings",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PlayoutSettings"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The settings as saved.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PlayoutSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/playout/zone": {
|
|
"get": {
|
|
"tags": [
|
|
"playout"
|
|
],
|
|
"summary": "The station's time zone",
|
|
"description": "The station's zone and whether anyone has chosen it (ADR-0189). The studio asks an admin to choose once, with the configuration's zone offered; any signed-in staff may read it.",
|
|
"operationId": "get_zone",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The zone.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ZoneBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"playout:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/public/episodes": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "Published episodes",
|
|
"description": "For a station's own website: aired episodes with published files, newest first, with where to hear them, their card, their page and their feed. Page back with `before_ms`. No bearer; CORS open to any origin; limited per address. Cached for 30 s.",
|
|
"operationId": "public_episodes",
|
|
"parameters": [
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"description": "How many, 1 to 50.",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"default": 20,
|
|
"maximum": 50,
|
|
"minimum": 1
|
|
}
|
|
},
|
|
{
|
|
"name": "before_ms",
|
|
"in": "query",
|
|
"description": "Only episodes that aired before this time (the last one's `air_at_ms`, to page back).",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episodes.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PublishedEpisodes"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/public/schedule": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "The coming schedule",
|
|
"description": "For a station's own website: the episodes with an air time from now for `days` days, in air order. An episode that has not aired shows as its slot (show, series, number, time, length, kind, hosts); its title, description, guests and tags appear once it has aired. No person a retention rule erased appears. No bearer; CORS open to any origin; limited per address. Cached for 30 s.",
|
|
"operationId": "public_schedule",
|
|
"parameters": [
|
|
{
|
|
"name": "days",
|
|
"in": "query",
|
|
"description": "How many days from now, 1 to 14.",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"default": 7,
|
|
"maximum": 14,
|
|
"minimum": 1
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The schedule.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PublicSchedule"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/public/station": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "The station's public facts",
|
|
"description": "For a station's own website: the station, the show now, the stream, whether the show is live, whether call-in is open, the video, the zone. No bearer; CORS open to any origin; limited per address. Cached for 5 s.",
|
|
"operationId": "public_station",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The facts.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/PublicStation"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/reports/audience": {
|
|
"get": {
|
|
"tags": [
|
|
"reports"
|
|
],
|
|
"summary": "Audience",
|
|
"description": "Listener hours, sessions, peak and tracks per hour between `from_ms` and `to_ms` (default: the last day).",
|
|
"operationId": "report_audience",
|
|
"parameters": [
|
|
{
|
|
"name": "from_ms",
|
|
"in": "query",
|
|
"description": "From, in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
{
|
|
"name": "to_ms",
|
|
"in": "query",
|
|
"description": "To (exclusive), in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The audience.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/AudienceBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"reports:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/reports/plays": {
|
|
"get": {
|
|
"tags": [
|
|
"reports"
|
|
],
|
|
"summary": "The per-play log",
|
|
"description": "What aired between `from_ms` and `to_ms` (default: the last day), as JSON, CSV, or in SoundExchange's layout.",
|
|
"operationId": "report_plays",
|
|
"parameters": [
|
|
{
|
|
"name": "from_ms",
|
|
"in": "query",
|
|
"description": "From, in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
{
|
|
"name": "to_ms",
|
|
"in": "query",
|
|
"description": "To (exclusive), in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
{
|
|
"name": "format",
|
|
"in": "query",
|
|
"description": "`json` (the default), `csv` or `soundexchange`",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The plays as CSV.",
|
|
"content": {
|
|
"text/csv": {
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"reports:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/retention": {
|
|
"get": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "The Jurisdiction setting",
|
|
"description": "Admin only. The setting, each period in force with its source and floor, warnings, the presets, the last sweep.",
|
|
"operationId": "retention_view",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The setting.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/RetentionView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Choose the Jurisdiction setting",
|
|
"description": "Admin only. A preset, or Custom with a period for every kind of record. Answers with the view as it now is.",
|
|
"operationId": "retention_choose",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Choice"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The view as it now is.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/RetentionView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/consents": {
|
|
"get": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Find callers' consents",
|
|
"description": "Admin only. By at least two letters of the caller's name.",
|
|
"operationId": "retention_find_consents",
|
|
"parameters": [
|
|
{
|
|
"name": "name",
|
|
"in": "query",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The consents found.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ConsentFound"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/consents/{id}/erase": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Erase a caller's consent",
|
|
"description": "Admin only. Erases the consent record and forgets the caller in the studio.",
|
|
"operationId": "retention_erase_consent",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The consent",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EraseConsent"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "How many rows were erased.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ConsentErased"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/consents/{id}/recordings": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Link a consent to a recording",
|
|
"description": "Admin only.",
|
|
"operationId": "retention_link_consent",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The consent",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Link"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"204": {
|
|
"description": "Linked."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/holds": {
|
|
"get": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Holds",
|
|
"description": "Admin only. Evidence holds, placed and released.",
|
|
"operationId": "retention_holds",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The holds.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Hold"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Place a hold",
|
|
"description": "Admin only. Keep records past their period for a stated reason.",
|
|
"operationId": "retention_place_hold",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewHold"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The hold.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Hold"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/holds/{id}/extend": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Extend a hold",
|
|
"description": "Admin only.",
|
|
"operationId": "retention_extend_hold",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The hold",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Extension"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The hold, extended.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Hold"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/holds/{id}/release": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Release a hold",
|
|
"description": "Admin only.",
|
|
"operationId": "retention_release_hold",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The hold",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Release"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The hold, released.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Hold"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/preview": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "What a setting would delete",
|
|
"description": "Admin only. A dry run: the warnings and what a sweep would do under the setting, nothing changed.",
|
|
"operationId": "retention_preview",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Choice"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The warnings and the dry sweep.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Preview"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/recordings": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Note a recording",
|
|
"description": "Admin only. Record that a programme recording exists, so retention can keep and delete it.",
|
|
"operationId": "retention_add_recording",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewRecording"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The recording's number.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Created"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/recordings/{id}/end": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "End a recording",
|
|
"description": "Admin only.",
|
|
"operationId": "retention_end_recording",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The recording",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/End"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"204": {
|
|
"description": "Ended."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/retention/sweep": {
|
|
"post": {
|
|
"tags": [
|
|
"retention"
|
|
],
|
|
"summary": "Sweep now",
|
|
"description": "Admin only. Run the sweeper once. 503 also when the sweeper is not running in this control plane.",
|
|
"operationId": "retention_sweep_now",
|
|
"responses": {
|
|
"200": {
|
|
"description": "What the sweep did.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SweepReport"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/room/tokens": {
|
|
"post": {
|
|
"tags": [
|
|
"room"
|
|
],
|
|
"summary": "A room token for one person",
|
|
"description": "A short-lived LiveKit token for one person, with their role in it for the desk to read. A `listener` token is a monitor that hears every return (ADR-0118): only an admin may ask for one (403 otherwise). A `caller` token records the caller's consent on the station's behalf, against the words the station shows now (`consent`).",
|
|
"operationId": "room_token",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/TokenRequest"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The token.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/TokenResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/clocks": {
|
|
"get": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "The hour clocks",
|
|
"operationId": "list_clocks",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The clocks.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClocksBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/clocks/{id}": {
|
|
"put": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Make or change a clock",
|
|
"operationId": "put_clock",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The clock",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClockBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The clock as saved.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClockView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Remove a clock",
|
|
"operationId": "delete_clock",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The clock",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Removed."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/episodes": {
|
|
"get": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Episodes in a range",
|
|
"description": "Every episode airing in the range with its show, series and resolved fields: the calendar's week.",
|
|
"operationId": "shows_episodes_between",
|
|
"parameters": [
|
|
{
|
|
"name": "from_ms",
|
|
"in": "query",
|
|
"description": "From, in milliseconds since the Unix epoch",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
{
|
|
"name": "to_ms",
|
|
"in": "query",
|
|
"description": "To (exclusive)",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episodes.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/WeekEpisodes"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/generate": {
|
|
"post": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Generate the log",
|
|
"description": "(Re)generate the log for `from_ms` to `to_ms` (default: a week from now; at most 31 days ahead). The body may be left out.",
|
|
"operationId": "schedule_generate",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GenerateBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "How many items were made, and what could not be filled.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GeneratedBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/log": {
|
|
"get": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "The log",
|
|
"description": "The log between `from_ms` and `to_ms` (default: from an hour ago to a day ahead; at most 8 days), with each item's words and any rule it breaks.",
|
|
"operationId": "schedule_log",
|
|
"parameters": [
|
|
{
|
|
"name": "from_ms",
|
|
"in": "query",
|
|
"description": "From, in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
{
|
|
"name": "to_ms",
|
|
"in": "query",
|
|
"description": "To (exclusive), in milliseconds since the Unix epoch",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The log.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/LogBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/log/{id}": {
|
|
"put": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Another track for a log item",
|
|
"description": "The log editor: another track for an item, checked against the rules; `force` accepts a rule it breaks.",
|
|
"operationId": "edit_item",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The log item",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EditBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The item as edited, with a note of the rules it now breaks.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EditedBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Take a planned item out of the log",
|
|
"operationId": "delete_item",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The log item",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Removed."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/schedule/week": {
|
|
"get": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Which clock runs each hour",
|
|
"operationId": "get_week",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The week.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/WeekBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database refused.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"schedule"
|
|
],
|
|
"summary": "Set which clock runs each hour",
|
|
"description": "Each hour is a weekday 0-6 (Monday 0) and an hour 0-23, once; every clock must be known.",
|
|
"operationId": "put_week",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/WeekBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The week as saved.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/WeekBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"schedule:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/screener/commands": {
|
|
"post": {
|
|
"tags": [
|
|
"screener"
|
|
],
|
|
"summary": "What the screener does to a caller",
|
|
"description": "`screen`, `send`, `back`, `decline`, `notes`, `release` or `drop`. 404 for someone who is not a caller; 409 when the command does not fit the caller's state; `drop` answers 502 when the caller is off air but LiveKit did not remove them from the room.",
|
|
"operationId": "screener_command",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ScreenerCommand"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The new studio view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"502": {
|
|
"description": "The caller is off air, but LiveKit did not remove them from the room.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"screener:control"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions": {
|
|
"post": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Sign in with a password",
|
|
"description": "`username` and `password` for a session token (starts `rss_`). A refused sign-in answers 401 with the same sentence whether the username exists or not, after the same work.",
|
|
"operationId": "staff_sign_in",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SignIn"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The session.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SignedIn"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "That username and password do not match an account here.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"429": {
|
|
"description": "Too many tries: five failures for a username within 15 minutes, or twenty for an address. Wait for the window to pass.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions/code": {
|
|
"post": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Ask for an emailed sign-in code",
|
|
"description": "A station with mail answers 202 for every username and address alike, and sends a code only to an address that belongs to that username's account when it is on, so neither the words nor the time tell a stranger who has an account. 503 when the station has no mail; 422 (`field` `email`) for something that is not an address; 429 when one address has asked ten times in ten minutes.",
|
|
"operationId": "staff_ask_code",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/AskCode"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"202": {
|
|
"description": "Asked.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CodeAsked"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"description": "Too many tries: five failures for a username within 15 minutes, or twenty for an address. Wait for the window to pass.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions/code/finish": {
|
|
"post": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Sign in with an emailed code",
|
|
"description": "`username`, `email` and the six-digit `code`. Any failure (unknown username, an account that is off, a wrong, used, expired or spent code) answers 401 with one sentence.",
|
|
"operationId": "staff_finish_code",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FinishCode"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The session.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SignedIn"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"description": "That code does not match, or has run out. Ask for a new one.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"description": "Too many tries: five failures for a username within 15 minutes, or twenty for an address. Wait for the window to pass.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions/me": {
|
|
"get": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Who the bearer is",
|
|
"description": "`kind` (`staff` or `station`), `role`, and for staff the `account` and when the session ends.",
|
|
"operationId": "staff_me",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The bearer.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Me"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Sign out",
|
|
"description": "Ends this session. The station key has no session: 422.",
|
|
"operationId": "staff_sign_out",
|
|
"responses": {
|
|
"204": {
|
|
"description": "Signed out."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions/me/email": {
|
|
"put": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Set your own sign-in address",
|
|
"description": "`current` (your password) and `email` (an address, or `null` to take it away): the address your codes go to. The station key has no account: 422.",
|
|
"operationId": "staff_own_email",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/OwnEmail"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The account.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Account"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/sessions/me/password": {
|
|
"post": {
|
|
"tags": [
|
|
"sessions"
|
|
],
|
|
"summary": "Change your own password",
|
|
"description": "`current` and `new`; ends the account's other sessions.",
|
|
"operationId": "staff_own_password",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/OwnPassword"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"204": {
|
|
"description": "Changed."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows": {
|
|
"get": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Every show",
|
|
"operationId": "shows_list",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The shows.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Show"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}": {
|
|
"get": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "A show",
|
|
"description": "The show, resolved, and its series.",
|
|
"operationId": "shows_get_show",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The show.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ShowView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Make or change a show",
|
|
"description": "Its cards are drawn first, and a name that cannot fit, or holds characters the card fonts cannot draw, refuses the save (422, with the field named).",
|
|
"operationId": "shows_put_show",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ShowInput"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The show.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ShowView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/cards": {
|
|
"post": {
|
|
"tags": [
|
|
"cards"
|
|
],
|
|
"summary": "Draw the show's cards again",
|
|
"description": "Four renders per save (ADR-0054).",
|
|
"operationId": "shows_show_cards",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The cards now current.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardsKept"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}": {
|
|
"get": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "A series",
|
|
"description": "The series and its episodes, resolved, with what each inherits.",
|
|
"operationId": "shows_get_series",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The series.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SeriesView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Make or change a series",
|
|
"description": "A field left out inherits the show's.",
|
|
"operationId": "shows_put_series",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SeriesInput"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The series and its episodes.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SeriesView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/cards": {
|
|
"post": {
|
|
"tags": [
|
|
"cards"
|
|
],
|
|
"summary": "Draw the series' cards again",
|
|
"operationId": "shows_series_cards",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The cards now current.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardsKept"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes": {
|
|
"post": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Draft episodes",
|
|
"description": "The next episode, or `count` of them, filled in from the series' rule.",
|
|
"operationId": "shows_create_episodes",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewEpisodes"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The new episodes.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes/{episode}": {
|
|
"patch": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Change an episode",
|
|
"description": "`null` resets a field to inheriting; `kind` is `live` or `prerecorded` (ADR-0188). An aired episode is frozen (409): correct it instead.",
|
|
"operationId": "shows_patch_episode",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EpisodePatch"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episode.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes/{episode}/air": {
|
|
"post": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Put an episode on air",
|
|
"description": "Frozen, its cards drawn once more.",
|
|
"operationId": "shows_air",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episode.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes/{episode}/cards": {
|
|
"post": {
|
|
"tags": [
|
|
"cards"
|
|
],
|
|
"summary": "Draw the episode's cards again",
|
|
"operationId": "shows_episode_cards",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The cards now current.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CardsKept"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes/{episode}/corrections": {
|
|
"get": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "An episode's corrections",
|
|
"operationId": "shows_list_corrections",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The log, newest last.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Correction"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Correct an aired episode",
|
|
"description": "Corrects the public text of an aired episode (ADR-0177) with a `reason` and any of `title`, `description`, `hosts`, `guests` and `tags`. Its cards are drawn again, its feed item changes under the same id, and the log names who made the correction (a username, or `station key`). An admin (or the station key) may, and so may the member of staff who made the episode (ADR-0198); an episode made before makers were recorded, or by the station key or a token, is an admin's to correct.",
|
|
"operationId": "shows_correct",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CorrectionInput"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episode and the correction.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Corrected"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/series/{series}/episodes/{episode}/files": {
|
|
"put": {
|
|
"tags": [
|
|
"shows"
|
|
],
|
|
"summary": "Name the episode's published files",
|
|
"description": "The files are in `publishing.episodes_dir`: their tags and the card are written into them, last.",
|
|
"operationId": "shows_put_files",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "series",
|
|
"in": "path",
|
|
"description": "The series' number in the show",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
{
|
|
"name": "episode",
|
|
"in": "path",
|
|
"description": "The episode's number in the series",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FilesInput"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The episode.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"shows:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/still": {
|
|
"get": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "A show's slate picture",
|
|
"description": "Whether the show has a picture of its own for the slate (ADR-0200), its size and when it was set. The slate shows it while the show is on air by the schedule, else the station's.",
|
|
"operationId": "shows_still_info",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The still as it is now.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/StillInfo"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "Set a show's slate picture",
|
|
"description": "A PNG or JPEG as the body, as for the station's (ADR-0200). The slate shows it within a few seconds whenever the show is on air by the schedule.",
|
|
"operationId": "shows_put_still",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"description": "A PNG or JPEG.",
|
|
"content": {
|
|
"image/*": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The still.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/StillInfo"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"413": {
|
|
"description": "The picture is larger than `video.still_max_upload_mb`.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The media worker or the disk failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:write"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "Take a show's slate picture away",
|
|
"description": "The slate shows the station's picture while the show is on air. 204 also when there was none.",
|
|
"operationId": "shows_delete_still",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Gone."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The file could not be removed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/shows/{show}/still/image": {
|
|
"get": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "A show's slate picture",
|
|
"description": "The show's PNG, never cached.",
|
|
"operationId": "shows_still_image",
|
|
"parameters": [
|
|
{
|
|
"name": "show",
|
|
"in": "path",
|
|
"description": "The show's slug",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The picture.",
|
|
"content": {
|
|
"image/png": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/staff": {
|
|
"get": {
|
|
"tags": [
|
|
"staff"
|
|
],
|
|
"summary": "Staff accounts",
|
|
"description": "Admin only. Every account, on and off, by username.",
|
|
"operationId": "staff_list",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The accounts.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/AccountsBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"staff"
|
|
],
|
|
"summary": "Make an account",
|
|
"description": "Admin only. `username`, `name`, `role` and `password`. The password is kept only as an Argon2id hash.",
|
|
"operationId": "staff_create",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewAccount"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The account.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Account"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/staff/{id}": {
|
|
"put": {
|
|
"tags": [
|
|
"staff"
|
|
],
|
|
"summary": "Change an account",
|
|
"description": "Admin only. Any of `name`, `role`, `disabled`; turning one off ends its sessions at once.",
|
|
"operationId": "staff_change",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The account",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ChangeReq"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The account.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Account"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/staff/{id}/email": {
|
|
"put": {
|
|
"tags": [
|
|
"staff"
|
|
],
|
|
"summary": "Set someone's sign-in address",
|
|
"description": "Admin only. `email` (an address, or `null` to take it away). Setting needs the station's mail to be on (503 otherwise); one address belongs to one account (422, `field` `email`).",
|
|
"operationId": "staff_set_email",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The account",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SetEmail"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The account.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Account"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/staff/{id}/password": {
|
|
"post": {
|
|
"tags": [
|
|
"staff"
|
|
],
|
|
"summary": "Set someone's password",
|
|
"description": "Admin only. Ends every session the account has.",
|
|
"operationId": "staff_set_password",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The account",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SetPassword"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"204": {
|
|
"description": "Set."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/station": {
|
|
"get": {
|
|
"tags": [
|
|
"station"
|
|
],
|
|
"summary": "The station",
|
|
"description": "The station's identifier and name.",
|
|
"operationId": "station",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The station.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Station"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/steering": {
|
|
"get": {
|
|
"tags": [
|
|
"delivery"
|
|
],
|
|
"summary": "The content-steering manifest",
|
|
"description": "HLS content steering (RFC 8216bis section 7): which edge a player takes first, per viewer. Never cached; CORS open to any origin. 404 while no edges are configured.",
|
|
"operationId": "steering_manifest",
|
|
"parameters": [
|
|
{
|
|
"name": "session",
|
|
"in": "query",
|
|
"description": "A session a player sent back from `RELOAD-URI`, so the viewer keeps its edge",
|
|
"required": false,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The manifest.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/SteeringManifest"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/steering/edges": {
|
|
"get": {
|
|
"tags": [
|
|
"delivery"
|
|
],
|
|
"summary": "The edges' health",
|
|
"description": "The station key only (not a staff session).",
|
|
"operationId": "steering_edges",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The edges.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/EdgesBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"station_key": []
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/studio": {
|
|
"get": {
|
|
"tags": [
|
|
"studio"
|
|
],
|
|
"summary": "The studio's view",
|
|
"description": "Sources in their slots, callers, seats, chat modes, notices, the playout link and the station mode. The studio app fetches it once and then follows `GET /api/v1/studio/events`.",
|
|
"operationId": "studio_view",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The studio's view.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/View"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"studio:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/studio/events": {
|
|
"get": {
|
|
"tags": [
|
|
"studio"
|
|
],
|
|
"summary": "The studio's view as events",
|
|
"description": "Server-sent events: one `state` event at once whose data is the studio view as JSON, then one per change; a keep-alive comment every 10 seconds.",
|
|
"operationId": "studio_events",
|
|
"responses": {
|
|
"200": {
|
|
"description": "An event stream (`text/event-stream`).",
|
|
"content": {
|
|
"text/event-stream": {
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"studio:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/tokens": {
|
|
"get": {
|
|
"tags": [
|
|
"tokens"
|
|
],
|
|
"summary": "API tokens",
|
|
"description": "Admin only. Every token the station has made, live, expired and revoked, never its secret; and every scope a token can hold, with what it opens.",
|
|
"operationId": "tokens_list",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The tokens and the scopes.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Listed"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"tokens"
|
|
],
|
|
"summary": "Make an API token",
|
|
"description": "Admin only. `name` (up to 80 characters), `scopes` (at least one, from the list), and `expires_in_days` (1 to 3650; left out, it does not expire). The answer carries the secret (`rsa_` and 64 hex digits) this once; the station keeps only a keyed hash of it. At most 100 live tokens (409).",
|
|
"operationId": "tokens_create",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The token, and its secret, shown once.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Made"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/tokens/{id}": {
|
|
"delete": {
|
|
"tags": [
|
|
"tokens"
|
|
],
|
|
"summary": "Revoke an API token",
|
|
"description": "Admin only. The token stops working at once and stays in the list, marked revoked.",
|
|
"operationId": "tokens_revoke",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The token's id.",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Revoked."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/video/still": {
|
|
"get": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "The slate's picture",
|
|
"description": "Whether there is one, its size in pixels and bytes, and when it was set.",
|
|
"operationId": "video_still_info",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The still as it is now.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/StillInfo"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:read"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "Set the station's slate picture",
|
|
"description": "The slate shows it while the show on air has no picture of its own (ADR-0200). A PNG or JPEG as the body (at most `video.still_max_upload_mb`, 24 MB by default). The media worker reads it in its sandbox and writes a clean PNG, fitted and never enlarged.",
|
|
"operationId": "video_put_still",
|
|
"requestBody": {
|
|
"description": "A PNG or JPEG.",
|
|
"content": {
|
|
"image/*": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The still.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/StillInfo"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"413": {
|
|
"description": "The picture is larger than `video.still_max_upload_mb`.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The media worker or the disk failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:write"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "Take the station's picture away",
|
|
"description": "The slate shows the show on air's picture if it has one, else words. 204 also when there was none.",
|
|
"operationId": "video_delete_still",
|
|
"responses": {
|
|
"204": {
|
|
"description": "Gone."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"500": {
|
|
"description": "The file could not be removed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:write"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/video/still/image": {
|
|
"get": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "The slate's picture",
|
|
"description": "The PNG the desk shows, never cached.",
|
|
"operationId": "video_still_image",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The picture.",
|
|
"content": {
|
|
"image/png": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/video/thumbs": {
|
|
"get": {
|
|
"tags": [
|
|
"video"
|
|
],
|
|
"summary": "Camera thumbnails",
|
|
"description": "A small picture of each camera the desk sees now, made by the desk about once a second. 409 with video off, 503 while the desk does not answer.",
|
|
"operationId": "video_thumbs",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The thumbnails.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ThumbsBody"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/ScopeMissing"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"429": {
|
|
"$ref": "#/components/responses/TooManyRequests"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
},
|
|
{
|
|
"api_token": [
|
|
"video:read"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"/api/v1/webhooks": {
|
|
"get": {
|
|
"tags": [
|
|
"webhooks"
|
|
],
|
|
"summary": "Webhooks",
|
|
"description": "Admin only. Every webhook with the record of its last delivery (never its secret), and every event one can ask for.",
|
|
"operationId": "webhooks_list",
|
|
"responses": {
|
|
"200": {
|
|
"description": "The webhooks and the events.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Listed"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"webhooks"
|
|
],
|
|
"summary": "Make a webhook",
|
|
"description": "Admin only. `name`, `url` and `events`. The address must be `https` and reach only public addresses, unless `[api] webhooks_allow_private` is on. The answer carries the signing secret (`whsec_…`) this once. At most 20 webhooks (409).",
|
|
"operationId": "webhooks_create",
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NewBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"201": {
|
|
"description": "The webhook, and its signing secret, shown once.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Made"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/webhooks/{id}": {
|
|
"put": {
|
|
"tags": [
|
|
"webhooks"
|
|
],
|
|
"summary": "Change a webhook",
|
|
"description": "Admin only. Any of `name`, `url`, `events` and `enabled`; a field left out is kept. A new address is checked as when the webhook is made.",
|
|
"operationId": "webhooks_change",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The webhook's id.",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ChangeBody"
|
|
}
|
|
}
|
|
},
|
|
"required": true
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "The webhook as it is now.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Webhook"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"422": {
|
|
"$ref": "#/components/responses/Unprocessable"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"webhooks"
|
|
],
|
|
"summary": "Remove a webhook",
|
|
"description": "Admin only. It is told about nothing more; deliveries waiting to be retried are given up.",
|
|
"operationId": "webhooks_remove",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The webhook's id.",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Removed."
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/api/v1/webhooks/{id}/secret": {
|
|
"post": {
|
|
"tags": [
|
|
"webhooks"
|
|
],
|
|
"summary": "A new signing secret",
|
|
"description": "Admin only. A new signing secret, shown this once; the old one stops signing at once.",
|
|
"operationId": "webhooks_new_secret",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "The webhook's id.",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The webhook, and its new signing secret, shown once.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Made"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"403": {
|
|
"$ref": "#/components/responses/Forbidden"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"staff_session": []
|
|
},
|
|
{
|
|
"station_key": []
|
|
}
|
|
],
|
|
"x-admin": true
|
|
}
|
|
},
|
|
"/feeds/{file}": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "A show's podcast feed",
|
|
"description": "`{slug}.xml`, the show's RSS feed with its episodes. 503 while the show's card has not been drawn or `publishing.public_url` is not set.",
|
|
"operationId": "shows_feed",
|
|
"parameters": [
|
|
{
|
|
"name": "file",
|
|
"in": "path",
|
|
"description": "The show's slug and `.xml`",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The feed.",
|
|
"content": {
|
|
"application/rss+xml": {
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"description": "The database or the card renderer failed.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Problem"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"$ref": "#/components/responses/Unavailable"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/health": {
|
|
"get": {
|
|
"tags": [
|
|
"station"
|
|
],
|
|
"summary": "Liveness",
|
|
"description": "200 when the service and, if there is one, its database answer; 503 with `status` `degraded` when the database does not. Used by the proxy and the container healthcheck.",
|
|
"operationId": "health",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Alive.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Health"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"503": {
|
|
"description": "The database does not answer.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Health"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
},
|
|
"/hls/{path}": {
|
|
"get": {
|
|
"tags": [
|
|
"public"
|
|
],
|
|
"summary": "A file of the desk's HLS",
|
|
"description": "Playlists never cached, segments briefly. Only names the desk writes (letters, digits, `-`, `_`, `.`; at most two levels) are served, and nothing while video is off. The multivariant playlists name the steering route while steering has edges (ADR-0159).",
|
|
"operationId": "public_hls_file",
|
|
"parameters": [
|
|
{
|
|
"name": "path",
|
|
"in": "path",
|
|
"description": "A playlist or segment, such as `live.m3u8` or `audio/seg1.m4s`",
|
|
"required": true,
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "The file.",
|
|
"content": {
|
|
"application/vnd.apple.mpegurl": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/File"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
}
|
|
},
|
|
"security": [
|
|
{}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"schemas": {
|
|
"Account": {
|
|
"type": "object",
|
|
"description": "A staff account as the routes show it (never the hash).",
|
|
"required": [
|
|
"id",
|
|
"username",
|
|
"name",
|
|
"role",
|
|
"created_ms",
|
|
"has_email"
|
|
],
|
|
"properties": {
|
|
"created_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"disabled_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "Unix milliseconds; `None` while the account is on.",
|
|
"minimum": 0
|
|
},
|
|
"has_email": {
|
|
"type": "boolean",
|
|
"description": "Whether an address is set for the emailed code (the address itself is never kept)."
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/StaffRole"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"AccountsBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"accounts"
|
|
],
|
|
"properties": {
|
|
"accounts": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Account"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Answer": {
|
|
"type": "object",
|
|
"description": "The page's answer, in the call-in request.",
|
|
"required": [
|
|
"token",
|
|
"nonce"
|
|
],
|
|
"properties": {
|
|
"nonce": {
|
|
"type": "string"
|
|
},
|
|
"token": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ApiToken": {
|
|
"type": "object",
|
|
"description": "A token as it is listed: everything but the hash.",
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"scopes",
|
|
"prefix",
|
|
"created_by",
|
|
"created_ms"
|
|
],
|
|
"properties": {
|
|
"created_by": {
|
|
"type": "string"
|
|
},
|
|
"created_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"expires_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"last_used_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"prefix": {
|
|
"type": "string",
|
|
"description": "The secret's first characters, to tell tokens apart."
|
|
},
|
|
"revoked_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"scopes": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"AskCode": {
|
|
"type": "object",
|
|
"required": [
|
|
"username",
|
|
"email"
|
|
],
|
|
"properties": {
|
|
"email": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"AudienceBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"from_ms",
|
|
"to_ms",
|
|
"listener_hours",
|
|
"sessions",
|
|
"peak",
|
|
"tracks",
|
|
"tracks_per_hour",
|
|
"hours"
|
|
],
|
|
"properties": {
|
|
"from_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"hours": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ListenerHour"
|
|
}
|
|
},
|
|
"listener_hours": {
|
|
"type": "number",
|
|
"format": "double"
|
|
},
|
|
"peak": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"sessions": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"to_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"tracks": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"tracks_per_hour": {
|
|
"type": "number",
|
|
"format": "double"
|
|
}
|
|
}
|
|
},
|
|
"AudienceView": {
|
|
"type": "object",
|
|
"description": "The audience as the app shows it, and the figures its CDN warning (ADR-0017) reads.",
|
|
"required": [
|
|
"edges"
|
|
],
|
|
"properties": {
|
|
"edges": {
|
|
"type": "boolean",
|
|
"description": "The station has edges or a CDN configured (steering has a pathway beside the origin)."
|
|
},
|
|
"listeners": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "Listeners connected to the station's stream now; `None` while not counted.",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"AutodjStatus": {
|
|
"type": "object",
|
|
"required": [
|
|
"current",
|
|
"queued",
|
|
"remaining"
|
|
],
|
|
"properties": {
|
|
"current": {
|
|
"type": "string"
|
|
},
|
|
"queued": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"remaining": {
|
|
"type": "number",
|
|
"format": "double"
|
|
}
|
|
}
|
|
},
|
|
"Ban": {
|
|
"type": "object",
|
|
"required": [
|
|
"date",
|
|
"reason"
|
|
],
|
|
"properties": {
|
|
"date": {
|
|
"type": "string",
|
|
"description": "The day it was made, as the screener reads it (`2026-09-12`)."
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Bank": {
|
|
"type": "object",
|
|
"required": [
|
|
"number",
|
|
"name",
|
|
"colour_slot"
|
|
],
|
|
"properties": {
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "1 to [`COLOUR_SLOTS`]: the bank's (and its show's) colour.",
|
|
"minimum": 0
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "1 to [`BANKS`].",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"BankRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"colour_slot"
|
|
],
|
|
"properties": {
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"CallInInfo": {
|
|
"type": "object",
|
|
"required": [
|
|
"open",
|
|
"consent_text",
|
|
"consent_version",
|
|
"name_max",
|
|
"topic_max"
|
|
],
|
|
"properties": {
|
|
"consent_text": {
|
|
"type": "string"
|
|
},
|
|
"consent_version": {
|
|
"type": "string"
|
|
},
|
|
"name_max": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"open": {
|
|
"type": "boolean"
|
|
},
|
|
"topic_max": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"why_not": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Why not, in a sentence for the listener."
|
|
}
|
|
}
|
|
},
|
|
"CallInRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"topic"
|
|
],
|
|
"properties": {
|
|
"challenge": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Answer",
|
|
"description": "The answered challenge ([`crate::challenge`]); needed unless `join.challenge_bits` is 0."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"consent": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ConsentGiven"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"topic": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"CallerNote": {
|
|
"type": "object",
|
|
"required": [
|
|
"line",
|
|
"note",
|
|
"name_on_air",
|
|
"sent",
|
|
"taken"
|
|
],
|
|
"properties": {
|
|
"line": {
|
|
"type": "string"
|
|
},
|
|
"name_on_air": {
|
|
"type": "string"
|
|
},
|
|
"note": {
|
|
"type": "string"
|
|
},
|
|
"sent": {
|
|
"type": "boolean"
|
|
},
|
|
"taken": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"CallerState": {
|
|
"type": "string",
|
|
"enum": [
|
|
"waiting",
|
|
"screening",
|
|
"ready"
|
|
]
|
|
},
|
|
"CallerView": {
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"name",
|
|
"ordinal",
|
|
"state",
|
|
"since_ms",
|
|
"arrived_ms",
|
|
"line",
|
|
"note",
|
|
"name_on_air",
|
|
"topic",
|
|
"on_air",
|
|
"cue",
|
|
"linked",
|
|
"present"
|
|
],
|
|
"properties": {
|
|
"arrived_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"banned_before": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Ban"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"consent": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Consent",
|
|
"description": "Their consent to record; `None` means they cannot go to the desk."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"cue": {
|
|
"type": "boolean"
|
|
},
|
|
"declined": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Declined"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"dropped_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"line": {
|
|
"type": "string"
|
|
},
|
|
"linked": {
|
|
"type": "boolean"
|
|
},
|
|
"lufs": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"name_on_air": {
|
|
"type": "string"
|
|
},
|
|
"note": {
|
|
"type": "string"
|
|
},
|
|
"on_air": {
|
|
"type": "boolean"
|
|
},
|
|
"ordinal": {
|
|
"type": "integer",
|
|
"description": "1, 2, 3...: their place in the queue, the screener's jump key.",
|
|
"minimum": 0
|
|
},
|
|
"present": {
|
|
"type": "boolean"
|
|
},
|
|
"since_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"slot": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 0
|
|
},
|
|
"state": {
|
|
"$ref": "#/components/schemas/CallerState"
|
|
},
|
|
"topic": {
|
|
"type": "string",
|
|
"description": "What they typed on the player page."
|
|
}
|
|
}
|
|
},
|
|
"CardFields": {
|
|
"type": "object",
|
|
"description": "A card's fields, as `weavesignal-cards`' `CardData` has them (inheritance already resolved).",
|
|
"required": [
|
|
"layout",
|
|
"colour_slot",
|
|
"show",
|
|
"hosts"
|
|
],
|
|
"properties": {
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "1 to 12: the show's bank slot in the palette (ADR-0066).",
|
|
"minimum": 0
|
|
},
|
|
"episode": {
|
|
"description": "`number`, `title`, and optionally `air` (a zoned time). Needs `series`."
|
|
},
|
|
"guests": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"hosts": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"layout": {
|
|
"type": "string",
|
|
"description": "The layout: `poster` or `slate`."
|
|
},
|
|
"series": {
|
|
"description": "`number`, and optionally `title`, `first`, `last` and `episodes`."
|
|
},
|
|
"show": {
|
|
"description": "`name`, `slug`, and optionally `description` and `slot` (`weekday`, `start`, `end`)."
|
|
},
|
|
"station": {
|
|
"description": "`name`, `place` and `address`; left out, the station's own are filled in."
|
|
}
|
|
}
|
|
},
|
|
"CardWords": {
|
|
"type": "object",
|
|
"required": [
|
|
"alt",
|
|
"path",
|
|
"level",
|
|
"station"
|
|
],
|
|
"properties": {
|
|
"alt": {
|
|
"type": "string"
|
|
},
|
|
"level": {
|
|
"type": "string",
|
|
"description": "`show`, `series` or `episode`."
|
|
},
|
|
"path": {
|
|
"type": "string",
|
|
"description": "The page the card links to, on the station's public address."
|
|
},
|
|
"station": {
|
|
"description": "The station fields the preview will print."
|
|
}
|
|
}
|
|
},
|
|
"CardsKept": {
|
|
"type": "object",
|
|
"description": "Documentation of the answers and bodies the handlers build from `serde_json::Value`.",
|
|
"required": [
|
|
"link",
|
|
"post",
|
|
"square",
|
|
"alt"
|
|
],
|
|
"properties": {
|
|
"alt": {
|
|
"type": "string",
|
|
"description": "The cards' alternative text."
|
|
},
|
|
"link": {
|
|
"type": "string",
|
|
"description": "The file names of the current cards, in `/cards/`."
|
|
},
|
|
"post": {
|
|
"type": "string"
|
|
},
|
|
"square": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Cart": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"bank",
|
|
"slot",
|
|
"label",
|
|
"detail",
|
|
"mode",
|
|
"duration_ms",
|
|
"gain_db",
|
|
"origin",
|
|
"licence"
|
|
],
|
|
"properties": {
|
|
"bank": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"detail": {
|
|
"type": "string",
|
|
"description": "A second line: an intro's artist, say."
|
|
},
|
|
"duration_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"file": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The media worker's FLAC, `<uuid>.flac`; `None` is FILE MISSING."
|
|
},
|
|
"gain_db": {
|
|
"type": "number",
|
|
"format": "float",
|
|
"description": "Applied at play time, to bring the cart to the station's loudness target."
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"label": {
|
|
"type": "string"
|
|
},
|
|
"licence": {
|
|
"type": "string"
|
|
},
|
|
"loudness_lufs": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float",
|
|
"description": "The file as it came: integrated loudness and true peak."
|
|
},
|
|
"mode": {
|
|
"$ref": "#/components/schemas/CartMode"
|
|
},
|
|
"origin": {
|
|
"type": "string",
|
|
"description": "Where it came from: an uploaded file's name, or `demo:<id>`."
|
|
},
|
|
"ramp_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "Milliseconds to the first vocal, for the talk-up countdown.",
|
|
"minimum": 0
|
|
},
|
|
"slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "1 to [`SLOTS`].",
|
|
"minimum": 0
|
|
},
|
|
"true_peak_dbtp": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
}
|
|
}
|
|
},
|
|
"CartCommand": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"description": "A cart's key: fire it, or fade it out if it is sounding (keymap section 4).",
|
|
"required": [
|
|
"cart",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"toggle"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"cart",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"fire"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"cart",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"stop"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "`Space`: fade out the cart started last.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"stop_last"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "`⇧Space ⇧Space`: fade out everything sounding.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"fade_all"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "`⇧` and a cart's key: cue it into the presenters' ears, or take it out of the cue.",
|
|
"required": [
|
|
"cart",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cue"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "`Esc`: take every cued cart out of the cue.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"clear_cue"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "What the studio app asks of the wall (`POST /api/v1/carts/commands`)."
|
|
},
|
|
"CartMode": {
|
|
"type": "string",
|
|
"description": "How a cart plays (report 08's three modes).",
|
|
"enum": [
|
|
"one_shot",
|
|
"bed",
|
|
"sweeper"
|
|
]
|
|
},
|
|
"CartsView": {
|
|
"type": "object",
|
|
"description": "The cart wall in the studio's view (every change is an event); the banks and carts\nthemselves come from `GET /api/v1/carts` when `version` changes.",
|
|
"required": [
|
|
"version",
|
|
"desk",
|
|
"sounding",
|
|
"ducked",
|
|
"mic_open",
|
|
"missing"
|
|
],
|
|
"properties": {
|
|
"desk": {
|
|
"type": "boolean",
|
|
"description": "The desk, which plays the carts, answers; else why not."
|
|
},
|
|
"desk_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"ducked": {
|
|
"type": "boolean"
|
|
},
|
|
"importing": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": false,
|
|
"prefixItems": [
|
|
{
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
{
|
|
"type": "integer",
|
|
"minimum": 0
|
|
}
|
|
],
|
|
"description": "Loading a pack: `[done, total]`."
|
|
},
|
|
"mic_open": {
|
|
"type": "boolean"
|
|
},
|
|
"missing": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
},
|
|
"sounding": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Sounding"
|
|
}
|
|
},
|
|
"version": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"Catalogue": {
|
|
"type": "object",
|
|
"description": "`GET /api/v1/carts`.",
|
|
"required": [
|
|
"version",
|
|
"banks",
|
|
"carts",
|
|
"loudness_lufs"
|
|
],
|
|
"properties": {
|
|
"banks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Bank"
|
|
}
|
|
},
|
|
"carts": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/CatalogueCart"
|
|
}
|
|
},
|
|
"loudness_lufs": {
|
|
"type": "number",
|
|
"format": "double",
|
|
"description": "The loudness every cart is brought to, in LUFS."
|
|
},
|
|
"version": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"CatalogueCart": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Cart"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"missing"
|
|
],
|
|
"properties": {
|
|
"missing": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"Challenge": {
|
|
"type": "object",
|
|
"description": "A challenge as the page receives it.",
|
|
"required": [
|
|
"token",
|
|
"salt",
|
|
"bits",
|
|
"expires_at_ms"
|
|
],
|
|
"properties": {
|
|
"bits": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"expires_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"salt": {
|
|
"type": "string",
|
|
"description": "What the page hashes: `salt \":\" nonce`."
|
|
},
|
|
"token": {
|
|
"type": "string",
|
|
"description": "The signed challenge, sent back as it is."
|
|
}
|
|
}
|
|
},
|
|
"ChangeBody": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"events": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"name": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"url": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ChangeReq": {
|
|
"type": "object",
|
|
"properties": {
|
|
"disabled": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"name": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"role": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/StaffRole"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ChatCommand": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"mode",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"mode": {
|
|
"$ref": "#/components/schemas/Mode"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"mode"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "On: five settings at once; off: the earlier settings back (ADR-0068).",
|
|
"required": [
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"influx"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"ChatModes": {
|
|
"type": "object",
|
|
"required": [
|
|
"slow",
|
|
"hold_new",
|
|
"links_trusted",
|
|
"accounts_only",
|
|
"min_age_24h"
|
|
],
|
|
"properties": {
|
|
"accounts_only": {
|
|
"type": "boolean"
|
|
},
|
|
"hold_new": {
|
|
"type": "boolean"
|
|
},
|
|
"links_trusted": {
|
|
"type": "boolean"
|
|
},
|
|
"min_age_24h": {
|
|
"type": "boolean"
|
|
},
|
|
"slow": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"ChatView": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ChatModes"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"influx"
|
|
],
|
|
"properties": {
|
|
"influx": {
|
|
"type": "boolean"
|
|
},
|
|
"influx_since_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"Choice": {
|
|
"type": "object",
|
|
"description": "A setting as the screen sends it.",
|
|
"required": [
|
|
"preset"
|
|
],
|
|
"properties": {
|
|
"based_on": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Under Custom: the preset whose floors become warnings."
|
|
},
|
|
"broadcast_licence": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"by": {
|
|
"type": "string",
|
|
"description": "Who is making the change (needed to save; a preview leaves it out)."
|
|
},
|
|
"periods": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Periods",
|
|
"description": "Under Custom: every period."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"preset": {
|
|
"type": "string"
|
|
},
|
|
"us_statutory_licence": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ClockBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"slots"
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"slots": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ClockSlot"
|
|
}
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ClockSlot": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"description": "The next track of a library category (`a`, `gold`, ...), by rotation.",
|
|
"required": [
|
|
"category"
|
|
],
|
|
"properties": {
|
|
"category": {
|
|
"type": "string",
|
|
"description": "The next track of a library category (`a`, `gold`, ...), by rotation."
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "A cart from the wall: a station ident, a sweeper.",
|
|
"required": [
|
|
"cart"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid",
|
|
"description": "A cart from the wall: a station ident, a sweeper."
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "One position in a clock."
|
|
},
|
|
"ClockView": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"slots"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"slots": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ClockSlot"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ClocksBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"clocks"
|
|
],
|
|
"properties": {
|
|
"clocks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ClockView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"CodeAsked": {
|
|
"type": "object",
|
|
"required": [
|
|
"asked",
|
|
"expires_s"
|
|
],
|
|
"properties": {
|
|
"asked": {
|
|
"type": "boolean"
|
|
},
|
|
"expires_s": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Seconds the code is good for.",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"ComplaintHold": {
|
|
"type": "object",
|
|
"description": "What a rule says about keeping records longer once a complaint arrives (ADR-0116).",
|
|
"required": [
|
|
"rule"
|
|
],
|
|
"properties": {
|
|
"days": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "The extended period from the broadcast, where the rule fixes one.",
|
|
"minimum": 0
|
|
},
|
|
"rule": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Consent": {
|
|
"type": "object",
|
|
"description": "A caller's consent to record: when, to which words, and who gave it.",
|
|
"required": [
|
|
"at_ms",
|
|
"version",
|
|
"by"
|
|
],
|
|
"properties": {
|
|
"at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"by": {
|
|
"$ref": "#/components/schemas/ConsentBy"
|
|
},
|
|
"version": {
|
|
"type": "string",
|
|
"description": "The words' version: the first 16 hex digits of their SHA-256."
|
|
}
|
|
}
|
|
},
|
|
"ConsentBy": {
|
|
"type": "string",
|
|
"description": "Who gave the consent: the caller on the player page, or the station on their behalf (an\nadmin's token request, for a test or a consent taken another way).",
|
|
"enum": [
|
|
"caller",
|
|
"station"
|
|
]
|
|
},
|
|
"ConsentErased": {
|
|
"type": "object",
|
|
"required": [
|
|
"erased"
|
|
],
|
|
"properties": {
|
|
"erased": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"ConsentFound": {
|
|
"type": "object",
|
|
"description": "A caller's consent as the erasure search shows it.",
|
|
"required": [
|
|
"id",
|
|
"identity",
|
|
"name",
|
|
"topic",
|
|
"accepted_at_ms",
|
|
"erased"
|
|
],
|
|
"properties": {
|
|
"accepted_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Unix ms."
|
|
},
|
|
"erased": {
|
|
"type": "boolean"
|
|
},
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"topic": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"ConsentGiven": {
|
|
"type": "object",
|
|
"description": "The consent the caller gave on the page: that they accepted, and the words' version.",
|
|
"required": [
|
|
"accepted",
|
|
"version"
|
|
],
|
|
"properties": {
|
|
"accepted": {
|
|
"type": "boolean"
|
|
},
|
|
"version": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Corrected": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"correction",
|
|
"files_retagged"
|
|
],
|
|
"properties": {
|
|
"correction": {
|
|
"$ref": "#/components/schemas/Correction"
|
|
},
|
|
"files_problem": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Why they were not, when they should have been: the correction itself stands."
|
|
},
|
|
"files_retagged": {
|
|
"type": "boolean",
|
|
"description": "The published files were tagged again with the corrected text and the new square."
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "What a correction answers (ADR-0177)."
|
|
},
|
|
"Correction": {
|
|
"type": "object",
|
|
"description": "One line of the corrections log. `old_values` and `new_values` hold the fields that\nchanged, as they were and as they became.",
|
|
"required": [
|
|
"id",
|
|
"episode_id",
|
|
"made_at",
|
|
"made_by",
|
|
"reason",
|
|
"old_values",
|
|
"new_values",
|
|
"redacted"
|
|
],
|
|
"properties": {
|
|
"episode_id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"made_at": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Seconds since the Unix epoch."
|
|
},
|
|
"made_by": {
|
|
"type": "string",
|
|
"description": "How the log names who made it: a username, or \"station key\"."
|
|
},
|
|
"new_values": {},
|
|
"old_values": {},
|
|
"reason": {
|
|
"type": "string"
|
|
},
|
|
"redacted": {
|
|
"type": "boolean",
|
|
"description": "An erasure (ADR-0122) took a person's name out of this line."
|
|
}
|
|
}
|
|
},
|
|
"CorrectionInput": {
|
|
"type": "object",
|
|
"description": "A correction to the public text of an aired episode (ADR-0177). Fields left out are not\nchanged. What was broadcast (the air time, the length, the kind, the colour and layout) is\nnot text and is not corrected; the frozen record under it stays.",
|
|
"required": [
|
|
"reason"
|
|
],
|
|
"properties": {
|
|
"description": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"guests": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"hosts": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"reason": {
|
|
"type": "string",
|
|
"description": "Why, in a sentence: the log keeps it beside who made the correction."
|
|
},
|
|
"tags": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Created": {
|
|
"type": "object",
|
|
"required": [
|
|
"id"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
},
|
|
"Current": {
|
|
"type": "object",
|
|
"required": [
|
|
"kind",
|
|
"title",
|
|
"artist",
|
|
"album",
|
|
"started_at_ms"
|
|
],
|
|
"properties": {
|
|
"album": {
|
|
"type": "string"
|
|
},
|
|
"artist": {
|
|
"type": "string"
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "`track`, `cart`, `fallback` or `live`."
|
|
},
|
|
"started_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Declined": {
|
|
"type": "object",
|
|
"required": [
|
|
"at_ms",
|
|
"reason"
|
|
],
|
|
"properties": {
|
|
"at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"DelayView": {
|
|
"type": "object",
|
|
"description": "The profanity delay as the desk's delay panel shows it.",
|
|
"required": [
|
|
"delay_ms",
|
|
"target_ms",
|
|
"rebuilding",
|
|
"dumps"
|
|
],
|
|
"properties": {
|
|
"delay_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"dumped_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "When the last dump was, on the station's clock, to the second (so the view does not\nchange with every look at the desk).",
|
|
"minimum": 0
|
|
},
|
|
"dumps": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"rebuilding": {
|
|
"type": "boolean"
|
|
},
|
|
"target_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"DeskCommand": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"on_air"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"mute"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cue"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"talk"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"to",
|
|
"on",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"talk_to"
|
|
]
|
|
},
|
|
"to": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Dump the profanity delay (`Del Del`): listeners jump to the live programme, and the\ndelay builds back up. Allowed while it rebuilds; refused only when nothing is held.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"dump"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Who chooses the picture (video on): `auto` follows the audio, `slate` holds the slate\n(desk B's F7), `person` holds one camera.",
|
|
"required": [
|
|
"mode",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"mode": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"picture"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "A line over the picture for `ms` (a featured chat message); `text` empty takes it down.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"caption"
|
|
]
|
|
},
|
|
"text": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "The slate's text (ADR-0010), from what playout says is playing.",
|
|
"required": [
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"artist": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"now_playing"
|
|
]
|
|
},
|
|
"show": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"station": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "The station's mode (ADR-0045): in auto mode the video's sound is playout's feed whoever\nis live at the desk (ADR-0172). Sent when the desk's status says another.",
|
|
"required": [
|
|
"mode",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"mode": {
|
|
"$ref": "#/components/schemas/StationMode"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"mode"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "A command for the desk; the socket's own words."
|
|
},
|
|
"DeskPerson": {
|
|
"type": "object",
|
|
"description": "A person as the desk reports them.",
|
|
"required": [
|
|
"identity",
|
|
"role",
|
|
"on_air",
|
|
"talk",
|
|
"present",
|
|
"linked"
|
|
],
|
|
"properties": {
|
|
"away_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"cue": {
|
|
"type": "boolean"
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"linked": {
|
|
"type": "boolean"
|
|
},
|
|
"lufs": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
},
|
|
"lufs_peak": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
},
|
|
"mute": {
|
|
"type": "boolean"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"on_air": {
|
|
"type": "boolean"
|
|
},
|
|
"present": {
|
|
"type": "boolean"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
},
|
|
"talk": {
|
|
"type": "boolean"
|
|
},
|
|
"talk_to": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"DeskVideo": {
|
|
"type": "object",
|
|
"description": "The video path as the desk reports it (M5, ADR-0009): absent with video off.",
|
|
"properties": {
|
|
"cameras": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "Whose camera has a picture at the desk."
|
|
},
|
|
"hls": {
|
|
"type": "boolean",
|
|
"description": "The encoders and the HLS writer are running."
|
|
},
|
|
"identity": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"mode": {
|
|
"description": "Who chooses the picture: `{\"mode\": \"auto\"}`, `{\"mode\": \"slate\"}` (F7), or\n`{\"mode\": \"person\", \"identity\": …}`."
|
|
},
|
|
"room": {
|
|
"type": "boolean",
|
|
"description": "The programme picture is published into the room."
|
|
},
|
|
"shot": {
|
|
"type": "string",
|
|
"description": "What is on air: `slate` or `person` (with `identity`)."
|
|
},
|
|
"still": {
|
|
"type": "boolean",
|
|
"description": "The slate has a picture (ADR-0010)."
|
|
}
|
|
}
|
|
},
|
|
"DeskView": {
|
|
"type": "object",
|
|
"required": [
|
|
"reachable",
|
|
"playout"
|
|
],
|
|
"properties": {
|
|
"delay": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/DelayView",
|
|
"description": "The profanity delay (desk B's `desk.delay`); `None` while the desk does not answer."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"picture": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/DeskVideo",
|
|
"description": "The picture (desk B's `desk.picture`, F7): `None` with video off."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"playout": {
|
|
"$ref": "#/components/schemas/PlayoutLink"
|
|
},
|
|
"reachable": {
|
|
"type": "boolean",
|
|
"description": "The desk answers on its control socket."
|
|
}
|
|
}
|
|
},
|
|
"EdgeHealth": {
|
|
"type": "object",
|
|
"description": "What the control plane knows of one edge's health.",
|
|
"required": [
|
|
"up",
|
|
"failures",
|
|
"since"
|
|
],
|
|
"properties": {
|
|
"failures": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Failed checks in a row.",
|
|
"minimum": 0
|
|
},
|
|
"last_check": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"last_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The last failure's reason, cleared by a pass."
|
|
},
|
|
"last_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "How long the last check took, in milliseconds.",
|
|
"minimum": 0
|
|
},
|
|
"since": {
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "When `up` last changed (or the control plane started)."
|
|
},
|
|
"up": {
|
|
"type": "boolean",
|
|
"description": "In the order: checked and passing, or never checked."
|
|
}
|
|
}
|
|
},
|
|
"EdgeView": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/EdgeHealth"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"pathway",
|
|
"host",
|
|
"weight",
|
|
"checked",
|
|
"first"
|
|
],
|
|
"properties": {
|
|
"checked": {
|
|
"type": "boolean"
|
|
},
|
|
"first": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Manifests since the control plane started that put this edge first.",
|
|
"minimum": 0
|
|
},
|
|
"host": {
|
|
"type": "string"
|
|
},
|
|
"pathway": {
|
|
"type": "string"
|
|
},
|
|
"weight": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"EdgesBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"enabled",
|
|
"ttl_s",
|
|
"edges"
|
|
],
|
|
"properties": {
|
|
"edges": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EdgeView"
|
|
}
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"ttl_s": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"EditBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"track"
|
|
],
|
|
"properties": {
|
|
"force": {
|
|
"type": "boolean",
|
|
"description": "Accept a break of the station's own separations (never of the US statutory licence)."
|
|
},
|
|
"track": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"EditedBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"track",
|
|
"note"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"note": {
|
|
"type": "string"
|
|
},
|
|
"track": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
},
|
|
"End": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ended_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "When it ended; now when left out.",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"EndPassRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"identity"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string",
|
|
"description": "The person whose pass ends."
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Episode": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"series_id",
|
|
"number",
|
|
"title",
|
|
"description",
|
|
"kind",
|
|
"guests"
|
|
],
|
|
"properties": {
|
|
"air_at": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "Seconds since the Unix epoch."
|
|
},
|
|
"aired_at": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"cards": {},
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"files": {},
|
|
"frozen": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Resolved"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"guests": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
},
|
|
"hosts": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/EpisodeKind",
|
|
"description": "Live unless marked pre-recorded (ADR-0188)."
|
|
},
|
|
"minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "`None` inherits the slot's length.",
|
|
"minimum": 0
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"series_id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"tags": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"EpisodeKind": {
|
|
"type": "string",
|
|
"description": "Whether an episode is broadcast live or played from a recording (ADR-0188). Studios, the\nother half of that decision, are not modelled yet.",
|
|
"enum": [
|
|
"live",
|
|
"prerecorded"
|
|
]
|
|
},
|
|
"EpisodePatch": {
|
|
"type": "object",
|
|
"description": "A change to an episode. An inheriting field set to `null` goes back to inheriting.",
|
|
"properties": {
|
|
"air_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"description": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"guests": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"hosts": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"kind": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/EpisodeKind",
|
|
"description": "Live or pre-recorded (ADR-0188); it has no level above to inherit from."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"tags": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"EpisodeRef": {
|
|
"type": "object",
|
|
"description": "An episode named in an erasure's answer.",
|
|
"required": [
|
|
"show",
|
|
"series",
|
|
"episode",
|
|
"title"
|
|
],
|
|
"properties": {
|
|
"episode": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"series": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"show": {
|
|
"type": "string"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"EpisodeView": {
|
|
"type": "object",
|
|
"required": [
|
|
"episode",
|
|
"resolved"
|
|
],
|
|
"properties": {
|
|
"episode": {
|
|
"$ref": "#/components/schemas/Episode"
|
|
},
|
|
"resolved": {
|
|
"$ref": "#/components/schemas/Resolved"
|
|
}
|
|
}
|
|
},
|
|
"EraseConsent": {
|
|
"type": "object",
|
|
"required": [
|
|
"by"
|
|
],
|
|
"properties": {
|
|
"by": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Erased": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"shows",
|
|
"series",
|
|
"episodes",
|
|
"cards_redrawn",
|
|
"card_files_deleted",
|
|
"cards_not_redrawn",
|
|
"corrections_redacted",
|
|
"mentions",
|
|
"files"
|
|
],
|
|
"properties": {
|
|
"card_files_deleted": {
|
|
"type": "integer",
|
|
"description": "Card files that named them, deleted.",
|
|
"minimum": 0
|
|
},
|
|
"cards_not_redrawn": {
|
|
"type": "integer",
|
|
"description": "Cards that could not be drawn again (cards are off: no public address): still old.",
|
|
"minimum": 0
|
|
},
|
|
"cards_redrawn": {
|
|
"type": "integer",
|
|
"description": "Cards drawn again without the name.",
|
|
"minimum": 0
|
|
},
|
|
"corrections_redacted": {
|
|
"type": "integer",
|
|
"description": "Lines of the corrections log that held the name, redacted (ADR-0177).",
|
|
"minimum": 0
|
|
},
|
|
"episodes": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"files": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EpisodeRef"
|
|
},
|
|
"description": "Published audio files whose tags may still name them: to be published again."
|
|
},
|
|
"mentions": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EpisodeRef"
|
|
},
|
|
"description": "Episodes whose title or description still names them: for a person to edit."
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"series": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"shows": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"EventInfo": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"description"
|
|
],
|
|
"properties": {
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Extension": {
|
|
"type": "object",
|
|
"description": "What extending a hold says (ADR-0156).",
|
|
"required": [
|
|
"until_ms",
|
|
"by",
|
|
"reason"
|
|
],
|
|
"properties": {
|
|
"by": {
|
|
"type": "string",
|
|
"description": "Who extends it."
|
|
},
|
|
"reason": {
|
|
"type": "string",
|
|
"description": "Why it has to be kept longer."
|
|
},
|
|
"until_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "The new date to keep it until, in milliseconds since the epoch.",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"File": {
|
|
"type": "string",
|
|
"format": "binary",
|
|
"description": "A file as the whole body: audio to normalise, a picture."
|
|
},
|
|
"FilesInput": {
|
|
"type": "object",
|
|
"required": [
|
|
"enclosure"
|
|
],
|
|
"properties": {
|
|
"enclosure": {
|
|
"type": "string",
|
|
"description": "The MP3 or AAC file (ADR-0018), as named in `publishing.episodes_dir`."
|
|
},
|
|
"opus": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The Ogg Opus copy."
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"FinishCode": {
|
|
"type": "object",
|
|
"required": [
|
|
"username",
|
|
"email",
|
|
"code"
|
|
],
|
|
"properties": {
|
|
"code": {
|
|
"type": "string"
|
|
},
|
|
"email": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Floor": {
|
|
"type": "object",
|
|
"description": "The least a rule requires, in days, and the rule.",
|
|
"required": [
|
|
"days",
|
|
"rule"
|
|
],
|
|
"properties": {
|
|
"condition": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "When the floor applies, where it applies only in some cases (ADR-0155); `None` when it\nalways does."
|
|
},
|
|
"days": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"rule": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"GenerateBody": {
|
|
"type": "object",
|
|
"properties": {
|
|
"from_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"to_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"GeneratedBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"items",
|
|
"gaps"
|
|
],
|
|
"properties": {
|
|
"gaps": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "What could not be filled, in words."
|
|
},
|
|
"items": {
|
|
"type": "integer",
|
|
"description": "How many items the log now holds for the span.",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"Health": {
|
|
"type": "object",
|
|
"required": [
|
|
"status",
|
|
"version",
|
|
"database"
|
|
],
|
|
"properties": {
|
|
"database": {
|
|
"type": "string"
|
|
},
|
|
"status": {
|
|
"type": "string"
|
|
},
|
|
"version": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Hold": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"reason",
|
|
"placed_by",
|
|
"placed_at_ms",
|
|
"records",
|
|
"recordings",
|
|
"consents"
|
|
],
|
|
"properties": {
|
|
"consents": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"extend_reason": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"extended_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"extended_by": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"extended_until_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "The date its latest extension fixed, which replaces the date the complaint rule gives\n(ADR-0156), and who extended it, when and why.",
|
|
"minimum": 0
|
|
},
|
|
"from_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"placed_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"placed_by": {
|
|
"type": "string"
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
},
|
|
"recordings": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "What it keeps now: recordings not yet deleted, and consents."
|
|
},
|
|
"records": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/HoldRecord"
|
|
}
|
|
},
|
|
"release_reason": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"released_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"released_by": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"to_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"HoldRecord": {
|
|
"type": "object",
|
|
"required": [
|
|
"kind",
|
|
"id"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/HoldTarget"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"HoldTarget": {
|
|
"type": "string",
|
|
"description": "What a hold can name one by one in this release.",
|
|
"enum": [
|
|
"recording",
|
|
"consent"
|
|
]
|
|
},
|
|
"Invite": {
|
|
"type": "object",
|
|
"required": [
|
|
"pass",
|
|
"identity",
|
|
"role",
|
|
"name",
|
|
"expires_at_ms",
|
|
"link"
|
|
],
|
|
"properties": {
|
|
"expires_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"link": {
|
|
"type": "string",
|
|
"description": "The join page's path with the pass in the fragment, which browsers never send."
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"pass": {
|
|
"type": "string"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
}
|
|
}
|
|
},
|
|
"InviteRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"role"
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
},
|
|
"ttl_s": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "Seconds; the station's `join.invite_ttl_s` when left out, and never more.",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Joined": {
|
|
"type": "object",
|
|
"description": "What a person gets to join: a room token, its pass, and the one track to listen to.",
|
|
"required": [
|
|
"pass",
|
|
"token",
|
|
"url",
|
|
"room",
|
|
"identity",
|
|
"role",
|
|
"name",
|
|
"hear",
|
|
"pass_expires_at_ms"
|
|
],
|
|
"properties": {
|
|
"hear": {
|
|
"type": "string",
|
|
"description": "The desk's participant that publishes this person's mix-minus: the only one to\nsubscribe to (every mix-minus is visible to everyone in the room)."
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"pass": {
|
|
"type": "string"
|
|
},
|
|
"pass_expires_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
},
|
|
"room": {
|
|
"type": "string"
|
|
},
|
|
"see": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "While the desk has video on: the desk's participant that publishes the programme\npicture, the only picture to subscribe to (ADR-0028), and the page offers the camera."
|
|
},
|
|
"token": {
|
|
"type": "string"
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Kind": {
|
|
"type": "string",
|
|
"description": "The kinds of record a preset sets a period for (ADR-0113's list, recce 27's columns).",
|
|
"enum": [
|
|
"programme_recordings",
|
|
"per_play_log",
|
|
"chat_messages",
|
|
"moderation_records",
|
|
"consent",
|
|
"call_recordings",
|
|
"listener_statistics",
|
|
"access_logs"
|
|
]
|
|
},
|
|
"LastSweep": {
|
|
"type": "object",
|
|
"description": "The last sweep, as logged.",
|
|
"required": [
|
|
"finished_at_ms",
|
|
"preset",
|
|
"recordings_deleted",
|
|
"files_missing",
|
|
"consents_deleted",
|
|
"held",
|
|
"errors"
|
|
],
|
|
"properties": {
|
|
"consents_deleted": {
|
|
"type": "integer",
|
|
"format": "int32"
|
|
},
|
|
"errors": {
|
|
"type": "string"
|
|
},
|
|
"files_missing": {
|
|
"type": "integer",
|
|
"format": "int32"
|
|
},
|
|
"finished_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"held": {
|
|
"type": "integer",
|
|
"format": "int32"
|
|
},
|
|
"preset": {
|
|
"type": "string"
|
|
},
|
|
"recordings_deleted": {
|
|
"type": "integer",
|
|
"format": "int32"
|
|
}
|
|
}
|
|
},
|
|
"Level": {
|
|
"type": "string",
|
|
"enum": [
|
|
"warning",
|
|
"serious"
|
|
]
|
|
},
|
|
"Link": {
|
|
"type": "object",
|
|
"required": [
|
|
"recording_id"
|
|
],
|
|
"properties": {
|
|
"recording_id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Listed": {
|
|
"type": "object",
|
|
"required": [
|
|
"tokens",
|
|
"scopes"
|
|
],
|
|
"properties": {
|
|
"scopes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Scope"
|
|
}
|
|
},
|
|
"tokens": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ApiToken"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ListenerDelay": {
|
|
"type": "object",
|
|
"description": "The listener delay the surfaces show: a setting until it is measured (ADR-0103), plus the\nprofanity delay's current length (ADR-0165).",
|
|
"required": [
|
|
"ms",
|
|
"measured"
|
|
],
|
|
"properties": {
|
|
"measured": {
|
|
"type": "boolean",
|
|
"description": "Always false in this build: nothing measures it yet, so the app labels it a setting."
|
|
},
|
|
"ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "The `studio.listener_delay_ms` setting plus how much the desk's profanity delay holds now.",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"ListenerHour": {
|
|
"type": "object",
|
|
"description": "An hour's anonymous totals.",
|
|
"required": [
|
|
"hour_ms",
|
|
"listener_seconds",
|
|
"sessions",
|
|
"peak"
|
|
],
|
|
"properties": {
|
|
"hour_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"listener_seconds": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"peak": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"sessions": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"LogBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"items"
|
|
],
|
|
"properties": {
|
|
"items": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/LogEntry"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"LogEntry": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/LogItem"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"title",
|
|
"artist",
|
|
"breaches"
|
|
],
|
|
"properties": {
|
|
"artist": {
|
|
"type": "string"
|
|
},
|
|
"breaches": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"LogItem": {
|
|
"type": "object",
|
|
"description": "An item of the generated log.",
|
|
"required": [
|
|
"id",
|
|
"planned_at_ms",
|
|
"hour_ms",
|
|
"slot",
|
|
"kind",
|
|
"category",
|
|
"duration_ms",
|
|
"status",
|
|
"note"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
},
|
|
"category": {
|
|
"type": "string"
|
|
},
|
|
"clock": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
},
|
|
"duration_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"hour_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "`track` or `cart`."
|
|
},
|
|
"note": {
|
|
"type": "string"
|
|
},
|
|
"planned_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"description": "`planned`, `queued`, `played` or `skipped`."
|
|
},
|
|
"track": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
},
|
|
"LoggerBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"records",
|
|
"recordings",
|
|
"missing_hours"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"missing_hours": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "The hours of the last day with no recording while the logger was on."
|
|
},
|
|
"on": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
],
|
|
"description": "Whether the logger is on; `null` while playout does not say."
|
|
},
|
|
"recordings": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Recording"
|
|
}
|
|
},
|
|
"records": {
|
|
"type": "boolean",
|
|
"description": "Whether the retention setting lets the logger record."
|
|
}
|
|
}
|
|
},
|
|
"LoggerStatus": {
|
|
"type": "object",
|
|
"required": [
|
|
"on"
|
|
],
|
|
"properties": {
|
|
"dir": {
|
|
"type": "string"
|
|
},
|
|
"on": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"Made": {
|
|
"type": "object",
|
|
"required": [
|
|
"token",
|
|
"secret"
|
|
],
|
|
"properties": {
|
|
"secret": {
|
|
"type": "string",
|
|
"description": "The secret, shown this once."
|
|
},
|
|
"token": {
|
|
"$ref": "#/components/schemas/ApiToken"
|
|
}
|
|
}
|
|
},
|
|
"Me": {
|
|
"type": "object",
|
|
"required": [
|
|
"kind",
|
|
"role"
|
|
],
|
|
"properties": {
|
|
"account": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Account"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"expires_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "`staff`, `station` (the station key) or `token`."
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/StaffRole"
|
|
}
|
|
}
|
|
},
|
|
"Mode": {
|
|
"type": "string",
|
|
"description": "A room-wide chat mode the screener switches with one key.",
|
|
"enum": [
|
|
"slow",
|
|
"hold_new",
|
|
"links_trusted"
|
|
]
|
|
},
|
|
"NewAccount": {
|
|
"type": "object",
|
|
"required": [
|
|
"username",
|
|
"name",
|
|
"role",
|
|
"password"
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"password": {
|
|
"type": "string"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/StaffRole"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"NewBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"scopes"
|
|
],
|
|
"properties": {
|
|
"expires_in_days": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "Days from now; left out, the token does not expire.",
|
|
"minimum": 0
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"scopes": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"NewEpisodes": {
|
|
"type": "object",
|
|
"description": "The new episodes' own fields; the rest is filled in or inherited.",
|
|
"properties": {
|
|
"count": {
|
|
"type": "integer",
|
|
"description": "How many to draft from the rule: one, or a whole season (\"create 10 episodes\").",
|
|
"minimum": 0
|
|
},
|
|
"guests": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string",
|
|
"description": "The first one's title and guests; the rest start blank."
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"NewHold": {
|
|
"type": "object",
|
|
"required": [
|
|
"reason",
|
|
"by"
|
|
],
|
|
"properties": {
|
|
"by": {
|
|
"type": "string",
|
|
"description": "Who places it."
|
|
},
|
|
"from_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "A stretch of broadcast time: every recording and consent overlapping it is held.",
|
|
"minimum": 0
|
|
},
|
|
"reason": {
|
|
"type": "string",
|
|
"description": "Why: the complaint or report, in a line."
|
|
},
|
|
"records": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/HoldRecord"
|
|
},
|
|
"description": "Records named one by one."
|
|
},
|
|
"to_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"NewRecording": {
|
|
"type": "object",
|
|
"required": [
|
|
"kind",
|
|
"started_at_ms"
|
|
],
|
|
"properties": {
|
|
"ended_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"file": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Relative to the recordings directory."
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/RecordingKind"
|
|
},
|
|
"label": {
|
|
"type": "string"
|
|
},
|
|
"started_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"NextUp": {
|
|
"type": "object",
|
|
"required": [
|
|
"title",
|
|
"artist"
|
|
],
|
|
"properties": {
|
|
"artist": {
|
|
"type": "string"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Notice": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"at_ms",
|
|
"surface",
|
|
"tone",
|
|
"kind",
|
|
"title",
|
|
"message"
|
|
],
|
|
"properties": {
|
|
"at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "What it is about (`caller.ready`, `caller.declined`, ...), for the app to pick keys."
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"subject": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The person it is about, if any."
|
|
},
|
|
"surface": {
|
|
"$ref": "#/components/schemas/Surface"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
},
|
|
"tone": {
|
|
"$ref": "#/components/schemas/Tone"
|
|
}
|
|
}
|
|
},
|
|
"NowPlaying": {
|
|
"type": "object",
|
|
"description": "What listeners are told is playing.",
|
|
"required": [
|
|
"on_air",
|
|
"up_next_shown"
|
|
],
|
|
"properties": {
|
|
"next": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"$ref": "#/components/schemas/NextUp"
|
|
},
|
|
"description": "What comes next; left out for a US statutory webcaster (17 U.S.C. 114(d)(2)(C)(ii))."
|
|
},
|
|
"now": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Current"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"on_air": {
|
|
"type": "string",
|
|
"description": "`desk` (a live show), `automation`, `fallback`, `silence`, or `unknown` while playout is\nnot answering. The default loop WeaveSignal ships (ADR-0130) is told as `fallback`: to a\nlistener it is the station's fallback, and only the studio is told it is the default."
|
|
},
|
|
"up_next_shown": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"OwnEmail": {
|
|
"type": "object",
|
|
"required": [
|
|
"current",
|
|
"email"
|
|
],
|
|
"properties": {
|
|
"current": {
|
|
"type": "string"
|
|
},
|
|
"email": {}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"OwnPassword": {
|
|
"type": "object",
|
|
"required": [
|
|
"current",
|
|
"new"
|
|
],
|
|
"properties": {
|
|
"current": {
|
|
"type": "string"
|
|
},
|
|
"new": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"PassInfo": {
|
|
"type": "object",
|
|
"required": [
|
|
"kind",
|
|
"role",
|
|
"identity",
|
|
"name",
|
|
"station",
|
|
"show",
|
|
"expires_at_ms",
|
|
"ended",
|
|
"relay"
|
|
],
|
|
"properties": {
|
|
"ended": {
|
|
"type": "boolean"
|
|
},
|
|
"expires_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/PassKind"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"relay": {
|
|
"$ref": "#/components/schemas/RelayInfo"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
},
|
|
"show": {
|
|
"type": "string"
|
|
},
|
|
"station": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"PassKind": {
|
|
"type": "string",
|
|
"description": "How the pass was issued.",
|
|
"enum": [
|
|
"call",
|
|
"invite"
|
|
]
|
|
},
|
|
"Period": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"description": "A number of days after the record is complete (a recording ended, a call over); 0 is\n\"not kept after the show\".",
|
|
"required": [
|
|
"days",
|
|
"keep"
|
|
],
|
|
"properties": {
|
|
"days": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"keep": {
|
|
"type": "string",
|
|
"enum": [
|
|
"days"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Kept with its programme's archive and removed with it (ADR-0039's \"A\").",
|
|
"required": [
|
|
"keep"
|
|
],
|
|
"properties": {
|
|
"keep": {
|
|
"type": "string",
|
|
"enum": [
|
|
"with_archive"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Consent: kept while any recording it covers exists, then `days` more (ADR-0107's\n\"R+42\"); until a recording is linked, it follows the logger's period.",
|
|
"required": [
|
|
"days",
|
|
"keep"
|
|
],
|
|
"properties": {
|
|
"days": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"keep": {
|
|
"type": "string",
|
|
"enum": [
|
|
"after_recordings"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Consent under No retention: it goes when the call's last trace does (ADR-0113).",
|
|
"required": [
|
|
"keep"
|
|
],
|
|
"properties": {
|
|
"keep": {
|
|
"type": "string",
|
|
"enum": [
|
|
"with_call"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Anonymous counts only, with nothing that identifies a person (ADR-0115).",
|
|
"required": [
|
|
"keep"
|
|
],
|
|
"properties": {
|
|
"keep": {
|
|
"type": "string",
|
|
"enum": [
|
|
"no_limit"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "How long one kind of record is kept."
|
|
},
|
|
"Periods": {
|
|
"type": "object",
|
|
"description": "A period for each kind of record.",
|
|
"required": [
|
|
"programme_recordings",
|
|
"per_play_log",
|
|
"chat_messages",
|
|
"moderation_records",
|
|
"consent",
|
|
"call_recordings",
|
|
"listener_statistics",
|
|
"access_logs"
|
|
],
|
|
"properties": {
|
|
"access_logs": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"call_recordings": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"chat_messages": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"consent": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"listener_statistics": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"moderation_records": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"per_play_log": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"programme_recordings": {
|
|
"$ref": "#/components/schemas/Period"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"PersonView": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Play": {
|
|
"type": "object",
|
|
"description": "One row of the per-play log.",
|
|
"required": [
|
|
"id",
|
|
"started_at_ms",
|
|
"kind",
|
|
"title",
|
|
"artist",
|
|
"album",
|
|
"label",
|
|
"duration_ms",
|
|
"listeners",
|
|
"aired"
|
|
],
|
|
"properties": {
|
|
"aired": {
|
|
"type": "boolean",
|
|
"description": "False for a desk cart a dump threw away before listeners heard it."
|
|
},
|
|
"album": {
|
|
"type": "string"
|
|
},
|
|
"artist": {
|
|
"type": "string"
|
|
},
|
|
"cart": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
},
|
|
"duration_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"ended_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"id": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"isrc": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"item": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "`track`, `cart` or `fallback`."
|
|
},
|
|
"label": {
|
|
"type": "string"
|
|
},
|
|
"listeners": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"started_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
},
|
|
"track": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
}
|
|
}
|
|
},
|
|
"PlayerInfo": {
|
|
"type": "object",
|
|
"required": [
|
|
"station",
|
|
"show",
|
|
"stream_url",
|
|
"presenter",
|
|
"presenter_live",
|
|
"show_on_air",
|
|
"call_in",
|
|
"relay"
|
|
],
|
|
"properties": {
|
|
"call_in": {
|
|
"$ref": "#/components/schemas/CallInInfo"
|
|
},
|
|
"presenter": {
|
|
"type": "string"
|
|
},
|
|
"presenter_live": {
|
|
"type": "boolean"
|
|
},
|
|
"relay": {
|
|
"$ref": "#/components/schemas/RelayInfo",
|
|
"description": "TURN over TLS, for networks and browsers that block WebRTC's UDP (ADR-0059, ADR-0080)."
|
|
},
|
|
"show": {
|
|
"type": "string"
|
|
},
|
|
"show_on_air": {
|
|
"type": "boolean",
|
|
"description": "Listeners hear the show now."
|
|
},
|
|
"station": {
|
|
"type": "string"
|
|
},
|
|
"stream_url": {
|
|
"type": "string",
|
|
"description": "The listener stream through the proxy; empty when not set up."
|
|
},
|
|
"video": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/VideoInfo",
|
|
"description": "The picture and its sound as HLS, while the desk has video on (ADR-0009); `None`\notherwise, and the player plays `stream_url`."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"PlayoutLink": {
|
|
"type": "object",
|
|
"description": "Whether playout is connected to the desk's programme output.",
|
|
"required": [
|
|
"connected"
|
|
],
|
|
"properties": {
|
|
"connected": {
|
|
"type": "boolean"
|
|
},
|
|
"for_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"PlayoutSettings": {
|
|
"type": "object",
|
|
"description": "The station's playout settings (`playout_settings`).",
|
|
"required": [
|
|
"time_zone",
|
|
"artist_separation_min",
|
|
"title_separation_min",
|
|
"album_separation_min",
|
|
"mode"
|
|
],
|
|
"properties": {
|
|
"album_separation_min": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"artist_separation_min": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"default_clock": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"description": "`live` or `auto`."
|
|
},
|
|
"time_zone": {
|
|
"type": "string",
|
|
"description": "An IANA zone; the clocks run in its local hours."
|
|
},
|
|
"title_separation_min": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"PlaysBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"from_ms",
|
|
"to_ms",
|
|
"plays"
|
|
],
|
|
"properties": {
|
|
"from_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"plays": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Play"
|
|
}
|
|
},
|
|
"to_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
},
|
|
"Pool": {
|
|
"type": "string",
|
|
"description": "Which of the desk's cart players a cart sounds in.",
|
|
"enum": [
|
|
"shot",
|
|
"bed"
|
|
]
|
|
},
|
|
"Preset": {
|
|
"type": "object",
|
|
"description": "A Jurisdiction preset (ADR-0114).",
|
|
"required": [
|
|
"key",
|
|
"name",
|
|
"summary",
|
|
"licensed",
|
|
"chat_min_age"
|
|
],
|
|
"properties": {
|
|
"chat_min_age": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "The age a chatter declares they are at least, for this jurisdiction (ADR-0148, recce 29):\nthe age below which a person cannot consent alone to the chat processing their data. 13\nin the UK, the US and Canada (UK GDPR Art. 8, COPPA, the OPC's guidance), 16 in Ireland,\nGermany and the EU preset (GDPR Art. 8's default, safe in every member state), 15 in\nAustralia (the OAIC's presumption); 13 under No retention and Custom. A station can\nset its own (13 to 21) in the chat's settings.",
|
|
"minimum": 0
|
|
},
|
|
"complaint_hold": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ComplaintHold"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"key": {
|
|
"type": "string"
|
|
},
|
|
"licensed": {
|
|
"type": "boolean",
|
|
"description": "For a station that holds a broadcast licence."
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"summary": {
|
|
"type": "string",
|
|
"description": "The rule each period follows, in a line (recce 27's last column)."
|
|
}
|
|
}
|
|
},
|
|
"PresetView": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Preset"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"rows"
|
|
],
|
|
"properties": {
|
|
"rows": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Row"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"Preview": {
|
|
"type": "object",
|
|
"description": "A proposed setting's warnings, and what the next sweep would delete under it.",
|
|
"required": [
|
|
"warnings",
|
|
"sweep"
|
|
],
|
|
"properties": {
|
|
"sweep": {
|
|
"$ref": "#/components/schemas/SweepReport"
|
|
},
|
|
"warnings": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Warning"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Problem": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
},
|
|
"ProgrammeStatus": {
|
|
"type": "object",
|
|
"required": [
|
|
"boot",
|
|
"mode",
|
|
"on_air",
|
|
"dead_air",
|
|
"desk_connected",
|
|
"desk_sounding"
|
|
],
|
|
"properties": {
|
|
"boot": {
|
|
"type": "string"
|
|
},
|
|
"dead_air": {
|
|
"type": "boolean"
|
|
},
|
|
"desk_connected": {
|
|
"type": "boolean"
|
|
},
|
|
"desk_sounding": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string"
|
|
},
|
|
"on_air": {
|
|
"type": "string",
|
|
"description": "`desk`, `automation`, `fallback` (the station's files), `default` (the shipped loop,\nADR-0130) or `silence`."
|
|
}
|
|
}
|
|
},
|
|
"PublicEpisode": {
|
|
"type": "object",
|
|
"description": "One episode as the public schedule and the episode list show it.\n\nAn episode that has not aired is a slot in the schedule: the show, the series, its number,\nwhen and how long, its kind and its hosts. Its own words (title, description), its guests,\nits tags and its own card are left out (`null` and empty) until it airs, because the\nstation has no step that publishes a drafted episode before then: a season drafted from the\nrule, or a guest pencilled in, is not yet something the station has announced.",
|
|
"required": [
|
|
"id",
|
|
"show",
|
|
"series",
|
|
"number",
|
|
"aired",
|
|
"kind",
|
|
"hosts",
|
|
"guests",
|
|
"tags",
|
|
"explicit"
|
|
],
|
|
"properties": {
|
|
"air_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Its air time in the station's zone (RFC 3339 with the offset)."
|
|
},
|
|
"air_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"aired": {
|
|
"type": "boolean",
|
|
"description": "It has aired: its words are the frozen copy of what went out (corrected, if staff\ncorrected it)."
|
|
},
|
|
"description": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "`null` until it airs."
|
|
},
|
|
"explicit": {
|
|
"type": "boolean"
|
|
},
|
|
"guests": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "Empty until it airs."
|
|
},
|
|
"hosts": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"image": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The square card: the episode's once it has aired, else the show's."
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/EpisodeKind"
|
|
},
|
|
"minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "Its length: the episode's, else its slot's.",
|
|
"minimum": 0
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"series": {
|
|
"$ref": "#/components/schemas/PublicSeries"
|
|
},
|
|
"show": {
|
|
"$ref": "#/components/schemas/PublicShow"
|
|
},
|
|
"tags": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "Empty until it airs."
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "`null` until it airs."
|
|
}
|
|
}
|
|
},
|
|
"PublicFile": {
|
|
"type": "object",
|
|
"description": "A published audio file.",
|
|
"required": [
|
|
"url",
|
|
"mime",
|
|
"length"
|
|
],
|
|
"properties": {
|
|
"duration_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"length": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "In bytes.",
|
|
"minimum": 0
|
|
},
|
|
"mime": {
|
|
"type": "string"
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"PublicSchedule": {
|
|
"type": "object",
|
|
"required": [
|
|
"zone",
|
|
"from_ms",
|
|
"to_ms",
|
|
"episodes"
|
|
],
|
|
"properties": {
|
|
"episodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/PublicEpisode"
|
|
},
|
|
"description": "In air order."
|
|
},
|
|
"from_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"to_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"zone": {
|
|
"type": "string",
|
|
"description": "The station's time zone (IANA)."
|
|
}
|
|
}
|
|
},
|
|
"PublicSeries": {
|
|
"type": "object",
|
|
"required": [
|
|
"number"
|
|
],
|
|
"properties": {
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"PublicShow": {
|
|
"type": "object",
|
|
"required": [
|
|
"slug",
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"slug": {
|
|
"type": "string",
|
|
"description": "The show's path segment, as in its feed's and page's addresses."
|
|
}
|
|
}
|
|
},
|
|
"PublicStation": {
|
|
"type": "object",
|
|
"description": "The station's public facts, as the player page shows them (without the presenter).",
|
|
"required": [
|
|
"station",
|
|
"show",
|
|
"stream_url",
|
|
"live",
|
|
"call_in_open",
|
|
"zone"
|
|
],
|
|
"properties": {
|
|
"call_in_open": {
|
|
"type": "boolean",
|
|
"description": "The player page takes calls now."
|
|
},
|
|
"live": {
|
|
"type": "boolean",
|
|
"description": "Listeners hear the live show now (the desk is on air)."
|
|
},
|
|
"show": {
|
|
"type": "string",
|
|
"description": "The show on now."
|
|
},
|
|
"station": {
|
|
"type": "string",
|
|
"description": "The station's name."
|
|
},
|
|
"stream_url": {
|
|
"type": "string",
|
|
"description": "The listener stream; empty when not set up."
|
|
},
|
|
"video": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/VideoInfo",
|
|
"description": "The HLS addresses while the desk has video on; `null` otherwise."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"zone": {
|
|
"type": "string",
|
|
"description": "The station's time zone (IANA), the one every time here is shown in."
|
|
}
|
|
}
|
|
},
|
|
"PublishedEpisode": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/PublicEpisode"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"audio": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/PublicFile",
|
|
"description": "The podcast file (MP3 or M4A)."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"audio_opus": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/PublicFile",
|
|
"description": "The Opus file, where one is published."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"feed": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The show's podcast feed."
|
|
},
|
|
"link": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The episode's page."
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "An aired episode with its published files."
|
|
},
|
|
"PublishedEpisodes": {
|
|
"type": "object",
|
|
"required": [
|
|
"episodes"
|
|
],
|
|
"properties": {
|
|
"episodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/PublishedEpisode"
|
|
},
|
|
"description": "Newest first."
|
|
}
|
|
}
|
|
},
|
|
"Recording": {
|
|
"type": "object",
|
|
"description": "A recording of the legal logger: the hour (UTC) it starts, its path and size.",
|
|
"required": [
|
|
"start_ms",
|
|
"name",
|
|
"bytes"
|
|
],
|
|
"properties": {
|
|
"bytes": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"start_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
}
|
|
}
|
|
},
|
|
"RecordingKind": {
|
|
"type": "string",
|
|
"description": "What kind of recording: the programme (logger, archive) or the screener's off-air audio.",
|
|
"enum": [
|
|
"programme",
|
|
"call"
|
|
]
|
|
},
|
|
"RelayInfo": {
|
|
"type": "object",
|
|
"required": [
|
|
"turn_tls_port"
|
|
],
|
|
"properties": {
|
|
"turn_tls_port": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"Release": {
|
|
"type": "object",
|
|
"required": [
|
|
"by",
|
|
"reason"
|
|
],
|
|
"properties": {
|
|
"by": {
|
|
"type": "string"
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Resolved": {
|
|
"type": "object",
|
|
"description": "An episode, series or show with everything it inherits filled in: what its card, its feed\nitem and its archive file say. An aired episode's is the frozen copy.",
|
|
"required": [
|
|
"show",
|
|
"slug",
|
|
"description",
|
|
"colour_slot",
|
|
"layout",
|
|
"hosts",
|
|
"guests",
|
|
"tags",
|
|
"explicit",
|
|
"inherited",
|
|
"frozen"
|
|
],
|
|
"properties": {
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"episode": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ResolvedEpisode"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"explicit": {
|
|
"type": "boolean"
|
|
},
|
|
"frozen": {
|
|
"type": "boolean"
|
|
},
|
|
"guests": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"hosts": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"inherited": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "The fields that came from the level above, for the editor's \"inherited\" mark."
|
|
},
|
|
"layout": {
|
|
"type": "string"
|
|
},
|
|
"series": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ResolvedSeries"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"show": {
|
|
"type": "string"
|
|
},
|
|
"slot": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Slot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"slug": {
|
|
"type": "string"
|
|
},
|
|
"tags": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ResolvedEpisode": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"number",
|
|
"title",
|
|
"description"
|
|
],
|
|
"properties": {
|
|
"air_at": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/EpisodeKind",
|
|
"description": "Frozen copies from before ADR-0188 have none, and were all live."
|
|
},
|
|
"minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"ResolvedSeries": {
|
|
"type": "object",
|
|
"required": [
|
|
"number"
|
|
],
|
|
"properties": {
|
|
"episodes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"first": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date"
|
|
},
|
|
"last": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date"
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"Retained": {
|
|
"type": "object",
|
|
"description": "What retention decides for the playout layer.",
|
|
"required": [
|
|
"logger",
|
|
"us_statutory"
|
|
],
|
|
"properties": {
|
|
"logger": {
|
|
"type": "boolean",
|
|
"description": "The logger records: programme recordings are kept for some time."
|
|
},
|
|
"per_play_days": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "How long the per-play log is kept after a play, in days; `None` without limit.",
|
|
"minimum": 0
|
|
},
|
|
"us_statutory": {
|
|
"type": "boolean",
|
|
"description": "Under the US statutory licence: the performance complement, and no up-next."
|
|
}
|
|
}
|
|
},
|
|
"RetentionView": {
|
|
"type": "object",
|
|
"required": [
|
|
"setting",
|
|
"rows",
|
|
"warnings",
|
|
"presets",
|
|
"presets_as_of"
|
|
],
|
|
"properties": {
|
|
"complaint_hold": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ComplaintHold",
|
|
"description": "What the rules that apply say about a complaint (ADR-0116)."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"last_sweep": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/LastSweep"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"presets": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/PresetView"
|
|
}
|
|
},
|
|
"presets_as_of": {
|
|
"type": "string"
|
|
},
|
|
"rows": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Row"
|
|
},
|
|
"description": "Each period in force, with its source and the floor of the rules that apply."
|
|
},
|
|
"setting": {
|
|
"$ref": "#/components/schemas/SettingView"
|
|
},
|
|
"sweep_every_s": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "How often the sweeper runs; `null` when it is not running.",
|
|
"minimum": 0
|
|
},
|
|
"warnings": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Warning"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Role": {
|
|
"type": "string",
|
|
"description": "What a participant does in the room; the desk routes their voice by it.",
|
|
"enum": [
|
|
"presenter",
|
|
"dj",
|
|
"guest",
|
|
"caller",
|
|
"screener",
|
|
"producer",
|
|
"listener"
|
|
]
|
|
},
|
|
"Row": {
|
|
"type": "object",
|
|
"description": "One period as the screen shows it.",
|
|
"required": [
|
|
"kind",
|
|
"label",
|
|
"period",
|
|
"source",
|
|
"swept"
|
|
],
|
|
"properties": {
|
|
"floor": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Floor"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"kind": {
|
|
"$ref": "#/components/schemas/Kind"
|
|
},
|
|
"label": {
|
|
"type": "string"
|
|
},
|
|
"period": {
|
|
"$ref": "#/components/schemas/Period"
|
|
},
|
|
"source": {
|
|
"type": "string"
|
|
},
|
|
"swept": {
|
|
"type": "boolean",
|
|
"description": "Whether this release keeps records of the kind (and so deletes them)."
|
|
}
|
|
}
|
|
},
|
|
"RundownItem": {
|
|
"type": "object",
|
|
"description": "One row of the \"coming up\" rundown: a setting (`studio.rundown`); the schedule does not fill it yet.",
|
|
"required": [
|
|
"at",
|
|
"title"
|
|
],
|
|
"properties": {
|
|
"at": {
|
|
"type": "string",
|
|
"description": "The time it starts, `HH:MM` or `HH:MM:SS`, in the station's time."
|
|
},
|
|
"detail": {
|
|
"type": "string"
|
|
},
|
|
"hard_post": {
|
|
"type": "boolean",
|
|
"description": "A hard post: the clock back-times to the first one still ahead."
|
|
},
|
|
"key": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The cart key it needs, if any (`F1` to `F6`)."
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Scope": {
|
|
"type": "object",
|
|
"required": [
|
|
"name",
|
|
"description"
|
|
],
|
|
"properties": {
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"ScreenerCommand": {
|
|
"oneOf": [
|
|
{
|
|
"type": "object",
|
|
"description": "Open the screening conversation (the queue's selection).",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"screen"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Send to the desk (`P`), or send again after a decline.",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"send"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Back to the queue (`W`).",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"back"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "The presenter declines a caller sent to the desk (DESK BUSY).",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"decline"
|
|
]
|
|
},
|
|
"reason": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "What the presenter reads: one line, the note, the name on air.",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"line": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"name_on_air": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"note": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"notes"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Let a dropped caller's held place go (`⇧C`).",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"release"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "object",
|
|
"description": "Drop the caller (`⌃D ⌃D`): off air, out of the room, out of the queue.",
|
|
"required": [
|
|
"identity",
|
|
"op"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"op": {
|
|
"type": "string",
|
|
"enum": [
|
|
"drop"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"description": "What the screener (and the presenter, for a decline) does to a caller."
|
|
},
|
|
"Seats": {
|
|
"type": "object",
|
|
"description": "Who sits where: the identities the studio app acts as on each surface, until accounts.",
|
|
"required": [
|
|
"presenter_name",
|
|
"screener_name"
|
|
],
|
|
"properties": {
|
|
"presenter": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"presenter_name": {
|
|
"type": "string",
|
|
"description": "Their names, as the room gives them (may be empty)."
|
|
},
|
|
"screener": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"screener_name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Series": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"show_id",
|
|
"number"
|
|
],
|
|
"properties": {
|
|
"cards": {},
|
|
"description": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"hosts": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"description": "`None` inherits the show's."
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"number": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"planned_episodes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"show_id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"slot": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Slot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"starts_on": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date"
|
|
},
|
|
"tags": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"SeriesInput": {
|
|
"type": "object",
|
|
"description": "A series as the studio app sends it: a field left out or `null` inherits the show's.",
|
|
"properties": {
|
|
"description": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"hosts": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"planned_episodes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"slot": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Slot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"starts_on": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date"
|
|
},
|
|
"tags": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"SeriesView": {
|
|
"type": "object",
|
|
"required": [
|
|
"series",
|
|
"resolved",
|
|
"episodes"
|
|
],
|
|
"properties": {
|
|
"episodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EpisodeView"
|
|
}
|
|
},
|
|
"resolved": {
|
|
"$ref": "#/components/schemas/Resolved"
|
|
},
|
|
"series": {
|
|
"$ref": "#/components/schemas/Series"
|
|
}
|
|
}
|
|
},
|
|
"SetEmail": {
|
|
"type": "object",
|
|
"required": [
|
|
"email"
|
|
],
|
|
"properties": {
|
|
"email": {}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"SetPassword": {
|
|
"type": "object",
|
|
"required": [
|
|
"password"
|
|
],
|
|
"properties": {
|
|
"password": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"SettingView": {
|
|
"type": "object",
|
|
"required": [
|
|
"preset"
|
|
],
|
|
"properties": {
|
|
"based_on": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"broadcast_licence": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"preset": {
|
|
"type": "string"
|
|
},
|
|
"updated_at_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"updated_by": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"us_statutory_licence": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"Show": {
|
|
"type": "object",
|
|
"required": [
|
|
"id",
|
|
"slug",
|
|
"name",
|
|
"description",
|
|
"colour_slot",
|
|
"layout",
|
|
"hosts",
|
|
"tags",
|
|
"explicit"
|
|
],
|
|
"properties": {
|
|
"cards": {},
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"explicit": {
|
|
"type": "boolean"
|
|
},
|
|
"feed_guid": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "uuid"
|
|
},
|
|
"hosts": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
}
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"layout": {
|
|
"type": "string",
|
|
"description": "`poster` or `slate`."
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"slot": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Slot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"slug": {
|
|
"type": "string"
|
|
},
|
|
"tags": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ShowInput": {
|
|
"type": "object",
|
|
"description": "A show as the studio app sends it; hosts by name.",
|
|
"required": [
|
|
"name",
|
|
"colour_slot"
|
|
],
|
|
"properties": {
|
|
"colour_slot": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"description": {
|
|
"type": "string"
|
|
},
|
|
"explicit": {
|
|
"type": "boolean"
|
|
},
|
|
"hosts": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"layout": {
|
|
"type": "string"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"slot": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Slot"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"tags": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ShowView": {
|
|
"type": "object",
|
|
"required": [
|
|
"show",
|
|
"resolved",
|
|
"series"
|
|
],
|
|
"properties": {
|
|
"resolved": {
|
|
"$ref": "#/components/schemas/Resolved"
|
|
},
|
|
"series": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Series"
|
|
}
|
|
},
|
|
"show": {
|
|
"$ref": "#/components/schemas/Show"
|
|
}
|
|
}
|
|
},
|
|
"SignIn": {
|
|
"type": "object",
|
|
"required": [
|
|
"username",
|
|
"password"
|
|
],
|
|
"properties": {
|
|
"password": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"SignedIn": {
|
|
"type": "object",
|
|
"required": [
|
|
"token",
|
|
"expires_ms",
|
|
"account"
|
|
],
|
|
"properties": {
|
|
"account": {
|
|
"$ref": "#/components/schemas/Account"
|
|
},
|
|
"expires_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"token": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Slot": {
|
|
"type": "object",
|
|
"description": "A weekly slot: a weekday (1 Monday to 7 Sunday), a start in minutes after midnight in the\nstation's zone, and a length in minutes.",
|
|
"required": [
|
|
"weekday",
|
|
"start"
|
|
],
|
|
"properties": {
|
|
"minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"start": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"weekday": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"Sounding": {
|
|
"type": "object",
|
|
"description": "One cart sounding, as the control plane keeps it.",
|
|
"required": [
|
|
"cart",
|
|
"pool",
|
|
"player",
|
|
"mode",
|
|
"cue",
|
|
"play",
|
|
"started_ms",
|
|
"stopping",
|
|
"seq"
|
|
],
|
|
"properties": {
|
|
"cart": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"cue": {
|
|
"type": "boolean",
|
|
"description": "Cued into the presenters' ears, not on air."
|
|
},
|
|
"ends_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"mode": {
|
|
"$ref": "#/components/schemas/CartMode"
|
|
},
|
|
"play": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "The desk's number for this play.",
|
|
"minimum": 0
|
|
},
|
|
"player": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"pool": {
|
|
"$ref": "#/components/schemas/Pool"
|
|
},
|
|
"seq": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Higher is later: `Space` stops the highest.",
|
|
"minimum": 0
|
|
},
|
|
"started_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "When this play started and when it ends, in the station's epoch ms; a bed has no end.",
|
|
"minimum": 0
|
|
},
|
|
"stopping": {
|
|
"type": "boolean",
|
|
"description": "Fading out (300 ms)."
|
|
}
|
|
}
|
|
},
|
|
"Source": {
|
|
"allOf": [
|
|
{
|
|
"$ref": "#/components/schemas/DeskPerson"
|
|
},
|
|
{
|
|
"type": "object",
|
|
"required": [
|
|
"slot"
|
|
],
|
|
"properties": {
|
|
"caller": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/CallerNote",
|
|
"description": "For a caller: what the screener sent with them."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"slot": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"StaffRole": {
|
|
"type": "string",
|
|
"description": "A staff member's role, station-wide (`top-roles-scoped` a). Release one enforces two\ntiers: `Admin` alone may change retention, erase people, see personal data and manage\nstaff; every role may run the studio. The role is recorded either way, so a finer split\ncan follow without a migration.",
|
|
"enum": [
|
|
"admin",
|
|
"producer",
|
|
"presenter",
|
|
"screener"
|
|
]
|
|
},
|
|
"Station": {
|
|
"type": "object",
|
|
"description": "A station: what release one's interface shows one of.",
|
|
"required": [
|
|
"id",
|
|
"name"
|
|
],
|
|
"properties": {
|
|
"id": {
|
|
"$ref": "#/components/schemas/StationId"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"StationId": {
|
|
"type": "string",
|
|
"format": "uuid",
|
|
"description": "A station's identifier: a UUID, stable for the station's life."
|
|
},
|
|
"StationMode": {
|
|
"type": "string",
|
|
"description": "The station's mode as playout runs it (`programme.mode`, ADR-0045): `live`, the desk first\nwith automation on dead air, or `auto`, automation only (ADR-0183's AUTO lamp).",
|
|
"enum": [
|
|
"live",
|
|
"auto"
|
|
]
|
|
},
|
|
"Status": {
|
|
"type": "object",
|
|
"description": "The playout layer's state, for the studio app (`GET /api/v1/playout`).",
|
|
"required": [
|
|
"retained",
|
|
"listeners",
|
|
"default_fallback",
|
|
"settings",
|
|
"gaps",
|
|
"now_playing"
|
|
],
|
|
"properties": {
|
|
"automation": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/AutodjStatus"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"default_fallback": {
|
|
"type": "boolean",
|
|
"description": "Listeners hear the shipped default loop, not the station's own fallback files\n(ADR-0130), whether playout or the listener process is playing it."
|
|
},
|
|
"gaps": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"description": "What the last generation could not fill, in words."
|
|
},
|
|
"listeners": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"logger": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/LoggerStatus"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"logger_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"now_playing": {
|
|
"$ref": "#/components/schemas/NowPlaying"
|
|
},
|
|
"playout": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ProgrammeStatus"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"playout_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"retained": {
|
|
"$ref": "#/components/schemas/Retained"
|
|
},
|
|
"settings": {
|
|
"$ref": "#/components/schemas/PlayoutSettings"
|
|
}
|
|
}
|
|
},
|
|
"SteeringManifest": {
|
|
"type": "object",
|
|
"description": "The steering manifest (HLS content steering): the keys are the specification's.",
|
|
"required": [
|
|
"VERSION",
|
|
"TTL",
|
|
"RELOAD-URI",
|
|
"PATHWAY-PRIORITY"
|
|
],
|
|
"properties": {
|
|
"PATHWAY-CLONES": {
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
],
|
|
"items": {},
|
|
"description": "Present while an edge has a host: `BASE-ID`, `ID` and `URI-REPLACEMENT` (`HOST`)."
|
|
},
|
|
"PATHWAY-PRIORITY": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"RELOAD-URI": {
|
|
"type": "string"
|
|
},
|
|
"TTL": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"VERSION": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"StillInfo": {
|
|
"type": "object",
|
|
"description": "The slate's still as it is now.",
|
|
"required": [
|
|
"present",
|
|
"width",
|
|
"height",
|
|
"bytes",
|
|
"set_at_ms"
|
|
],
|
|
"properties": {
|
|
"bytes": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"height": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"present": {
|
|
"type": "boolean"
|
|
},
|
|
"set_at_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "When it was set, in milliseconds since the Unix epoch.",
|
|
"minimum": 0
|
|
},
|
|
"width": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"StudioShow": {
|
|
"type": "object",
|
|
"required": [
|
|
"title",
|
|
"rundown"
|
|
],
|
|
"properties": {
|
|
"rundown": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/RundownItem"
|
|
}
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Surface": {
|
|
"type": "string",
|
|
"enum": [
|
|
"desk",
|
|
"screener"
|
|
]
|
|
},
|
|
"SweepReport": {
|
|
"type": "object",
|
|
"description": "What one sweep did, or (dry run) would do.",
|
|
"required": [
|
|
"dry_run",
|
|
"preset",
|
|
"recordings_deleted",
|
|
"files_missing",
|
|
"consents_deleted",
|
|
"holds_deleted",
|
|
"held",
|
|
"errors"
|
|
],
|
|
"properties": {
|
|
"consents_deleted": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"dry_run": {
|
|
"type": "boolean"
|
|
},
|
|
"errors": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"files_missing": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Recordings whose file was already gone; the row is still marked deleted.",
|
|
"minimum": 0
|
|
},
|
|
"held": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Records past their period that a hold kept.",
|
|
"minimum": 0
|
|
},
|
|
"holds_deleted": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Released holds whose own record went, the moderation-records period after their release\n(ADR-0157).",
|
|
"minimum": 0
|
|
},
|
|
"preset": {
|
|
"type": "string"
|
|
},
|
|
"recordings_deleted": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
}
|
|
}
|
|
},
|
|
"ThumbsBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"thumbs"
|
|
],
|
|
"properties": {
|
|
"thumbs": {
|
|
"type": "object",
|
|
"description": "Each camera's identity and its picture: a JPEG in base64.",
|
|
"additionalProperties": {
|
|
"type": "string"
|
|
},
|
|
"propertyNames": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"TokenRequest": {
|
|
"type": "object",
|
|
"required": [
|
|
"identity",
|
|
"role"
|
|
],
|
|
"properties": {
|
|
"booth": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "A listener (a monitor) for one caller's booth, by the caller's identity (ADR-0193);\nleft out, a monitor joins the studio room."
|
|
},
|
|
"consent": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/ConsentGiven",
|
|
"description": "A caller's token needs their consent to record, given on their behalf by the station\n(the player page's call-in route records the caller's own)."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"identity": {
|
|
"type": "string",
|
|
"description": "The person's identity in the room (rules in the reference for roles)."
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"description": "The name others see: at most 120 characters, no control characters."
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role",
|
|
"description": "One of the seven roles."
|
|
},
|
|
"subscribe": {
|
|
"type": "boolean",
|
|
"description": "Whether the token may subscribe (default yes). A native GStreamer publisher (the\nstudio app's native path) asks for a publish-only token and listens on a second one."
|
|
},
|
|
"ttl_s": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64",
|
|
"description": "Seconds; the station's `room.token_ttl_s` when left out, and never more.",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"TokenResponse": {
|
|
"type": "object",
|
|
"required": [
|
|
"token",
|
|
"url",
|
|
"room",
|
|
"identity",
|
|
"role",
|
|
"ttl_s"
|
|
],
|
|
"properties": {
|
|
"identity": {
|
|
"type": "string"
|
|
},
|
|
"role": {
|
|
"$ref": "#/components/schemas/Role"
|
|
},
|
|
"room": {
|
|
"type": "string",
|
|
"description": "The room it is for: a caller's booth for a caller, the named booth for a monitor that\nasked for one, the studio room for anyone else."
|
|
},
|
|
"token": {
|
|
"type": "string",
|
|
"description": "The LiveKit access token."
|
|
},
|
|
"ttl_s": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"description": "Seconds the token can be used to join.",
|
|
"minimum": 0
|
|
},
|
|
"url": {
|
|
"type": "string",
|
|
"description": "Where browsers reach LiveKit."
|
|
}
|
|
}
|
|
},
|
|
"Tone": {
|
|
"type": "string",
|
|
"enum": [
|
|
"good",
|
|
"warning",
|
|
"serious"
|
|
]
|
|
},
|
|
"Track": {
|
|
"type": "object",
|
|
"description": "A track in the library.",
|
|
"required": [
|
|
"id",
|
|
"title",
|
|
"artist",
|
|
"album",
|
|
"label",
|
|
"category",
|
|
"file",
|
|
"duration_ms",
|
|
"gain_db",
|
|
"enabled"
|
|
],
|
|
"properties": {
|
|
"album": {
|
|
"type": "string"
|
|
},
|
|
"artist": {
|
|
"type": "string"
|
|
},
|
|
"category": {
|
|
"type": "string"
|
|
},
|
|
"duration_ms": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"file": {
|
|
"type": "string",
|
|
"description": "The media worker's FLAC, `<uuid>.flac`, in the library directory."
|
|
},
|
|
"gain_db": {
|
|
"type": "number",
|
|
"format": "float"
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"isrc": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"label": {
|
|
"type": "string"
|
|
},
|
|
"loudness_lufs": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
},
|
|
"true_peak_dbtp": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"format": "float"
|
|
}
|
|
}
|
|
},
|
|
"TracksBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"tracks"
|
|
],
|
|
"properties": {
|
|
"tracks": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Track"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"VideoInfo": {
|
|
"type": "object",
|
|
"description": "Where the player finds the HLS: `live` (AV1 with Opus) and `audio` (the same Opus alone:\nthe audio-only toggle, ADR-0026, and older Apple devices, ADR-0024).",
|
|
"required": [
|
|
"live",
|
|
"audio"
|
|
],
|
|
"properties": {
|
|
"audio": {
|
|
"type": "string"
|
|
},
|
|
"live": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"View": {
|
|
"type": "object",
|
|
"required": [
|
|
"station",
|
|
"now_ms",
|
|
"show",
|
|
"desk",
|
|
"seats",
|
|
"sources",
|
|
"callers",
|
|
"desk_taking_callers",
|
|
"chat",
|
|
"notices",
|
|
"carts",
|
|
"listener_delay",
|
|
"default_fallback",
|
|
"audience"
|
|
],
|
|
"properties": {
|
|
"audience": {
|
|
"$ref": "#/components/schemas/AudienceView",
|
|
"description": "Who is listening and what carries them (desk B's `desk.audience`)."
|
|
},
|
|
"callers": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/CallerView"
|
|
}
|
|
},
|
|
"carts": {
|
|
"$ref": "#/components/schemas/CartsView",
|
|
"description": "The cart wall: what is sounding, playout's link, FILE MISSING, the catalogue's version."
|
|
},
|
|
"chat": {
|
|
"$ref": "#/components/schemas/ChatView"
|
|
},
|
|
"default_fallback": {
|
|
"type": "boolean",
|
|
"description": "Listeners are hearing the default loop WeaveSignal ships, not the station's own fallback\n(ADR-0130): the desk's playout panel says so until the station adds fallback files."
|
|
},
|
|
"desk": {
|
|
"$ref": "#/components/schemas/DeskView"
|
|
},
|
|
"desk_taking_callers": {
|
|
"type": "boolean",
|
|
"description": "No caller sits declined: the screener's status bar says the desk takes callers."
|
|
},
|
|
"listener_delay": {
|
|
"$ref": "#/components/schemas/ListenerDelay",
|
|
"description": "How far behind the studio listeners hear."
|
|
},
|
|
"mode": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/StationMode",
|
|
"description": "The station's mode (ADR-0045): `live`, the desk first with automation on dead air, or\n`auto`, automation holding the air, where the master lamp is to say AUTO (ADR-0183).\nThe playout setting the control plane holds playout to; `None` until it has been read\n(and on a station without the playout layer)."
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"notices": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Notice"
|
|
}
|
|
},
|
|
"now_ms": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"seats": {
|
|
"$ref": "#/components/schemas/Seats"
|
|
},
|
|
"show": {
|
|
"$ref": "#/components/schemas/StudioShow"
|
|
},
|
|
"sources": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Source"
|
|
},
|
|
"description": "Slots 1 to 5 that hold a source, in slot order."
|
|
},
|
|
"station": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Warning": {
|
|
"type": "object",
|
|
"required": [
|
|
"level",
|
|
"title",
|
|
"message",
|
|
"source"
|
|
],
|
|
"properties": {
|
|
"kind": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/Kind"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"level": {
|
|
"$ref": "#/components/schemas/Level"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"source": {
|
|
"type": "string"
|
|
},
|
|
"title": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"Webhook": {
|
|
"type": "object",
|
|
"description": "A webhook as it is kept.",
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"url",
|
|
"events",
|
|
"enabled",
|
|
"created_by",
|
|
"created_ms",
|
|
"failures"
|
|
],
|
|
"properties": {
|
|
"created_by": {
|
|
"type": "string"
|
|
},
|
|
"created_ms": {
|
|
"type": "integer",
|
|
"format": "int64"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"events": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"failures": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Deliveries failed since the last good one."
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"last_attempt_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"last_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"last_status": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int32",
|
|
"description": "The HTTP status the receiver answered with; 0 when it did not answer."
|
|
},
|
|
"last_success_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"format": "int64"
|
|
},
|
|
"name": {
|
|
"type": "string"
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
},
|
|
"WeekBody": {
|
|
"type": "object",
|
|
"required": [
|
|
"hours"
|
|
],
|
|
"properties": {
|
|
"hours": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/WeekHour"
|
|
}
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"WeekEpisode": {
|
|
"type": "object",
|
|
"required": [
|
|
"show",
|
|
"series",
|
|
"episode",
|
|
"resolved"
|
|
],
|
|
"properties": {
|
|
"episode": {
|
|
"$ref": "#/components/schemas/Episode"
|
|
},
|
|
"resolved": {
|
|
"$ref": "#/components/schemas/Resolved"
|
|
},
|
|
"series": {
|
|
"$ref": "#/components/schemas/Series"
|
|
},
|
|
"show": {
|
|
"$ref": "#/components/schemas/Show"
|
|
}
|
|
}
|
|
},
|
|
"WeekEpisodes": {
|
|
"type": "object",
|
|
"required": [
|
|
"zone",
|
|
"episodes"
|
|
],
|
|
"properties": {
|
|
"episodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/WeekEpisode"
|
|
}
|
|
},
|
|
"zone": {
|
|
"type": "string",
|
|
"description": "The zone the station's air times are read in."
|
|
}
|
|
}
|
|
},
|
|
"WeekHour": {
|
|
"type": "object",
|
|
"required": [
|
|
"weekday",
|
|
"hour",
|
|
"clock"
|
|
],
|
|
"properties": {
|
|
"clock": {
|
|
"type": "string",
|
|
"format": "uuid"
|
|
},
|
|
"hour": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"minimum": 0
|
|
},
|
|
"weekday": {
|
|
"type": "integer",
|
|
"format": "int32",
|
|
"description": "Monday is 0.",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"ZoneBody": {
|
|
"type": "object",
|
|
"description": "Documentation of the answers the handlers build with `json!`; the handlers send these shapes.",
|
|
"required": [
|
|
"zone",
|
|
"set"
|
|
],
|
|
"properties": {
|
|
"set": {
|
|
"type": "boolean",
|
|
"description": "Whether an admin has chosen it."
|
|
},
|
|
"zone": {
|
|
"type": "string",
|
|
"description": "An IANA zone name."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"Conflict": {
|
|
"description": "It does not fit the current state (or the desk refused it).",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Forbidden": {
|
|
"description": "The bearer is a staff session whose role may not do this: the route is admin only.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"NotFound": {
|
|
"description": "There is no such thing.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ScopeMissing": {
|
|
"description": "The bearer is an API token without the scope this route needs (\"This API token does not hold the `…` scope.\"); or a staff session whose role may not do this.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"TooManyRequests": {
|
|
"description": "Too many requests just now: per address on the open routes, per API token elsewhere. `Retry-After` says how many seconds to wait.",
|
|
"headers": {
|
|
"Retry-After": {
|
|
"schema": {
|
|
"type": "integer",
|
|
"format": "int64",
|
|
"minimum": 0
|
|
},
|
|
"description": "Seconds until the limit's window turns over."
|
|
}
|
|
},
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Unauthorized": {
|
|
"description": "No bearer, a wrong one, or a staff session that has ended (\"Your sign-in has ended. Sign in again.\").",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Unavailable": {
|
|
"description": "The part of the station that answers is not configured or does not answer (the desk, the database, LiveKit, mail).",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Unprocessable": {
|
|
"description": "The request is well formed but not acceptable; the sentence names the problem, and `field` the field.",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"description": "A refusal or a failure: one plain sentence, and for a refused field its name.",
|
|
"required": [
|
|
"error"
|
|
],
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "What went wrong, in a sentence for a person."
|
|
},
|
|
"field": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "The field that was refused, where the route names one (`422`)."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"securitySchemes": {
|
|
"api_token": {
|
|
"type": "http",
|
|
"scheme": "bearer",
|
|
"description": "An API token (`rsa_…`, ADR-0195) from `POST /api/v1/tokens`, made by an admin for one integration with the scopes it needs. A token reaches only the routes its scopes open (each such route lists `api_token` with the scope it needs) and is never an admin: no route marked `x-admin` takes one. Each token is limited per minute (`429`). The scopes:\n\n- `studio:read`: Read the studio's view: sources, callers (with the names and topics they gave), chat modes, notices; and follow it live.\n- `desk:control`: Work the desk: on air, mute, cue, talk, and dump the profanity delay.\n- `screener:control`: Work the screener: screen, send, decline and drop callers; end a pass.\n- `chat:moderate`: Change the chat's modes (slow mode, hold new, links). The chat's own moderation routes are not reachable with a token.\n- `carts:read`: Read the cart wall's banks and carts.\n- `carts:fire`: Fire, stop and cue carts; stop the last; fade all.\n- `carts:write`: Make and rename banks; load and empty cart slots.\n- `schedule:read`: Read the clocks, the week, the log of what is to play, and the episodes airing in a range.\n- `schedule:write`: Change clocks, the week and the log; generate a day.\n- `playout:read`: Read playout's status and zone, the logger, and the track library.\n- `library:write`: Add tracks to the library and delete them.\n- `reports:read`: Read the play and audience reports.\n- `shows:read`: Read shows, series, episodes and corrections.\n- `shows:write`: Change shows, series and episodes; put an episode on air; correct one; publish its files; draw cards.\n- `video:read`: Read the video slate's still and the cameras' thumbnails.\n- `video:write`: Change or remove the video slate's still."
|
|
},
|
|
"pass": {
|
|
"type": "http",
|
|
"scheme": "bearer",
|
|
"description": "A pass (ADR-0119): the link a guest, a remote DJ, a presenter or a caller joins by; from `POST /api/v1/invites` or `POST /api/v1/call-in`."
|
|
},
|
|
"staff_session": {
|
|
"type": "http",
|
|
"scheme": "bearer",
|
|
"description": "A staff session token (`rss_…`) from `POST /api/v1/sessions`. An account's role decides which routes it reaches; routes marked admin only need the `admin` role."
|
|
},
|
|
"station_key": {
|
|
"type": "http",
|
|
"scheme": "bearer",
|
|
"description": "The station key (`WEAVESIGNAL_CONTROL_ADMIN_TOKEN`): the station's own credential, with an admin's powers."
|
|
}
|
|
}
|
|
},
|
|
"tags": [
|
|
{
|
|
"name": "station",
|
|
"description": "The station, and whether the service is alive."
|
|
},
|
|
{
|
|
"name": "sessions",
|
|
"description": "Staff sign-in: the session tokens that open the studio's routes."
|
|
},
|
|
{
|
|
"name": "staff",
|
|
"description": "Staff accounts."
|
|
},
|
|
{
|
|
"name": "studio",
|
|
"description": "The studio's view: sources, callers, chat modes, notices."
|
|
},
|
|
{
|
|
"name": "desk",
|
|
"description": "The desk's switches."
|
|
},
|
|
{
|
|
"name": "screener",
|
|
"description": "What the screener does to a caller."
|
|
},
|
|
{
|
|
"name": "room",
|
|
"description": "Room tokens and passes."
|
|
},
|
|
{
|
|
"name": "join",
|
|
"description": "Invites and the pass a guest, a remote DJ, a presenter or a caller joins by."
|
|
},
|
|
{
|
|
"name": "chat",
|
|
"description": "The studio's chat modes. The chat service's own routes are its own document."
|
|
},
|
|
{
|
|
"name": "carts",
|
|
"description": "The cart wall."
|
|
},
|
|
{
|
|
"name": "shows",
|
|
"description": "Shows, series and episodes."
|
|
},
|
|
{
|
|
"name": "cards",
|
|
"description": "Show cards: the pictures that go with shows, series and episodes."
|
|
},
|
|
{
|
|
"name": "people",
|
|
"description": "The remembered guests and hosts."
|
|
},
|
|
{
|
|
"name": "schedule",
|
|
"description": "Clocks, the week, the log and the calendar's episodes."
|
|
},
|
|
{
|
|
"name": "playout",
|
|
"description": "The playout layer."
|
|
},
|
|
{
|
|
"name": "library",
|
|
"description": "The music library."
|
|
},
|
|
{
|
|
"name": "reports",
|
|
"description": "Plays, audience and the legal logger."
|
|
},
|
|
{
|
|
"name": "retention",
|
|
"description": "The Jurisdiction setting, holds, recordings and consents. Admin only."
|
|
},
|
|
{
|
|
"name": "video",
|
|
"description": "The slate's picture and the cameras' thumbnails."
|
|
},
|
|
{
|
|
"name": "delivery",
|
|
"description": "Content steering for the edges."
|
|
},
|
|
{
|
|
"name": "public",
|
|
"description": "Routes that need no bearer: the player, now playing, the feeds, the HLS files, and the open routes for a station's website (`/api/v1/public/…`, now playing), which carry CORS open to any origin and are limited per address."
|
|
},
|
|
{
|
|
"name": "tokens",
|
|
"description": "API tokens for integrations. Admin only."
|
|
},
|
|
{
|
|
"name": "webhooks",
|
|
"description": "Webhooks: signed deliveries of the station's events to an integration. Admin only."
|
|
}
|
|
]
|
|
}
|