4
0
mirror of https://github.com/AzuraCast/AzuraCast.git synced 2024-06-18 06:57:05 +00:00

#802 -- Update to OpenAPI 3.0 spec

This commit is contained in:
Buster "Silver Eagle" Neece 2018-09-18 09:09:48 -05:00
parent 2fafe54e24
commit 989bbd39a1
40 changed files with 1089 additions and 1370 deletions

View File

@ -51,7 +51,7 @@
"mockery/mockery": "^1.0",
"roave/security-advisories": "dev-master",
"squizlabs/php_codesniffer": "3.*",
"zircote/swagger-php": "^2.0"
"zircote/swagger-php": "^3.0"
},
"authors": [
{

88
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "60ee6f1c461351f586ab6db94458f938",
"content-hash": "594ac3f2423a143d5621fb2cffbd11fa",
"packages": [
{
"name": "azuracast/azuraforms",
@ -12,12 +12,12 @@
"source": {
"type": "git",
"url": "https://github.com/AzuraCast/azuraforms.git",
"reference": "a04cfc78dc6864fbff8bfdba14186bef4fb551a7"
"reference": "b03ccbbef274506529cac3a5b0b387b315757fda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/a04cfc78dc6864fbff8bfdba14186bef4fb551a7",
"reference": "a04cfc78dc6864fbff8bfdba14186bef4fb551a7",
"url": "https://api.github.com/repos/AzuraCast/azuraforms/zipball/b03ccbbef274506529cac3a5b0b387b315757fda",
"reference": "b03ccbbef274506529cac3a5b0b387b315757fda",
"shasum": ""
},
"require": {
@ -49,7 +49,7 @@
],
"description": "A modern, namespaced, configuration-driven forms engine for PHP.",
"homepage": "https://github.com/AzuraCast/azuraforms",
"time": "2018-09-11T04:25:54+00:00"
"time": "2018-09-13T06:55:01+00:00"
},
{
"name": "azuracast/nowplaying",
@ -2540,16 +2540,16 @@
},
{
"name": "paragonie/sodium_compat",
"version": "v1.6.4",
"version": "v1.6.5",
"source": {
"type": "git",
"url": "https://github.com/paragonie/sodium_compat.git",
"reference": "3f2fd07977541b4d630ea0365ad0eceddee5179c"
"reference": "aaaf71f3f7713248703c23cfbd1189ce1215f57f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/3f2fd07977541b4d630ea0365ad0eceddee5179c",
"reference": "3f2fd07977541b4d630ea0365ad0eceddee5179c",
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/aaaf71f3f7713248703c23cfbd1189ce1215f57f",
"reference": "aaaf71f3f7713248703c23cfbd1189ce1215f57f",
"shasum": ""
},
"require": {
@ -2618,7 +2618,7 @@
"secret-key cryptography",
"side-channel resistant"
],
"time": "2018-08-29T22:02:48+00:00"
"time": "2018-09-14T00:17:10+00:00"
},
{
"name": "php-http/discovery",
@ -3222,16 +3222,16 @@
},
{
"name": "slim/slim",
"version": "3.10.0",
"version": "3.11.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748"
"reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
"reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
"reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a",
"shasum": ""
},
"require": {
@ -3289,7 +3289,7 @@
"micro",
"router"
],
"time": "2018-04-19T19:29:08+00:00"
"time": "2018-09-16T10:54:21+00:00"
},
{
"name": "supervisorphp/supervisor",
@ -4729,21 +4729,24 @@
},
{
"name": "phpunit/php-file-iterator",
"version": "2.0.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c"
"reference": "050bedf145a257b1ff02746c31894800e5122946"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"reference": "cecbc684605bb0cc288828eb5d65d93d5c676d3c",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
"reference": "050bedf145a257b1ff02746c31894800e5122946",
"shasum": ""
},
"require": {
"php": "^7.1"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
},
"type": "library",
"extra": {
"branch-alias": {
@ -4772,7 +4775,7 @@
"filesystem",
"iterator"
],
"time": "2018-06-11T11:44:00+00:00"
"time": "2018-09-13T20:33:42+00:00"
},
{
"name": "phpunit/php-text-template",
@ -5007,6 +5010,7 @@
"amphp/http": "<1.0.1",
"asymmetricrypt/asymmetricrypt": ">=0,<9.9.99",
"aws/aws-sdk-php": ">=3,<3.2.1",
"brightlocal/phpwhois": "<=4.2.5",
"bugsnag/bugsnag-laravel": ">=2,<2.0.2",
"cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4",
"cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4",
@ -5018,6 +5022,7 @@
"contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8",
"contao/listing-bundle": ">=4,<4.4.8",
"contao/newsletter-bundle": ">=4,<4.1",
"david-garcia/phpwhois": "<=4.3.1",
"doctrine/annotations": ">=1,<1.2.7",
"doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2",
"doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1",
@ -5032,6 +5037,7 @@
"drupal/drupal": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3",
"erusev/parsedown": "<1.7",
"ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1",
"ezyang/htmlpurifier": "<4.1.1",
"firebase/php-jwt": "<2",
"friendsofsymfony/rest-bundle": ">=1.2,<1.2.2",
"friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
@ -5043,7 +5049,11 @@
"illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
"illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29",
"illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
"ivankristianto/phpwhois": "<=4.3",
"james-heinrich/getid3": "<1.9.9",
"joomla/session": "<1.3.1",
"jsmitty12/phpwhois": "<5.1",
"kazist/phpwhois": "<=4.2.6",
"kreait/firebase-php": ">=3.2,<3.8.1",
"laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
"laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
@ -5053,6 +5063,7 @@
"monolog/monolog": ">=1.8,<1.12",
"namshi/jose": "<2.2",
"onelogin/php-saml": "<2.10.4",
"openid/php-openid": "<2.3",
"oro/crm": ">=1.7,<1.7.4",
"oro/platform": ">=1.7,<1.7.4",
"padraic/humbug_get_contents": "<1.1.2",
@ -5061,21 +5072,25 @@
"paypal/merchant-sdk-php": "<3.12",
"phpmailer/phpmailer": ">=5,<5.2.24",
"phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3",
"phpwhois/phpwhois": "<=4.2.5",
"phpxmlrpc/extras": "<0.6.1",
"propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7",
"propel/propel1": ">=1,<=1.7.1",
"pusher/pusher-php-server": "<2.2.1",
"sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9",
"sensiolabs/connect": "<4.2.3",
"serluck/phpwhois": "<=4.2.6",
"shopware/shopware": "<5.3.7",
"silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11",
"silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3",
"silverstripe/framework": ">=3,<3.3",
"silverstripe/userforms": "<3",
"simple-updates/phpwhois": "<=1",
"simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4",
"simplesamlphp/simplesamlphp": "<1.15.2",
"simplesamlphp/simplesamlphp-module-infocard": "<1.0.1",
"slim/slim": "<2.6",
"smarty/smarty": "<3.1.33",
"socalnick/scn-social-auth": "<1.15.2",
"squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1",
"stormpath/sdk": ">=0,<9.9.99",
@ -5102,8 +5117,10 @@
"symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4",
"symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7",
"thelia/backoffice-default-template": ">=2.1,<2.1.2",
"thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3",
"thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2",
"theonedemon/phpwhois": "<=4.2.5",
"titon/framework": ">=0,<9.9.99",
"truckersmp/phpwhois": "<=4.3.1",
"twig/twig": "<1.20",
"typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.30|>=8,<8.7.17|>=9,<9.3.2",
"typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2",
@ -5156,7 +5173,7 @@
}
],
"description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
"time": "2018-08-14T15:39:17+00:00"
"time": "2018-09-17T20:20:31+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -6260,35 +6277,36 @@
},
{
"name": "zircote/swagger-php",
"version": "2.0.13",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/zircote/swagger-php.git",
"reference": "8b42fdc3d8c5a5e0d1f8d344aa359822c9f085e0"
"reference": "67f517375c0c8180bf2c09dbad6f305524cff2ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/8b42fdc3d8c5a5e0d1f8d344aa359822c9f085e0",
"reference": "8b42fdc3d8c5a5e0d1f8d344aa359822c9f085e0",
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/67f517375c0c8180bf2c09dbad6f305524cff2ab",
"reference": "67f517375c0c8180bf2c09dbad6f305524cff2ab",
"shasum": ""
},
"require": {
"doctrine/annotations": "*",
"php": ">=5.6",
"symfony/finder": ">=2.2"
"php": ">=7.0",
"symfony/finder": ">=2.2",
"symfony/yaml": ">=2.8"
},
"require-dev": {
"phpunit/phpunit": ">=4.8.35 <=5.6",
"squizlabs/php_codesniffer": ">=2.7",
"phpunit/phpunit": ">=6.3",
"squizlabs/php_codesniffer": ">=3.3",
"zendframework/zend-form": "<2.8"
},
"bin": [
"bin/swagger"
"bin/openapi"
],
"type": "library",
"autoload": {
"psr-4": {
"Swagger\\": "src"
"OpenApi\\": "src"
},
"files": [
"src/functions.php"
@ -6296,7 +6314,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache2"
"Apache-2.0"
],
"authors": [
{
@ -6310,7 +6328,7 @@
"homepage": "http://bfanger.nl"
}
],
"description": "Swagger-PHP - Generate interactive documentation for your RESTful API using phpdoc annotations",
"description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations",
"homepage": "https://github.com/zircote/swagger-php/",
"keywords": [
"api",
@ -6318,7 +6336,7 @@
"rest",
"service discovery"
],
"time": "2017-12-01T09:22:05+00:00"
"time": "2018-08-16T06:06:29+00:00"
}
],
"aliases": [],

