AzuraCast/src/Controller/Api/NowplayingController.php

151 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controller\Api;
use App\Entity;
use App\Event\Radio\LoadNowPlaying;
use App\Http\Response;
use App\Http\ServerRequest;
use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Annotations as OA;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class NowplayingController implements EventSubscriberInterface
{
public function __construct(
protected EntityManagerInterface $em,
protected Entity\Repository\SettingsRepository $settingsRepo,
protected CacheInterface $cache,
protected EventDispatcherInterface $dispatcher
) {
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2')))
*
* @return mixed[] The event names to listen to
*/
public static function getSubscribedEvents(): array
{
return [
LoadNowPlaying::class => [
['loadFromCache', 5],
['loadFromSettings', 0],
['loadFromStations', -5],
],
];
}
/**
* @OA\Get(path="/nowplaying",
* tags={"Now Playing"},
* description="Returns a full summary of all stations' current state.",
* parameters={},
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/Api_NowPlaying"))
* )
* )
*
* @OA\Get(path="/nowplaying/{station_id}",
* tags={"Now Playing"},
* description="Returns a full summary of the specified station's current state.",
* @OA\Parameter(ref="#/components/parameters/station_id_required"),
* @OA\Response(
* response=200,
* description="Success",
* @OA\JsonContent(ref="#/components/schemas/Api_NowPlaying")
* ),
* @OA\Response(response=404, description="Station not found")
* )
*
* @param ServerRequest $request
* @param Response $response
* @param int|string|null $station_id
*/
public function __invoke(
ServerRequest $request,
Response $response,
$station_id = null
): ResponseInterface {
$router = $request->getRouter();
// Pull NP data from the fastest/first available source using the EventDispatcher.
$event = new LoadNowPlaying();
$this->dispatcher->dispatch($event);
if (!$event->hasNowPlaying()) {
return $response->withStatus(408)
->withJson(new Entity\Api\Error(408, 'Now Playing data has not loaded yet. Please try again later.'));
}
if (!empty($station_id)) {
$npStation = $event->getForStation($station_id);
if (null !== $npStation) {
$npStation->resolveUrls($router->getBaseUrl());
return $response->withJson($npStation);
}
return $response->withStatus(404)
->withJson(Entity\Api\Error::notFound());
}
// If unauthenticated, hide non-public stations from full view.
$np = ($request->getAttribute('user') === null)
? $event->getAllPublic()
: $event->getNowPlaying();
foreach ($np as $npRow) {
$npRow->resolveUrls($router->getBaseUrl());
}
return $response->withJson($np);
}
public function loadFromCache(LoadNowPlaying $event): void
{
$event->setNowPlaying((array)$this->cache->get('nowplaying'), 'redis');
}
public function loadFromSettings(LoadNowPlaying $event): void
{
$settings = $this->settingsRepo->readSettings();
$event->setNowPlaying((array)$settings->getNowplaying(), 'settings');
}
public function loadFromStations(LoadNowPlaying $event): void
{
$nowplaying_db = $this->em->createQuery(
<<<'DQL'
SELECT s.nowplaying FROM App\Entity\Station s WHERE s.is_enabled = 1
DQL
)->getArrayResult();
$np = [];
foreach ($nowplaying_db as $np_row) {
$np[] = $np_row['nowplaying'];
}
$event->setNowPlaying($np, 'station');
}
}