AzuraCast/src/Controller/Api/Admin/RelaysController.php

182 lines
5.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controller\Api\Admin;
use App\Acl;
use App\Entity;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Adapters;
use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Annotations as OA;
use Psr\Http\Message\ResponseInterface;
/**
* @OA\Get(path="/internal/relays",
* operationId="internalGetRelayDetails",
* tags={"Administration: Relays"},
* description="Returns all necessary information to relay all 'relayable' stations.",
* parameters={},
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/Api_Admin_Relay"))
* )
* )
*/
class RelaysController
{
public function __construct(
protected EntityManagerInterface $em,
protected Adapters $adapters
) {
}
public function __invoke(ServerRequest $request, Response $response): ResponseInterface
{
$stations = $this->getManageableStations($request);
$router = $request->getRouter();
$return = [];
foreach ($stations as $station) {
$fa = $this->adapters->getFrontendAdapter($station);
$row = new Entity\Api\Admin\Relay();
$row->id = $station->getIdRequired();
$row->name = $station->getName();
$row->shortcode = $station->getShortName();
$row->description = $station->getDescription();
$row->url = $station->getUrl();
$row->genre = $station->getGenre();
$row->type = $station->getFrontendType();
$frontend_config = $station->getFrontendConfig();
$row->port = $frontend_config->getPort();
$row->relay_pw = $frontend_config->getRelayPassword();
$row->admin_pw = $frontend_config->getAdminPassword();
$mounts = [];
if ($station->getMounts()->count() > 0) {
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
$mounts[] = $mount->api($fa);
}
}
$row->mounts = $mounts;
$row->resolveUrls($router->getBaseUrl());
$return[] = $row;
}
return $response->withJson($return);
}
/**
* @param ServerRequest $request
*
* @return Entity\Station[]
*/
protected function getManageableStations(ServerRequest $request): array
{
$all_stations = $this->em->createQuery(
<<<'DQL'
SELECT s, sm
FROM App\Entity\Station s
JOIN s.mounts sm
WHERE s.is_enabled = 1
AND s.frontend_type != :remote_frontend
DQL
)->setParameter('remote_frontend', Adapters::FRONTEND_REMOTE)
->execute();
$acl = $request->getAcl();
return array_filter(
$all_stations,
static function (Entity\Station $station) use ($acl) {
return $acl->isAllowed(Acl::STATION_BROADCASTING, $station->getId());
}
);
}
public function updateAction(ServerRequest $request, Response $response): ResponseInterface
{
$relay_repo = $this->em->getRepository(Entity\Relay::class);
$body = (array)$request->getParsedBody();
if (!empty($body['base_url'])) {
$base_url = $body['base_url'];
} else {
/** @noinspection HttpUrlsUsage */
$base_url = 'http://' . $request->getIp();
}
$relay = $relay_repo->findOneBy(['base_url' => $base_url]);
if (!$relay instanceof Entity\Relay) {
$relay = new Entity\Relay($base_url);
}
$relay->setName($body['name'] ?? 'Relay');
$relay->setIsVisibleOnPublicPages($body['is_visible_on_public_pages'] ?? true);
$relay->setNowplaying((array)$body['nowplaying']);
$relay->setUpdatedAt(time());
$this->em->persist($relay);
// List existing remotes to avoid duplication.
$existing_remotes = [];
foreach ($relay->getRemotes() as $remote) {
/** @var Entity\StationRemote $remote */
$existing_remotes[$remote->getStation()->getId()][$remote->getMount()] = $remote;
}
// Iterate through all remotes that *should* exist.
foreach ($this->getManageableStations($request) as $station) {
$station_id = $station->getId();
foreach ($station->getMounts() as $mount) {
/** @var Entity\StationMount $mount */
$mount_path = $mount->getName();
if (isset($existing_remotes[$station_id][$mount_path])) {
/** @var Entity\StationRemote $remote */
$remote = $existing_remotes[$station_id][$mount_path];
unset($existing_remotes[$station_id][$mount_path]);
} else {
$remote = new Entity\StationRemote($station);
}
$remote->setRelay($relay);
$remote->setType(Adapters::REMOTE_AZURARELAY);
$remote->setDisplayName($mount->getDisplayName() . ' (' . $relay->getName() . ')');
$remote->setIsVisibleOnPublicPages($relay->getIsVisibleOnPublicPages());
$remote->setAutodjBitrate($mount->getAutodjBitrate());
$remote->setAutodjFormat($mount->getAutodjFormat());
$remote->setUrl($relay->getBaseUrl());
$remote->setMount($mount->getName());
$this->em->persist($remote);
}
}
// Remove all remotes that weren't processed earlier.
foreach ($existing_remotes as $existing_remote_station) {
foreach ($existing_remote_station as $existing_remote) {
$this->em->remove($existing_remote);
}
}
$this->em->flush();
return $response->withJson(Entity\Api\Status::success());
}
}