View File

@ -25,10 +25,10 @@ class GenerateApiDocs extends \App\Console\Command\CommandAbstract
define('AZURACAST_VERSION', \App\Version::getVersion());
define('SAMPLE_TIMESTAMP', rand(time() - 86400, time() + 86400));
$swagger = \Swagger\scan([
APP_INCLUDE_ROOT . '/util/swagger.php',
APP_INCLUDE_ROOT . '/Entity/Api',
APP_INCLUDE_ROOT . '/Controller/Api',
$oa = \OpenApi\scan([
APP_INCLUDE_ROOT . '/util/openapi.php',
APP_INCLUDE_ROOT . '/src/Entity/Api',
APP_INCLUDE_ROOT . '/src/Controller/Api',
], [
'exclude' => [
'bootstrap',
@ -37,7 +37,10 @@ class GenerateApiDocs extends \App\Console\Command\CommandAbstract
],
]);
file_put_contents(APP_INCLUDE_STATIC . '/api/swagger.json', $swagger);
$yaml_path = APP_INCLUDE_STATIC.'/api/openapi.yml';
$yaml = $oa->toYaml();
file_put_contents($yaml_path, $yaml);
$output->writeln('API documentation updated!');
return 0;

View File

@ -16,14 +16,14 @@ class IndexController
}
/**
* @SWG\Get(path="/status",
* @OA\Get(path="/status",
* tags={"Miscellaneous"},
* description="Returns an affirmative response if the API is active.",
* parameters={},
* @SWG\Response(
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(ref="#/definitions/SystemStatus")
* @OA\Schema(ref="#/components/schemas/SystemStatus")
* )
* )
*/
@ -33,14 +33,14 @@ class IndexController
}
/**
* @SWG\Get(path="/time",
* @OA\Get(path="/time",
* tags={"Miscellaneous"},
* description="Returns the time (with formatting) in GMT and the user's local time zone, if logged in.",
* parameters={},
* @SWG\Response(
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(ref="#/definitions/Time")
* @OA\Schema(ref="#/components/schemas/Time")
* )
* )
*/

View File

@ -33,20 +33,20 @@ class ListenersController
}
/**
* @SWG\Get(path="/station/{station_id}/listeners",
* @OA\Get(path="/station/{station_id}/listeners",
* tags={"Stations: Listeners"},
* description="Return detailed information about current listeners.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Response(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* @OA\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/Listener")
* @OA\Items(ref="#/components/schemas/Listener")
* )
* ),
* @SWG\Response(response=404, description="Station not found"),
* @SWG\Response(response=403, description="Access denied"),
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=403, description="Access denied"),
* security={
* {"api_key": {"view station reports"}}
* },

View File

@ -27,32 +27,32 @@ class NowplayingController
}
/**
* @SWG\Get(path="/nowplaying",
* @OA\Get(path="/nowplaying",
* tags={"Now Playing"},
* description="Returns a full summary of all stations' current state.",
* parameters={},
* @SWG\Response(
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* @OA\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/NowPlaying")
* @OA\Items(ref="#/components/schemas/NowPlaying")
* )
* )
* )
*
* @SWG\Get(path="/nowplaying/{station_id}",
* @OA\Get(path="/nowplaying/{station_id}",
* tags={"Now Playing"},
* description="Returns a full summary of the specified station's current state.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Response(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* ref="#/definitions/NowPlaying"
* @OA\Schema(
* ref="#/components/schemas/NowPlaying"
* )
* ),
* @SWG\Response(response=404, description="Station not found")
* @OA\Response(response=404, description="Station not found")
* )
*/
public function indexAction(Request $request, Response $response, $id = null): Response

View File

@ -29,20 +29,20 @@ class RequestsController
}
/**
* @SWG\Get(path="/station/{station_id}/requests",
* @OA\Get(path="/station/{station_id}/requests",
* tags={"Stations: Song Requests"},
* description="Return a list of requestable songs.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Response(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* @OA\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/StationRequest")
* @OA\Items(ref="#/components/schemas/StationRequest")
* )
* ),
* @SWG\Response(response=404, description="Station not found"),
* @SWG\Response(response=403, description="Station does not support requests")
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=403, description="Station does not support requests")
* )
*/
public function listAction(Request $request, Response $response, $station_id): Response
@ -119,21 +119,22 @@ class RequestsController
}
/**
* @SWG\Post(path="/station/{station_id}/request/{request_id}",
* @OA\Post(path="/station/{station_id}/request/{request_id}",
* tags={"Stations: Song Requests"},
* description="Submit a song request.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Parameter(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Parameter(
* name="request_id",
* description="The requestable song ID",
* type="integer",
* format="int64",
* in="path",
* required=true
* required=true,
* @OA\Schema(
* type="int64"
* )
* ),
* @SWG\Response(response=200, description="Success"),
* @SWG\Response(response=404, description="Station not found"),
* @SWG\Response(response=403, description="Station does not support requests")
* @OA\Response(response=200, description="Success"),
* @OA\Response(response=404, description="Station not found"),
* @OA\Response(response=403, description="Station does not support requests")
* )
*/
public function submitAction(Request $request, Response $response, $station_id, $media_id): Response

View File

@ -27,16 +27,16 @@ class IndexController
}
/**
* @SWG\Get(path="/stations",
* @OA\Get(path="/stations",
* tags={"Stations: General"},
* description="Returns a list of stations.",
* parameters={},
* @SWG\Response(
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* @OA\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/Station")
* @OA\Items(ref="#/components/schemas/Station")
* )
* )
* )
@ -63,18 +63,18 @@ class IndexController
}
/**
* @SWG\Get(path="/station/{station_id}",
* @OA\Get(path="/station/{station_id}",
* tags={"Stations: General"},
* description="Return information about a single station.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Response(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(
* response=200,
* description="Success",
* @SWG\Schema(
* ref="#/definitions/Station"
* @OA\Schema(
* ref="#/components/schemas/Station"
* )
* ),
* @SWG\Response(response=404, description="Station not found")
* @OA\Response(response=404, description="Station not found")
* )
*/
public function indexAction(Request $request, Response $response): Response

View File

