AzuraCast/src/Radio/Backend/Liquidsoap/PlaylistFileWriter.php

157 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Radio\Backend\Liquidsoap;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Entity;
use App\Event\Radio\AnnotateNextSong;
use App\Event\Radio\WriteLiquidsoapConfiguration;
use App\Exception;
use App\Flysystem\StationFilesystems;
use App\Message;
use App\Radio\Backend\Liquidsoap;
use League\Flysystem\StorageAttributes;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Filesystem\Filesystem;
use Throwable;
class PlaylistFileWriter implements EventSubscriberInterface
{
public function __construct(
protected LoggerInterface $logger,
protected EventDispatcherInterface $eventDispatcher,
protected ReloadableEntityManagerInterface $em,
protected Filesystem $fsUtils,
protected Liquidsoap $liquidsoap,
) {
}
/**
* Handle event dispatch.
*
* @param Message\AbstractMessage $message
*/
public function __invoke(Message\AbstractMessage $message): void
{
if ($message instanceof Message\WritePlaylistFileMessage) {
$playlist = $this->em->find(Entity\StationPlaylist::class, $message->playlist_id);
if ($playlist instanceof Entity\StationPlaylist) {
$this->writePlaylistFile($playlist);
$playlistVarName = ConfigWriter::getPlaylistVariableName($playlist);
$station = $playlist->getStation();
try {
$this->liquidsoap->command($station, $playlistVarName . '.reload');
} catch (Exception $e) {
$this->logger->error(
'Could not reload playlist with AutoDJ.',
[
'message' => $e->getMessage(),
'playlist' => $playlistVarName,
'station' => $station->getId(),
]
);
}
}
}
}
public static function getSubscribedEvents(): array
{
return [
WriteLiquidsoapConfiguration::class => [
['writePlaylistsForLiquidsoap', 32],
],
];
}
public function writePlaylistsForLiquidsoap(WriteLiquidsoapConfiguration $event): void
{
if ($event->shouldWriteToDisk()) {
$this->writeAllPlaylistFiles($event->getStation());
}
}
public function writeAllPlaylistFiles(Entity\Station $station): void
{
// Clear out existing playlists directory.
$fsPlaylists = (new StationFilesystems($station))->getPlaylistsFilesystem();
foreach ($fsPlaylists->listContents('', false) as $file) {
/** @var StorageAttributes $file */
if ($file->isDir()) {
$fsPlaylists->deleteDirectory($file->path());
} else {
$fsPlaylists->delete($file->path());
}
}
foreach ($station->getPlaylists() as $playlist) {
if (!$playlist->getIsEnabled()) {
continue;
}
$this->writePlaylistFile($playlist);
}
}
protected function writePlaylistFile(Entity\StationPlaylist $playlist): void
{
$station = $playlist->getStation();
$this->logger->info(
'Writing playlist file to disk...',
[
'station' => $station->getName(),
'playlist' => $playlist->getName(),
]
);
$playlistFile = [];
$mediaQuery = $this->em->createQuery(
<<<'DQL'
SELECT DISTINCT sm
FROM App\Entity\StationMedia sm
JOIN sm.playlists spm
WHERE spm.playlist = :playlist
ORDER BY spm.weight ASC
DQL
)->setParameter('playlist', $playlist);
/** @var Entity\StationMedia $mediaFile */
foreach ($mediaQuery->toIterable() as $mediaFile) {
$event = new AnnotateNextSong(
station: $station,
media: $mediaFile,
playlist: $playlist,
asAutoDj: false
);
try {
$this->eventDispatcher->dispatch($event);
$playlistFile[] = $event->buildAnnotations();
} catch (Throwable $e) {
}
}
$playlistFilePath = self::getPlaylistFilePath($playlist);
$this->fsUtils->dumpFile(
$playlistFilePath,
implode("\n", $playlistFile)
);
}
public static function getPlaylistFilePath(Entity\StationPlaylist $playlist): string
{
return $playlist->getStation()->getRadioPlaylistsDir() . '/'
. ConfigWriter::getPlaylistVariableName($playlist) . '.m3u';
}
}