Adapter simplification:
- Remove the stub "None"/"Remote" adapters; return null for disabled adapters - Add capability checks to adapter enums - Remove the Remote proxy
This commit is contained in:
parent
80400dc28f
commit
ad3d2b2c69
|
@ -13,13 +13,14 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
$backendConfig = $station->getBackendConfig();
|
||||
|
||||
$router = $request->getRouter();
|
||||
$backend = $request->getStationBackend();
|
||||
$frontend = $request->getStationFrontend();
|
||||
|
||||
$backendEnum = $station->getBackendTypeEnum();
|
||||
$frontendEnum = $station->getFrontendTypeEnum();
|
||||
|
||||
$willDisconnectMessage = __('Restart broadcasting? This will disconnect any current listeners.');
|
||||
$willNotDisconnectMessage = __('Reload broadcasting? Current listeners will not be disconnected.');
|
||||
|
||||
$reloadSupported = $frontend->supportsReload();
|
||||
$reloadSupported = $frontendEnum->supportsReload();
|
||||
$reloadMessage = $reloadSupported ? $willNotDisconnectMessage : $willDisconnectMessage;
|
||||
|
||||
$settings = $e->getSettings();
|
||||
|
@ -67,28 +68,28 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Music Files'),
|
||||
'icon' => 'library_music',
|
||||
'url' => (string)$router->fromHere('stations:files:index'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
'reports_duplicates' => [
|
||||
'label' => __('Duplicate Songs'),
|
||||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:files:index') . '#special:duplicates',
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
'reports_unprocessable' => [
|
||||
'label' => __('Unprocessable Files'),
|
||||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:files:index') . '#special:unprocessable',
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
'reports_unassigned' => [
|
||||
'label' => __('Unassigned Files'),
|
||||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:files:index') . '#special:unassigned',
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
'ondemand' => [
|
||||
|
@ -110,7 +111,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Bulk Media Import/Export'),
|
||||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:bulk-media'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
],
|
||||
|
@ -120,7 +121,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Playlists'),
|
||||
'icon' => 'queue_music',
|
||||
'url' => (string)$router->fromHere('stations:playlists:index'),
|
||||
'visible' => $backend->supportsMedia(),
|
||||
'visible' => $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Media,
|
||||
],
|
||||
|
||||
|
@ -139,7 +140,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Streamer/DJ Accounts'),
|
||||
'icon' => 'mic',
|
||||
'url' => (string)$router->fromHere('stations:streamers:index'),
|
||||
'visible' => $backend->supportsStreamers() && $station->getEnableStreamers(),
|
||||
'visible' => $backendEnum->isEnabled() && $station->getEnableStreamers(),
|
||||
'permission' => StationPermissions::Streamers,
|
||||
],
|
||||
|
||||
|
@ -203,13 +204,13 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Mount Points'),
|
||||
'icon' => 'wifi_tethering',
|
||||
'url' => (string)$router->fromHere('stations:mounts:index'),
|
||||
'visible' => $frontend->supportsMounts(),
|
||||
'visible' => $frontendEnum->supportsMounts(),
|
||||
'permission' => StationPermissions::MountPoints,
|
||||
],
|
||||
'hls_streams' => [
|
||||
'label' => __('HLS Streams'),
|
||||
'url' => (string)$router->fromHere('stations:hls_streams:index'),
|
||||
'visible' => $backend->supportsHls() && $station->getEnableHls(),
|
||||
'visible' => $backendEnum->isEnabled() && $station->getEnableHls(),
|
||||
'permission' => StationPermissions::MountPoints,
|
||||
],
|
||||
'remotes' => [
|
||||
|
@ -228,8 +229,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'label' => __('Edit Liquidsoap Configuration'),
|
||||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:util:ls_config'),
|
||||
'visible' => $settings->getEnableAdvancedFeatures()
|
||||
&& $backend instanceof App\Radio\Backend\Liquidsoap,
|
||||
'visible' => $settings->getEnableAdvancedFeatures() && $backendEnum->isEnabled(),
|
||||
'permission' => StationPermissions::Broadcasting,
|
||||
],
|
||||
'stations:stereo_tool_config' => [
|
||||
|
@ -237,7 +237,7 @@ return function (App\Event\BuildStationMenu $e) {
|
|||
'class' => 'text-muted',
|
||||
'url' => (string)$router->fromHere('stations:stereo_tool_config'),
|
||||
'visible' => $settings->getEnableAdvancedFeatures()
|
||||
&& $backend instanceof App\Radio\Backend\Liquidsoap
|
||||
&& App\Radio\Enums\BackendAdapters::Liquidsoap === $backendEnum
|
||||
&& AudioProcessingMethods::StereoTool === $backendConfig->getAudioProcessingMethodEnum(),
|
||||
'permission' => StationPermissions::Broadcasting,
|
||||
],
|
||||
|
|
|
@ -35,10 +35,12 @@ class OnSslRenewal extends CommandAbstract
|
|||
|
||||
foreach ($stations as $station) {
|
||||
/** @var Entity\Station $station */
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
if ($frontend->supportsReload()) {
|
||||
$frontend->write($station);
|
||||
$frontend->reload($station);
|
||||
if ($station->getFrontendTypeEnum()->supportsReload()) {
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
if (null !== $frontend) {
|
||||
$frontend->write($station);
|
||||
$frontend->reload($station);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Admin\Debug;
|
||||
|
||||
use App\Exception\StationUnsupportedException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Radio\Adapters;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\Logger;
|
||||
|
@ -15,7 +16,8 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class TelnetAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Logger $logger
|
||||
private readonly Logger $logger,
|
||||
private readonly Adapters $adapters
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -28,20 +30,22 @@ final class TelnetAction
|
|||
$this->logger->pushHandler($testHandler);
|
||||
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
if ($backend instanceof Liquidsoap) {
|
||||
$command = $request->getParam('command');
|
||||
|
||||
$telnetResponse = $backend->command($station, $command);
|
||||
$this->logger->debug(
|
||||
'Telnet Command Response',
|
||||
[
|
||||
'response' => $telnetResponse,
|
||||
]
|
||||
);
|
||||
if (null === $backend) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
$command = $request->getParam('command');
|
||||
|
||||
$telnetResponse = $backend->command($station, $command);
|
||||
$this->logger->debug(
|
||||
'Telnet Command Response',
|
||||
[
|
||||
'response' => $telnetResponse,
|
||||
]
|
||||
);
|
||||
|
||||
$this->logger->popHandler();
|
||||
|
||||
return $request->getView()->renderToResponse(
|
||||
|
|
|
@ -52,8 +52,6 @@ final class RelaysController
|
|||
|
||||
$return = [];
|
||||
foreach ($stations as $station) {
|
||||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
$row = new Entity\Api\Admin\Relay();
|
||||
$row->id = $station->getIdRequired();
|
||||
$row->name = $station->getName();
|
||||
|
@ -70,7 +68,9 @@ final class RelaysController
|
|||
$row->admin_pw = $frontend_config->getAdminPassword();
|
||||
|
||||
$mounts = [];
|
||||
if ($station->getMounts()->count() > 0) {
|
||||
|
||||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
if (null !== $fa && $station->getMounts()->count() > 0) {
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
/** @var Entity\StationMount $mount */
|
||||
$mounts[] = $mount->api($fa);
|
||||
|
|
|
@ -10,7 +10,6 @@ use App\Entity;
|
|||
use App\Environment;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use App\Radio\Configuration;
|
||||
use DeepCopy;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
@ -36,7 +35,6 @@ final class CloneAction extends StationsController
|
|||
Entity\Repository\StationRepository $stationRepo,
|
||||
Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
Entity\Repository\StationQueueRepository $queueRepo,
|
||||
Adapters $adapters,
|
||||
Configuration $configuration,
|
||||
ReloadableEntityManagerInterface $reloadableEm,
|
||||
Serializer $serializer,
|
||||
|
@ -47,7 +45,6 @@ final class CloneAction extends StationsController
|
|||
$stationRepo,
|
||||
$storageLocationRepo,
|
||||
$queueRepo,
|
||||
$adapters,
|
||||
$configuration,
|
||||
$reloadableEm,
|
||||
$serializer,
|
||||
|
@ -164,10 +161,7 @@ final class CloneAction extends StationsController
|
|||
$this->cloneCollection($record->getMounts(), $newStation, $copier);
|
||||
} else {
|
||||
$newStation = $this->reloadableEm->refetch($newStation);
|
||||
|
||||
// Create default mountpoints if station supports them.
|
||||
$frontendAdapter = $this->adapters->getFrontendAdapter($newStation);
|
||||
$this->stationRepo->resetMounts($newStation, $frontendAdapter);
|
||||
$this->stationRepo->resetMounts($newStation);
|
||||
}
|
||||
|
||||
if (in_array(self::CLONE_REMOTES, $toClone, true)) {
|
||||
|
|
|
@ -11,7 +11,6 @@ use App\Exception\ValidationException;
|
|||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Radio\Adapters;
|
||||
use App\Radio\Configuration;
|
||||
use InvalidArgumentException;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
@ -147,7 +146,6 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
protected Entity\Repository\StationRepository $stationRepo,
|
||||
protected Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
protected Entity\Repository\StationQueueRepository $queueRepo,
|
||||
protected Adapters $adapters,
|
||||
protected Configuration $configuration,
|
||||
protected ReloadableEntityManagerInterface $reloadableEm,
|
||||
Serializer $serializer,
|
||||
|
@ -323,13 +321,11 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
$hls_changed = $old_hls !== $station->getEnableHls();
|
||||
|
||||
if ($frontend_changed) {
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
$this->stationRepo->resetMounts($station, $frontend);
|
||||
$this->stationRepo->resetMounts($station);
|
||||
}
|
||||
|
||||
if ($hls_changed || $backend_changed) {
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
$this->stationRepo->resetHls($station, $backend);
|
||||
$this->stationRepo->resetHls($station);
|
||||
}
|
||||
|
||||
if ($adapter_changed || !$station->getIsEnabled()) {
|
||||
|
@ -355,8 +351,7 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
$this->configuration->initializeConfiguration($station);
|
||||
|
||||
// Create default mountpoints if station supports them.
|
||||
$frontend_adapter = $this->adapters->getFrontendAdapter($station);
|
||||
$this->stationRepo->resetMounts($station, $frontend_adapter);
|
||||
$this->stationRepo->resetMounts($station);
|
||||
|
||||
return $station;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ final class BatchAction
|
|||
$fs
|
||||
);
|
||||
|
||||
$this->writePlaylistChanges($request, $affectedPlaylists);
|
||||
$this->writePlaylistChanges($station, $affectedPlaylists);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ final class BatchAction
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
$this->writePlaylistChanges($request, $affectedPlaylists);
|
||||
$this->writePlaylistChanges($station, $affectedPlaylists);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -440,13 +440,11 @@ final class BatchAction
|
|||
}
|
||||
|
||||
private function writePlaylistChanges(
|
||||
ServerRequest $request,
|
||||
Entity\Station $station,
|
||||
array $playlists
|
||||
): void {
|
||||
// Write new PLS playlist configuration.
|
||||
$backend = $request->getStationBackend();
|
||||
|
||||
if ($backend instanceof Liquidsoap) {
|
||||
if ($station->getBackendTypeEnum()->isEnabled()) {
|
||||
foreach ($playlists as $playlistId => $playlistRow) {
|
||||
// Instruct the message queue to start a new "write playlist to file" task.
|
||||
$message = new Message\WritePlaylistFileMessage();
|
||||
|
|
|
@ -145,8 +145,7 @@ final class HlsStreamsController extends AbstractStationApiCrudController
|
|||
{
|
||||
$station = parent::getStation($request);
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
if (!$backend->supportsHls()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Http\Response;
|
|||
use App\Http\Router;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Radio\Adapters;
|
||||
use App\Service\Flow\UploadedFile;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
@ -152,7 +153,8 @@ final class MountsController extends AbstractStationApiCrudController
|
|||
ReloadableEntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
parent::__construct($em, $serializer, $validator);
|
||||
}
|
||||
|
@ -195,20 +197,23 @@ final class MountsController extends AbstractStationApiCrudController
|
|||
$return = parent::viewRecord($record, $request);
|
||||
|
||||
$station = $request->getStation();
|
||||
$frontend = $request->getStationFrontend();
|
||||
$router = $request->getRouter();
|
||||
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
$return['links']['intro'] = (string)$router->fromHere(
|
||||
route_name: 'api:stations:mounts:intro',
|
||||
route_params: ['id' => $record->getId()],
|
||||
absolute: true
|
||||
);
|
||||
|
||||
$return['links']['listen'] = (string)Router::resolveUri(
|
||||
$router->getBaseUrl(),
|
||||
$frontend->getUrlForMount($station, $record),
|
||||
true
|
||||
);
|
||||
if (null !== $frontend) {
|
||||
$return['links']['listen'] = (string)Router::resolveUri(
|
||||
$router->getBaseUrl(),
|
||||
$frontend->getUrlForMount($station, $record),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
@ -259,8 +264,7 @@ final class MountsController extends AbstractStationApiCrudController
|
|||
{
|
||||
$station = parent::getStation($request);
|
||||
|
||||
$frontend = $request->getStationFrontend();
|
||||
if (!$frontend->supportsMounts()) {
|
||||
if (!$station->getFrontendTypeEnum()->supportsMounts()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Controller\Api\Stations;
|
|||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
|
@ -15,7 +16,8 @@ final class ProfileAction
|
|||
public function __construct(
|
||||
private readonly Entity\Repository\StationScheduleRepository $scheduleRepo,
|
||||
private readonly Entity\ApiGenerator\NowPlayingApiGenerator $nowPlayingApiGenerator,
|
||||
private readonly Entity\ApiGenerator\StationApiGenerator $stationApiGenerator
|
||||
private readonly Entity\ApiGenerator\StationApiGenerator $stationApiGenerator,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -25,8 +27,8 @@ final class ProfileAction
|
|||
string $station_id
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
$frontend = $request->getStationFrontend();
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
$baseUri = new Uri('');
|
||||
$nowPlayingApi = $this->nowPlayingApiGenerator->currentOrEmpty($station, $baseUri);
|
||||
|
@ -38,8 +40,8 @@ final class ProfileAction
|
|||
$apiResponse->cache = 'database';
|
||||
|
||||
$apiResponse->services = new Entity\Api\StationServiceStatus(
|
||||
$backend->isRunning($station),
|
||||
$frontend->isRunning($station),
|
||||
null !== $backend && $backend->isRunning($station),
|
||||
null !== $frontend && $frontend->isRunning($station),
|
||||
$station->getHasStarted(),
|
||||
$station->getNeedsRestart()
|
||||
);
|
||||
|
|
|
@ -81,8 +81,7 @@ final class RequestsController
|
|||
$station = $request->getStation();
|
||||
|
||||
// Verify that the station supports requests.
|
||||
$ba = $request->getStationBackend();
|
||||
if (!$ba->supportsRequests() || !$station->getEnableRequests()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled() || !$station->getEnableRequests()) {
|
||||
return $response->withStatus(403)
|
||||
->withJson(new Entity\Api\Error(403, __('This station does not accept requests currently.')));
|
||||
}
|
||||
|
@ -190,8 +189,7 @@ final class RequestsController
|
|||
$station = $request->getStation();
|
||||
|
||||
// Verify that the station supports requests.
|
||||
$ba = $request->getStationBackend();
|
||||
if (!$ba->supportsRequests() || !$station->getEnableRequests()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled() || !$station->getEnableRequests()) {
|
||||
return $response->withStatus(403)
|
||||
->withJson(new Entity\Api\Error(403, __('This station does not accept requests currently.')));
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\StationUnsupportedException;
|
||||
use App\Exception\Supervisor\NotRunningException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Nginx\Nginx;
|
||||
use App\OpenApi;
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Radio\Adapters;
|
||||
use App\Radio\Configuration;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
@ -109,6 +110,7 @@ final class ServicesController
|
|||
private readonly EntityManagerInterface $em,
|
||||
private readonly Configuration $configuration,
|
||||
private readonly Nginx $nginx,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -119,13 +121,13 @@ final class ServicesController
|
|||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
$frontend = $request->getStationFrontend();
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
return $response->withJson(
|
||||
new Entity\Api\StationServiceStatus(
|
||||
$backend->isRunning($station),
|
||||
$frontend->isRunning($station),
|
||||
null !== $backend && $backend->isRunning($station),
|
||||
null !== $frontend && $frontend->isRunning($station),
|
||||
$station->getHasStarted(),
|
||||
$station->getNeedsRestart()
|
||||
)
|
||||
|
@ -202,7 +204,11 @@ final class ServicesController
|
|||
string $do = 'restart'
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$frontend = $request->getStationFrontend();
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
if (null === $frontend) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
switch ($do) {
|
||||
case 'stop':
|
||||
|
@ -242,20 +248,20 @@ final class ServicesController
|
|||
string $do = 'restart'
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
if (null === $backend) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
switch ($do) {
|
||||
case 'skip':
|
||||
if ($backend instanceof Liquidsoap) {
|
||||
$backend->skip($station);
|
||||
}
|
||||
$backend->skip($station);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, __('Song skipped.')));
|
||||
|
||||
case 'disconnect':
|
||||
if ($backend instanceof Liquidsoap) {
|
||||
$backend->disconnectStreamer($station);
|
||||
}
|
||||
$backend->disconnectStreamer($station);
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, __('Streamer disconnected.')));
|
||||
|
||||
|
|
|
@ -311,8 +311,7 @@ final class StreamersController extends AbstractScheduledEntityController
|
|||
{
|
||||
$station = parent::getStation($request);
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
if (!$backend->supportsStreamers()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,25 +5,32 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\StationUnsupportedException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
use const ARRAY_FILTER_USE_KEY;
|
||||
|
||||
final class UpdateMetadataAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
string $station_id
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
|
||||
if (!method_exists($backend, 'updateMetadata')) {
|
||||
return $response->withStatus(500)
|
||||
->withJson(new Entity\Api\Error(500, 'This function is not supported on this station.'));
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
if (null === $backend) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
$allowedMetaFields = [
|
||||
|
|
|
@ -7,10 +7,16 @@ namespace App\Controller\Frontend\PublicPages;
|
|||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class PlaylistAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
|
@ -22,31 +28,31 @@ final class PlaylistAction
|
|||
$streams = [];
|
||||
$stream_urls = [];
|
||||
|
||||
$fa = $request->getStationFrontend();
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
/** @var Entity\StationMount $mount */
|
||||
if (!$mount->getIsVisibleOnPublicPages()) {
|
||||
continue;
|
||||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
if (null !== $fa) {
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
/** @var Entity\StationMount $mount */
|
||||
if (!$mount->getIsVisibleOnPublicPages()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stream_url = $fa->getUrlForMount($station, $mount);
|
||||
|
||||
$stream_urls[] = $stream_url;
|
||||
$streams[] = [
|
||||
'name' => $station->getName() . ' - ' . $mount->getDisplayName(),
|
||||
'url' => $stream_url,
|
||||
];
|
||||
}
|
||||
|
||||
$stream_url = $fa->getUrlForMount($station, $mount);
|
||||
|
||||
$stream_urls[] = $stream_url;
|
||||
$streams[] = [
|
||||
'name' => $station->getName() . ' - ' . $mount->getDisplayName(),
|
||||
'url' => $stream_url,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($request->getStationRemotes() as $remote_proxy) {
|
||||
$adapter = $remote_proxy->getAdapter();
|
||||
$remote = $remote_proxy->getRemote();
|
||||
|
||||
foreach ($station->getRemotes() as $remote) {
|
||||
if (!$remote->getIsVisibleOnPublicPages()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stream_url = $adapter->getPublicUrl($remote);
|
||||
$stream_url = $this->adapters->getRemoteAdapter($station, $remote)
|
||||
->getPublicUrl($remote);
|
||||
|
||||
$stream_urls[] = $stream_url;
|
||||
$streams[] = [
|
||||
|
|
|
@ -9,13 +9,14 @@ use App\Exception\StationNotFoundException;
|
|||
use App\Exception\StationUnsupportedException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Radio\Adapters;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class WebDjAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Assets $assets
|
||||
private readonly Assets $assets,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -34,9 +35,8 @@ final class WebDjAction
|
|||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
|
||||
if (!($backend instanceof Liquidsoap)) {
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
if (null === $backend) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,7 @@ final class EditLiquidsoapConfigAction
|
|||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
if (!($backend instanceof Liquidsoap)) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ final class FilesAction
|
|||
|
||||
$router = $request->getRouter();
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
$backendEnum = $station->getBackendTypeEnum();
|
||||
|
||||
return $request->getView()->renderVuePage(
|
||||
response: $response,
|
||||
|
@ -63,7 +63,7 @@ final class FilesAction
|
|||
'stationTimeZone' => $station->getTimezone(),
|
||||
'showSftp' => SftpGo::isSupportedForStation($station),
|
||||
'sftpUrl' => (string)$router->fromHere('stations:sftp_users:index'),
|
||||
'supportsImmediateQueue' => $backend->supportsImmediateQueue(),
|
||||
'supportsImmediateQueue' => $backendEnum->isEnabled(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,8 @@ final class HlsStreamsAction
|
|||
string $station_id
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
|
||||
if (!$backend->supportsHls() || !$station->getEnableHls()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled() || !$station->getEnableHls()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@ final class PlaylistsAction
|
|||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
if (!$backend->supportsMedia()) {
|
||||
if (!$station->getBackendTypeEnum()->isEnabled()) {
|
||||
throw new Exception(__('This feature is not currently supported on this station.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Controller\Stations;
|
|||
use App\Enums\StationPermissions;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use App\VueComponent\StationFormComponent;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
@ -18,6 +19,7 @@ final class ProfileController
|
|||
public function __construct(
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly StationFormComponent $stationFormComponent,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -57,9 +59,9 @@ final class ProfileController
|
|||
|
||||
$csrf = $request->getCsrf()->generate(self::CSRF_NAMESPACE);
|
||||
|
||||
$backend = $request->getStationBackend();
|
||||
$frontend = $request->getStationFrontend();
|
||||
$backendEnum = $station->getBackendTypeEnum();
|
||||
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
$frontendConfig = $station->getFrontendConfig();
|
||||
|
||||
$acl = $request->getAcl();
|
||||
|
@ -75,8 +77,8 @@ final class ProfileController
|
|||
'backendType' => $station->getBackendType(),
|
||||
'frontendType' => $station->getFrontendType(),
|
||||
'stationTimeZone' => $station->getTimezone(),
|
||||
'stationSupportsRequests' => $backend->supportsRequests(),
|
||||
'stationSupportsStreamers' => $backend->supportsStreamers(),
|
||||
'stationSupportsRequests' => $backendEnum->isEnabled(),
|
||||
'stationSupportsStreamers' => $backendEnum->isEnabled(),
|
||||
'enableRequests' => $station->getEnableRequests(),
|
||||
'enableStreamers' => $station->getEnableStreamers(),
|
||||
'enablePublicPage' => $station->getEnablePublicPage(),
|
||||
|
@ -175,7 +177,7 @@ final class ProfileController
|
|||
),
|
||||
|
||||
// Frontend
|
||||
'frontendAdminUri' => (string)$frontend->getAdminUrl($station, $router->getBaseUrl()),
|
||||
'frontendAdminUri' => (string)$frontend?->getAdminUrl($station, $router->getBaseUrl()),
|
||||
'frontendAdminPassword' => $frontendConfig->getAdminPassword(),
|
||||
'frontendSourcePassword' => $frontendConfig->getSourcePassword(),
|
||||
'frontendRelayPassword' => $frontendConfig->getRelayPassword(),
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity;
|
|||
use App\Exception\StationUnsupportedException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use App\Service\AzuraCastCentral;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
|
@ -15,7 +16,8 @@ final class StreamersAction
|
|||
{
|
||||
public function __construct(
|
||||
private readonly AzuraCastCentral $acCentral,
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo,
|
||||
private readonly Adapters $adapters,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -25,9 +27,9 @@ final class StreamersAction
|
|||
string $station_id
|
||||
): ResponseInterface {
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
if (!$backend->supportsStreamers() && !$station->getEnableStreamers()) {
|
||||
if (null === $backend || !$station->getEnableStreamers()) {
|
||||
throw new StationUnsupportedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class Station implements ResolvableUrlInterface
|
|||
description: 'The full URL to listen to the default mount of the station',
|
||||
example: 'http://localhost:8000/radio.mp3'
|
||||
)]
|
||||
public string|UriInterface $listen_url;
|
||||
public string|UriInterface|null $listen_url;
|
||||
|
||||
#[OA\Property(
|
||||
description: 'The public URL of the station.',
|
||||
|
@ -115,7 +115,9 @@ class Station implements ResolvableUrlInterface
|
|||
*/
|
||||
public function resolveUrls(UriInterface $base): void
|
||||
{
|
||||
$this->listen_url = (string)Router::resolveUri($base, $this->listen_url, true);
|
||||
$this->listen_url = (null !== $this->listen_url)
|
||||
? (string)Router::resolveUri($base, $this->listen_url, true)
|
||||
: null;
|
||||
|
||||
$this->public_player_url = (string)Router::resolveUri($base, $this->public_player_url, true);
|
||||
$this->playlist_pls_url = (string)Router::resolveUri($base, $this->playlist_pls_url, true);
|
||||
|
|
|
@ -22,9 +22,8 @@ class StationApiGenerator
|
|||
?UriInterface $baseUri = null,
|
||||
bool $showAllMounts = false
|
||||
): Entity\Api\NowPlaying\Station {
|
||||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
$remoteAdapters = $this->adapters->getRemoteAdapters($station);
|
||||
|
||||
$response = new Entity\Api\NowPlaying\Station();
|
||||
$response->id = (int)$station->getId();
|
||||
|
@ -35,7 +34,7 @@ class StationApiGenerator
|
|||
$response->backend = (string)$station->getBackendType();
|
||||
$response->url = $station->getUrl();
|
||||
$response->is_public = $station->getEnablePublicPage();
|
||||
$response->listen_url = $fa->getStreamUrl($station, $baseUri);
|
||||
$response->listen_url = $frontend?->getStreamUrl($station, $baseUri);
|
||||
|
||||
$response->public_player_url = (string)$this->router->named(
|
||||
'public:index',
|
||||
|
@ -51,26 +50,31 @@ class StationApiGenerator
|
|||
);
|
||||
|
||||
$mounts = [];
|
||||
if ($fa->supportsMounts() && $station->getMounts()->count() > 0) {
|
||||
if (
|
||||
null !== $frontend && $station->getFrontendTypeEnum()->supportsMounts() && $station->getMounts()->count(
|
||||
) > 0
|
||||
) {
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
if ($showAllMounts || $mount->getIsVisibleOnPublicPages()) {
|
||||
$mounts[] = $mount->api($fa, $baseUri);
|
||||
$mounts[] = $mount->api($frontend, $baseUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
$response->mounts = $mounts;
|
||||
|
||||
$remotes = [];
|
||||
foreach ($remoteAdapters as $ra_proxy) {
|
||||
$remote = $ra_proxy->getRemote();
|
||||
foreach ($station->getRemotes() as $remote) {
|
||||
if ($showAllMounts || $remote->getIsVisibleOnPublicPages()) {
|
||||
$remotes[] = $remote->api($ra_proxy->getAdapter());
|
||||
$remotes[] = $remote->api(
|
||||
$this->adapters->getRemoteAdapter($station, $remote)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$response->remotes = $remotes;
|
||||
|
||||
$response->hls_enabled = $backend->supportsHls() && $station->getEnableHls();
|
||||
$response->hls_url = ($response->hls_enabled)
|
||||
$response->hls_enabled = $station->getBackendTypeEnum()->isEnabled() && $station->getEnableHls();
|
||||
$response->hls_url = (null !== $backend && $response->hls_enabled)
|
||||
? $backend->getHlsUrl($station, $baseUri)
|
||||
: null;
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ use App\Doctrine\ReloadableEntityManagerInterface;
|
|||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Radio\Backend\AbstractBackend;
|
||||
use App\Radio\Frontend\AbstractFrontend;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use App\Service\Flow\UploadedFile;
|
||||
use Azura\Files\ExtendedFilesystemInterface;
|
||||
use Closure;
|
||||
|
@ -87,47 +86,49 @@ final class StationRepository extends Repository
|
|||
)->toIterable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $short_code
|
||||
*/
|
||||
public function findByShortCode(string $short_code): ?Entity\Station
|
||||
{
|
||||
return $this->repository->findOneBy(['short_name' => $short_code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset mount points to their adapter defaults (in the event of an adapter change).
|
||||
*
|
||||
* @param Entity\Station $station
|
||||
* @param AbstractFrontend $frontend_adapter
|
||||
*/
|
||||
public function resetMounts(Entity\Station $station, AbstractFrontend $frontend_adapter): void
|
||||
public function resetMounts(Entity\Station $station): void
|
||||
{
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
$this->em->remove($mount);
|
||||
}
|
||||
|
||||
// Create default mountpoints if station supports them.
|
||||
if ($frontend_adapter->supportsMounts()) {
|
||||
// Create default mount points.
|
||||
foreach ($frontend_adapter->getDefaultMounts($station) as $mount) {
|
||||
$this->em->persist($mount);
|
||||
}
|
||||
if ($station->getFrontendTypeEnum()->supportsMounts()) {
|
||||
$record = new Entity\StationMount($station);
|
||||
$record->setName('/radio.mp3');
|
||||
$record->setIsDefault(true);
|
||||
$record->setEnableAutodj(true);
|
||||
$record->setAutodjFormat(StreamFormats::Mp3->value);
|
||||
$record->setAutodjBitrate(128);
|
||||
$this->em->persist($record);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
$this->em->refresh($station);
|
||||
}
|
||||
|
||||
public function resetHls(Entity\Station $station, AbstractBackend $backend): void
|
||||
public function resetHls(Entity\Station $station): void
|
||||
{
|
||||
foreach ($station->getHlsStreams() as $hlsStream) {
|
||||
$this->em->remove($hlsStream);
|
||||
}
|
||||
|
||||
if ($station->getEnableHls() && $backend->supportsHls()) {
|
||||
foreach ($backend->getDefaultHlsStreams($station) as $hlsStream) {
|
||||
$this->em->persist($hlsStream);
|
||||
if ($station->getEnableHls() && $station->getBackendTypeEnum()->isEnabled()) {
|
||||
$streams = [
|
||||
'aac_lofi' => 48,
|
||||
'aac_midfi' => 96,
|
||||
'aac_hifi' => 192,
|
||||
];
|
||||
|
||||
foreach ($streams as $name => $bitrate) {
|
||||
$record = new Entity\StationHlsStream($station);
|
||||
$record->setName($name);
|
||||
$record->setFormat(StreamFormats::Aac->value);
|
||||
$record->setBitrate($bitrate);
|
||||
$this->em->persist($record);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ declare(strict_types=1);
|
|||
namespace App\Event\Radio;
|
||||
|
||||
use App\Entity\Station;
|
||||
use App\Radio;
|
||||
use App\Radio\Adapters;
|
||||
use App\Radio\Frontend\AbstractFrontend;
|
||||
use NowPlaying\Result\Result;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
|
@ -14,9 +15,8 @@ class GenerateRawNowPlaying extends Event
|
|||
protected ?Result $result = null;
|
||||
|
||||
public function __construct(
|
||||
protected Adapters $adapters,
|
||||
protected Station $station,
|
||||
protected Radio\Frontend\AbstractFrontend $frontend,
|
||||
protected array $remotes,
|
||||
protected bool $include_clients = false
|
||||
) {
|
||||
}
|
||||
|
@ -26,17 +26,21 @@ class GenerateRawNowPlaying extends Event
|
|||
return $this->station;
|
||||
}
|
||||
|
||||
public function getFrontend(): Radio\Frontend\AbstractFrontend
|
||||
public function getFrontend(): ?AbstractFrontend
|
||||
{
|
||||
return $this->frontend;
|
||||
return $this->adapters->getFrontendAdapter($this->station);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Radio\Remote\AdapterProxy[]
|
||||
*/
|
||||
public function getRemotes(): array
|
||||
{
|
||||
return $this->remotes;
|
||||
$remotes = [];
|
||||
foreach ($this->station->getRemotes() as $remote) {
|
||||
$remotes[] = [
|
||||
$remote,
|
||||
$this->adapters->getRemoteAdapter($this->station, $remote),
|
||||
];
|
||||
}
|
||||
return $remotes;
|
||||
}
|
||||
|
||||
public function includeClients(): bool
|
||||
|
|
|
@ -10,7 +10,6 @@ use App\Customization;
|
|||
use App\Entity;
|
||||
use App\Enums\SupportedLocales;
|
||||
use App\Exception;
|
||||
use App\Radio;
|
||||
use App\RateLimit;
|
||||
use App\Session;
|
||||
use App\View;
|
||||
|
@ -30,9 +29,6 @@ final class ServerRequest extends \Slim\Http\ServerRequest
|
|||
public const ATTR_CUSTOMIZATION = 'customization';
|
||||
public const ATTR_AUTH = 'auth';
|
||||
public const ATTR_STATION = 'station';
|
||||
public const ATTR_STATION_BACKEND = 'station_backend';
|
||||
public const ATTR_STATION_FRONTEND = 'station_frontend';
|
||||
public const ATTR_STATION_REMOTES = 'station_remotes';
|
||||
public const ATTR_USER = 'user';
|
||||
|
||||
public function getView(): View
|
||||
|
@ -95,34 +91,6 @@ final class ServerRequest extends \Slim\Http\ServerRequest
|
|||
return $this->getAttributeOfClass(self::ATTR_STATION, Entity\Station::class);
|
||||
}
|
||||
|
||||
public function getStationFrontend(): Radio\Frontend\AbstractFrontend
|
||||
{
|
||||
return $this->getAttributeOfClass(self::ATTR_STATION_FRONTEND, Radio\Frontend\AbstractFrontend::class);
|
||||
}
|
||||
|
||||
public function getStationBackend(): Radio\Backend\AbstractBackend
|
||||
{
|
||||
return $this->getAttributeOfClass(self::ATTR_STATION_BACKEND, Radio\Backend\AbstractBackend::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Radio\Remote\AdapterProxy[]
|
||||
* @throws Exception\InvalidRequestAttribute
|
||||
*/
|
||||
public function getStationRemotes(): array
|
||||
{
|
||||
$remotes = $this->serverRequest->getAttribute(self::ATTR_STATION_REMOTES);
|
||||
|
||||
if (null === $remotes) {
|
||||
throw new Exception\InvalidRequestAttribute(sprintf(
|
||||
'Attribute "%s" was not set.',
|
||||
self::ATTR_STATION_REMOTES
|
||||
));
|
||||
}
|
||||
|
||||
return $remotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attr
|
||||
* @param string $class_name
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace App\Middleware;
|
|||
use App\Entity;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
|
@ -20,8 +19,7 @@ use Slim\Routing\RouteContext;
|
|||
class GetStation implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected StationRepository $station_repo,
|
||||
protected Adapters $adapters
|
||||
protected StationRepository $station_repo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -35,15 +33,7 @@ class GetStation implements MiddlewareInterface
|
|||
$record = $this->station_repo->findByIdentifier($id);
|
||||
|
||||
if ($record instanceof Entity\Station) {
|
||||
$backend = $this->adapters->getBackendAdapter($record);
|
||||
$frontend = $this->adapters->getFrontendAdapter($record);
|
||||
$remotes = $this->adapters->getRemoteAdapters($record);
|
||||
|
||||
$request = $request
|
||||
->withAttribute(ServerRequest::ATTR_STATION, $record)
|
||||
->withAttribute(ServerRequest::ATTR_STATION_BACKEND, $backend)
|
||||
->withAttribute(ServerRequest::ATTR_STATION_FRONTEND, $frontend)
|
||||
->withAttribute(ServerRequest::ATTR_STATION_REMOTES, $remotes);
|
||||
$request = $request->withAttribute(ServerRequest::ATTR_STATION, $record);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@ class StationFiles
|
|||
{
|
||||
public function __invoke(ServerRequest $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$backend = $request->getStationBackend();
|
||||
if (!$backend->supportsMedia()) {
|
||||
if (!$request->getStation()->getBackendTypeEnum()->isEnabled()) {
|
||||
throw new Exception(__('This feature is not currently supported on this station.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,14 +29,9 @@ class Stations
|
|||
$view = $request->getView();
|
||||
|
||||
$station = $request->getStation();
|
||||
$backend = $request->getStationBackend();
|
||||
$frontend = $request->getStationFrontend();
|
||||
|
||||
$view->addData(
|
||||
[
|
||||
'station' => $station,
|
||||
'frontend' => $frontend,
|
||||
'backend' => $backend,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use Supervisor\Exception\Fault;
|
|||
use Supervisor\Exception\SupervisorException as SupervisorLibException;
|
||||
use Supervisor\SupervisorInterface;
|
||||
|
||||
abstract class AbstractAdapter
|
||||
abstract class AbstractLocalAdapter
|
||||
{
|
||||
public function __construct(
|
||||
protected Environment $environment,
|
||||
|
@ -155,14 +155,6 @@ abstract class AbstractAdapter
|
|||
$this->start($station);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Whether this adapter supports a non-destructive reload.
|
||||
*/
|
||||
public function supportsReload(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a non-destructive reload if the adapter supports it.
|
||||
*
|
|
@ -6,6 +6,7 @@ namespace App\Radio;
|
|||
|
||||
use App\Entity;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Radio\Enums\AdapterTypeInterface;
|
||||
use App\Radio\Enums\BackendAdapters;
|
||||
use App\Radio\Enums\FrontendAdapters;
|
||||
|
@ -22,19 +23,13 @@ class Adapters
|
|||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
*
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function getFrontendAdapter(Entity\Station $station): Frontend\AbstractFrontend
|
||||
public function getFrontendAdapter(Entity\Station $station): ?Frontend\AbstractFrontend
|
||||
{
|
||||
$class_name = $station->getFrontendTypeEnum()->getClass();
|
||||
if ($this->adapters->has($class_name)) {
|
||||
return $this->adapters->get($class_name);
|
||||
}
|
||||
$className = $station->getFrontendTypeEnum()->getClass();
|
||||
|
||||
throw new NotFoundException('Adapter not found: ' . $class_name);
|
||||
return (null !== $className && $this->adapters->has($className))
|
||||
? $this->adapters->get($className)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,19 +41,13 @@ class Adapters
|
|||
return $this->listAdaptersFromEnum(FrontendAdapters::cases(), $checkInstalled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
*
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function getBackendAdapter(Entity\Station $station): Backend\AbstractBackend
|
||||
public function getBackendAdapter(Entity\Station $station): ?Liquidsoap
|
||||
{
|
||||
$class_name = $station->getBackendTypeEnum()->getClass();
|
||||
if ($this->adapters->has($class_name)) {
|
||||
return $this->adapters->get($class_name);
|
||||
}
|
||||
$className = $station->getBackendTypeEnum()->getClass();
|
||||
|
||||
throw new NotFoundException('Adapter not found: ' . $class_name);
|
||||
return (null !== $className && $this->adapters->has($className))
|
||||
? $this->adapters->get($className)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,21 +59,6 @@ class Adapters
|
|||
return $this->listAdaptersFromEnum(BackendAdapters::cases(), $checkInstalled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
*
|
||||
* @return Remote\AdapterProxy[]
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function getRemoteAdapters(Entity\Station $station): array
|
||||
{
|
||||
$remote_adapters = [];
|
||||
foreach ($station->getRemotes() as $remote) {
|
||||
$remote_adapters[] = new Remote\AdapterProxy($this->getRemoteAdapter($station, $remote), $remote);
|
||||
}
|
||||
return $remote_adapters;
|
||||
}
|
||||
|
||||
public function getRemoteAdapter(Entity\Station $station, Entity\StationRemote $remote): Remote\AbstractRemote
|
||||
{
|
||||
$class_name = $remote->getTypeEnum()->getClass();
|
||||
|
@ -113,8 +87,8 @@ class Adapters
|
|||
$adapters = [];
|
||||
foreach ($cases as $adapter) {
|
||||
$adapters[$adapter->getValue()] = [
|
||||
'enum' => $adapter,
|
||||
'name' => $adapter->getName(),
|
||||
'enum' => $adapter,
|
||||
'name' => $adapter->getName(),
|
||||
'class' => $adapter->getClass(),
|
||||
];
|
||||
}
|
||||
|
@ -123,7 +97,11 @@ class Adapters
|
|||
return array_filter(
|
||||
$adapters,
|
||||
function ($adapter_info) {
|
||||
/** @var AbstractAdapter $adapter */
|
||||
if (null === $adapter_info['class']) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var AbstractLocalAdapter $adapter */
|
||||
$adapter = $this->adapters->get($adapter_info['class']);
|
||||
return $adapter->isInstalled();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,9 @@ class Annotations implements EventSubscriberInterface
|
|||
$event->setSongPath('media:' . ltrim($media->getPath(), '/'));
|
||||
|
||||
$backend = $this->adapters->getBackendAdapter($event->getStation());
|
||||
$event->addAnnotations($backend->annotateMedia($media));
|
||||
if (null !== $backend) {
|
||||
$event->addAnnotations($backend->annotateMedia($media));
|
||||
}
|
||||
} else {
|
||||
$queue = $event->getQueue();
|
||||
if ($queue instanceof Entity\StationQueue) {
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Radio\Backend;
|
||||
|
||||
use App\Entity;
|
||||
use App\Nginx\CustomUrls;
|
||||
use App\Radio\AbstractAdapter;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use RuntimeException;
|
||||
|
||||
abstract class AbstractBackend extends AbstractAdapter
|
||||
{
|
||||
public function supportsMedia(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function supportsRequests(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function supportsStreamers(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function supportsWebStreaming(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function supportsImmediateQueue(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function supportsHls(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDefaultHlsStreams(Entity\Station $station): array
|
||||
{
|
||||
return array_map(
|
||||
function (string $name, int $bitrate) use ($station) {
|
||||
$record = new Entity\StationHlsStream($station);
|
||||
$record->setName($name);
|
||||
$record->setFormat(StreamFormats::Aac->value);
|
||||
$record->setBitrate($bitrate);
|
||||
return $record;
|
||||
},
|
||||
['aac_lofi', 'aac_midfi', 'aac_hifi'],
|
||||
[48, 96, 192]
|
||||
);
|
||||
}
|
||||
|
||||
public function getHlsUrl(Entity\Station $station, UriInterface $baseUrl = null): UriInterface
|
||||
{
|
||||
if (!$this->supportsHls()) {
|
||||
throw new RuntimeException('Cannot generate HLS URL.');
|
||||
}
|
||||
|
||||
$baseUrl ??= $this->router->getBaseUrl();
|
||||
|
||||
return $baseUrl->withPath(
|
||||
$baseUrl->getPath() . CustomUrls::getHlsUrl($station) . '/live.m3u8'
|
||||
);
|
||||
}
|
||||
|
||||
public function getStreamPort(Entity\Station $station): ?int
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\StationMedia $media
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function annotateMedia(Entity\StationMedia $media): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getProgramName(Entity\Station $station): string
|
||||
{
|
||||
return 'station_' . $station->getId() . ':station_' . $station->getId() . '_backend';
|
||||
}
|
||||
}
|
|
@ -8,43 +8,14 @@ use App\Entity;
|
|||
use App\Event\Radio\WriteLiquidsoapConfiguration;
|
||||
use App\Exception;
|
||||
use App\Nginx\CustomUrls;
|
||||
use App\Radio\AbstractLocalAdapter;
|
||||
use App\Radio\Enums\LiquidsoapQueues;
|
||||
use LogicException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class Liquidsoap extends AbstractBackend
|
||||
class Liquidsoap extends AbstractLocalAdapter
|
||||
{
|
||||
public function supportsMedia(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsRequests(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsStreamers(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsWebStreaming(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsImmediateQueue(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsHls(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
@ -234,6 +205,14 @@ class Liquidsoap extends AbstractBackend
|
|||
: null;
|
||||
}
|
||||
|
||||
public function getHlsUrl(Entity\Station $station, UriInterface $baseUrl = null): UriInterface
|
||||
{
|
||||
$baseUrl ??= $this->router->getBaseUrl();
|
||||
return $baseUrl->withPath(
|
||||
$baseUrl->getPath() . CustomUrls::getHlsUrl($station) . '/live.m3u8'
|
||||
);
|
||||
}
|
||||
|
||||
public function isQueueEmpty(
|
||||
Entity\Station $station,
|
||||
LiquidsoapQueues $queue
|
||||
|
@ -337,4 +316,9 @@ class Liquidsoap extends AbstractBackend
|
|||
throw new LogicException($process->getOutput());
|
||||
}
|
||||
}
|
||||
|
||||
public function getProgramName(Entity\Station $station): string
|
||||
{
|
||||
return 'station_' . $station->getIdRequired() . ':station_' . $station->getIdRequired() . '_backend';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Radio\Backend;
|
||||
|
||||
use App\Entity;
|
||||
|
||||
class None extends AbstractBackend
|
||||
{
|
||||
public function isInstalled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function start(Entity\Station $station): void
|
||||
{
|
||||
$this->logger->error(
|
||||
'Cannot start process; AutoDJ is currently disabled.',
|
||||
['station_id' => $station->getId(), 'station_name' => $station->getName()]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -113,51 +113,52 @@ class Configuration
|
|||
throw new RuntimeException('Station is disabled.');
|
||||
}
|
||||
|
||||
$frontendEnum = $station->getFrontendTypeEnum();
|
||||
$backendEnum = $station->getBackendTypeEnum();
|
||||
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
// If no processes need to be managed, remove any existing config.
|
||||
if (!$frontend->hasCommand($station) && !$backend->hasCommand($station)) {
|
||||
if (
|
||||
(null === $frontend || !$frontend->hasCommand($station))
|
||||
&& (null === $backend || !$backend->hasCommand($station))
|
||||
) {
|
||||
$this->unlinkAndStopStation($station, $reloadSupervisor);
|
||||
throw new RuntimeException('Station has no local services.');
|
||||
}
|
||||
|
||||
// If using AutoDJ and there is no media, don't spin up services.
|
||||
if (
|
||||
BackendAdapters::None !== $station->getBackendTypeEnum()
|
||||
$backendEnum->isEnabled()
|
||||
&& !$this->stationPlaylistRepo->stationHasActivePlaylists($station)
|
||||
) {
|
||||
$this->unlinkAndStopStation($station, $reloadSupervisor);
|
||||
throw new RuntimeException('Station has no media assigned to playlists.');
|
||||
}
|
||||
|
||||
// Get group information
|
||||
$backend_name = $backend->getProgramName($station);
|
||||
[$backend_group, $backend_program] = explode(':', $backend_name);
|
||||
|
||||
$frontend_name = $frontend->getProgramName($station);
|
||||
[, $frontend_program] = explode(':', $frontend_name);
|
||||
|
||||
// Write group section of config
|
||||
$programs = [];
|
||||
if ($backend->hasCommand($station)) {
|
||||
$programs[] = $backend_program;
|
||||
if (null !== $backend && $backend->hasCommand($station)) {
|
||||
$programs[] = (explode(':', $backend->getProgramName($station)))[2];
|
||||
}
|
||||
if ($frontend->hasCommand($station)) {
|
||||
$programs[] = $frontend_program;
|
||||
if (null !== $frontend && $frontend->hasCommand($station)) {
|
||||
$programs[] = (explode(':', $frontend->getProgramName($station)))[2];
|
||||
}
|
||||
|
||||
$supervisorConfig[] = '[group:' . $backend_group . ']';
|
||||
$stationGroup = 'station_' . $station->getIdRequired();
|
||||
|
||||
$supervisorConfig[] = '[group:' . $stationGroup . ']';
|
||||
$supervisorConfig[] = 'programs=' . implode(',', $programs);
|
||||
$supervisorConfig[] = '';
|
||||
|
||||
// Write frontend
|
||||
if ($frontend->hasCommand($station)) {
|
||||
if (null !== $frontend && $frontend->hasCommand($station)) {
|
||||
$supervisorConfig[] = $this->writeConfigurationSection($station, $frontend, 90);
|
||||
}
|
||||
|
||||
// Write backend
|
||||
if ($backend->hasCommand($station)) {
|
||||
if (null !== $backend && $backend->hasCommand($station)) {
|
||||
$supervisorConfig[] = $this->writeConfigurationSection($station, $backend, 100);
|
||||
}
|
||||
|
||||
|
@ -166,22 +167,22 @@ class Configuration
|
|||
file_put_contents($supervisorConfigFile, $supervisor_config_data);
|
||||
|
||||
// Write supporting configurations.
|
||||
$frontend->write($station);
|
||||
$backend->write($station);
|
||||
$frontend?->write($station);
|
||||
$backend?->write($station);
|
||||
|
||||
// Reload Supervisord and process groups
|
||||
if ($reloadSupervisor) {
|
||||
$affected_groups = $this->reloadSupervisor();
|
||||
$was_restarted = in_array($backend_group, $affected_groups, true);
|
||||
$was_restarted = in_array($stationGroup, $affected_groups, true);
|
||||
|
||||
if (!$was_restarted && $forceRestart) {
|
||||
try {
|
||||
if ($attemptReload && ($backend->supportsReload() || $frontend->supportsReload())) {
|
||||
$backend->reload($station);
|
||||
$frontend->reload($station);
|
||||
if ($attemptReload && ($backendEnum->isEnabled() || $frontendEnum->supportsReload())) {
|
||||
$backend?->reload($station);
|
||||
$frontend?->reload($station);
|
||||
} else {
|
||||
$this->supervisor->stopProcessGroup($backend_group);
|
||||
$this->supervisor->startProcessGroup($backend_group);
|
||||
$this->supervisor->stopProcessGroup($stationGroup);
|
||||
$this->supervisor->startProcessGroup($stationGroup);
|
||||
}
|
||||
} catch (SupervisorException) {
|
||||
}
|
||||
|
@ -310,8 +311,8 @@ class Configuration
|
|||
public function assignRadioPorts(Station $station, bool $force = false): void
|
||||
{
|
||||
if (
|
||||
FrontendAdapters::Remote !== $station->getFrontendTypeEnum()
|
||||
|| BackendAdapters::Liquidsoap !== $station->getBackendTypeEnum()
|
||||
$station->getFrontendTypeEnum()->isEnabled()
|
||||
|| $station->getBackendTypeEnum()->isEnabled()
|
||||
) {
|
||||
$frontend_config = $station->getFrontendConfig();
|
||||
$backend_config = $station->getBackendConfig();
|
||||
|
@ -444,7 +445,7 @@ class Configuration
|
|||
|
||||
protected function writeConfigurationSection(
|
||||
Station $station,
|
||||
AbstractAdapter $adapter,
|
||||
AbstractLocalAdapter $adapter,
|
||||
?int $priority
|
||||
): string {
|
||||
[, $program_name] = explode(':', $adapter->getProgramName($station));
|
||||
|
|
|
@ -10,5 +10,5 @@ interface AdapterTypeInterface
|
|||
|
||||
public function getName(): string;
|
||||
|
||||
public function getClass(): string;
|
||||
public function getClass(): ?string;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
|||
namespace App\Radio\Enums;
|
||||
|
||||
use App\Radio\Backend\Liquidsoap;
|
||||
use App\Radio\Backend\None;
|
||||
|
||||
enum BackendAdapters: string implements AdapterTypeInterface
|
||||
{
|
||||
|
@ -27,14 +26,19 @@ enum BackendAdapters: string implements AdapterTypeInterface
|
|||
};
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
public function getClass(): ?string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Liquidsoap => Liquidsoap::class,
|
||||
self::None => None::class,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return self::None !== $this;
|
||||
}
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
return self::Liquidsoap;
|
||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
|||
namespace App\Radio\Enums;
|
||||
|
||||
use App\Radio\Frontend\Icecast;
|
||||
use App\Radio\Frontend\Remote;
|
||||
use App\Radio\Frontend\Shoutcast;
|
||||
|
||||
enum FrontendAdapters: string implements AdapterTypeInterface
|
||||
|
@ -30,15 +29,33 @@ enum FrontendAdapters: string implements AdapterTypeInterface
|
|||
};
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
public function getClass(): ?string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Icecast => Icecast::class,
|
||||
self::Shoutcast => Shoutcast::class,
|
||||
self::Remote => Remote::class,
|
||||
default => null
|
||||
};
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return self::Remote !== $this;
|
||||
}
|
||||
|
||||
public function supportsMounts(): bool
|
||||
{
|
||||
return match ($this) {
|
||||
self::Shoutcast, self::Icecast => true,
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
public function supportsReload(): bool
|
||||
{
|
||||
return self::Icecast === $this;
|
||||
}
|
||||
|
||||
public static function default(): self
|
||||
{
|
||||
return self::Icecast;
|
||||
|
|
|
@ -8,8 +8,7 @@ use App\Entity;
|
|||
use App\Environment;
|
||||
use App\Http\Router;
|
||||
use App\Nginx\CustomUrls;
|
||||
use App\Radio\AbstractAdapter;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use App\Radio\AbstractLocalAdapter;
|
||||
use App\Xml\Reader;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
|
@ -24,7 +23,7 @@ use Psr\Http\Message\UriInterface;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Supervisor\SupervisorInterface;
|
||||
|
||||
abstract class AbstractFrontend extends AbstractAdapter
|
||||
abstract class AbstractFrontend extends AbstractLocalAdapter
|
||||
{
|
||||
public function __construct(
|
||||
Environment $environment,
|
||||
|
@ -41,31 +40,6 @@ abstract class AbstractFrontend extends AbstractAdapter
|
|||
parent::__construct($environment, $em, $supervisor, $dispatcher, $logger, $router);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Whether the station supports multiple mount points per station
|
||||
*/
|
||||
public function supportsMounts(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default mounts when resetting or initializing a station.
|
||||
*
|
||||
* @return Entity\StationMount[]
|
||||
*/
|
||||
public function getDefaultMounts(Entity\Station $station): array
|
||||
{
|
||||
$record = new Entity\StationMount($station);
|
||||
$record->setName('/radio.mp3');
|
||||
$record->setIsDefault(true);
|
||||
$record->setEnableAutodj(true);
|
||||
$record->setAutodjFormat(StreamFormats::Mp3->value);
|
||||
$record->setAutodjBitrate(128);
|
||||
|
||||
return [$record];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -22,16 +22,6 @@ class Icecast extends AbstractFrontend
|
|||
public const LOGLEVEL_WARN = 2;
|
||||
public const LOGLEVEL_ERROR = 1;
|
||||
|
||||
public function supportsMounts(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsReload(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function reload(Entity\Station $station): void
|
||||
{
|
||||
if ($this->hasCommand($station)) {
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Radio\Frontend;
|
||||
|
||||
use App\Entity;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
class Remote extends AbstractFrontend
|
||||
{
|
||||
public function isInstalled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getStreamUrl(Entity\Station $station, UriInterface $base_url = null): UriInterface
|
||||
{
|
||||
return new Uri('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getStreamUrls(Entity\Station $station, UriInterface $base_url = null): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getAdminUrl(Entity\Station $station, UriInterface $base_url = null): UriInterface
|
||||
{
|
||||
return new Uri('');
|
||||
}
|
||||
}
|
|
@ -13,11 +13,6 @@ use Symfony\Component\Process\Process;
|
|||
|
||||
class Shoutcast extends AbstractFrontend
|
||||
{
|
||||
public function supportsMounts(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Radio\Remote;
|
||||
|
||||
use App\Entity;
|
||||
|
||||
class AdapterProxy
|
||||
{
|
||||
public function __construct(
|
||||
protected AbstractRemote $adapter,
|
||||
protected Entity\StationRemote $remote
|
||||
) {
|
||||
}
|
||||
|
||||
public function getAdapter(): AbstractRemote
|
||||
{
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
public function getRemote(): Entity\StationRemote
|
||||
{
|
||||
return $this->remote;
|
||||
}
|
||||
}
|
|
@ -176,13 +176,13 @@ final class Acme
|
|||
$this->nginx->reload();
|
||||
|
||||
foreach ($this->stationRepo->iterateEnabledStations() as $station) {
|
||||
if (!$station->getHasStarted()) {
|
||||
$frontendType = $station->getFrontendTypeEnum();
|
||||
if (!$station->getHasStarted() || !$frontendType->supportsReload()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
||||
if ($frontend->supportsReload() && $frontend->isRunning($station)) {
|
||||
if (null !== $frontend && $frontend->isRunning($station)) {
|
||||
$frontend->reload($station);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,15 +63,11 @@ class NowPlayingTask implements NowPlayingTaskInterface, EventSubscriberInterfac
|
|||
|
||||
$include_clients = $this->settingsRepo->readSettings()->isAnalyticsEnabled();
|
||||
|
||||
$frontend_adapter = $this->adapters->getFrontendAdapter($station);
|
||||
$remote_adapters = $this->adapters->getRemoteAdapters($station);
|
||||
|
||||
// Build the new "raw" NowPlaying data.
|
||||
try {
|
||||
$event = new GenerateRawNowPlaying(
|
||||
$this->adapters,
|
||||
$station,
|
||||
$frontend_adapter,
|
||||
$remote_adapters,
|
||||
$include_clients
|
||||
);
|
||||
$this->eventDispatcher->dispatch($event);
|
||||
|
@ -121,15 +117,13 @@ class NowPlayingTask implements NowPlayingTaskInterface, EventSubscriberInterfac
|
|||
public function loadRawFromFrontend(GenerateRawNowPlaying $event): void
|
||||
{
|
||||
try {
|
||||
$result = $event
|
||||
->getFrontend()
|
||||
->getNowPlaying($event->getStation(), $event->includeClients());
|
||||
$result = $event->getFrontend()?->getNowPlaying($event->getStation(), $event->includeClients());
|
||||
if (null !== $result) {
|
||||
$event->setResult($result);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
$event->setResult($result);
|
||||
}
|
||||
|
||||
public function addToRawFromRemotes(GenerateRawNowPlaying $event): void
|
||||
|
@ -137,11 +131,11 @@ class NowPlayingTask implements NowPlayingTaskInterface, EventSubscriberInterfac
|
|||
$result = $event->getResult();
|
||||
|
||||
// Loop through all remotes and update NP data accordingly.
|
||||
foreach ($event->getRemotes() as $ra_proxy) {
|
||||
foreach ($event->getRemotes() as [$remote, $adapter]) {
|
||||
try {
|
||||
$result = $ra_proxy->getAdapter()->updateNowPlaying(
|
||||
$result = $adapter->updateNowPlaying(
|
||||
$result,
|
||||
$ra_proxy->getRemote(),
|
||||
$remote,
|
||||
$event->includeClients()
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
|
|
Loading…
Reference in New Issue