@ -27,23 +27,24 @@ class MediaController
}
/**
* @SWG\Get(path="/station/{station_id}/art/{media_id}",
* @OA\Get(path="/station/{station_id}/art/{media_id}",
* tags={"Stations: Media"},
* description="Returns the album art for a song, or a generic image.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Parameter(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Parameter(
* name="media_id",
* description="The station media ID",
* type="integer",
* format="int64",
* in="path",
* required=true
* required=true,
* @OA\Schema(
* type="int64"
* )
* ),
* @SWG\Response(
* @OA\Response(
* response=200,
* description="The requested album artwork"
* ),
* @SWG\Response(
* @OA\Response(
* response=404,
* description="Image not found; generic filler image."
* )

View File

@ -23,12 +23,12 @@ class ServicesController
}
/**
* @SWG\Post(path="/station/{station_id}/restart",
* @OA\Post(path="/station/{station_id}/restart",
* tags={"Stations: Service Control"},
* description="Restart all services associated with the radio broadcast.",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Response(response=200, description="Success", @SWG\Schema(ref="#/definitions/Status")),
* @SWG\Response(response=403, description="Access Forbidden", @SWG\Schema(ref="#/definitions/Error")),
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(response=200, description="Success", @OA\Schema(ref="#/components/schemas/Status")),
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Error")),
* security={
* {"api_key": {"manage station broadcasting"}}
* }
@ -65,21 +65,22 @@ class ServicesController
}
/**
* @SWG\Post(path="/station/{station_id}/frontend/{action}",
* @OA\Post(path="/station/{station_id}/frontend/{action}",
* tags={"Stations: Service Control"},
* description="Perform service control actions on the radio frontend (Icecast, SHOUTcast, etc.)",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Parameter(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Parameter(
* name="action",
* description="The action to perform (start, stop, restart)",
* type="string",
* format="string",
* in="path",
* default="restart",
* required=false
* content="restart",
* required=false,
* @OA\Schema(
* type="string"
* )
* ),
* @SWG\Response(response=200, description="Success", @SWG\Schema(ref="#/definitions/Status")),
* @SWG\Response(response=403, description="Access Forbidden", @SWG\Schema(ref="#/definitions/Error")),
* @OA\Response(response=200, description="Success", @OA\Schema(ref="#/components/schemas/Status")),
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Error")),
* security={
* {"api_key": {"manage station broadcasting"}}
* }
@ -118,21 +119,22 @@ class ServicesController
}
/**
* @SWG\Post(path="/station/{station_id}/backend/{action}",
* @OA\Post(path="/station/{station_id}/backend/{action}",
* tags={"Stations: Service Control"},
* description="Perform service control actions on the radio backend (Liquidsoap)",
* @SWG\Parameter(ref="#/parameters/station_id_required"),
* @SWG\Parameter(
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Parameter(
* name="action",
* description="The action to perform (start, stop, restart)",
* type="string",
* format="string",
* in="path",
* default="restart",
* required=false
* content="restart",
* required=false,
* @OA\Schema(
* type="string"
* )
* ),
* @SWG\Response(response=200, description="Success", @SWG\Schema(ref="#/definitions/Status")),
* @SWG\Response(response=403, description="Access Forbidden", @SWG\Schema(ref="#/definitions/Error")),
* @OA\Response(response=200, description="Success", @OA\Schema(ref="#/components/schemas/Status")),
* @OA\Response(response=403, description="Access Forbidden", @OA\Schema(ref="#/components/schemas/Error")),
* security={
* {"api_key": {"manage station broadcasting"}}
* }

View File

@ -2,14 +2,14 @@
namespace App\Entity\Api;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class DetailedSongHistory extends SongHistory
{
/**
* Number of listeners when the song playback started.
*
* @SWG\Property(example=94)
* @OA\Property(example=94)
* @var int
*/
public $listeners_start;
@ -17,7 +17,7 @@ class DetailedSongHistory extends SongHistory
/**
* Number of listeners when song playback ended.
*
* @SWG\Property(example=105)
* @OA\Property(example=105)
* @var int
*/
public $listeners_end;
@ -25,7 +25,7 @@ class DetailedSongHistory extends SongHistory
/**
* The sum total change of listeners between the song's start and ending.
*
* @SWG\Property(example=11)
* @OA\Property(example=11)
* @var int
*/
public $delta_total;

View File

