AzuraCast/src/Sync/NowPlaying/Task/NowPlayingTask.php

195 lines
6.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Sync\NowPlaying\Task;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use App\Entity\Api\NowPlaying\NowPlaying;
use App\Entity\Station;
use App\Environment;
use App\Event\Radio\GenerateRawNowPlaying;
use App\Http\RouterInterface;
use App\Message;
use App\Radio\Adapters;
use DeepCopy\DeepCopy;
use Exception;
use NowPlaying\Result\Result;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBus;
class NowPlayingTask implements NowPlayingTaskInterface, EventSubscriberInterface
{
public function __construct(
protected Adapters $adapters,
protected CacheInterface $cache,
protected EventDispatcherInterface $eventDispatcher,
protected MessageBus $messageBus,
protected RouterInterface $router,
protected Entity\Repository\ListenerRepository $listenerRepo,
protected Entity\Repository\SettingsRepository $settingsRepo,
protected Entity\ApiGenerator\NowPlayingApiGenerator $nowPlayingApiGenerator,
protected ReloadableEntityManagerInterface $em,
protected LoggerInterface $logger,
) {
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents(): array
{
if (Environment::getInstance()->isTesting()) {
return [];
}
return [
GenerateRawNowPlaying::class => [
['loadRawFromFrontend', 10],
['addToRawFromRemotes', 0],
],
];
}
public function run(Station $station): void
{
if (!$station->getIsEnabled()) {
return;
}
$include_clients = $this->settingsRepo->readSettings()->isAnalyticsEnabled();
// Build the new "raw" NowPlaying data.
try {
$event = new GenerateRawNowPlaying(
$this->adapters,
$station,
$include_clients
);
$this->eventDispatcher->dispatch($event);
$npResult = $event->getResult();
} catch (Exception $e) {
$this->logger->error(
$e->getMessage(),
[
'file' => $e->getFile(),
'line' => $e->getLine(),
'code' => $e->getCode(),
]
);
$npResult = Result::blank();
}
$this->logger->debug(
'Final NowPlaying Response for Station',
[
'id' => $station->getId(),
'name' => $station->getName(),
'np' => $npResult,
]
);
// Update detailed listener statistics, if they exist for the station
if ($include_clients && null !== $npResult->clients) {
$this->listenerRepo->update($station, $npResult->clients);
}
$np = ($this->nowPlayingApiGenerator)($station, $npResult);
// Trigger the dispatching of webhooks.
$this->dispatchWebhooks($station, $np);
// Update caches
$this->cache->set('nowplaying.' . $station->getIdRequired(), $np, 120);
$this->cache->set('nowplaying.' . $station->getShortName(), $np, 120);
$station->setNowplaying($np);
$this->em->persist($station);
$this->em->flush();
}
public function loadRawFromFrontend(GenerateRawNowPlaying $event): void
{
try {
$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()));
}
}
public function addToRawFromRemotes(GenerateRawNowPlaying $event): void
{
$result = $event->getResult();
// Loop through all remotes and update NP data accordingly.
foreach ($event->getRemotes() as [$remote, $adapter]) {
try {
$result = $adapter->updateNowPlaying(
$result,
$remote,
$event->includeClients()
);
} catch (Exception $e) {
$this->logger->error(sprintf('NowPlaying adapter error: %s', $e->getMessage()));
}
}
$event->setResult($result);
}
protected function dispatchWebhooks(
Entity\Station $station,
NowPlaying $npOriginal
): void {
/** @var NowPlaying $np */
$np = (new DeepCopy())->copy($npOriginal);
$np->resolveUrls($this->router->getBaseUrl());
$np->cache = 'event';
$npOld = $station->getNowplaying();
$triggers = [
Entity\StationWebhook::TRIGGER_ALL,
];
if ($npOld instanceof NowPlaying) {
if ($npOld->now_playing?->song?->id !== $np->now_playing?->song?->id) {
$triggers[] = Entity\StationWebhook::TRIGGER_SONG_CHANGED;
}
if ($npOld->listeners->current > $np->listeners->current) {
$triggers[] = Entity\StationWebhook::TRIGGER_LISTENER_LOST;
} elseif ($npOld->listeners->current < $np->listeners->current) {
$triggers[] = Entity\StationWebhook::TRIGGER_LISTENER_GAINED;
}
if (!$npOld->live->is_live && $np->live->is_live) {
$triggers[] = Entity\StationWebhook::TRIGGER_LIVE_CONNECT;
} elseif ($npOld->live->is_live && !$np->live->is_live) {
$triggers[] = Entity\StationWebhook::TRIGGER_LIVE_DISCONNECT;
}
if ($npOld->is_online && !$np->is_online) {
$triggers[] = Entity\StationWebhook::TRIGGER_STATION_OFFLINE;
} elseif (!$npOld->is_online && $np->is_online) {
$triggers[] = Entity\StationWebhook::TRIGGER_STATION_ONLINE;
}
}
$message = new Message\DispatchWebhookMessage();
$message->station_id = (int)$station->getId();
$message->np = $np;
$message->triggers = $triggers;
$this->messageBus->dispatch($message);
}
}