Incorporate new NowPlaying library

- Move much of AzuraCast's merging and client integration into the library itself
 - The library now uses typed properties on a return object for much more reliable hinting
 - Update both this library and SupervisorPHP to use PSR-17 and PSR-18 standardized factories
This commit is contained in:
Buster "Silver Eagle" Neece 2020-07-03 15:24:04 -05:00
parent 90e12fec62
commit 0adda37403
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
18 changed files with 328 additions and 424 deletions

View File

@ -43,7 +43,7 @@
"league/flysystem-aws-s3-v3": "^1.0",
"league/flysystem-cached-adapter": "^1.0",
"league/plates": "^3.1",
"lstrojny/fxmlrpc": "^0.15",
"lstrojny/fxmlrpc": "dev-master",
"malkusch/lock": "^2.1",
"maxmind-db/reader": "~1.0",
"mezzio/mezzio-session": "^1.3",

170
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7b700975885f74d5c8b0a1f83fd7247f",
"content-hash": "925aceab5c1165782215531ba732c16f",
"packages": [
{
"name": "aws/aws-sdk-php",
"version": "3.143.2",
"version": "3.145.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "d44eac162f8ed1869d20c076adca9869c70a8ad9"
"reference": "df5406b49f4f5774045e51e8fecc75717c4d6454"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d44eac162f8ed1869d20c076adca9869c70a8ad9",
"reference": "d44eac162f8ed1869d20c076adca9869c70a8ad9",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/df5406b49f4f5774045e51e8fecc75717c4d6454",
"reference": "df5406b49f4f5774045e51e8fecc75717c4d6454",
"shasum": ""
},
"require": {
@ -89,7 +89,7 @@
"s3",
"sdk"
],
"time": "2020-06-26T18:21:03+00:00"
"time": "2020-07-02T18:12:35+00:00"
},
{
"name": "azuracast/azuraforms",
@ -148,23 +148,26 @@
"source": {
"type": "git",
"url": "https://github.com/AzuraCast/nowplaying.git",
"reference": "3b6cb5848482341dc2614e4e49d84db35d4c5078"
"reference": "645880eecde55ccd3feefdf0bad6b52d41b83d70"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AzuraCast/nowplaying/zipball/3b6cb5848482341dc2614e4e49d84db35d4c5078",
"reference": "3b6cb5848482341dc2614e4e49d84db35d4c5078",
"url": "https://api.github.com/repos/AzuraCast/nowplaying/zipball/645880eecde55ccd3feefdf0bad6b52d41b83d70",
"reference": "645880eecde55ccd3feefdf0bad6b52d41b83d70",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-libxml": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"guzzlehttp/guzzle": ">6.0",
"php": ">=7.2"
"php": ">=7.4",
"psr/http-client": "*",
"psr/http-factory": "*"
},
"require-dev": {
"overtrue/phplint": "^1.1",
"php-http/discovery": "^1.9",
"phpstan/phpstan": "^0.11.1",
"phpstan/phpstan-strict-rules": "^0.11.0",
"roave/security-advisories": "dev-master"
@ -186,7 +189,7 @@
}
],
"description": "A lightweight PHP adapter for viewing the current now playing data in Icecast and SHOUTcast 1/2. A part of the AzuraCast software suite.",
"time": "2020-05-05T04:11:51+00:00"
"time": "2020-07-03T20:07:48+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -2750,12 +2753,12 @@
"source": {
"type": "git",
"url": "https://github.com/JamesHeinrich/getID3.git",
"reference": "cde8ac014c7d8fce9af004974eff400a9ee348a6"
"reference": "03ce1bc314aa17e0a8943127c3868bb151181a22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/cde8ac014c7d8fce9af004974eff400a9ee348a6",
"reference": "cde8ac014c7d8fce9af004974eff400a9ee348a6",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/03ce1bc314aa17e0a8943127c3868bb151181a22",
"reference": "03ce1bc314aa17e0a8943127c3868bb151181a22",
"shasum": ""
},
"require": {
@ -2805,7 +2808,7 @@
"php",
"tags"
],
"time": "2020-06-06T20:57:42+00:00"
"time": "2020-07-01T01:52:46+00:00"
},
{
"name": "jean85/pretty-package-versions",
@ -3432,31 +3435,32 @@
},
{
"name": "lstrojny/fxmlrpc",
"version": "0.15.0",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/lstrojny/fxmlrpc.git",
"reference": "d0336746bef99d5d9cb39ae826975d3a1462b23e"
"reference": "f21eb6edbf44d9fa79e7ff583b136bdb156ee3d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lstrojny/fxmlrpc/zipball/d0336746bef99d5d9cb39ae826975d3a1462b23e",
"reference": "d0336746bef99d5d9cb39ae826975d3a1462b23e",
"url": "https://api.github.com/repos/lstrojny/fxmlrpc/zipball/f21eb6edbf44d9fa79e7ff583b136bdb156ee3d7",
"reference": "f21eb6edbf44d9fa79e7ff583b136bdb156ee3d7",
"shasum": ""
},
"require": {
"php": "~7.1",
"php-http/discovery": "^1.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0"
"php-http/discovery": "^1.0"
},
"require-dev": {
"internations/kodierungsregelwerksammlung": "dev-master",
"lstrojny/hmmmath": "dev-master",
"monolog/monolog": "~1",
"php-http/guzzle6-adapter": "^1.0 || ^2.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message": "^1.2",
"php-http/message-factory": "^1.0",
"phpunit/phpunit": "~6",
"psr/http-factory": "*",
"psr/log": "*",
"symfony/process": "~2.1",
"zendframework/zend-diactoros": "^1.3",
@ -3502,7 +3506,7 @@
"xml",
"xmlrpc"
],
"time": "2019-02-07T14:10:11+00:00"
"time": "2020-07-02T22:06:59+00:00"
},
{
"name": "malkusch/lock",
@ -4061,16 +4065,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.10.0",
"version": "1.10.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "5796d127b0c4ff505b77455148ea9d5269d99758"
"reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/5796d127b0c4ff505b77455148ea9d5269d99758",
"reference": "5796d127b0c4ff505b77455148ea9d5269d99758",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
"reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
"shasum": ""
},
"require": {
@ -4111,7 +4115,7 @@
"type": "tidelift"
}
],
"time": "2020-06-28T07:02:41+00:00"
"time": "2020-06-29T13:22:24+00:00"
},
{
"name": "n98/junit-xml",
@ -4894,16 +4898,16 @@
},
{
"name": "php-http/client-common",
"version": "2.1.0",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/client-common.git",
"reference": "a8b29678d61556f45d6236b1667db16d998ceec5"
"reference": "f3985360f3d054292605e9ec7c4bc24ebcf249bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/client-common/zipball/a8b29678d61556f45d6236b1667db16d998ceec5",
"reference": "a8b29678d61556f45d6236b1667db16d998ceec5",
"url": "https://api.github.com/repos/php-http/client-common/zipball/f3985360f3d054292605e9ec7c4bc24ebcf249bb",
"reference": "f3985360f3d054292605e9ec7c4bc24ebcf249bb",
"shasum": ""
},
"require": {
@ -4911,13 +4915,19 @@
"php-http/httplug": "^2.0",
"php-http/message": "^1.6",
"php-http/message-factory": "^1.0",
"symfony/options-resolver": " ^3.4.20 || ~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0"
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
"symfony/options-resolver": "^2.6 || ^3.4.20 || ~4.0.15 || ~4.1.9 || ^4.2.1 || ^5.0",
"symfony/polyfill-php80": "^1.17"
},
"require-dev": {
"doctrine/instantiator": "^1.1",
"guzzlehttp/psr7": "^1.4",
"phpspec/phpspec": "^5.1",
"nyholm/psr7": "^1.2",
"phpspec/phpspec": "^5.1 || ^6.0",
"phpspec/prophecy": "^1.8",
"phpunit/phpunit": "^7.5",
"sebastian/comparator": "^3.0"
},
"suggest": {
@ -4930,7 +4940,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "2.2.x-dev"
}
},
"autoload": {
@ -4956,20 +4966,20 @@
"http",
"httplug"
],
"time": "2019-11-18T08:58:18+00:00"
"time": "2020-07-02T06:51:04+00:00"
},
{
"name": "php-http/discovery",
"version": "1.8.0",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/discovery.git",
"reference": "10d9019f393773345aedc0dc79e7fd678da874ee"
"reference": "9ab7668fee74a5ad61996095e50917bd50ee8bfe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/10d9019f393773345aedc0dc79e7fd678da874ee",
"reference": "10d9019f393773345aedc0dc79e7fd678da874ee",
"url": "https://api.github.com/repos/php-http/discovery/zipball/9ab7668fee74a5ad61996095e50917bd50ee8bfe",
"reference": "9ab7668fee74a5ad61996095e50917bd50ee8bfe",
"shasum": ""
},
"require": {
@ -4992,7 +5002,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
@ -5021,7 +5031,7 @@
"message",
"psr7"
],
"time": "2020-06-14T10:44:12+00:00"
"time": "2020-07-02T11:43:45+00:00"
},
{
"name": "php-http/guzzle6-adapter",
@ -5513,20 +5523,20 @@
},
{
"name": "psr/http-client",
"version": "1.0.0",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "496a823ef742b632934724bf769560c2a5c7c44e"
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/496a823ef742b632934724bf769560c2a5c7c44e",
"reference": "496a823ef742b632934724bf769560c2a5c7c44e",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": ""
},
"require": {
"php": "^7.0",
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
},
"type": "library",
@ -5558,7 +5568,7 @@
"psr",
"psr-18"
],
"time": "2018-10-30T23:29:13+00:00"
"time": "2020-06-29T06:28:15+00:00"
},
{
"name": "psr/http-factory",
@ -6093,16 +6103,16 @@
},
{
"name": "sentry/sentry",
"version": "2.4.0",
"version": "2.4.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "e44561875e0d724bac3d9cdb705bf58847acd425"
"reference": "407573e22e6cc46b72cff07c117eeb16bf3a17de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/e44561875e0d724bac3d9cdb705bf58847acd425",
"reference": "e44561875e0d724bac3d9cdb705bf58847acd425",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/407573e22e6cc46b72cff07c117eeb16bf3a17de",
"reference": "407573e22e6cc46b72cff07c117eeb16bf3a17de",
"shasum": ""
},
"require": {
@ -6186,7 +6196,7 @@
"type": "custom"
}
],
"time": "2020-05-20T20:49:38+00:00"
"time": "2020-07-03T09:58:40+00:00"
},
{
"name": "slim/http",
@ -6491,12 +6501,12 @@
"source": {
"type": "git",
"url": "https://github.com/supervisorphp/supervisor.git",
"reference": "b7bd433a385edd38d2df77b0dfe52dc488608edc"
"reference": "3deb0b1e0a79ac155172074f727a47b9ee68940b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/supervisorphp/supervisor/zipball/b7bd433a385edd38d2df77b0dfe52dc488608edc",
"reference": "b7bd433a385edd38d2df77b0dfe52dc488608edc",
"url": "https://api.github.com/repos/supervisorphp/supervisor/zipball/3deb0b1e0a79ac155172074f727a47b9ee68940b",
"reference": "3deb0b1e0a79ac155172074f727a47b9ee68940b",
"shasum": ""
},
"require": {
@ -6545,7 +6555,7 @@
"process manager",
"supervisor"
],
"time": "2020-07-02T00:55:37+00:00"
"time": "2020-07-02T01:08:38+00:00"
},
{
"name": "symfony/amqp-messenger",
@ -9579,16 +9589,16 @@
},
{
"name": "codeception/stub",
"version": "3.6.1",
"version": "3.7.0",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Stub.git",
"reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880"
"reference": "468dd5fe659f131fc997f5196aad87512f9b1304"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Stub/zipball/a3ba01414cbee76a1bced9f9b6b169cc8d203880",
"reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880",
"url": "https://api.github.com/repos/Codeception/Stub/zipball/468dd5fe659f131fc997f5196aad87512f9b1304",
"reference": "468dd5fe659f131fc997f5196aad87512f9b1304",
"shasum": ""
},
"require": {
@ -9605,7 +9615,7 @@
"MIT"
],
"description": "Flexible Stub wrapper for PHPUnit's Mock Builder",
"time": "2020-02-07T18:42:28+00:00"
"time": "2020-07-03T15:54:43+00:00"
},
{
"name": "filp/whoops",
@ -10205,16 +10215,16 @@
},
{
"name": "phpstan/phpstan",
"version": "0.12.31",
"version": "0.12.32",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "776c8056b401e1b67f277b9e9fb334d1a274671d"
"reference": "d03863f504c8432b3de4d1881f73f6acb8c0e67c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/776c8056b401e1b67f277b9e9fb334d1a274671d",
"reference": "776c8056b401e1b67f277b9e9fb334d1a274671d",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d03863f504c8432b3de4d1881f73f6acb8c0e67c",
"reference": "d03863f504c8432b3de4d1881f73f6acb8c0e67c",
"shasum": ""
},
"require": {
@ -10257,7 +10267,7 @@
"type": "tidelift"
}
],
"time": "2020-06-24T20:55:29+00:00"
"time": "2020-07-01T11:57:52+00:00"
},
{
"name": "phpstan/phpstan-doctrine",
@ -10830,12 +10840,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "6d2e5ab854782830911ddd33b7d4649b9f18c10f"
"reference": "57353ec1a34527a2dbbd3c0fb9418ffc008c6f60"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/6d2e5ab854782830911ddd33b7d4649b9f18c10f",
"reference": "6d2e5ab854782830911ddd33b7d4649b9f18c10f",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/57353ec1a34527a2dbbd3c0fb9418ffc008c6f60",
"reference": "57353ec1a34527a2dbbd3c0fb9418ffc008c6f60",
"shasum": ""
},
"conflict": {
@ -10929,8 +10939,9 @@
"magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2",
"monolog/monolog": ">=1.8,<1.12",
"namshi/jose": "<2.2",
"nystudio107/craft-seomatic": "<3.3",
"nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
"october/october": ">=1.0.319,<1.0.466",
"october/october": ">=1.0.319,<1.0.467",
"onelogin/php-saml": "<2.10.4",
"oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5",
"openid/php-openid": "<2.3",
@ -11107,7 +11118,7 @@
"type": "tidelift"
}
],
"time": "2020-06-19T13:23:43+00:00"
"time": "2020-07-03T16:50:03+00:00"
},
{
"name": "sebastian/code-unit",
@ -11284,20 +11295,20 @@
},
{
"name": "sebastian/diff",
"version": "4.0.1",
"version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "3e523c576f29dacecff309f35e4cc5a5c168e78a"
"reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3e523c576f29dacecff309f35e4cc5a5c168e78a",
"reference": "3e523c576f29dacecff309f35e4cc5a5c168e78a",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
"reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113",
"shasum": ""
},
"require": {
"php": "^7.3"
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
@ -11342,7 +11353,7 @@
"type": "github"
}
],
"time": "2020-05-08T05:01:12+00:00"
"time": "2020-06-30T04:46:02+00:00"
},
{
"name": "sebastian/environment",
@ -12208,6 +12219,7 @@
"azuracast/azuraforms": 20,
"azuracast/nowplaying": 20,
"james-heinrich/getid3": 20,
"lstrojny/fxmlrpc": 20,
"supervisorphp/supervisor": 20,
"zircote/swagger-php": 20,
"roave/security-advisories": 20

View File

@ -385,15 +385,14 @@ return [
// Supervisor manager
Supervisor\Supervisor::class => function (Settings $settings) {
$guzzle_client = new GuzzleHttp\Client();
$client = new fXmlRpc\Client(
'http://' . ($settings->isDocker() ? 'stations' : '127.0.0.1') . ':9001/RPC2',
new fXmlRpc\Transport\HttpAdapterTransport(
new Http\Message\MessageFactory\GuzzleMessageFactory(),
new Http\Adapter\Guzzle6\Client($guzzle_client)
new fXmlRpc\Transport\PsrTransport(
new Http\Factory\Guzzle\RequestFactory,
new Http\Adapter\Guzzle6\Client
)
);
$supervisor = new Supervisor\Supervisor($client);
if (!$supervisor->isConnected()) {
@ -403,6 +402,15 @@ return [
return $supervisor;
},
// NowPlaying Adapter factory
NowPlaying\Adapter\AdapterFactory::class => function (GuzzleHttp\Client $httpClient) {
return new NowPlaying\Adapter\AdapterFactory(
new Http\Factory\Guzzle\UriFactory,
new Http\Factory\Guzzle\RequestFactory,
new Http\Adapter\Guzzle6\Client($httpClient)
);
},
// Asset Management
App\Assets::class => function (App\Config $config, Settings $settings) {
$libraries = $config->get('assets');

View File

@ -2,6 +2,7 @@
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use NowPlaying\Result\Client;
/**
* @ORM\Table(name="listener", indexes={
@ -72,16 +73,16 @@ class Listener
*/
protected $timestamp_end;
public function __construct(Station $station, array $client)
public function __construct(Station $station, Client $client)
{
$this->station = $station;
$this->timestamp_start = time();
$this->timestamp_end = 0;
$this->listener_uid = $client['uid'];
$this->listener_user_agent = $this->truncateString($client['user_agent']) ?? '';
$this->listener_ip = $client['ip'];
$this->listener_uid = $client->uid;
$this->listener_user_agent = $this->truncateString($client->userAgent) ?? '';
$this->listener_ip = $client->ip;
$this->listener_hash = self::calculateListenerHash($client);
}
@ -189,8 +190,17 @@ class Listener
return $seconds;
}
public static function calculateListenerHash(array $client): string
/**
* @param array|Client $client
*
* @return string
*/
public static function calculateListenerHash($client): string
{
if ($client instanceof Client) {
return md5($client->ip . $client->userAgent);
}
return md5($client['ip'] . $client['user_agent']);
}
}

View File

@ -3,6 +3,7 @@ namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use NowPlaying\Result\Client;
class ListenerRepository extends Repository
{
@ -33,7 +34,7 @@ class ListenerRepository extends Repository
* Update listener data for a station.
*
* @param Entity\Station $station
* @param array $clients
* @param Client[] $clients
*/
public function update(Entity\Station $station, $clients): void
{
@ -51,9 +52,9 @@ class ListenerRepository extends Repository
$existingClients[$identifier] = $client['id'];
}
foreach ((array)$clients as $client) {
foreach ($clients as $client) {
$listenerHash = Entity\Listener::calculateListenerHash($client);
$identifier = $client['uid'] . '_' . $listenerHash;
$identifier = $client->uid . '_' . $listenerHash;
// Check for an existing record for this client.
if (isset($existingClients[$identifier])) {

View File

@ -3,20 +3,27 @@ namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use NowPlaying\Result\CurrentSong;
class SongRepository extends Repository
{
/**
* Retrieve an existing Song entity or create a new one.
*
* @param array|string $song_info
* @param CurrentSong|array|string $song_info
* @param bool $is_radio_play
*
* @return Entity\Song
*/
public function getOrCreate($song_info, $is_radio_play = false): Entity\Song
{
if (!is_array($song_info)) {
if ($song_info instanceof CurrentSong) {
$song_info = [
'text' => $song_info->text,
'artist' => $song_info->artist,
'title' => $song_info->title,
];
} elseif (!is_array($song_info)) {
$song_info = ['text' => $song_info];
}

View File

@ -6,6 +6,7 @@ use App\Exception;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use NowPlaying\Result\CurrentSong;
use Psr\Http\Message\UriInterface;
/**
@ -120,6 +121,12 @@ class Song
'artist' => $song_info->getArtist(),
'title' => $song_info->getTitle(),
];
} elseif ($song_info instanceof CurrentSong) {
$song_info = [
'text' => $song_info->text,
'artist' => $song_info->artist,
'title' => $song_info->title,
];
} elseif (!is_array($song_info)) {
$song_info = [
'text' => $song_info,

View File

@ -3,6 +3,7 @@ namespace App\Event\Radio;
use App\Entity\Station;
use App\Radio;
use NowPlaying\Result\Result;
use Symfony\Contracts\EventDispatcher\Event;
class GenerateRawNowPlaying extends Event
@ -16,23 +17,17 @@ class GenerateRawNowPlaying extends Event
protected bool $include_clients = false;
/** @var string|null The preloaded "payload" to supply to the nowplaying adapters, if one is available. */
protected ?string $payload;
/** @var array The composed "raw" NowPlaying data. */
protected array $np_raw = [];
protected ?Result $result = null;
public function __construct(
Station $station,
Radio\Frontend\AbstractFrontend $frontend,
array $remotes,
$payload = null,
$include_clients = false
) {
$this->station = $station;
$this->frontend = $frontend;
$this->remotes = $remotes;
$this->payload = $payload;
$this->include_clients = $include_clients;
}
@ -59,18 +54,13 @@ class GenerateRawNowPlaying extends Event
return $this->include_clients;
}
public function getPayload(): ?string
public function getResult(): Result
{
return $this->payload;
return $this->result ?? Result::blank();
}
public function getRawResponse(): array
public function setResult(Result $result): void
{
return $this->np_raw;
}
public function setRawResponse(array $np): void
{
$this->np_raw = $np;
$this->result = $result;
}
}

View File

@ -151,7 +151,7 @@ abstract class AbstractAdapter
Logger::getInstance()->info('Adapter "' . static::class . '" stopped.',
['station_id' => $station->getId(), 'station_name' => $station->getName()]);
} catch (SupervisorLibException $e) {
$this->_handleSupervisorException($e, $program_name, $station);
$this->handleSupervisorException($e, $program_name, $station);
}
}
}
@ -174,7 +174,7 @@ abstract class AbstractAdapter
Logger::getInstance()->info('Adapter "' . static::class . '" started.',
['station_id' => $station->getId(), 'station_name' => $station->getName()]);
} catch (SupervisorLibException $e) {
$this->_handleSupervisorException($e, $program_name, $station);
$this->handleSupervisorException($e, $program_name, $station);
}
}
}
@ -191,7 +191,7 @@ abstract class AbstractAdapter
* @throws NotRunningException
* @throws SupervisorException
*/
protected function _handleSupervisorException(
protected function handleSupervisorException(
SupervisorLibException $e,
$program_name,
Entity\Station $station

View File

@ -4,14 +4,14 @@ namespace App\Radio\Frontend;
use App\Entity;
use App\EventDispatcher;
use App\Http\Router;
use App\Logger;
use App\Radio\AbstractAdapter;
use App\Settings;
use App\Xml\Reader;
use Doctrine\ORM\EntityManagerInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Uri;
use NowPlaying\Adapter\AdapterAbstract;
use NowPlaying\Adapter\AdapterFactory;
use NowPlaying\Result\Result;
use PhpIP\IP;
use PhpIP\IPBlock;
use Psr\Http\Message\UriInterface;
@ -19,6 +19,8 @@ use Supervisor\Supervisor;
abstract class AbstractFrontend extends AbstractAdapter
{
protected AdapterFactory $adapterFactory;
protected Client $http_client;
protected Router $router;
@ -29,20 +31,22 @@ abstract class AbstractFrontend extends AbstractAdapter
public function __construct(
EntityManagerInterface $em,
Entity\Repository\SettingsRepository $settingsRepo,
Entity\Repository\StationMountRepository $stationMountRepo,
Supervisor $supervisor,
EventDispatcher $dispatcher,
AdapterFactory $adapterFactory,
Client $client,
Router $router
Router $router,
Entity\Repository\SettingsRepository $settingsRepo,
Entity\Repository\StationMountRepository $stationMountRepo
) {
parent::__construct($em, $supervisor, $dispatcher);
$this->settingsRepo = $settingsRepo;
$this->stationMountRepo = $stationMountRepo;
$this->adapterFactory = $adapterFactory;
$this->http_client = $client;
$this->router = $router;
$this->settingsRepo = $settingsRepo;
$this->stationMountRepo = $stationMountRepo;
}
/**
@ -183,74 +187,9 @@ abstract class AbstractFrontend extends AbstractAdapter
abstract public function getAdminUrl(Entity\Station $station, UriInterface $base_url = null): UriInterface;
/**
* @param Entity\Station $station
* @param string|null $payload A prepopulated payload (to avoid duplicate web requests)
* @param bool $include_clients Whether to try to retrieve detailed listener client info
*
* @return array Whether the NP update succeeded
*/
public function getNowPlaying(Entity\Station $station, $payload = null, $include_clients = true): array
public function getNowPlaying(Entity\Station $station, bool $includeClients = true): Result
{
return AdapterAbstract::NOWPLAYING_EMPTY;
}
/**
* @param Entity\StationMount $mount
* @param array $np_aggregate The aggregated nowplaying data for all mounts.
* @param array $np The nowplaying data for this specific mount.
* @param array|null $clients
*
* @return array The processed aggregate nowplaying data for all mounts.
*/
protected function _processNowPlayingForMount(
Entity\StationMount $mount,
array $np_aggregate,
array $np,
?array $clients
): array {
if (null !== $clients) {
$original_num_clients = count($clients);
$np['listeners']['clients'] = Entity\Listener::filterClients($clients);
$num_clients = count($np['listeners']['clients']);
// If clients were filtered out, remove them from the listener count as well.
if ($num_clients < $original_num_clients) {
$client_diff = $original_num_clients - $num_clients;
$np['listeners']['total'] -= $client_diff;
}
$np['listeners']['unique'] = $num_clients;
$np['listeners']['current'] = $num_clients;
if ($np['listeners']['unique'] > $np['listeners']['total']) {
$np['listeners']['total'] = $np['listeners']['unique'];
}
} else {
$np['listeners']['clients'] = [];
}
Logger::getInstance()->debug('Response for mount point', ['mount' => $mount->getName(), 'response' => $np]);
$mount->setListenersTotal($np['listeners']['total']);
$mount->setListenersUnique($np['listeners']['unique']);
$this->em->persist($mount);
$this->em->flush();
if ($mount->getIsDefault()) {
$np_aggregate['current_song'] = $np['current_song'];
$np_aggregate['meta'] = $np['meta'];
}
$np_aggregate['listeners']['clients'] = array_merge((array)$np_aggregate['listeners']['clients'],
(array)$np['listeners']['clients']);
$np_aggregate['listeners']['current'] += $np['listeners']['current'];
$np_aggregate['listeners']['unique'] += $np['listeners']['unique'];
$np_aggregate['listeners']['total'] += $np['listeners']['total'];
return $np_aggregate;
return Result::blank();
}
protected function _processCustomConfig($custom_config_raw)

View File

@ -9,7 +9,8 @@ use App\Utilities;
use App\Xml\Reader;
use App\Xml\Writer;
use GuzzleHttp\Psr7\Uri;
use NowPlaying\Adapter\AdapterAbstract;
use NowPlaying\Adapter\AdapterFactory;
use NowPlaying\Result\Result;
use Psr\Http\Message\UriInterface;
class Icecast extends AbstractFrontend
@ -19,34 +20,48 @@ class Icecast extends AbstractFrontend
public const LOGLEVEL_WARN = 2;
public const LOGLEVEL_ERROR = 1;
public function getNowPlaying(Entity\Station $station, $payload = null, $include_clients = true): array
public function getNowPlaying(Entity\Station $station, bool $includeClients = true): Result
{
$fe_config = $station->getFrontendConfig();
$radio_port = $fe_config->getPort();
$feConfig = $station->getFrontendConfig();
$radioPort = $feConfig->getPort();
$base_url = 'http://' . (Settings::getInstance()->isDocker() ? 'stations' : 'localhost') . ':' . $radio_port;
$baseUrl = 'http://' . (Settings::getInstance()->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
$np_adapter = new \NowPlaying\Adapter\Icecast($base_url, $this->http_client);
$np_adapter->setAdminPassword($fe_config->getAdminPassword());
$npAdapter = $this->adapterFactory->getAdapter(
AdapterFactory::ADAPTER_ICECAST,
$baseUrl,
$feConfig->getAdminPassword()
);
$np_final = AdapterAbstract::NOWPLAYING_EMPTY;
$np_final['listeners']['clients'] = [];
$defaultResult = Result::blank();
$otherResults = [];
try {
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
$np_final = $this->_processNowPlayingForMount(
$mount,
$np_final,
$np_adapter->getNowPlaying($mount->getName()),
$include_clients ? $np_adapter->getClients($mount->getName(), true) : null
);
$result = $npAdapter->getNowPlaying($mount->getName(), $includeClients);
$mount->setListenersTotal($result->listeners->total);
$mount->setListenersUnique($result->listeners->unique);
$this->em->persist($mount);
if ($mount->getIsDefault()) {
$defaultResult = $result;
} else {
$otherResults[] = $result;
}
}
$this->em->flush();
foreach ($otherResults as $otherResult) {
$defaultResult = $defaultResult->merge($otherResult);
}
} catch (\Exception $e) {
Logger::getInstance()->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
}
return $np_final;
return $defaultResult;
}
public function read(Entity\Station $station): bool

View File

@ -5,8 +5,8 @@ use App\Entity;
use App\Logger;
use App\Settings;
use App\Utilities;
use NowPlaying\Adapter\AdapterAbstract;
use NowPlaying\Adapter\SHOUTcast2;
use NowPlaying\Adapter\AdapterFactory;
use NowPlaying\Result\Result;
use Psr\Http\Message\UriInterface;
use Symfony\Component\Process\Process;
@ -48,37 +48,50 @@ class SHOUTcast extends AbstractFrontend
: false;
}
public function getNowPlaying(Entity\Station $station, $payload = null, $include_clients = true): array
public function getNowPlaying(Entity\Station $station, bool $includeClients = true): Result
{
$fe_config = $station->getFrontendConfig();
$radio_port = $fe_config->getPort();
$feConfig = $station->getFrontendConfig();
$radioPort = $feConfig->getPort();
$baseUrl = 'http://' . (Settings::getInstance()->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
$base_url = 'http://' . (Settings::getInstance()->isDocker() ? 'stations' : 'localhost') . ':' . $radio_port;
$npAdapter = $this->adapterFactory->getAdapter(
AdapterFactory::ADAPTER_SHOUTCAST2,
$baseUrl,
$feConfig->getAdminPassword()
);
$np_adapter = new SHOUTcast2($base_url, $this->http_client);
$np_adapter->setAdminPassword($fe_config->getAdminPassword());
$np_final = AdapterAbstract::NOWPLAYING_EMPTY;
$np_final['listeners']['clients'] = [];
$defaultResult = Result::blank();
$otherResults = [];
try {
$sid = 0;
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
$sid++;
$np_final = $this->_processNowPlayingForMount(
$mount,
$np_final,
$np_adapter->getNowPlaying($sid),
$include_clients ? $np_adapter->getClients($sid, true) : null
);
$result = $npAdapter->getNowPlaying($sid, $includeClients);
$mount->setListenersTotal($result->listeners->total);
$mount->setListenersUnique($result->listeners->unique);
$this->em->persist($mount);
if ($mount->getIsDefault()) {
$defaultResult = $result;
} else {
$otherResults[] = $result;
}
}
$this->em->flush();
foreach ($otherResults as $otherResult) {
$defaultResult = $defaultResult->merge($otherResult);
}
} catch (\Exception $e) {
Logger::getInstance()->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
}
return $np_final;
return $defaultResult;
}
/*

View File

@ -6,7 +6,8 @@ use Doctrine\ORM\EntityManagerInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Uri;
use Monolog\Logger;
use NowPlaying\Adapter\AdapterAbstract;
use NowPlaying\Adapter\AdapterFactory;
use NowPlaying\Result\Result;
abstract class AbstractRemote
{
@ -18,33 +19,62 @@ abstract class AbstractRemote
protected Logger $logger;
protected AdapterFactory $adapterFactory;
public function __construct(
EntityManagerInterface $em,
Entity\Repository\SettingsRepository $settingsRepo,
Client $http_client,
Logger $logger
Logger $logger,
AdapterFactory $adapterFactory
) {
$this->em = $em;
$this->settingsRepo = $settingsRepo;
$this->http_client = $http_client;
$this->logger = $logger;
$this->adapterFactory = $adapterFactory;
}
/**
* @param Result $np
* @param Entity\StationRemote $remote
* @param array $np_aggregate
* @param bool $include_clients
* @param bool $includeClients
*
* @return array The aggregated now-playing result.
* @return Result The aggregated now-playing result.
*/
public function updateNowPlaying(
Result $np,
Entity\StationRemote $remote,
$np_aggregate,
bool $include_clients = false
): array {
return $np_aggregate;
bool $includeClients = false
): Result {
$adapterType = $this->getAdapterType();
$npAdapter = $this->adapterFactory->getAdapter(
$adapterType,
$remote->getUrl(),
$remote->getAdminPassword()
);
try {
$npRemote = $npAdapter->getNowPlaying($remote->getMount(), $includeClients);
$this->logger->debug('NowPlaying adapter response', ['response' => $npRemote]);
$remote->setListenersTotal($npRemote->listeners->total);
$remote->setListenersUnique($npRemote->listeners->unique);
$this->em->persist($remote);
$this->em->flush();
return $np->merge($npRemote);
} catch (\Exception $e) {
$this->logger->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
}
return $np;
}
abstract protected function getAdapterType(): string;
/**
* Return the likely "public" listen URL for the remote.
*
@ -58,7 +88,7 @@ abstract class AbstractRemote
return (!empty($custom_listen_url))
? $custom_listen_url
: $this->_getRemoteUrl($remote, $remote->getMount());
: $this->getRemoteUrl($remote, $remote->getMount());
}
/**
@ -69,7 +99,7 @@ abstract class AbstractRemote
*
* @return string
*/
protected function _getRemoteUrl(Entity\StationRemote $remote, $custom_path = null): string
protected function getRemoteUrl(Entity\StationRemote $remote, $custom_path = null): string
{
$uri = new Uri($remote->getUrl());
@ -77,111 +107,4 @@ abstract class AbstractRemote
? (string)$uri->withPath($custom_path)
: (string)$uri;
}
/**
* @param Entity\StationRemote $remote
* @param array $np_aggregate
* @param string $adapter_class
* @param bool $include_clients
*
* @return array The resulting aggregated now-playing response.
*/
protected function _updateNowPlayingFromAdapter(
Entity\StationRemote $remote,
$np_aggregate,
$adapter_class,
bool $include_clients = false
): array {
/** @var AdapterAbstract $np_adapter */
$np_adapter = new $adapter_class($remote->getUrl(), $this->http_client);
try {
$adminPassword = $remote->getAdminPassword();
if (!empty($adminPassword)) {
$np_adapter->setAdminPassword($adminPassword);
}
$np = $np_adapter->getNowPlaying($remote->getMount());
if (empty($np)) {
return $np_aggregate;
}
$clients = ($include_clients && !empty($adminPassword))
? $np_adapter->getClients($remote->getMount(), true)
: null;
$this->logger->debug('NowPlaying adapter response', ['response' => $np, 'clients' => $clients]);
return $this->_mergeNowPlaying(
$remote,
$np_aggregate,
$np,
$clients
);
} catch (\Exception $e) {
$this->logger->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
}
return $np_aggregate;
}
/**
* @param Entity\StationRemote $remote
* @param array $np_aggregate
* @param array $np
* @param array|null $clients
*
* @return array The composed aggregate now-playing response.
*/
protected function _mergeNowPlaying(
Entity\StationRemote $remote,
array $np_aggregate,
array $np,
?array $clients
): array {
if (null !== $clients) {
$original_num_clients = count($clients);
$np['listeners']['clients'] = Entity\Listener::filterClients($clients);
$num_clients = count($np['listeners']['clients']);
// If clients were filtered out, remove them from the listener count as well.
if ($num_clients < $original_num_clients) {
$client_diff = $original_num_clients - $num_clients;
$np['listeners']['total'] -= $client_diff;
}
$np['listeners']['unique'] = $num_clients;
$np['listeners']['current'] = $num_clients;
if ($np['listeners']['unique'] > $np['listeners']['total']) {
$np['listeners']['total'] = $np['listeners']['unique'];
}
} else {
$np['listeners']['clients'] = [];
}
$this->logger->debug('Response for remote relay', ['remote' => $remote->getDisplayName(), 'response' => $np]);
$remote->setListenersTotal($np['listeners']['total']);
$remote->setListenersUnique($np['listeners']['unique']);
$this->em->persist($remote);
$this->em->flush();
if ($np_aggregate['meta']['status'] === 'offline' && $np['meta']['status'] === 'online') {
$np_aggregate['current_song'] = $np['current_song'];
$np_aggregate['meta'] = $np['meta'];
}
$np_aggregate['listeners']['clients'] = array_merge(
(array)$np_aggregate['listeners']['clients'],
(array)$np['listeners']['clients']
);
$np_aggregate['listeners']['current'] += $np['listeners']['current'];
$np_aggregate['listeners']['unique'] += $np['listeners']['unique'];
$np_aggregate['listeners']['total'] += $np['listeners']['total'];
return $np_aggregate;
}
}

View File

@ -5,11 +5,15 @@ use App\Entity;
use App\Settings;
use GuzzleHttp\Psr7\Uri;
use InvalidArgumentException;
use NowPlaying\Result\Result;
class AzuraRelay extends AbstractRemote
{
public function updateNowPlaying(Entity\StationRemote $remote, $np_aggregate, bool $include_clients = false): array
{
public function updateNowPlaying(
Result $np,
Entity\StationRemote $remote,
bool $includeClients = false
): Result {
$station = $remote->getStation();
$relay = $remote->getRelay();
@ -17,24 +21,30 @@ class AzuraRelay extends AbstractRemote
throw new InvalidArgumentException('AzuraRelay remote must have a corresponding relay.');
}
$relay_np = $relay->getNowplaying();
$npRawRelay = $relay->getNowplaying();
if (isset($relay_np[$station->getId()][$remote->getMount()])) {
$np_new = $relay_np[$station->getId()][$remote->getMount()];
if (isset($npRawRelay[$station->getId()][$remote->getMount()])) {
$npRaw = $npRawRelay[$station->getId()][$remote->getMount()];
$clients = ($include_clients)
? $np_new['listeners']['clients']
: null;
$npNew = Result::fromArray($npRaw);
$np_aggregate = $this->_mergeNowPlaying(
$remote,
$np_aggregate,
$np_new,
$clients
);
$this->logger->debug('Response for remote relay',
['remote' => $remote->getDisplayName(), 'response' => $npNew]);
$remote->setListenersTotal($np['listeners']['total']);
$remote->setListenersUnique($np['listeners']['unique']);
$this->em->persist($remote);
$this->em->flush();
return $np->merge($npNew);
}
return $np_aggregate;
return $np;
}
protected function getAdapterType(): string
{
return '';
}
/**

View File

@ -1,20 +1,12 @@
<?php
namespace App\Radio\Remote;
use App\Entity;
use NowPlaying\Adapter\AdapterFactory;
class Icecast extends AbstractRemote
{
/**
* @inheritDoc
*/
public function updateNowPlaying(Entity\StationRemote $remote, $np_aggregate, bool $include_clients = false): array
protected function getAdapterType(): string
{
return $this->_updateNowPlayingFromAdapter(
$remote,
$np_aggregate,
\NowPlaying\Adapter\Icecast::class,
$include_clients
);
return AdapterFactory::ADAPTER_ICECAST;
}
}

View File

@ -2,25 +2,18 @@
namespace App\Radio\Remote;
use App\Entity;
use NowPlaying\Adapter\AdapterFactory;
class SHOUTcast1 extends AbstractRemote
{
protected function getAdapterType(): string
{
return AdapterFactory::ADAPTER_SHOUTCAST1;
}
/** @inheritDoc */
public function getPublicUrl(Entity\StationRemote $remote): string
{
return $this->_getRemoteUrl($remote, '/;stream.nsv');
}
/**
* @inheritDoc
*/
public function updateNowPlaying(Entity\StationRemote $remote, $np_aggregate, bool $include_clients = false): array
{
return $this->_updateNowPlayingFromAdapter(
$remote,
$np_aggregate,
\NowPlaying\Adapter\SHOUTcast1::class,
$include_clients
);
return $this->getRemoteUrl($remote, '/;stream.nsv');
}
}

View File

@ -1,20 +1,12 @@
<?php
namespace App\Radio\Remote;
use App\Entity;
use NowPlaying\Adapter\AdapterFactory;
class SHOUTcast2 extends AbstractRemote
{
/**
* @inheritDoc
*/
public function updateNowPlaying(Entity\StationRemote $remote, $np_aggregate, bool $include_clients = false): array
protected function getAdapterType(): string
{
return $this->_updateNowPlayingFromAdapter(
$remote,
$np_aggregate,
\NowPlaying\Adapter\SHOUTcast2::class,
$include_clients
);
return AdapterFactory::ADAPTER_SHOUTCAST2;
}
}

View File

@ -18,7 +18,7 @@ use GuzzleHttp\Psr7\Uri;
use InfluxDB\Database;
use InfluxDB\Point;
use Monolog\Logger;
use NowPlaying\Adapter\AdapterAbstract;
use NowPlaying\Result\Result;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -96,7 +96,6 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
GenerateRawNowPlaying::class => [
['loadRawFromFrontend', 10],
['addToRawFromRemotes', 0],
['cleanUpRawOutput', -10],
],
];
}
@ -199,10 +198,10 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
$station,
$frontend_adapter,
$remote_adapters,
null,
$include_clients);
$this->event_dispatcher->dispatch($event);
$np_raw = $event->getRawResponse();
$npResult = $event->getResult();
} catch (Exception $e) {
$this->logger->log(Logger::ERROR, $e->getMessage(), [
'file' => $e->getFile(),
@ -210,22 +209,27 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
'code' => $e->getCode(),
]);
$np_raw = AdapterAbstract::NOWPLAYING_EMPTY;
$npResult = Result::blank();
}
$this->logger->debug('Final NowPlaying Response for Station', [
'id' => $station->getId(),
'name' => $station->getName(),
'np' => $np_raw,
'np' => $npResult,
]);
$np = new Entity\Api\NowPlaying;
$uri_empty = new Uri('');
$np->station = $station->api($frontend_adapter, $remote_adapters, $uri_empty);
$np->listeners = new Entity\Api\NowPlayingListeners($np_raw['listeners']);
$np->listeners = new Entity\Api\NowPlayingListeners([
'current' => $npResult->listeners->current,
'unique' => $npResult->listeners->unique,
'total' => $npResult->listeners->total,
]
);
if (empty($np_raw['current_song']['text'])) {
if (empty($npResult->currentSong->text)) {
$song_obj = $this->song_repo->getOrCreate(['text' => 'Stream Offline'], true);
$offline_sh = new Entity\Api\NowPlayingCurrentSong;
@ -252,7 +256,7 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
$np->live = new Entity\Api\NowPlayingLive(false);
} else {
// Pull from current NP data if song details haven't changed .
$current_song_hash = Entity\Song::getSongHash($np_raw['current_song']);
$current_song_hash = Entity\Song::getSongHash($npResult->currentSong);
if ($np_old instanceof Entity\Api\NowPlaying &&
0 === strcmp($current_song_hash, $np_old->now_playing->song->id)) {
@ -266,7 +270,7 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
} else {
// SongHistory registration must ALWAYS come before the history/nextsong calls
// otherwise they will not have up-to-date database info!
$song_obj = $this->song_repo->getOrCreate($np_raw['current_song'], true);
$song_obj = $this->song_repo->getOrCreate($npResult->currentSong, true);
$sh_obj = $this->history_repo->register($song_obj, $station, $np);
$np->song_history = $this->history_repo->getHistoryApi(
@ -283,8 +287,8 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
}
// Update detailed listener statistics, if they exist for the station
if ($include_clients && isset($np_raw['listeners']['clients'])) {
$this->listener_repo->update($station, $np_raw['listeners']['clients']);
if ($include_clients && null !== $npResult->clients) {
$this->listener_repo->update($station, $npResult->clients);
}
// Detect and report live DJ status
@ -403,39 +407,27 @@ class NowPlaying extends AbstractTask implements EventSubscriberInterface
public function loadRawFromFrontend(GenerateRawNowPlaying $event): void
{
$np_raw = $event
$result = $event
->getFrontend()
->getNowPlaying($event->getStation(), $event->getPayload(), $event->includeClients());
->getNowPlaying($event->getStation(), $event->includeClients());
$event->setRawResponse($np_raw);
$event->setResult($result);
}
public function addToRawFromRemotes(GenerateRawNowPlaying $event): void
{
$np_raw = $event->getRawResponse();
$result = $event->getResult();
// Loop through all remotes and update NP data accordingly.
foreach ($event->getRemotes() as $ra_proxy) {
$np_raw = $ra_proxy->getAdapter()->updateNowPlaying(
$result = $ra_proxy->getAdapter()->updateNowPlaying(
$result,
$ra_proxy->getRemote(),
$np_raw,
$event->includeClients()
);
}
$event->setRawResponse($np_raw);
}
public function cleanUpRawOutput(GenerateRawNowPlaying $event): void
{
$np_raw = $event->getRawResponse();
array_walk($np_raw['current_song'], function (&$value) {
$value = htmlspecialchars_decode($value);
$value = trim($value);
});
$event->setRawResponse($np_raw);
$event->setResult($result);
}
/**