@ -3,7 +3,7 @@
namespace App\Entity\Api;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Error
{
@ -18,7 +18,7 @@ class Error
/**
* The numeric code of the error.
*
* @SWG\Property(example=500)
* @OA\Property(example=500)
* @var int
*/
public $code;
@ -26,7 +26,7 @@ class Error
/**
* The text description of the error.
*
* @SWG\Property(example="Error description.")
* @OA\Property(example="Error description.")
* @var string
*/
public $message;
@ -34,7 +34,7 @@ class Error
/**
* A stack trace outlining the error, if permissions allow this to be shown.
*
* @SWG\Property(@SWG\Items)
* @OA\Property(@OA\Items)
* @var array
*/
public $stack_trace;
@ -42,7 +42,7 @@ class Error
/**
* Used for API calls that expect an \Entity\Api\Status type response.
*
* @SWG\Property(example=false)
* @OA\Property(example=false)
* @var bool
*/
public $success;

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Listener
{
/**
* The listener's IP address
*
* @SWG\Property(example="127.0.0.1")
* @OA\Property(example="127.0.0.1")
* @var string
*/
public $ip;
@ -20,7 +20,7 @@ class Listener
/**
* The listener's HTTP User-Agent
*
* @SWG\Property(example="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36")
* @OA\Property(example="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36")
* @var string
*/
public $user_agent;
@ -28,7 +28,7 @@ class Listener
/**
* Whether the user-agent is likely a mobile browser.
*
* @SWG\Property(example=true)
* @OA\Property(example=true)
* @var bool
*/
public $is_mobile;
@ -36,7 +36,7 @@ class Listener
/**
* UNIX timestamp that the user first connected.
*
* @SWG\Property(example=SAMPLE_TIMESTAMP)
* @OA\Property(example=SAMPLE_TIMESTAMP)
* @var int
*/
public $connected_on;
@ -44,7 +44,7 @@ class Listener
/**
* Number of seconds that the user has been connected.
*
* @SWG\Property(example=30)
* @OA\Property(example=30)
* @var int
*/
public $connected_time;
@ -52,7 +52,7 @@ class Listener
/**
* Location metadata, if available
*
* @SWG\Property(@SWG\Items)
* @OA\Property(@OA\Items)
* @var array
*/
public $location;

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class NowPlaying
{
/**
* Station
*
* @SWG\Property
* @OA\Property
* @var Station
*/
public $station;
@ -20,7 +20,7 @@ class NowPlaying
/**
* Listener details
*
* @SWG\Property
* @OA\Property
* @var NowPlayingListeners
*/
public $listeners;
@ -28,7 +28,7 @@ class NowPlaying
/**
* Live broadcast details
*
* @SWG\Property
* @OA\Property
* @var NowPlayingLive
*/
public $live;
@ -36,7 +36,7 @@ class NowPlaying
/**
* Current Song
*
* @SWG\Property
* @OA\Property
* @var NowPlayingCurrentSong
*/
public $now_playing;
@ -44,13 +44,13 @@ class NowPlaying
/**
* Next Playing Song
*
* @SWG\Property
* @OA\Property
* @var SongHistory
*/
public $playing_next;
/**
* @SWG\Property
* @OA\Property
* @var SongHistory[]
*/
public $song_history;
@ -58,7 +58,7 @@ class NowPlaying
/**
* Debugging information about where the now playing data comes from.
*
* @SWG\Property(enum={"hit", "database", "station"})
* @OA\Property(enum={"hit", "database", "station"})
* @var string
*/
public $cache;

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class NowPlayingCurrentSong extends SongHistory
{
/**
* Elapsed time of the song's playback since it started.
*
* @SWG\Property(example=25)
* @OA\Property(example=25)
* @var int
*/
public $elapsed;
@ -20,7 +20,7 @@ class NowPlayingCurrentSong extends SongHistory
/**
* Remaining time in the song, in seconds.
*
* @SWG\Property(example=155)
* @OA\Property(example=155)
* @var int
*/
public $remaining;

View File

@ -5,7 +5,7 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class NowPlayingListeners
{
@ -21,21 +21,21 @@ class NowPlayingListeners
/**
* Current listeners, either unique (if supplied) or total (non-unique)
* @SWG\Property(example=15)
* @OA\Property(example=15)
* @var int
*/
public $current;
/**
* Total unique current listeners
* @SWG\Property(example=15)
* @OA\Property(example=15)
* @var int
*/
public $unique;
/**
* Total non-unique current listeners
* @SWG\Property(example=20)
* @OA\Property(example=20)
* @var int
*/
public $total;

View File

@ -5,7 +5,7 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class NowPlayingLive
{
@ -18,7 +18,7 @@ class NowPlayingLive
/**
* Whether the stream is known to currently have a live DJ.
*
* @SWG\Property(example=false)
* @OA\Property(example=false)
* @var bool
*/
public $is_live;
@ -26,7 +26,7 @@ class NowPlayingLive
/**
* The current active streamer/DJ, if one is available.
*
* @SWG\Property(example="DJ Jazzy Jeff")
* @OA\Property(example="DJ Jazzy Jeff")
* @var string
*/
public $streamer_name;

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Song
{
/**
* The song's 32-character unique identifier hash
*
* @SWG\Property(example="9f33bbc912c19603e51be8e0987d076b")
* @OA\Property(example="9f33bbc912c19603e51be8e0987d076b")
* @var string
*/
public $id;
@ -20,7 +20,7 @@ class Song
/**
* The song title, usually "Artist - Title"
*
* @SWG\Property(example="Chet Porter - Aluko River")
* @OA\Property(example="Chet Porter - Aluko River")
* @var string
*/
public $text;
@ -28,7 +28,7 @@ class Song
/**
* The song artist.
*
* @SWG\Property(example="Chet Porter")
* @OA\Property(example="Chet Porter")
* @var string
*/
public $artist;
@ -36,7 +36,7 @@ class Song
/**
* The song title.
*
* @SWG\Property(example="Aluko River")
* @OA\Property(example="Aluko River")
* @var string
*/
public $title;
@ -44,7 +44,7 @@ class Song
/**
* The song album.
*
* @SWG\Property(example="Moving Castle")
* @OA\Property(example="Moving Castle")
* @var string
*/
public $album = "";
@ -52,7 +52,7 @@ class Song
/**
* Lyrics to the song.
*
* @SWG\Property(example="")
* @OA\Property(example="")
* @var string
*/
public $lyrics = "";
@ -60,13 +60,18 @@ class Song
/**
* URL to the album artwork (if available).
*
* @SWG\Property(example="https://picsum.photos/1200/1200")
* @OA\Property(example="https://picsum.photos/1200/1200")
* @var string
*/
public $art = "";
/**
* @SWG\Property
* @OA\Property(
* @OA\Items(
* type="string",
* example="custom_field_value"
* )
* )
* @var array
*/
public $custom_fields = [];

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class SongHistory
{
/**
* Song history unique identifier
*
* @SWG\Property
* @OA\Property
* @var int
*/
public $sh_id;
@ -20,7 +20,7 @@ class SongHistory
/**
* UNIX timestamp when playback started.
*
* @SWG\Property(example=SAMPLE_TIMESTAMP)
* @OA\Property(example=SAMPLE_TIMESTAMP)
* @var int
*/
public $played_at;
@ -28,7 +28,7 @@ class SongHistory
/**
* Duration of the song in seconds
*
* @SWG\Property(example=180)
* @OA\Property(example=180)
* @var int
*/
public $duration;
@ -36,7 +36,7 @@ class SongHistory
/**
* Indicates the playlist that the song was played from, if available, or empty string if not.
*
* @SWG\Property(example="Top 100")
* @OA\Property(example="Top 100")
* @var string
*/
public $playlist;
@ -44,7 +44,7 @@ class SongHistory
/**
* Indicates whether the song is a listener request.
*
* @SWG\Property
* @OA\Property
* @var bool
*/
public $is_request;
@ -52,7 +52,7 @@ class SongHistory
/**
* Song
*
* @SWG\Property
* @OA\Property
* @var Song
*/
public $song;

View File

@ -5,74 +5,74 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Station
{
/**
* Station ID
* @SWG\Property(example=1)
* @OA\Property(example=1)
* @var int
*/
public $id;
/**
* Station name
* @SWG\Property(example="AzuraTest Radio")
* @OA\Property(example="AzuraTest Radio")
* @var string
*/
public $name;
/**
* Station "short code", used for URL and folder paths
* @SWG\Property(example="azuratest_radio")
* @OA\Property(example="azuratest_radio")
* @var string
*/
public $shortcode;
/**
* Station description
* @SWG\Property(example="An AzuraCast station!")
* @OA\Property(example="An AzuraCast station!")
* @var string
*/
public $description;
/**
* Which broadcasting software (frontend) the station uses
* @SWG\Property(example="shoutcast2")
* @OA\Property(example="shoutcast2")
* @var string
*/
public $frontend;
/**
* Which AutoDJ software (backend) the station uses
* @SWG\Property(example="liquidsoap")
* @OA\Property(example="liquidsoap")
* @var string
*/
public $backend;
/**
* The full URL to listen to the default mount of the station
* @SWG\Property(example="http://localhost:8000/radio.mp3")
* @OA\Property(example="http://localhost:8000/radio.mp3")
* @var string
*/
public $listen_url;
/**
* If the station is public (i.e. should be shown in listings of all stations)
* @SWG\Property(example=true)
* @OA\Property(example=true)
* @var bool
*/
public $is_public;
/**
* @SWG\Property(type="array", @SWG\Items(ref="#/definitions/StationMount"))
* @OA\Property(type="array", @OA\Items(ref="#/components/schemas/StationMount"))
* @var array
*/
public $mounts;
/**
* @SWG\Property(type="array", @SWG\Items(ref="#/definitions/StationRemote"))
* @OA\Property(type="array", @OA\Items(ref="#/components/schemas/StationRemote"))
* @var array
*/
public $remotes;

View File

@ -2,14 +2,14 @@
namespace App\Entity\Api;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class StationMount
{
/**
* Mount point name/URL
*
* @SWG\Property(example="/radio.mp3")
* @OA\Property(example="/radio.mp3")
* @var string
*/
public $name;
@ -17,7 +17,7 @@ class StationMount
/**
* If the mount is the default mount for the parent station
*
* @SWG\Property(example=true)
* @OA\Property(example=true)
* @var bool
*/
public $is_default;
@ -25,7 +25,7 @@ class StationMount
/**
* Full listening URL specific to this mount
*
* @SWG\Property(example="http://localhost:8000/radio.mp3")
* @OA\Property(example="http://localhost:8000/radio.mp3")
* @var string
*/
public $url;
@ -33,7 +33,7 @@ class StationMount
/**
* Bitrate (kbps) of the broadcasted audio (if known)
*
* @SWG\Property(example=128)
* @OA\Property(example=128)
* @var int
*/
public $bitrate;
@ -41,7 +41,7 @@ class StationMount
/**
* Audio encoding format of broadcasted audio (if known)
*
* @SWG\Property(example="mp3")
* @OA\Property(example="mp3")
* @var string
*/
public $format;

View File

@ -2,14 +2,14 @@
namespace App\Entity\Api;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class StationRemote
{
/**
* Full listening URL specific to this mount
*
* @SWG\Property(example="http://localhost:8000/radio.mp3")
* @OA\Property(example="http://localhost:8000/radio.mp3")
* @var string
*/
public $url;
@ -17,7 +17,7 @@ class StationRemote
/**
* Bitrate (kbps) of the broadcasted audio (if known)
*
* @SWG\Property(example=128)
* @OA\Property(example=128)
* @var int
*/
public $bitrate;
@ -25,7 +25,7 @@ class StationRemote
/**
* Audio encoding format of broadcasted audio (if known)
*
* @SWG\Property(example="mp3")
* @OA\Property(example="mp3")
* @var string
*/
public $format;

View File

@ -5,14 +5,14 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class StationRequest
{
/**
* Requestable ID unique identifier
*
* @SWG\Property(example=1)
* @OA\Property(example=1)
* @var int
*/
public $request_id;
@ -20,7 +20,7 @@ class StationRequest
/**
* URL to directly submit request
*
* @SWG\Property(example="/api/station/1/request/1")
* @OA\Property(example="/api/station/1/request/1")
* @var int
*/
public $request_url;
@ -28,7 +28,7 @@ class StationRequest
/**
* Song
*
* @SWG\Property
* @OA\Property
* @var Song
*/
public $song;

View File

@ -5,7 +5,7 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Status
{
@ -16,13 +16,13 @@ class Status
}
/**
* @SWG\Property(example=true)
* @OA\Property(example=true)
* @var bool
*/
public $success;
/**
* @SWG\Property(example="Changes saved successfully.")
* @OA\Property(example="Changes saved successfully.")
* @var string
*/
public $message;

View File

@ -5,7 +5,7 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class SystemStatus
{
@ -18,7 +18,7 @@ class SystemStatus
/**
* Whether the service is online or not (should always be true)
*
* @SWG\Property(example=true)
* @OA\Property(example=true)
* @var boolean
*/
public $online;
@ -26,7 +26,7 @@ class SystemStatus
/**
* The current UNIX timestamp
*
* @SWG\Property(example=SAMPLE_TIMESTAMP)
* @OA\Property(example=SAMPLE_TIMESTAMP)
* @var int
*/
public $timestamp;

View File

@ -5,7 +5,7 @@ namespace App\Entity\Api;
use App\Entity;
/**
* @SWG\Definition(type="object")
* @OA\Schema(type="object")
*/
class Time
{
@ -35,67 +35,67 @@ class Time
/**
* The current UNIX timestamp
*
* @SWG\Property(example=1497652397)
* @OA\Property(example=1497652397)
* @var int
*/
public $timestamp;
/**
* @SWG\Property(example="2017-06-16 10:33:17")
* @OA\Property(example="2017-06-16 10:33:17")
* @var string
*/
public $gmt_datetime;
/**
* @SWG\Property(example="June 16, 2017")
* @OA\Property(example="June 16, 2017")
* @var string
*/
public $gmt_date;
/**
* @SWG\Property(example="10:33pm")
* @OA\Property(example="10:33pm")
* @var string
*/
public $gmt_time;
/**
* @SWG\Property(example="GMT")
* @OA\Property(example="GMT")
* @var string
*/
public $gmt_timezone;
/**
* @SWG\Property(example="GMT")
* @OA\Property(example="GMT")
* @var string
*/
public $gmt_timezone_abbr;
/**
* @SWG\Property(example="2017-06-16 10:33:17")
* @OA\Property(example="2017-06-16 10:33:17")
* @var string
*/
public $local_datetime;
/**
* @SWG\Property(example="June 16, 2017")
* @OA\Property(example="June 16, 2017")
* @var string
*/
public $local_date;
/**
* @SWG\Property(example="10:33pm")
* @OA\Property(example="10:33pm")
* @var string
*/
public $local_time;
/**
* @SWG\Property(example="UTC")
* @OA\Property(example="UTC")
* @var string
*/
public $local_timezone;
/**
* @SWG\Property(example="UTC")
* @OA\Property(example="UTC")
* @var string
*/
public $local_timezone_abbr;

55
util/openapi.php Normal file
View File

@ -0,0 +1,55 @@
<?php
/**
* @OA\Info(
* version=AZURACAST_VERSION,
* title="AzuraCast",
* description="AzuraCast is a standalone, turnkey web radio management tool. Radio stations hosted by AzuraCast expose a public API for viewing now playing data, making requests and more.",
* @OA\License(
* name="Apache 2.0",
* url="http://www.apache.org/licenses/LICENSE-2.0.html"
* )
* )
*
* @OA\Server(
* description="AzuraCast Demo API",
* url="https://demo.azuracast.com/api"
* )
*
* @OA\ExternalDocumentation(
* description="AzuraCast on GitHub",
* url="https://github.com/AzuraCast/AzuraCast"
* )
*
* @OA\Parameter(
* parameter="station_id_required",
* name="station_id",
* description="The station ID",
* example=1,
* in="path",
* required=true,
* @OA\Schema(
* type="int64"
* )
* )
*
* @OA\Response(
* response="todo",
* description="This API call has no documented response (yet)",
* )
*
* @OA\Tag(
* name="Now Playing",
* description="Endpoints that provide full summaries of the current state of stations.",
* )
* @OA\Tag(name="Miscellaneous")
* @OA\Tag(name="Stations: General")
* @OA\Tag(name="Stations: Song Requests")
* @OA\Tag(name="Stations: Listeners")
*
* @OA\SecurityScheme(
* type="apiKey",
* in="header",
* securityScheme="api_key",
* name="X-API-Key"
* )
*/

View File

@ -1,57 +0,0 @@
<?php
/**
* @SWG\Swagger(
* schemes={"http","https"},
* consumes={"application/json"},
* produces={"application/json"},
* basePath="/api",
* @SWG\Info(
* version=AZURACAST_VERSION,
* title="AzuraCast",
* description="AzuraCast is a standalone, turnkey web radio management tool. Radio stations hosted by AzuraCast expose a public API for viewing now playing data, making requests and more.",
* @SWG\License(
* name="Apache 2.0",
* url="http://www.apache.org/licenses/LICENSE-2.0.html"
* )
* ),
* @SWG\ExternalDocumentation(
* description="AzuraCast on GitHub",
* url="https://github.com/AzuraCast/AzuraCast"
* )
* )
*
* @SWG\Parameter(
* parameter="station_id_required",
* name="station_id",
* description="The station ID",
* type="integer",
* format="int64",
* in="path",
* required=true
* )
*
* @SWG\Response(
* response="todo",
* description="This API call has no documented response (yet)",
* )
*
* @SWG\Tag(
* name="Now Playing",
* description="Endpoints that provide full summaries of the current state of stations.",
* )
* @SWG\Tag(name="Miscellaneous")
* @SWG\Tag(name="Stations: General")
* @SWG\Tag(name="Stations: Song Requests")
* @SWG\Tag(name="Stations: Listeners")
*
* @SWG\SecurityScheme(
* securityDefinition="api_key",
* type="apiKey",
* in="header",
* name="X-API-Key"
* )
*
*
*
*
*/

View File

@ -1,96 +1,60 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700"
rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
<link rel="icon" type="image/png" sizes="192x192" href="../icons/production/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="../icons/production/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="../icons/production/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="../icons/production/favicon-16x16.png">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
</head>
<body>
<body>
<div id="swagger-ui"></div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
// Build a system
const ui = SwaggerUIBundle({
url: "openapi.yml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"></script>
<script src="./swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Build a system
const ui = SwaggerUIBundle({
url: "swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
window.ui = ui
}
</script>
</body>
</script>
</body>
</html>

View File

@ -5,27 +5,32 @@
</html>
<script>
'use strict';
function run() {
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
qp = (window.location.hash || location.search).substring(1);
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v, i, _arr) {
_arr[i] = '"' + v.replace('=', '":"') + '"';
})
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if (oauth2.auth.schema.get("flow") === "accessCode" && !oauth2.auth.code) {
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
@ -40,11 +45,18 @@
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: "Authorization failed: no accessCode received from the server"
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {

605
web/static/api/openapi.yml Normal file
View File

@ -0,0 +1,605 @@
openapi: 3.0.0
info:
title: AzuraCast
description: 'AzuraCast is a standalone, turnkey web radio management tool. Radio stations hosted by AzuraCast expose a public API for viewing now playing data, making requests and more.'
license:
name: 'Apache 2.0'
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
version: 0.8.2-2018.04
servers:
-
url: 'https://demo.azuracast.com/api'
description: 'AzuraCast Demo API'
paths:
/status:
get:
tags:
- Miscellaneous
description: 'Returns an affirmative response if the API is active.'
operationId: 'App\Controller\Api\IndexController::statusAction'
parameters: { }
responses:
'200':
description: Success
/time:
get:
tags:
- Miscellaneous
description: 'Returns the time (with formatting) in GMT and the user''s local time zone, if logged in.'
operationId: 'App\Controller\Api\IndexController::timeAction'
parameters: { }
responses:
'200':
description: Success
'/station/{station_id}/listeners':
get:
tags:
- 'Stations: Listeners'
description: 'Return detailed information about current listeners.'
operationId: 'App\Controller\Api\ListenersController::indexAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
responses:
'200':
description: Success
'404':
description: 'Station not found'
'403':
description: 'Access denied'
security:
-
api_key:
- 'view station reports'
/nowplaying:
get:
tags:
- 'Now Playing'
description: 'Returns a full summary of all stations'' current state.'
operationId: 'App\Controller\Api\NowplayingController::indexAction'
parameters: { }
responses:
'200':
description: Success
'/nowplaying/{station_id}':
get:
tags:
- 'Now Playing'
description: 'Returns a full summary of the specified station''s current state.'
operationId: 'App\Controller\Api\NowplayingController::indexAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
responses:
'200':
description: Success
'404':
description: 'Station not found'
'/station/{station_id}/requests':
get:
tags:
- 'Stations: Song Requests'
description: 'Return a list of requestable songs.'
operationId: 'App\Controller\Api\RequestsController::listAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
responses:
'200':
description: Success
'404':
description: 'Station not found'
'403':
description: 'Station does not support requests'
'/station/{station_id}/request/{request_id}':
post:
tags:
- 'Stations: Song Requests'
description: 'Submit a song request.'
operationId: 'App\Controller\Api\RequestsController::submitAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
-
name: request_id
in: path
description: 'The requestable song ID'
required: true
schema:
type: int64
responses:
'200':
description: Success
'404':
description: 'Station not found'
'403':
description: 'Station does not support requests'
/stations:
get:
tags:
- 'Stations: General'
description: 'Returns a list of stations.'
operationId: 'App\Controller\Api\Stations\IndexController::listAction'
parameters: { }
responses:
'200':
description: Success
'/station/{station_id}':
get:
tags:
- 'Stations: General'
description: 'Return information about a single station.'
operationId: 'App\Controller\Api\Stations\IndexController::indexAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
responses:
'200':
description: Success
'404':
description: 'Station not found'
'/station/{station_id}/art/{media_id}':
get:
tags:
- 'Stations: Media'
description: 'Returns the album art for a song, or a generic image.'
operationId: 'App\Controller\Api\Stations\MediaController::artAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
-
name: media_id
in: path
description: 'The station media ID'
required: true
schema:
type: int64
responses:
'200':
description: 'The requested album artwork'
'404':
description: 'Image not found; generic filler image.'
'/station/{station_id}/restart':
post:
tags:
- 'Stations: Service Control'
description: 'Restart all services associated with the radio broadcast.'
operationId: 'App\Controller\Api\Stations\ServicesController::restartAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
responses:
'200':
description: Success
'403':
description: 'Access Forbidden'
security:
-
api_key:
- 'manage station broadcasting'
'/station/{station_id}/frontend/{action}':
post:
tags:
- 'Stations: Service Control'
description: 'Perform service control actions on the radio frontend (Icecast, SHOUTcast, etc.)'
operationId: 'App\Controller\Api\Stations\ServicesController::frontendAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
-
name: action
in: path
description: 'The action to perform (start, stop, restart)'
required: false
schema:
type: string
content: restart
responses:
'200':
description: Success
'403':
description: 'Access Forbidden'
security:
-
api_key:
- 'manage station broadcasting'
'/station/{station_id}/backend/{action}':
post:
tags:
- 'Stations: Service Control'
description: 'Perform service control actions on the radio backend (Liquidsoap)'
operationId: 'App\Controller\Api\Stations\ServicesController::backendAction'
parameters:
-
$ref: '#/components/parameters/station_id_required'
-
name: action
in: path
description: 'The action to perform (start, stop, restart)'
required: false
schema:
type: string
content: restart
responses:
'200':
description: Success
'403':
description: 'Access Forbidden'
security:
-
api_key:
- 'manage station broadcasting'
components:
schemas:
DetailedSongHistory:
allOf:
-
$ref: '#/components/schemas/SongHistory'
-
properties:
listeners_start:
description: 'Number of listeners when the song playback started.'
type: integer
example: 94
listeners_end:
description: 'Number of listeners when song playback ended.'
type: integer
example: 105
delta_total:
description: 'The sum total change of listeners between the song''s start and ending.'
type: integer
example: 11
type: object
Error:
properties:
code:
description: 'The numeric code of the error.'
type: integer
example: 500
message:
description: 'The text description of the error.'
type: string
example: 'Error description.'
stack_trace:
description: 'A stack trace outlining the error, if permissions allow this to be shown.'
type: array
items: { }
success:
description: 'Used for API calls that expect an \Entity\Api\Status type response.'
type: boolean
example: false
type: object
Listener:
properties:
ip:
description: 'The listener''s IP address'
type: string
example: 127.0.0.1
user_agent:
description: 'The listener''s HTTP User-Agent'
type: string
example: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36'
is_mobile:
description: 'Whether the user-agent is likely a mobile browser.'
type: boolean
example: true
connected_on:
description: 'UNIX timestamp that the user first connected.'
type: integer
example: 1537220436
connected_time:
description: 'Number of seconds that the user has been connected.'
type: integer
example: 30
location:
description: 'Location metadata, if available'
type: array
items: { }
type: object
NowPlaying:
properties:
station:
$ref: '#/components/schemas/Station'
listeners:
$ref: '#/components/schemas/NowPlayingListeners'
live:
$ref: '#/components/schemas/NowPlayingLive'
now_playing:
$ref: '#/components/schemas/NowPlayingCurrentSong'
playing_next:
$ref: '#/components/schemas/SongHistory'
song_history:
type: array
items:
$ref: '#/components/schemas/SongHistory'
cache:
description: 'Debugging information about where the now playing data comes from.'
type: string
enum:
- hit
- database
- station
type: object
NowPlayingCurrentSong:
allOf:
-
$ref: '#/components/schemas/SongHistory'
-
properties:
elapsed:
description: 'Elapsed time of the song''s playback since it started.'
type: integer
example: 25
remaining:
description: 'Remaining time in the song, in seconds.'
type: integer
example: 155
type: object
NowPlayingListeners:
properties:
current:
description: 'Current listeners, either unique (if supplied) or total (non-unique)'
type: integer
example: 15
unique:
description: 'Total unique current listeners'
type: integer
example: 15
total:
description: 'Total non-unique current listeners'
type: integer
example: 20
type: object
NowPlayingLive:
properties:
is_live:
description: 'Whether the stream is known to currently have a live DJ.'
type: boolean
example: false
streamer_name:
description: 'The current active streamer/DJ, if one is available.'
type: string
example: 'DJ Jazzy Jeff'
type: object
Song:
properties:
id:
description: 'The song''s 32-character unique identifier hash'
type: string
example: 9f33bbc912c19603e51be8e0987d076b
text:
description: 'The song title, usually "Artist - Title"'
type: string
example: 'Chet Porter - Aluko River'
artist:
description: 'The song artist.'
type: string
example: 'Chet Porter'
title:
description: 'The song title.'
type: string
example: 'Aluko River'
album:
description: 'The song album.'
type: string
example: 'Moving Castle'
lyrics:
description: 'Lyrics to the song.'
type: string
example: ''
art:
description: 'URL to the album artwork (if available).'
type: string
example: 'https://picsum.photos/1200/1200'
custom_fields:
type: array
items:
type: string
example: custom_field_value
type: object
SongHistory:
properties:
sh_id:
description: 'Song history unique identifier'
type: integer
played_at:
description: 'UNIX timestamp when playback started.'
type: integer
example: 1537220436
duration:
description: 'Duration of the song in seconds'
type: integer
example: 180
playlist:
description: 'Indicates the playlist that the song was played from, if available, or empty string if not.'
type: string
example: 'Top 100'
is_request:
description: 'Indicates whether the song is a listener request.'
type: boolean
song:
$ref: '#/components/schemas/Song'
type: object
Station:
properties:
id:
description: 'Station ID'
type: integer
example: 1
name:
description: 'Station name'
type: string
example: 'AzuraTest Radio'
shortcode:
description: 'Station "short code", used for URL and folder paths'
type: string
example: azuratest_radio
description:
description: 'Station description'
type: string
example: 'An AzuraCast station!'
frontend:
description: 'Which broadcasting software (frontend) the station uses'
type: string
example: shoutcast2
backend:
description: 'Which AutoDJ software (backend) the station uses'
type: string
example: liquidsoap
listen_url:
description: 'The full URL to listen to the default mount of the station'
type: string
example: 'http://localhost:8000/radio.mp3'
is_public:
description: 'If the station is public (i.e. should be shown in listings of all stations)'
type: boolean
example: true
mounts:
type: array
items:
$ref: '#/components/schemas/StationMount'
remotes:
type: array
items:
$ref: '#/components/schemas/StationRemote'
type: object
StationMount:
properties:
name:
description: 'Mount point name/URL'
type: string
example: /radio.mp3
is_default:
description: 'If the mount is the default mount for the parent station'
type: boolean
example: true
url:
description: 'Full listening URL specific to this mount'
type: string
example: 'http://localhost:8000/radio.mp3'
bitrate:
description: 'Bitrate (kbps) of the broadcasted audio (if known)'
type: integer
example: 128
format:
description: 'Audio encoding format of broadcasted audio (if known)'
type: string
example: mp3
type: object
StationRemote:
properties:
url:
description: 'Full listening URL specific to this mount'
type: string
example: 'http://localhost:8000/radio.mp3'
bitrate:
description: 'Bitrate (kbps) of the broadcasted audio (if known)'
type: integer
example: 128
format:
description: 'Audio encoding format of broadcasted audio (if known)'
type: string
example: mp3
type: object
StationRequest:
properties:
request_id:
description: 'Requestable ID unique identifier'
type: integer
example: 1
request_url:
description: 'URL to directly submit request'
type: integer
example: /api/station/1/request/1
song:
$ref: '#/components/schemas/Song'
type: object
Status:
properties:
success:
type: boolean
example: true
message:
type: string
example: 'Changes saved successfully.'
type: object
SystemStatus:
properties:
online:
description: 'Whether the service is online or not (should always be true)'
type: boolean
example: true
timestamp:
description: 'The current UNIX timestamp'
type: integer
example: 1537220436
type: object
Time:
properties:
timestamp:
description: 'The current UNIX timestamp'
type: integer
example: 1497652397
gmt_datetime:
type: string
example: '2017-06-16 10:33:17'
gmt_date:
type: string
example: 'June 16, 2017'
gmt_time:
type: string
example: '10:33pm'
gmt_timezone:
type: string
example: GMT
gmt_timezone_abbr:
type: string
example: GMT
local_datetime:
type: string
example: '2017-06-16 10:33:17'
local_date:
type: string
example: 'June 16, 2017'
local_time:
type: string
example: '10:33pm'
local_timezone:
type: string
example: UTC
local_timezone_abbr:
type: string
example: UTC
type: object
responses:
todo:
description: 'This API call has no documented response (yet)'
parameters:
station_id_required:
name: station_id
in: path
description: 'The station ID'
required: true
schema:
type: int64
example: 1
securitySchemes:
api_key:
type: apiKey
name: X-API-Key
in: header
tags:
-
name: 'Now Playing'
description: 'Endpoints that provide full summaries of the current state of stations.'
-
name: Miscellaneous
-
name: 'Stations: General'
-
name: 'Stations: Song Requests'
-
name: 'Stations: Listeners'
externalDocs:
description: 'AzuraCast on GitHub'
url: 'https://github.com/AzuraCast/AzuraCast'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,868 +0,0 @@
{
"swagger": "2.0",
"info": {
"title": "AzuraCast",
"description": "AzuraCast is a standalone, turnkey web radio management tool. Radio stations hosted by AzuraCast expose a public API for viewing now playing data, making requests and more.",
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "0.8.2-2018.04"
},
"basePath": "/api",
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/status": {
"get": {
"tags": [
"Miscellaneous"
],
"description": "Returns an affirmative response if the API is active.",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/SystemStatus"
}
}
}
}
},
"/time": {
"get": {
"tags": [
"Miscellaneous"
],
"description": "Returns the time (with formatting) in GMT and the user's local time zone, if logged in.",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Time"
}
}
}
}
},
"/station/{station_id}/listeners": {
"get": {
"tags": [
"Stations: Listeners"
],
"description": "Return detailed information about current listeners.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Listener"
}
}
},
"404": {
"description": "Station not found"
},
"403": {
"description": "Access denied"
}
},
"security": [
{
"api_key": [
"view station reports"
]
}
]
}
},
"/nowplaying": {
"get": {
"tags": [
"Now Playing"
],
"description": "Returns a full summary of all stations' current state.",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/NowPlaying"
}
}
}
}
}
},
"/nowplaying/{station_id}": {
"get": {
"tags": [
"Now Playing"
],
"description": "Returns a full summary of the specified station's current state.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/NowPlaying"
}
},
"404": {
"description": "Station not found"
}
}
}
},
"/station/{station_id}/requests": {
"get": {
"tags": [
"Stations: Song Requests"
],
"description": "Return a list of requestable songs.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/StationRequest"
}
}
},
"404": {
"description": "Station not found"
},
"403": {
"description": "Station does not support requests"
}
}
}
},
"/station/{station_id}/request/{request_id}": {
"post": {
"tags": [
"Stations: Song Requests"
],
"description": "Submit a song request.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
},
{
"name": "request_id",
"in": "path",
"description": "The requestable song ID",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "Success"
},
"404": {
"description": "Station not found"
},
"403": {
"description": "Station does not support requests"
}
}
}
},
"/stations": {
"get": {
"tags": [
"Stations: General"
],
"description": "Returns a list of stations.",
"parameters": [],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Station"
}
}
}
}
}
},
"/station/{station_id}": {
"get": {
"tags": [
"Stations: General"
],
"description": "Return information about a single station.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Station"
}
},
"404": {
"description": "Station not found"
}
}
}
},
"/station/{station_id}/art/{media_id}": {
"get": {
"tags": [
"Stations: Media"
],
"description": "Returns the album art for a song, or a generic image.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
},
{
"name": "media_id",
"in": "path",
"description": "The station media ID",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "The requested album artwork"
},
"404": {
"description": "Image not found; generic filler image."
}
}
}
},
"/station/{station_id}/restart": {
"post": {
"tags": [
"Stations: Service Control"
],
"description": "Restart all services associated with the radio broadcast.",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Status"
}
},
"403": {
"description": "Access Forbidden",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"security": [
{
"api_key": [
"manage station broadcasting"
]
}
]
}
},
"/station/{station_id}/frontend/{action}": {
"post": {
"tags": [
"Stations: Service Control"
],
"description": "Perform service control actions on the radio frontend (Icecast, SHOUTcast, etc.)",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
},
{
"name": "action",
"in": "path",
"description": "The action to perform (start, stop, restart)",
"required": false,
"type": "string",
"format": "string",
"default": "restart"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Status"
}
},
"403": {
"description": "Access Forbidden",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"security": [
{
"api_key": [
"manage station broadcasting"
]
}
]
}
},
"/station/{station_id}/backend/{action}": {
"post": {
"tags": [
"Stations: Service Control"
],
"description": "Perform service control actions on the radio backend (Liquidsoap)",
"parameters": [
{
"$ref": "#/parameters/station_id_required"
},
{
"name": "action",
"in": "path",
"description": "The action to perform (start, stop, restart)",
"required": false,
"type": "string",
"format": "string",
"default": "restart"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Status"
}
},
"403": {
"description": "Access Forbidden",
"schema": {
"$ref": "#/definitions/Error"
}
}
},
"security": [
{
"api_key": [
"manage station broadcasting"
]
}
]
}
}
},
"definitions": {
"Error": {
"properties": {
"code": {
"description": "The numeric code of the error.",
"type": "integer",
"example": 500
},
"message": {
"description": "The text description of the error.",
"type": "string",
"example": "Error description."
},
"stack_trace": {
"description": "A stack trace outlining the error, if permissions allow this to be shown.",
"type": "array",
"items": {}
},
"success": {
"description": "Used for API calls that expect an \\Entity\\Api\\Status type response.",
"type": "boolean",
"example": false
}
},
"type": "object"
},
"Listener": {
"properties": {
"ip": {
"description": "The listener's IP address",
"type": "string",
"example": "127.0.0.1"
},
"user_agent": {
"description": "The listener's HTTP User-Agent",
"type": "string",
"example": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"
},
"is_mobile": {
"description": "Whether the user-agent is likely a mobile browser.",
"type": "boolean",
"example": true
},
"connected_on": {
"description": "UNIX timestamp that the user first connected.",
"type": "integer",
"example": 1523164613
},
"connected_time": {
"description": "Number of seconds that the user has been connected.",
"type": "integer",
"example": 30
},
"location": {
"description": "Location metadata, if available",
"type": "array",
"items": {}
}
},
"type": "object"
},
"NowPlaying": {
"properties": {
"station": {
"description": "Station",
"$ref": "#/definitions/Station"
},
"listeners": {
"description": "Listener details",
"$ref": "#/definitions/NowPlayingListeners"
},
"live": {
"description": "Live broadcast details",
"$ref": "#/definitions/NowPlayingLive"
},
"now_playing": {
"description": "Current Song",
"$ref": "#/definitions/NowPlayingCurrentSong"
},
"playing_next": {
"description": "Next Playing Song",
"$ref": "#/definitions/SongHistory"
},
"song_history": {
"type": "array",
"items": {
"$ref": "#/definitions/SongHistory"
}
},
"cache": {
"description": "Debugging information about where the now playing data comes from.",
"type": "string",
"enum": [
"hit",
"database",
"station"
]
}
},
"type": "object"
},
"NowPlayingCurrentSong": {
"properties": {
"elapsed": {
"description": "Elapsed time of the song's playback since it started.",
"type": "integer",
"example": 25
},
"remaining": {
"description": "Remaining time in the song, in seconds.",
"type": "integer",
"example": 155
},
"sh_id": {
"description": "Song history unique identifier",
"type": "integer"
},
"played_at": {
"description": "UNIX timestamp when playback started.",
"type": "integer",
"example": 1523164613
},
"duration": {
"description": "Duration of the song in seconds",
"type": "integer",
"example": 180
},
"playlist": {
"description": "Indicates the playlist that the song was played from, if available, or empty string if not.",
"type": "string",
"example": "Top 100"
},
"is_request": {
"description": "Indicates whether the song is a listener request.",
"type": "boolean"
},
"song": {
"description": "Song",
"$ref": "#/definitions/Song"
}
},
"type": "object"
},
"NowPlayingListeners": {
"properties": {
"current": {
"description": "Current listeners, either unique (if supplied) or total (non-unique)",
"type": "integer",
"example": 15
},
"unique": {
"description": "Total unique current listeners",
"type": "integer",
"example": 15
},
"total": {
"description": "Total non-unique current listeners",
"type": "integer",
"example": 20
}
},
"type": "object"
},
"NowPlayingLive": {
"properties": {
"is_live": {
"description": "Whether the stream is known to currently have a live DJ.",
"type": "boolean",
"example": false
},
"streamer_name": {
"description": "The current active streamer/DJ, if one is available.",
"type": "string",
"example": "DJ Jazzy Jeff"
}
},
"type": "object"
},
"Song": {
"properties": {
"id": {
"description": "The song's 32-character unique identifier hash",
"type": "string",
"example": "9f33bbc912c19603e51be8e0987d076b"
},
"text": {
"description": "The song title, usually \"Artist - Title\"",
"type": "string",
"example": "Chet Porter - Aluko River"
},
"artist": {
"description": "The song artist.",
"type": "string",
"example": "Chet Porter"
},
"title": {
"description": "The song title.",
"type": "string",
"example": "Aluko River"
},
"album": {
"description": "The song album.",
"type": "string",
"example": "Moving Castle"
},
"lyrics": {
"description": "Lyrics to the song.",
"type": "string",
"example": ""
},
"art": {
"description": "URL to the album artwork (if available).",
"type": "string",
"example": "https://picsum.photos/1200/1200"
}
},
"type": "object"
},
"SongHistory": {
"properties": {
"sh_id": {
"description": "Song history unique identifier",
"type": "integer"
},
"played_at": {
"description": "UNIX timestamp when playback started.",
"type": "integer",
"example": 1523164613
},
"duration": {
"description": "Duration of the song in seconds",
"type": "integer",
"example": 180
},
"playlist": {
"description": "Indicates the playlist that the song was played from, if available, or empty string if not.",
"type": "string",
"example": "Top 100"
},
"is_request": {
"description": "Indicates whether the song is a listener request.",
"type": "boolean"
},
"song": {
"description": "Song",
"$ref": "#/definitions/Song"
}
},
"type": "object"
},
"Station": {
"properties": {
"id": {
"description": "Station ID",
"type": "integer",
"example": 1
},
"name": {
"description": "Station name",
"type": "string",
"example": "AzuraTest Radio"
},
"shortcode": {
"description": "Station \"short code\", used for URL and folder paths",
"type": "string",
"example": "azuratest_radio"
},
"description": {
"description": "Station description",
"type": "string",
"example": "An AzuraCast station!"
},
"frontend": {
"description": "Which broadcasting software (frontend) the station uses",
"type": "string",
"example": "shoutcast2"
},
"backend": {
"description": "Which AutoDJ software (backend) the station uses",
"type": "string",
"example": "liquidsoap"
},
"listen_url": {
"description": "The full URL to listen to the default mount of the station",
"type": "string",
"example": "http://localhost:8000/radio.mp3"
},
"is_public": {
"description": "If the station is public (i.e. should be shown in listings of all stations)",
"type": "boolean",
"example": true
},
"mounts": {
"type": "array",
"items": {
"$ref": "#/definitions/StationMount"
}
}
},
"type": "object"
},
"StationMount": {
"properties": {
"name": {
"description": "Mount point name/URL",
"type": "string",
"example": "/radio.mp3"
},
"is_default": {
"description": "If the mount is the default mount for the parent station",
"type": "boolean",
"example": true
},
"url": {
"description": "Full listening URL specific to this mount",
"type": "string",
"example": "http://localhost:8000/radio.mp3"
},
"bitrate": {
"description": "Bitrate (kbps) of the broadcasted audio (if known)",
"type": "integer",
"example": 128
},
"format": {
"description": "Audio encoding format of broadcasted audio (if known)",
"type": "string",
"example": "mp3"
}
},
"type": "object"
},
"StationRequest": {
"properties": {
"request_id": {
"description": "Requestable ID unique identifier",
"type": "integer",
"example": 1
},
"request_url": {
"description": "URL to directly submit request",
"type": "integer",
"example": "/api/station/1/request/1"
},
"song": {
"description": "Song",
"$ref": "#/definitions/Song"
}
},
"type": "object"
},
"Status": {
"properties": {
"success": {
"type": "boolean",
"example": true
},
"message": {
"type": "string",
"example": "Changes saved successfully."
}
},
"type": "object"
},
"SystemStatus": {
"properties": {
"online": {
"description": "Whether the service is online or not (should always be true)",
"type": "boolean",
"example": true
},
"timestamp": {
"description": "The current UNIX timestamp",
"type": "integer",
"example": 1523164613
}
},
"type": "object"
},
"Time": {
"properties": {
"timestamp": {
"description": "The current UNIX timestamp",
"type": "integer",
"example": 1497652397
},
"gmt_datetime": {
"type": "string",
"example": "2017-06-16 10:33:17"
},
"gmt_date": {
"type": "string",
"example": "June 16, 2017"
},
"gmt_time": {
"type": "string",
"example": "10:33pm"
},
"gmt_timezone": {
"type": "string",
"example": "GMT"
},
"gmt_timezone_abbr": {
"type": "string",
"example": "GMT"
},
"local_datetime": {
"type": "string",
"example": "2017-06-16 10:33:17"
},
"local_date": {
"type": "string",
"example": "June 16, 2017"
},
"local_time": {
"type": "string",
"example": "10:33pm"
},
"local_timezone": {
"type": "string",
"example": "UTC"
},
"local_timezone_abbr": {
"type": "string",
"example": "UTC"
}
},
"type": "object"
}
},
"parameters": {
"station_id_required": {
"name": "station_id",
"in": "path",
"description": "The station ID",
"required": true,
"type": "integer",
"format": "int64"
}
},
"responses": {
"todo": {
"description": "This API call has no documentated response (yet)"
}
},
"securityDefinitions": {
"api_key": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
},
"tags": [
{
"name": "Now Playing",
"description": "Endpoints that provide full summaries of the current state of stations."
},
{
"name": "Miscellaneous"
},
{
"name": "Stations: General"
},
{
"name": "Stations: Song Requests"
},
{
"name": "Stations: Listeners"
}
],
"externalDocs": {
"description": "AzuraCast on GitHub",
"url": "https://github.com/AzuraCast/AzuraCast"
}
}