Code quality cleanup sweep.
This commit is contained in:
parent
fe61967c50
commit
a9f066602c
|
@ -6,10 +6,9 @@ declare(strict_types=1);
|
|||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$cli = App\AppFactory::createCli(
|
||||
$autoloader,
|
||||
[
|
||||
App\Environment::BASE_DIR => dirname(__DIR__),
|
||||
]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"ext-iconv": "*",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-maxminddb": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-redis": "*",
|
||||
|
|
|
@ -8,10 +8,8 @@ use App\Console\Application;
|
|||
use App\Enums\SupportedLocales;
|
||||
use App\Http\Factory\ResponseFactory;
|
||||
use App\Http\Factory\ServerRequestFactory;
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use DI;
|
||||
use DI\Bridge\Slim\ControllerInvoker;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use Invoker\Invoker;
|
||||
use Invoker\ParameterResolver\AssociativeArrayResolver;
|
||||
use Invoker\ParameterResolver\Container\TypeHintContainerResolver;
|
||||
|
@ -31,33 +29,19 @@ use const E_USER_ERROR;
|
|||
|
||||
class AppFactory
|
||||
{
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
*/
|
||||
public static function createApp(
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): App {
|
||||
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
|
||||
$di = self::buildContainer($appEnvironment, $diDefinitions);
|
||||
return self::buildAppFromContainer($di);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
*/
|
||||
public static function createCli(
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): Application {
|
||||
$di = self::buildContainer($autoloader, $appEnvironment, $diDefinitions);
|
||||
$di = self::buildContainer($appEnvironment, $diDefinitions);
|
||||
self::buildAppFromContainer($di);
|
||||
|
||||
$env = $di->get(Environment::class);
|
||||
|
@ -106,24 +90,10 @@ class AppFactory
|
|||
return $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassLoader|null $autoloader
|
||||
* @param array<string, mixed> $appEnvironment
|
||||
* @param array<string, mixed> $diDefinitions
|
||||
*
|
||||
* @noinspection SummerTimeUnsafeTimeManipulationInspection
|
||||
*
|
||||
*/
|
||||
public static function buildContainer(
|
||||
?ClassLoader $autoloader = null,
|
||||
array $appEnvironment = [],
|
||||
array $diDefinitions = []
|
||||
): DI\Container {
|
||||
// Register Annotation autoloader
|
||||
if (null !== $autoloader) {
|
||||
AnnotationRegistry::registerLoader([$autoloader, 'loadClass']);
|
||||
}
|
||||
|
||||
$environment = self::buildEnvironment($appEnvironment);
|
||||
Environment::setInstance($environment);
|
||||
|
||||
|
@ -132,22 +102,20 @@ class AppFactory
|
|||
// Override DI definitions for settings.
|
||||
$diDefinitions[Environment::class] = $environment;
|
||||
|
||||
if ($autoloader) {
|
||||
$plugins = new Plugins($environment->getBaseDirectory() . '/plugins');
|
||||
|
||||
$diDefinitions[Plugins::class] = $plugins;
|
||||
$diDefinitions = $plugins->registerServices($diDefinitions);
|
||||
}
|
||||
|
||||
$containerBuilder = new DI\ContainerBuilder();
|
||||
$containerBuilder->useAutowiring(true);
|
||||
|
||||
/*
|
||||
$containerBuilder->enableDefinitionCache();
|
||||
// TODO Implement APCu
|
||||
// $containerBuilder->enableDefinitionCache();
|
||||
|
||||
if ($environment->isProduction()) {
|
||||
$containerBuilder->enableCompilation($environment->getTempDirectory());
|
||||
}
|
||||
*/
|
||||
|
||||
$containerBuilder->addDefinitions($diDefinitions);
|
||||
|
||||
|
|
|
@ -253,9 +253,9 @@ class Assets
|
|||
|
||||
$this->addInlineJs(
|
||||
<<<JS
|
||||
let ${name};
|
||||
let {$name};
|
||||
$(function () {
|
||||
${name} = ${nameWithoutPrefix}.default('${elementId}', ${propsJson});
|
||||
{$name} = {$nameWithoutPrefix}.default('{$elementId}', {$propsJson});
|
||||
});
|
||||
JS
|
||||
);
|
||||
|
|
|
@ -15,6 +15,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use Throwable;
|
||||
|
||||
use const PATHINFO_EXTENSION;
|
||||
|
||||
|
@ -101,7 +102,7 @@ class BackupCommand extends AbstractBackupCommand
|
|||
$tmp_dir_mariadb = '/tmp/azuracast_backup_mariadb';
|
||||
try {
|
||||
$fsUtils->mkdir($tmp_dir_mariadb);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$io->error($e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use App\Entity;
|
|||
use App\Entity\Repository\StationRepository;
|
||||
use App\Radio\Backend\Liquidsoap\Command\AbstractCommand;
|
||||
use App\Radio\Enums\LiquidsoapCommands;
|
||||
use LogicException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
@ -17,6 +18,7 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Throwable;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'azuracast:internal:liquidsoap',
|
||||
|
@ -62,12 +64,12 @@ class LiquidsoapCommand extends CommandAbstract
|
|||
try {
|
||||
$station = $this->stationRepo->findByIdentifier($stationId);
|
||||
if (!($station instanceof Entity\Station)) {
|
||||
throw new \LogicException('Station not found.');
|
||||
throw new LogicException('Station not found.');
|
||||
}
|
||||
|
||||
$command = LiquidsoapCommands::tryFrom($action);
|
||||
if (null === $command || !$this->di->has($command->getClass())) {
|
||||
throw new \LogicException('Command not found.');
|
||||
throw new LogicException('Command not found.');
|
||||
}
|
||||
|
||||
/** @var AbstractCommand $commandObj */
|
||||
|
@ -75,7 +77,7 @@ class LiquidsoapCommand extends CommandAbstract
|
|||
|
||||
$result = $commandObj->run($station, $asAutoDj, $payload);
|
||||
$io->writeln($result);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
sprintf(
|
||||
'Liquidsoap command "%s" error: %s',
|
||||
|
|
|
@ -65,7 +65,7 @@ class SftpEventCommand extends CommandAbstract
|
|||
$storageLocation = $sftpUser->getStation()->getMediaStorageLocation();
|
||||
|
||||
if (!$storageLocation->isLocal()) {
|
||||
$this->logger->error(sprintf('Storage location "%s" is not local.', (string)$storageLocation));
|
||||
$this->logger->error(sprintf('Storage location "%s" is not local.', $storageLocation));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Throwable;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'azuracast:radio:restart',
|
||||
|
@ -73,7 +74,7 @@ class RestartRadioCommand extends CommandAbstract
|
|||
reloadSupervisor: !$noSupervisorRestart,
|
||||
forceRestart: true
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$io->error([
|
||||
$station . ': ' . $e->getMessage(),
|
||||
]);
|
||||
|
|
|
@ -12,6 +12,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
use Symfony\Component\Lock\Lock;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
use function random_int;
|
||||
|
||||
abstract class AbstractSyncCommand extends CommandAbstract
|
||||
{
|
||||
protected array $processes = [];
|
||||
|
@ -34,7 +36,7 @@ abstract class AbstractSyncCommand extends CommandAbstract
|
|||
$process = $processGroup['process'];
|
||||
|
||||
// 10% chance that refresh will be called
|
||||
if (\random_int(1, 100) <= 10) {
|
||||
if (random_int(1, 100) <= 10) {
|
||||
$lock->refresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ use Symfony\Component\Console\Input\InputOption;
|
|||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function random_int;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'azuracast:sync:nowplaying',
|
||||
description: 'Task to run the Now Playing worker task.'
|
||||
|
@ -81,7 +83,7 @@ class NowPlayingCommand extends AbstractSyncCommand
|
|||
|
||||
if (!isset($this->processes[$shortName])) {
|
||||
$npTimestamp = (int)$activeStation['nowplaying_timestamp'];
|
||||
if (time() > $npTimestamp + \random_int(5, 15)) {
|
||||
if (time() > $npTimestamp + random_int(5, 15)) {
|
||||
$this->start($io, $shortName);
|
||||
|
||||
usleep(250000);
|
||||
|
|
|
@ -15,6 +15,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Throwable;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'azuracast:sync:nowplaying:station',
|
||||
|
@ -63,7 +64,7 @@ class NowPlayingPerStationCommand extends CommandAbstract
|
|||
|
||||
try {
|
||||
$this->buildQueueTask->run($station);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
'Queue builder error: ' . $e->getMessage(),
|
||||
['exception' => $e]
|
||||
|
@ -72,7 +73,7 @@ class NowPlayingPerStationCommand extends CommandAbstract
|
|||
|
||||
try {
|
||||
$this->nowPlayingTask->run($station);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
'Now Playing error: ' . $e->getMessage(),
|
||||
['exception' => $e]
|
||||
|
|
|
@ -8,8 +8,10 @@ use App\Entity\Repository\SettingsRepository;
|
|||
use App\Environment;
|
||||
use App\Event\GetSyncTasks;
|
||||
use App\LockFactory;
|
||||
use App\Sync\Task\AbstractTask;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Cron\CronExpression;
|
||||
use DateTimeZone;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
@ -17,6 +19,8 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function usleep;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'azuracast:sync:run',
|
||||
description: 'Task to run the minute\'s synchronized tasks.'
|
||||
|
@ -46,7 +50,7 @@ class RunnerCommand extends AbstractSyncCommand
|
|||
$syncTasksEvent = new GetSyncTasks();
|
||||
$this->dispatcher->dispatch($syncTasksEvent);
|
||||
|
||||
$now = CarbonImmutable::now(new \DateTimeZone('UTC'));
|
||||
$now = CarbonImmutable::now(new DateTimeZone('UTC'));
|
||||
|
||||
foreach ($syncTasksEvent->getTasks() as $taskClass) {
|
||||
$schedulePattern = $taskClass::getSchedulePattern();
|
||||
|
@ -71,12 +75,12 @@ class RunnerCommand extends AbstractSyncCommand
|
|||
$this->checkRunningProcesses();
|
||||
}
|
||||
|
||||
\usleep(250000);
|
||||
usleep(250000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SymfonyStyle $io
|
||||
* @param class-string $taskClass
|
||||
* @param class-string<AbstractTask> $taskClass
|
||||
*/
|
||||
protected function start(
|
||||
SymfonyStyle $io,
|
||||
|
|
|
@ -6,9 +6,11 @@ namespace App\Console\Command\Sync;
|
|||
|
||||
use App\Console\Command\CommandAbstract;
|
||||
use App\Sync\Task\AbstractTask;
|
||||
use InvalidArgumentException;
|
||||
use Monolog\Logger;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use ReflectionClass;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
@ -43,7 +45,7 @@ class SingleTaskCommand extends CommandAbstract
|
|||
|
||||
try {
|
||||
$this->runTask($task);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$io->error($e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
|
@ -60,12 +62,12 @@ class SingleTaskCommand extends CommandAbstract
|
|||
bool $force = false
|
||||
): void {
|
||||
if (!$this->di->has($task)) {
|
||||
throw new \InvalidArgumentException('Task not found.');
|
||||
throw new InvalidArgumentException('Task not found.');
|
||||
}
|
||||
|
||||
$taskClass = $this->di->get($task);
|
||||
if (!($taskClass instanceof AbstractTask)) {
|
||||
throw new \InvalidArgumentException('Specified class is not a synchronized task.');
|
||||
throw new InvalidArgumentException('Specified class is not a synchronized task.');
|
||||
}
|
||||
|
||||
$taskShortName = self::getClassShortName($task);
|
||||
|
@ -106,6 +108,6 @@ class SingleTaskCommand extends CommandAbstract
|
|||
*/
|
||||
public static function getClassShortName(string $taskClass): string
|
||||
{
|
||||
return (new \ReflectionClass($taskClass))->getShortName();
|
||||
return (new ReflectionClass($taskClass))->getShortName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use App\Session\Flash;
|
|||
use App\Sync\NowPlaying\Task\NowPlayingTask;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Cron\CronExpression;
|
||||
use DateTimeZone;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Monolog\Handler\TestHandler;
|
||||
use Monolog\Logger;
|
||||
|
@ -55,7 +56,7 @@ class DebugController extends AbstractLogViewerController
|
|||
}
|
||||
|
||||
$syncTimes = [];
|
||||
$now = CarbonImmutable::now(new \DateTimeZone('UTC'));
|
||||
$now = CarbonImmutable::now(new DateTimeZone('UTC'));
|
||||
$syncTasksEvent = new GetSyncTasks();
|
||||
$dispatcher->dispatch($syncTasksEvent);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Controller\Admin;
|
|||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class ShoutcastAction
|
||||
{
|
||||
|
@ -15,7 +16,7 @@ class ShoutcastAction
|
|||
Response $response
|
||||
): ResponseInterface {
|
||||
if ('x86_64' !== php_uname('m')) {
|
||||
throw new \RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
|
||||
throw new RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
|
||||
}
|
||||
|
||||
$router = $request->getRouter();
|
||||
|
|
|
@ -29,8 +29,8 @@ class StationsAction
|
|||
$stationFormComponent->getProps($request),
|
||||
[
|
||||
'listUrl' => (string)$router->fromHere('api:admin:stations'),
|
||||
'frontendTypes' => $adapters->listFrontendAdapters(false),
|
||||
'backendTypes' => $adapters->listBackendAdapters(false),
|
||||
'frontendTypes' => $adapters->listFrontendAdapters(),
|
||||
'backendTypes' => $adapters->listBackendAdapters(),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
|
|
@ -21,6 +21,6 @@ class GetLogAction
|
|||
): ResponseInterface {
|
||||
$logPath = File::validateTempPath($path);
|
||||
|
||||
return $this->streamLogToResponse($request, $response, $logPath, true);
|
||||
return $this->streamLogToResponse($request, $response, $logPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use App\Http\Response;
|
|||
use App\Http\ServerRequest;
|
||||
use App\Service\Flow;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class PostAction
|
||||
|
@ -20,7 +21,7 @@ class PostAction
|
|||
Environment $environment
|
||||
): ResponseInterface {
|
||||
if ('x86_64' !== php_uname('m')) {
|
||||
throw new \RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
|
||||
throw new RuntimeException('SHOUTcast cannot be installed on non-X86_64 systems.');
|
||||
}
|
||||
|
||||
$flowResponse = Flow::process($request, $response);
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Http\ServerRequest;
|
|||
use DeepCopy;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
class CloneAction extends StationsController
|
||||
{
|
||||
|
@ -186,7 +187,7 @@ class CloneAction extends StationsController
|
|||
|
||||
try {
|
||||
$this->configuration->writeConfiguration($newStation);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
|
|
@ -20,6 +20,7 @@ use Symfony\Component\Filesystem\Filesystem;
|
|||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Throwable;
|
||||
|
||||
/** @extends AbstractAdminApiCrudController<Entity\Station> */
|
||||
#[
|
||||
|
@ -331,7 +332,7 @@ class StationsController extends AbstractAdminApiCrudController
|
|||
station: $station,
|
||||
forceRestart: true
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class DeleteTwoFactorAction extends UsersController
|
|||
$user = $request->getUser();
|
||||
$user = $this->em->refetch($user);
|
||||
|
||||
$user->setTwoFactorSecret(null);
|
||||
$user->setTwoFactorSecret();
|
||||
$this->em->persist($user);
|
||||
$this->em->flush();
|
||||
|
||||
|
|
|
@ -9,9 +9,12 @@ use App\Http\Response;
|
|||
use App\Http\ServerRequest;
|
||||
use App\Radio\Backend\Liquidsoap\Command\AbstractCommand;
|
||||
use App\Radio\Enums\LiquidsoapCommands;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
class LiquidsoapAction
|
||||
{
|
||||
|
@ -31,13 +34,13 @@ class LiquidsoapAction
|
|||
if (!$acl->isAllowed(StationPermissions::View, $station->getIdRequired())) {
|
||||
$authKey = $request->getHeaderLine('X-Liquidsoap-Api-Key');
|
||||
if (!$station->validateAdapterApiKey($authKey)) {
|
||||
throw new \RuntimeException('Invalid API key.');
|
||||
throw new RuntimeException('Invalid API key.');
|
||||
}
|
||||
}
|
||||
|
||||
$command = LiquidsoapCommands::tryFrom($action);
|
||||
if (null === $command || !$di->has($command->getClass())) {
|
||||
throw new \InvalidArgumentException('Command not found.');
|
||||
throw new InvalidArgumentException('Command not found.');
|
||||
}
|
||||
|
||||
/** @var AbstractCommand $commandObj */
|
||||
|
@ -45,7 +48,7 @@ class LiquidsoapAction
|
|||
|
||||
$result = $commandObj->run($station, $asAutoDj, $payload);
|
||||
$response->getBody()->write((string)$result);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$logger->error(
|
||||
sprintf(
|
||||
'Liquidsoap command "%s" error: %s',
|
||||
|
|
|
@ -24,6 +24,7 @@ use InvalidArgumentException;
|
|||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Messenger\MessageBus;
|
||||
use Throwable;
|
||||
|
||||
|
@ -306,7 +307,7 @@ class BatchAction
|
|||
$result = $this->parseRequest($request, $fs, true);
|
||||
|
||||
if (BackendAdapters::Liquidsoap !== $station->getBackendTypeEnum()) {
|
||||
throw new \RuntimeException('This functionality can only be used on stations that use Liquidsoap.');
|
||||
throw new RuntimeException('This functionality can only be used on stations that use Liquidsoap.');
|
||||
}
|
||||
|
||||
/** @var Liquidsoap $backend */
|
||||
|
@ -336,7 +337,7 @@ class BatchAction
|
|||
|
||||
$newQueue = Entity\StationQueue::fromMedia($station, $media);
|
||||
$newQueue->setTimestampCued($cuedTimestamp);
|
||||
$newQueue->setIsPlayed(true);
|
||||
$newQueue->setIsPlayed();
|
||||
$this->em->persist($newQueue);
|
||||
|
||||
$event = AnnotateNextSong::fromStationQueue($newQueue, true);
|
||||
|
|
|
@ -13,6 +13,7 @@ use App\Radio\Backend\Liquidsoap;
|
|||
use App\Radio\Backend\Liquidsoap\ConfigWriter;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
class PutAction
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ class PutAction
|
|||
|
||||
$config = $event->buildConfiguration();
|
||||
$liquidsoap->verifyConfig($config);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return $response->withStatus(500)->withJson(Entity\Api\Error::fromException($e));
|
||||
}
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ class PodcastEpisodesController extends AbstractApiCrudController
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function viewRecord(object $record, ServerRequest $request): mixed
|
||||
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\PodcastEpisode
|
||||
{
|
||||
if (!($record instanceof Entity\PodcastEpisode)) {
|
||||
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
||||
|
|
|
@ -268,16 +268,10 @@ class PodcastsController extends AbstractApiCrudController
|
|||
*/
|
||||
protected function getRecord(Entity\Station $station, string $id): ?object
|
||||
{
|
||||
$record = $this->podcastRepository->fetchPodcastForStation($station, $id);
|
||||
return $record;
|
||||
return $this->podcastRepository->fetchPodcastForStation($station, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Podcast $record
|
||||
* @param ServerRequest $request
|
||||
*
|
||||
*/
|
||||
protected function viewRecord(object $record, ServerRequest $request): mixed
|
||||
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\Podcast
|
||||
{
|
||||
if (!($record instanceof Entity\Podcast)) {
|
||||
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
||||
|
|
|
@ -179,7 +179,7 @@ class RemotesController extends AbstractStationApiCrudController
|
|||
return $this->listPaginatedFromQuery($request, $response, $qb->getQuery());
|
||||
}
|
||||
|
||||
protected function viewRecord(object $record, ServerRequest $request): mixed
|
||||
protected function viewRecord(object $record, ServerRequest $request): Entity\Api\StationRemote
|
||||
{
|
||||
if (!($record instanceof Entity\StationRemote)) {
|
||||
throw new InvalidArgumentException(
|
||||
|
|
|
@ -14,6 +14,7 @@ use App\Radio\Configuration;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
#[
|
||||
OA\Get(
|
||||
|
@ -136,7 +137,7 @@ class ServicesController
|
|||
station: $station,
|
||||
forceRestart: true
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return $response->withJson(
|
||||
new Entity\Api\Error(
|
||||
500,
|
||||
|
@ -159,7 +160,7 @@ class ServicesController
|
|||
forceRestart: true,
|
||||
attemptReload: false
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return $response->withJson(
|
||||
new Entity\Api\Error(
|
||||
500,
|
||||
|
|
|
@ -37,8 +37,7 @@ class TestLogAction extends AbstractWebhooksAction
|
|||
return $this->streamLogToResponse(
|
||||
$request,
|
||||
$response,
|
||||
$tempPath,
|
||||
true
|
||||
$tempPath
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ class Customization
|
|||
$this->user = $request->getAttribute(ServerRequest::ATTR_USER);
|
||||
|
||||
// Register current theme
|
||||
$this->theme = $this->determineTheme($request, false);
|
||||
$this->theme = $this->determineTheme($request);
|
||||
$this->publicTheme = $this->determineTheme($request, true);
|
||||
|
||||
// Register locale
|
||||
|
@ -114,7 +114,7 @@ class Customization
|
|||
|
||||
$publicCss .= <<<CSS
|
||||
[data-theme] body.page-minimal {
|
||||
background-image: url('${backgroundUrl}');
|
||||
background-image: url('{$backgroundUrl}');
|
||||
}
|
||||
CSS;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class DecoratedEntityManager extends EntityManagerDecorator implements Reloadabl
|
|||
public function __construct(callable $createEm)
|
||||
{
|
||||
parent::__construct($createEm());
|
||||
$this->createEm = Closure::fromCallable($createEm);
|
||||
$this->createEm = $createEm(...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,9 +67,7 @@ class NowPlaying implements ResolvableUrlInterface
|
|||
*/
|
||||
public function resolveUrls(UriInterface $base): void
|
||||
{
|
||||
if ($this->station instanceof ResolvableUrlInterface) {
|
||||
$this->station->resolveUrls($base);
|
||||
}
|
||||
|
||||
if ($this->now_playing instanceof ResolvableUrlInterface) {
|
||||
$this->now_playing->resolveUrls($base);
|
||||
|
|
|
@ -60,8 +60,6 @@ class SongHistory implements ResolvableUrlInterface
|
|||
*/
|
||||
public function resolveUrls(UriInterface $base): void
|
||||
{
|
||||
if ($this->song instanceof ResolvableUrlInterface) {
|
||||
$this->song->resolveUrls($base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,8 +55,6 @@ class StationQueue implements ResolvableUrlInterface
|
|||
*/
|
||||
public function resolveUrls(UriInterface $base): void
|
||||
{
|
||||
if ($this->song instanceof ResolvableUrlInterface) {
|
||||
$this->song->resolveUrls($base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,11 +126,7 @@ class NowPlayingApiGenerator
|
|||
?UriInterface $baseUri = null
|
||||
): Entity\Api\NowPlaying\NowPlaying {
|
||||
$np = $station->getNowplaying();
|
||||
if (null !== $np) {
|
||||
return $np;
|
||||
}
|
||||
|
||||
return $this->offlineApi($station, $baseUri);
|
||||
return $np ?? $this->offlineApi($station, $baseUri);
|
||||
}
|
||||
|
||||
protected function offlineApi(
|
||||
|
|
|
@ -5,9 +5,10 @@ declare(strict_types=1);
|
|||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JsonSerializable;
|
||||
|
||||
#[ORM\Embeddable]
|
||||
class ListenerDevice implements \JsonSerializable
|
||||
class ListenerDevice implements JsonSerializable
|
||||
{
|
||||
#[ORM\Column(length: 255)]
|
||||
protected ?string $client = null;
|
||||
|
@ -57,7 +58,7 @@ class ListenerDevice implements \JsonSerializable
|
|||
return $this->os_family;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'client' => $this->client,
|
||||
|
|
|
@ -5,9 +5,10 @@ declare(strict_types=1);
|
|||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JsonSerializable;
|
||||
|
||||
#[ORM\Embeddable]
|
||||
class ListenerLocation implements \JsonSerializable
|
||||
class ListenerLocation implements JsonSerializable
|
||||
{
|
||||
#[ORM\Column(length: 255, nullable: false)]
|
||||
protected string $description = 'Unknown';
|
||||
|
@ -57,7 +58,7 @@ class ListenerLocation implements \JsonSerializable
|
|||
return $this->lon;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'description' => $this->description,
|
||||
|
|
|
@ -17,17 +17,17 @@ final class Version20180425050351 extends AbstractMigration
|
|||
*/
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->changeCharset('utf8mb4', 'utf8mb4_bin');
|
||||
$this->changeCharset('utf8mb4_bin');
|
||||
}
|
||||
|
||||
private function changeCharset(string $charset, string $collate): void
|
||||
private function changeCharset(string $collate): void
|
||||
{
|
||||
$sqlLines = [
|
||||
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
|
||||
'ALTER TABLE `song_history` DROP FOREIGN KEY FK_2AD16164A0BDB2F3',
|
||||
'ALTER TABLE `station_media` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
|
||||
'ALTER TABLE `song_history` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
|
||||
'ALTER TABLE `songs` CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate,
|
||||
'ALTER TABLE `station_media` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
|
||||
'ALTER TABLE `song_history` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
|
||||
'ALTER TABLE `songs` CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate,
|
||||
'ALTER TABLE `song_history` ADD CONSTRAINT FK_2AD16164A0BDB2F3 FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE CASCADE',
|
||||
'ALTER TABLE `station_media` ADD CONSTRAINT FK_32AADE3AA0BDB2F3 FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE SET NULL',
|
||||
];
|
||||
|
@ -42,6 +42,6 @@ final class Version20180425050351 extends AbstractMigration
|
|||
*/
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
|
||||
$this->changeCharset('utf8mb4_unicode_ci');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ final class Version20180826043500 extends AbstractMigration
|
|||
*/
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->changeCharset('utf8mb4', 'utf8mb4_general_ci');
|
||||
$this->changeCharset('utf8mb4_general_ci');
|
||||
}
|
||||
|
||||
private function changeCharset(string $charset, string $collate): void
|
||||
private function changeCharset(string $collate): void
|
||||
{
|
||||
$db_name = $this->connection->getDatabase() ?? 'azuracast';
|
||||
|
||||
|
@ -51,7 +51,9 @@ final class Version20180826043500 extends AbstractMigration
|
|||
];
|
||||
|
||||
$sqlLines = [
|
||||
'ALTER DATABASE ' . $this->connection->quoteIdentifier($db_name) . ' CHARACTER SET = ' . $charset . ' COLLATE = ' . $collate,
|
||||
'ALTER DATABASE ' . $this->connection->quoteIdentifier(
|
||||
$db_name
|
||||
) . ' CHARACTER SET = utf8mb4 COLLATE = ' . $collate,
|
||||
'ALTER TABLE `song_history` DROP FOREIGN KEY FK_2AD16164A0BDB2F3',
|
||||
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
|
||||
];
|
||||
|
@ -60,7 +62,11 @@ final class Version20180826043500 extends AbstractMigration
|
|||
}
|
||||
|
||||
foreach ($tables as $table_name) {
|
||||
$this->addSql('ALTER TABLE ' . $this->connection->quoteIdentifier($table_name) . ' CONVERT TO CHARACTER SET ' . $charset . ' COLLATE ' . $collate);
|
||||
$this->addSql(
|
||||
'ALTER TABLE ' . $this->connection->quoteIdentifier(
|
||||
$table_name
|
||||
) . ' CONVERT TO CHARACTER SET utf8mb4 COLLATE ' . $collate
|
||||
);
|
||||
}
|
||||
|
||||
$sqlLines = [
|
||||
|
@ -77,6 +83,6 @@ final class Version20180826043500 extends AbstractMigration
|
|||
*/
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
|
||||
$this->changeCharset('utf8mb4_unicode_ci');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,20 @@ namespace App\Entity\Migration;
|
|||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210620131126 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Add "max_listener_duration" to station_mounts table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE station_mounts ADD max_listener_duration INT NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE station_mounts DROP max_listener_duration');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,26 +7,21 @@ namespace App\Entity\Migration;
|
|||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210703185549 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Add columns to facilitate "loop once" functionality.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE station_playlists ADD queue_reset_at INT NOT NULL');
|
||||
$this->addSql('ALTER TABLE station_schedules ADD loop_once TINYINT(1) NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE station_playlists DROP queue_reset_at');
|
||||
$this->addSql('ALTER TABLE station_schedules DROP loop_once');
|
||||
}
|
||||
|
|
|
@ -7,25 +7,20 @@ namespace App\Entity\Migration;
|
|||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210805004608 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Add author and e-mail to podcast table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE podcast ADD author VARCHAR(255) NOT NULL, ADD email VARCHAR(255) NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE podcast DROP author, DROP email');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,26 +7,21 @@ namespace App\Entity\Migration;
|
|||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20211227232320 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Change on-delete behavior of media on song_history table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE song_history DROP FOREIGN KEY FK_2AD16164EA9FDD75');
|
||||
$this->addSql('ALTER TABLE song_history ADD CONSTRAINT FK_2AD16164EA9FDD75 FOREIGN KEY (media_id) REFERENCES station_media (id) ON DELETE SET NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE song_history DROP FOREIGN KEY FK_2AD16164EA9FDD75');
|
||||
$this->addSql('ALTER TABLE song_history ADD CONSTRAINT FK_2AD16164EA9FDD75 FOREIGN KEY (media_id) REFERENCES station_media (id) ON DELETE CASCADE');
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use Doctrine\DBAL\Connection;
|
|||
use NowPlaying\Result\Client;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Listener>
|
||||
|
@ -188,7 +189,7 @@ class ListenerRepository extends Repository
|
|||
$record['device_is_bot'] = $browserResult->isBot ? 1 : 0;
|
||||
$record['device_browser_family'] = $this->truncateNullableString($browserResult->browserFamily, 150);
|
||||
$record['device_os_family'] = $this->truncateNullableString($browserResult->osFamily, 150);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error('Device Detector error: ' . $e->getMessage(), [
|
||||
'user_agent' => $userAgent,
|
||||
'exception' => $e,
|
||||
|
@ -211,7 +212,7 @@ class ListenerRepository extends Repository
|
|||
$record['location_country'] = $this->truncateNullableString($ipInfo->country, 2);
|
||||
$record['location_lat'] = $ipInfo->lat;
|
||||
$record['location_lon'] = $ipInfo->lon;
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error('IP Geolocation error: ' . $e->getMessage(), [
|
||||
'ip' => $ip,
|
||||
'exception' => $e,
|
||||
|
|
|
@ -191,9 +191,9 @@ class StationPlaylistMediaRepository extends Repository
|
|||
)->setParameter('playlist', $playlist)
|
||||
->execute();
|
||||
} elseif (Entity\Enums\PlaylistOrders::Shuffle === $playlist->getOrderEnum()) {
|
||||
$this->em->transactional(
|
||||
function () use ($playlist): void {
|
||||
$allSpmRecordsQuery = $this->em->createQuery(
|
||||
$this->em->wrapInTransaction(
|
||||
function (ReloadableEntityManagerInterface $em) use ($playlist): void {
|
||||
$allSpmRecordsQuery = $em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT spm.id
|
||||
FROM App\Entity\StationPlaylistMedia spm
|
||||
|
@ -202,7 +202,7 @@ class StationPlaylistMediaRepository extends Repository
|
|||
DQL
|
||||
)->setParameter('playlist', $playlist);
|
||||
|
||||
$updateSpmWeightQuery = $this->em->createQuery(
|
||||
$updateSpmWeightQuery = $em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationPlaylistMedia spm
|
||||
SET spm.weight=:weight, spm.is_queued=1
|
||||
|
|
|
@ -166,11 +166,7 @@ class StationRepository extends Repository
|
|||
}
|
||||
|
||||
$customUrl = $this->settingsRepo->readSettings()->getDefaultAlbumArtUrlAsUri();
|
||||
if (null !== $customUrl) {
|
||||
return $customUrl;
|
||||
}
|
||||
|
||||
return AssetFactory::createAlbumArt($this->environment)->getUri();
|
||||
return $customUrl ?? AssetFactory::createAlbumArt($this->environment)->getUri();
|
||||
}
|
||||
|
||||
public function setFallback(
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Service\Avatar;
|
|||
use App\Utilities\Urls;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use InvalidArgumentException;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use RuntimeException;
|
||||
|
@ -245,7 +246,7 @@ class Settings implements Stringable
|
|||
public function setAnalytics(?string $analytics): void
|
||||
{
|
||||
if (null !== $analytics && null === Entity\Enums\AnalyticsLevel::tryFrom($analytics)) {
|
||||
throw new \InvalidArgumentException('Invalid analytics level.');
|
||||
throw new InvalidArgumentException('Invalid analytics level.');
|
||||
}
|
||||
|
||||
$this->analytics = $analytics;
|
||||
|
@ -337,7 +338,7 @@ class Settings implements Stringable
|
|||
public function setPublicTheme(?string $publicTheme): void
|
||||
{
|
||||
if (null !== $publicTheme && null === SupportedThemes::tryFrom($publicTheme)) {
|
||||
throw new \InvalidArgumentException('Unsupported theme specified.');
|
||||
throw new InvalidArgumentException('Unsupported theme specified.');
|
||||
}
|
||||
|
||||
$this->public_theme = $publicTheme;
|
||||
|
|
|
@ -19,10 +19,12 @@ use DateTimeZone;
|
|||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use InvalidArgumentException;
|
||||
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
|
||||
use League\Flysystem\Visibility;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use RuntimeException;
|
||||
use Stringable;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
|
@ -456,7 +458,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function setFrontendType(?string $frontend_type = null): void
|
||||
{
|
||||
if (null !== $frontend_type && null === FrontendAdapters::tryFrom($frontend_type)) {
|
||||
throw new \InvalidArgumentException('Invalid frontend type specified.');
|
||||
throw new InvalidArgumentException('Invalid frontend type specified.');
|
||||
}
|
||||
|
||||
$this->frontend_type = $frontend_type;
|
||||
|
@ -511,7 +513,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function setBackendType(string $backend_type = null): void
|
||||
{
|
||||
if (null !== $backend_type && null === BackendAdapters::tryFrom($backend_type)) {
|
||||
throw new \InvalidArgumentException('Invalid frontend type specified.');
|
||||
throw new InvalidArgumentException('Invalid frontend type specified.');
|
||||
}
|
||||
|
||||
$this->backend_type = $backend_type;
|
||||
|
@ -962,7 +964,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function getMediaStorageLocation(): StorageLocation
|
||||
{
|
||||
if (null === $this->media_storage_location) {
|
||||
throw new \RuntimeException('Media storage location not initialized.');
|
||||
throw new RuntimeException('Media storage location not initialized.');
|
||||
}
|
||||
return $this->media_storage_location;
|
||||
}
|
||||
|
@ -970,7 +972,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function setMediaStorageLocation(?StorageLocation $storageLocation = null): void
|
||||
{
|
||||
if (null !== $storageLocation && StorageLocationTypes::StationMedia !== $storageLocation->getTypeEnum()) {
|
||||
throw new \RuntimeException('Invalid storage location.');
|
||||
throw new RuntimeException('Invalid storage location.');
|
||||
}
|
||||
|
||||
$this->media_storage_location = $storageLocation;
|
||||
|
@ -979,7 +981,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function getRecordingsStorageLocation(): StorageLocation
|
||||
{
|
||||
if (null === $this->recordings_storage_location) {
|
||||
throw new \RuntimeException('Recordings storage location not initialized.');
|
||||
throw new RuntimeException('Recordings storage location not initialized.');
|
||||
}
|
||||
return $this->recordings_storage_location;
|
||||
}
|
||||
|
@ -987,7 +989,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function setRecordingsStorageLocation(?StorageLocation $storageLocation = null): void
|
||||
{
|
||||
if (null !== $storageLocation && StorageLocationTypes::StationRecordings !== $storageLocation->getTypeEnum()) {
|
||||
throw new \RuntimeException('Invalid storage location.');
|
||||
throw new RuntimeException('Invalid storage location.');
|
||||
}
|
||||
|
||||
$this->recordings_storage_location = $storageLocation;
|
||||
|
@ -996,7 +998,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function getPodcastsStorageLocation(): StorageLocation
|
||||
{
|
||||
if (null === $this->podcasts_storage_location) {
|
||||
throw new \RuntimeException('Podcasts storage location not initialized.');
|
||||
throw new RuntimeException('Podcasts storage location not initialized.');
|
||||
}
|
||||
return $this->podcasts_storage_location;
|
||||
}
|
||||
|
@ -1004,7 +1006,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
public function setPodcastsStorageLocation(?StorageLocation $storageLocation = null): void
|
||||
{
|
||||
if (null !== $storageLocation && StorageLocationTypes::StationPodcasts !== $storageLocation->getTypeEnum()) {
|
||||
throw new \RuntimeException('Invalid storage location.');
|
||||
throw new RuntimeException('Invalid storage location.');
|
||||
}
|
||||
|
||||
$this->podcasts_storage_location = $storageLocation;
|
||||
|
@ -1016,7 +1018,7 @@ class Station implements Stringable, IdentifiableEntityInterface
|
|||
StorageLocationTypes::StationMedia => $this->getMediaStorageLocation(),
|
||||
StorageLocationTypes::StationRecordings => $this->getRecordingsStorageLocation(),
|
||||
StorageLocationTypes::StationPodcasts => $this->getPodcastsStorageLocation(),
|
||||
default => throw new \InvalidArgumentException('Invalid storage location.')
|
||||
default => throw new InvalidArgumentException('Invalid storage location.')
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Entity;
|
|||
use App\Entity\Enums\StationBackendPerformanceModes;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class StationBackendConfiguration extends ArrayCollection
|
||||
{
|
||||
|
@ -80,7 +81,7 @@ class StationBackendConfiguration extends ArrayCollection
|
|||
}
|
||||
|
||||
if (null !== $format && null === StreamFormats::tryFrom($format)) {
|
||||
throw new \InvalidArgumentException('Invalid recording type specified.');
|
||||
throw new InvalidArgumentException('Invalid recording type specified.');
|
||||
}
|
||||
|
||||
$this->set(self::RECORD_STREAMS_FORMAT, $format);
|
||||
|
|
|
@ -13,6 +13,7 @@ use Azura\Normalizer\Attributes\DeepNormalize;
|
|||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use InvalidArgumentException;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Stringable;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
@ -251,7 +252,7 @@ class StationPlaylist implements
|
|||
public function setType(string $type): void
|
||||
{
|
||||
if (null === PlaylistTypes::tryFrom($type)) {
|
||||
throw new \InvalidArgumentException('Invalid playlist type.');
|
||||
throw new InvalidArgumentException('Invalid playlist type.');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
|
@ -270,7 +271,7 @@ class StationPlaylist implements
|
|||
public function setSource(string $source): void
|
||||
{
|
||||
if (null === PlaylistSources::tryFrom($source)) {
|
||||
throw new \InvalidArgumentException('Invalid playlist source.');
|
||||
throw new InvalidArgumentException('Invalid playlist source.');
|
||||
}
|
||||
|
||||
$this->source = $source;
|
||||
|
@ -289,7 +290,7 @@ class StationPlaylist implements
|
|||
public function setOrder(string $order): void
|
||||
{
|
||||
if (null === PlaylistOrders::tryFrom($order)) {
|
||||
throw new \InvalidArgumentException('Invalid playlist order.');
|
||||
throw new InvalidArgumentException('Invalid playlist order.');
|
||||
}
|
||||
|
||||
$this->order = $order;
|
||||
|
@ -318,7 +319,7 @@ class StationPlaylist implements
|
|||
public function setRemoteType(?string $remote_type): void
|
||||
{
|
||||
if (null !== $remote_type && null === PlaylistRemoteTypes::tryFrom($remote_type)) {
|
||||
throw new \InvalidArgumentException('Invalid playlist remote type.');
|
||||
throw new InvalidArgumentException('Invalid playlist remote type.');
|
||||
}
|
||||
|
||||
$this->remote_type = $remote_type;
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Radio\Remote\AbstractRemote;
|
|||
use App\Utilities;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
|
@ -234,7 +235,7 @@ class StationRemote implements
|
|||
public function setType(string $type): void
|
||||
{
|
||||
if (null === RemoteAdapters::tryFrom($type)) {
|
||||
throw new \InvalidArgumentException('Invalid type specified.');
|
||||
throw new InvalidArgumentException('Invalid type specified.');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
|
|
|
@ -222,7 +222,7 @@ class StationSchedule implements IdentifiableEntityInterface
|
|||
7 => 'Sun',
|
||||
];
|
||||
|
||||
if (null !== $days) {
|
||||
if ([] !== $days) {
|
||||
$displayDays = [];
|
||||
foreach ($days as $day) {
|
||||
$displayDays[] = $daysOfWeek[$day];
|
||||
|
|
|
@ -17,7 +17,7 @@ trait HasSongFields
|
|||
use TruncateStrings;
|
||||
|
||||
#[
|
||||
OA\Property(),
|
||||
OA\Property,
|
||||
ORM\Column(length: 50),
|
||||
Groups([EntityGroupsInterface::GROUP_GENERAL, EntityGroupsInterface::GROUP_ALL])
|
||||
]
|
||||
|
|
|
@ -11,6 +11,7 @@ use App\Http\ServerRequest;
|
|||
use Gettext\GettextTranslator;
|
||||
use Gettext\TranslatorFunctions;
|
||||
use Gettext\TranslatorInterface;
|
||||
use Locale;
|
||||
use PhpMyAdmin\MoTranslator\Loader;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
|
@ -124,7 +125,7 @@ enum SupportedLocales: string
|
|||
}
|
||||
|
||||
$server_params = $request->getServerParams();
|
||||
$browser_locale = \Locale::acceptFromHttp($server_params['HTTP_ACCEPT_LANGUAGE'] ?? '');
|
||||
$browser_locale = Locale::acceptFromHttp($server_params['HTTP_ACCEPT_LANGUAGE'] ?? '');
|
||||
|
||||
if (!empty($browser_locale)) {
|
||||
if (2 === strlen($browser_locale)) {
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace App\Event\Radio;
|
||||
|
||||
use App\Entity;
|
||||
use RuntimeException;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
|
@ -80,7 +81,7 @@ class AnnotateNextSong extends Event
|
|||
public function buildAnnotations(): string
|
||||
{
|
||||
if (empty($this->songPath)) {
|
||||
throw new \RuntimeException('No valid path for song.');
|
||||
throw new RuntimeException('No valid path for song.');
|
||||
}
|
||||
|
||||
$this->annotations = array_filter($this->annotations);
|
||||
|
|
|
@ -19,6 +19,8 @@ use Symfony\Component\Lock\Exception\LockConflictedException;
|
|||
use Symfony\Component\Lock\Key;
|
||||
use Symfony\Component\Lock\PersistingStoreInterface;
|
||||
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
/**
|
||||
* Copied from Symfony 5.x as it was deprecated in 6.x with no suitable replacement.
|
||||
*
|
||||
|
@ -38,7 +40,7 @@ final class RetryTillSaveStore implements BlockingStoreInterface, LoggerAwareInt
|
|||
public function __construct(
|
||||
private PersistingStoreInterface $decorated,
|
||||
private int $retrySleep = 100,
|
||||
private int $retryCount = \PHP_INT_MAX
|
||||
private int $retryCount = PHP_INT_MAX
|
||||
) {
|
||||
$this->logger = new NullLogger();
|
||||
}
|
||||
|
@ -68,12 +70,10 @@ final class RetryTillSaveStore implements BlockingStoreInterface, LoggerAwareInt
|
|||
}
|
||||
} while (++$retry < $this->retryCount);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning(
|
||||
$this->logger?->warning(
|
||||
'Failed to store the "{resource}" lock. Abort after {retry} retry.',
|
||||
['resource' => $key, 'retry' => $retry]
|
||||
);
|
||||
}
|
||||
|
||||
throw new LockConflictedException();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class MimeTypeExtensionMap extends GeneratedExtensionToMimeTypeMap
|
|||
|
||||
public function lookupMimeType(string $extension): ?string
|
||||
{
|
||||
return self::MIME_TYPES_FOR_EXTENSIONS[$extension]
|
||||
return parent::lookupMimeType($extension)
|
||||
?? self::ADDED_MIME_TYPES[$extension]
|
||||
?? null;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Message;
|
||||
|
||||
use App\Entity\Api\NowPlaying\NowPlaying;
|
||||
use App\MessageQueue\QueueManager;
|
||||
use App\MessageQueue\QueueManagerInterface;
|
||||
|
||||
class DispatchWebhookMessage extends AbstractUniqueMessage
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Message;
|
||||
|
||||
use App\Environment;
|
||||
use App\MessageQueue\QueueManagerInterface;
|
||||
|
||||
class TestWebhookMessage extends AbstractUniqueMessage
|
||||
{
|
||||
|
@ -23,9 +22,4 @@ class TestWebhookMessage extends AbstractUniqueMessage
|
|||
{
|
||||
return Environment::getInstance()->getSyncLongExecutionTime();
|
||||
}
|
||||
|
||||
public function getQueue(): string
|
||||
{
|
||||
return QueueManagerInterface::QUEUE_NORMAL_PRIORITY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App;
|
||||
|
||||
use App\Http\Response;
|
||||
use App\Http\Router;
|
||||
use App\Http\RouterInterface;
|
||||
use App\Http\ServerRequest;
|
||||
use Countable;
|
||||
|
@ -179,7 +178,6 @@ class Paginator implements IteratorAggregate, Countable
|
|||
}
|
||||
|
||||
$pageLinks = [];
|
||||
if ($this->router instanceof Router) {
|
||||
$pageLinks['first'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => 1]);
|
||||
|
||||
$prevPage = $this->paginator->hasPreviousPage()
|
||||
|
@ -195,7 +193,6 @@ class Paginator implements IteratorAggregate, Countable
|
|||
$pageLinks['next'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $nextPage]);
|
||||
|
||||
$pageLinks['last'] = (string)$this->router->fromHereWithQuery(null, [], ['page' => $totalPages]);
|
||||
}
|
||||
|
||||
return $response->withJson(
|
||||
[
|
||||
|
|
|
@ -15,7 +15,6 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Supervisor\Exception\Fault;
|
||||
use Supervisor\Exception\SupervisorException as SupervisorLibException;
|
||||
use Supervisor\Process;
|
||||
use Supervisor\SupervisorInterface;
|
||||
|
||||
abstract class AbstractAdapter
|
||||
|
@ -106,9 +105,7 @@ abstract class AbstractAdapter
|
|||
$program_name = $this->getProgramName($station);
|
||||
|
||||
try {
|
||||
$process = $this->supervisor->getProcess($program_name);
|
||||
|
||||
return $process instanceof Process && $process->isRunning();
|
||||
return $this->supervisor->getProcess($program_name)->isRunning();
|
||||
} catch (Fault\BadNameException) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use App\Radio\Adapters;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class Annotations implements EventSubscriberInterface
|
||||
|
@ -52,7 +53,7 @@ class Annotations implements EventSubscriberInterface
|
|||
$queueRow = $this->queueRepo->getNextToSendToAutoDj($station);
|
||||
|
||||
if (null === $queueRow) {
|
||||
throw new \RuntimeException('Queue is empty for station.');
|
||||
throw new RuntimeException('Queue is empty for station.');
|
||||
}
|
||||
|
||||
$event = AnnotateNextSong::fromStationQueue($queueRow, $asAutoDj);
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity;
|
|||
use App\Event\Radio\WriteLiquidsoapConfiguration;
|
||||
use App\Exception;
|
||||
use App\Radio\Enums\LiquidsoapQueues;
|
||||
use LogicException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
|
@ -329,7 +330,7 @@ class Liquidsoap extends AbstractBackend
|
|||
$process->run();
|
||||
|
||||
if (1 === $process->getExitCode()) {
|
||||
throw new \LogicException($process->getOutput());
|
||||
throw new LogicException($process->getOutput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace App\Radio\Backend\Liquidsoap\Command;
|
|||
use App\Entity;
|
||||
use App\Radio\Enums\BackendAdapters;
|
||||
use Monolog\Logger;
|
||||
use ReflectionClass;
|
||||
use Throwable;
|
||||
|
||||
abstract class AbstractCommand
|
||||
{
|
||||
|
@ -30,7 +32,7 @@ abstract class AbstractCommand
|
|||
}
|
||||
);
|
||||
|
||||
$className = (new \ReflectionClass(static::class))->getShortName();
|
||||
$className = (new ReflectionClass(static::class))->getShortName();
|
||||
$this->logger->debug(
|
||||
sprintf('Running Internal Command %s', $className),
|
||||
[
|
||||
|
@ -54,7 +56,7 @@ abstract class AbstractCommand
|
|||
} else {
|
||||
return (string)$result;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
sprintf(
|
||||
'Error with Internal Command %s: %s',
|
||||
|
|
|
@ -6,13 +6,14 @@ namespace App\Radio\Backend\Liquidsoap\Command;
|
|||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use RuntimeException;
|
||||
|
||||
class CopyCommand extends AbstractCommand
|
||||
{
|
||||
protected function doRun(Entity\Station $station, bool $asAutoDj = false, array $payload = []): string
|
||||
{
|
||||
if (empty($payload['uri'])) {
|
||||
throw new \RuntimeException('No URI provided.');
|
||||
throw new RuntimeException('No URI provided.');
|
||||
}
|
||||
|
||||
$uri = $payload['uri'];
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace App\Radio\Backend\Liquidsoap\Command;
|
|||
|
||||
use App\Entity;
|
||||
use Monolog\Logger;
|
||||
use RuntimeException;
|
||||
|
||||
class DjAuthCommand extends AbstractCommand
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ class DjAuthCommand extends AbstractCommand
|
|||
array $payload = []
|
||||
): bool {
|
||||
if (!$station->getEnableStreamers()) {
|
||||
throw new \RuntimeException('Attempted DJ authentication when streamers are disabled on this station.');
|
||||
throw new RuntimeException('Attempted DJ authentication when streamers are disabled on this station.');
|
||||
}
|
||||
|
||||
$user = $payload['user'] ?? '';
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Monolog\Logger;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class FeedbackCommand extends AbstractCommand
|
||||
{
|
||||
|
@ -24,12 +25,12 @@ class FeedbackCommand extends AbstractCommand
|
|||
{
|
||||
// Process extra metadata sent by Liquidsoap (if it exists).
|
||||
if (empty($payload['media_id'])) {
|
||||
throw new \RuntimeException('No payload provided.');
|
||||
throw new RuntimeException('No payload provided.');
|
||||
}
|
||||
|
||||
$media = $this->em->find(Entity\StationMedia::class, $payload['media_id']);
|
||||
if (!$media instanceof Entity\StationMedia) {
|
||||
throw new \RuntimeException('Media ID does not exist for station.');
|
||||
throw new RuntimeException('Media ID does not exist for station.');
|
||||
}
|
||||
|
||||
$sq = $this->queueRepo->findRecentlyCuedSong($station, $media);
|
||||
|
|
|
@ -116,7 +116,7 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
$event->appendBlock(
|
||||
<<<EOF
|
||||
init.daemon.set(false)
|
||||
init.daemon.pidfile.path.set("${pidfile}")
|
||||
init.daemon.pidfile.path.set("{$pidfile}")
|
||||
|
||||
log.stdout.set(true)
|
||||
log.file.set(false)
|
||||
|
@ -125,14 +125,14 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
settings.server.socket.set(true)
|
||||
settings.server.socket.permissions.set(0o660)
|
||||
settings.server.socket.path.set("${socketFile}")
|
||||
settings.server.socket.path.set("{$socketFile}")
|
||||
|
||||
settings.harbor.bind_addrs.set(["0.0.0.0"])
|
||||
|
||||
settings.tag.encodings.set(["UTF-8","ISO-8859-1"])
|
||||
settings.encoder.metadata.export.set(["artist","title","album","song"])
|
||||
|
||||
setenv("TZ", "${stationTz}")
|
||||
setenv("TZ", "{$stationTz}")
|
||||
|
||||
autodj_is_loading = ref(true)
|
||||
ignore(autodj_is_loading)
|
||||
|
@ -154,8 +154,8 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
$event->appendBlock(
|
||||
<<<EOF
|
||||
azuracast_api_url = "${stationApiUrl}"
|
||||
azuracast_api_key = "${stationApiAuth}"
|
||||
azuracast_api_url = "{$stationApiUrl}"
|
||||
azuracast_api_key = "{$stationApiAuth}"
|
||||
|
||||
def azuracast_api_call(~timeout_ms=2000, url, payload) =
|
||||
full_url = "#{azuracast_api_url}/#{url}"
|
||||
|
@ -189,7 +189,7 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
$event->appendBlock(
|
||||
<<<EOF
|
||||
station_media_dir = "${stationMediaDir}"
|
||||
station_media_dir = "{$stationMediaDir}"
|
||||
def azuracast_media_protocol(~rlog=_,~maxtime=_,arg) =
|
||||
["#{station_media_dir}/#{arg}"]
|
||||
end
|
||||
|
@ -240,7 +240,7 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
<<<EOF
|
||||
# Optimize Performance
|
||||
runtime.gc.set(runtime.gc.get().{
|
||||
space_overhead = ${gcSpaceOverhead},
|
||||
space_overhead = {$gcSpaceOverhead},
|
||||
allocation_policy = 2
|
||||
})
|
||||
EOF
|
||||
|
@ -552,12 +552,12 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
$event->appendBlock(
|
||||
<<< EOF
|
||||
requests = request.queue(id="${requestsQueueName}")
|
||||
requests = cue_cut(id="cue_${requestsQueueName}", requests)
|
||||
requests = request.queue(id="{$requestsQueueName}")
|
||||
requests = cue_cut(id="cue_{$requestsQueueName}", requests)
|
||||
radio = fallback(id="requests_fallback", track_sensitive = true, [requests, radio])
|
||||
|
||||
interrupting_queue = request.queue(id="${interruptingQueueName}")
|
||||
interrupting_queue = cue_cut(id="cue_${interruptingQueueName}", interrupting_queue)
|
||||
interrupting_queue = request.queue(id="{$interruptingQueueName}")
|
||||
interrupting_queue = cue_cut(id="cue_{$interruptingQueueName}", interrupting_queue)
|
||||
radio = fallback(id="interrupting_fallback", track_sensitive = false, [interrupting_queue, radio])
|
||||
|
||||
add_skip_command(radio)
|
||||
|
@ -800,7 +800,7 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
ignore(radio_without_live)
|
||||
|
||||
# Live Broadcasting
|
||||
live = input.harbor(${harborParams})
|
||||
live = input.harbor({$harborParams})
|
||||
|
||||
def insert_missing(m) =
|
||||
if m == [] then
|
||||
|
@ -827,14 +827,14 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
$event->appendBlock(
|
||||
<<< EOF
|
||||
# Record Live Broadcasts
|
||||
recording_base_path = "${recordBasePath}"
|
||||
recording_extension = "${recordExtension}"
|
||||
recording_base_path = "{$recordBasePath}"
|
||||
recording_extension = "{$recordExtension}"
|
||||
|
||||
output.file(
|
||||
{$formatString},
|
||||
fun () -> begin
|
||||
if (!live_enabled) then
|
||||
"#{recording_base_path}/#{!live_dj}/${recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
|
||||
"#{recording_base_path}/#{!live_dj}/{$recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
|
||||
else
|
||||
""
|
||||
end
|
||||
|
@ -897,7 +897,7 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
|
||||
$event->appendBlock(
|
||||
<<<EOF
|
||||
radio = fallback(id="safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "${errorFile}")])
|
||||
radio = fallback(id="safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "{$errorFile}")])
|
||||
EOF
|
||||
);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Throwable;
|
||||
|
||||
class PlaylistFileWriter implements EventSubscriberInterface
|
||||
{
|
||||
|
@ -136,7 +137,7 @@ class PlaylistFileWriter implements EventSubscriberInterface
|
|||
try {
|
||||
$this->eventDispatcher->dispatch($event);
|
||||
$playlistFile[] = $event->buildAnnotations();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use App\Radio\Enums\BackendAdapters;
|
|||
use App\Radio\Enums\FrontendAdapters;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Monolog\Logger;
|
||||
use RuntimeException;
|
||||
use Supervisor\Exception\SupervisorException;
|
||||
use Supervisor\SupervisorInterface;
|
||||
|
||||
|
@ -104,7 +105,7 @@ class Configuration
|
|||
|
||||
if (!$station->getIsEnabled()) {
|
||||
$this->unlinkAndStopStation($station, $reloadSupervisor);
|
||||
throw new \RuntimeException('Station is disabled.');
|
||||
throw new RuntimeException('Station is disabled.');
|
||||
}
|
||||
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
|
@ -113,7 +114,7 @@ class Configuration
|
|||
// If no processes need to be managed, remove any existing config.
|
||||
if (!$frontend->hasCommand($station) && !$backend->hasCommand($station)) {
|
||||
$this->unlinkAndStopStation($station, $reloadSupervisor);
|
||||
throw new \RuntimeException('Station has no local services.');
|
||||
throw new RuntimeException('Station has no local services.');
|
||||
}
|
||||
|
||||
// If using AutoDJ and there is no media, don't spin up services.
|
||||
|
@ -122,7 +123,7 @@ class Configuration
|
|||
&& !$this->stationPlaylistRepo->stationHasActivePlaylists($station)
|
||||
) {
|
||||
$this->unlinkAndStopStation($station, $reloadSupervisor);
|
||||
throw new \RuntimeException('Station has no media assigned to playlists.');
|
||||
throw new RuntimeException('Station has no media assigned to playlists.');
|
||||
}
|
||||
|
||||
// Get group information
|
||||
|
@ -174,8 +175,8 @@ class Configuration
|
|||
$backend->reload($station);
|
||||
$frontend->reload($station);
|
||||
} else {
|
||||
$this->supervisor->stopProcessGroup($backend_group, true);
|
||||
$this->supervisor->startProcessGroup($backend_group, true);
|
||||
$this->supervisor->stopProcessGroup($backend_group);
|
||||
$this->supervisor->startProcessGroup($backend_group);
|
||||
}
|
||||
} catch (SupervisorException) {
|
||||
}
|
||||
|
@ -483,7 +484,7 @@ class Configuration
|
|||
|
||||
// Try forcing the group to stop, but don't hard-fail if it doesn't.
|
||||
try {
|
||||
$this->supervisor->stopProcessGroup($station_group, true);
|
||||
$this->supervisor->stopProcessGroup($station_group);
|
||||
$this->supervisor->removeProcessGroup($station_group);
|
||||
} catch (SupervisorException) {
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Radio\Frontend\Blocklist;
|
|||
use App\Entity;
|
||||
use App\Radio\Enums\FrontendAdapters;
|
||||
use App\Service\IpGeolocation;
|
||||
use InvalidArgumentException;
|
||||
use PhpIP\IP;
|
||||
use PhpIP\IPBlock;
|
||||
|
||||
|
@ -84,7 +85,7 @@ class BlocklistParser
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (\InvalidArgumentException) {
|
||||
} catch (InvalidArgumentException) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class RateLimit
|
|||
$rateLimiterFactory = new RateLimiterFactory($config, $cacheStore, $this->lockFactory);
|
||||
$rateLimiter = $rateLimiterFactory->create($key);
|
||||
|
||||
if (false === $rateLimiter->consume(1)->isAccepted()) {
|
||||
if (false === $rateLimiter->consume()->isAccepted()) {
|
||||
throw new Exception\RateLimitExceededException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,13 +65,13 @@ class Flow
|
|||
return self::handleStandardUpload($request, $tempDir);
|
||||
}
|
||||
|
||||
$flowIdentifier = $params['flowIdentifier'] ?? '';
|
||||
$flowIdentifier = $params['flowIdentifier'];
|
||||
$flowChunkNumber = (int)($params['flowChunkNumber'] ?? 1);
|
||||
|
||||
$targetSize = (int)($params['flowTotalSize'] ?? 0);
|
||||
$targetChunks = (int)($params['flowTotalChunks'] ?? 1);
|
||||
$targetChunks = (int)($params['flowTotalChunks']);
|
||||
|
||||
$flowFilename = $params['flowFilename'] ?? ($flowIdentifier ?: ('upload-' . date('Ymd')));
|
||||
$flowFilename = $params['flowFilename'] ?? ($flowIdentifier);
|
||||
|
||||
// init the destination file (format <filename.ext>.part<#chunk>
|
||||
$chunkBaseDir = $tempDir . '/' . $flowIdentifier;
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Service\IpGeolocator;
|
|||
use Exception;
|
||||
use MaxMind\Db\Reader;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
@ -76,7 +77,7 @@ class IpGeolocation
|
|||
|
||||
$reader = $this->reader;
|
||||
if (null === $reader) {
|
||||
throw new \RuntimeException('No IP Geolocation reader available.');
|
||||
throw new RuntimeException('No IP Geolocation reader available.');
|
||||
}
|
||||
|
||||
$cacheKey = $this->readerShortName . '_' . str_replace([':', '.'], '_', $ip);
|
||||
|
|
|
@ -74,7 +74,7 @@ class CheckMediaTask extends AbstractTask
|
|||
$this->logger->info(
|
||||
sprintf(
|
||||
'Processing media for storage location %s...',
|
||||
(string)$storageLocation
|
||||
$storageLocation
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -111,7 +111,7 @@ class CheckMediaTask extends AbstractTask
|
|||
);
|
||||
} catch (FilesystemException $e) {
|
||||
$this->logger->error(
|
||||
sprintf('Flysystem Error for Storage Space %s', (string)$storageLocation),
|
||||
sprintf('Flysystem Error for Storage Space %s', $storageLocation),
|
||||
[
|
||||
'exception' => $e,
|
||||
]
|
||||
|
@ -171,7 +171,7 @@ class CheckMediaTask extends AbstractTask
|
|||
|
||||
$this->processNewFiles($storageLocation, $queuedNewFiles, $musicFiles, $stats);
|
||||
|
||||
$this->logger->debug(sprintf('Media processed for "%s".', (string)$storageLocation), $stats);
|
||||
$this->logger->debug(sprintf('Media processed for "%s".', $storageLocation), $stats);
|
||||
}
|
||||
|
||||
protected function processExistingMediaRows(
|
||||
|
@ -221,7 +221,7 @@ class CheckMediaTask extends AbstractTask
|
|||
} else {
|
||||
$media = $this->em->find(Entity\StationMedia::class, $mediaRow['id']);
|
||||
if ($media instanceof Entity\StationMedia) {
|
||||
$this->mediaRepo->remove($media, false);
|
||||
$this->mediaRepo->remove($media);
|
||||
}
|
||||
|
||||
$stats['deleted']++;
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity;
|
|||
use Exception;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Throwable;
|
||||
|
||||
class CleanupStorageTask extends AbstractTask
|
||||
{
|
||||
|
@ -22,7 +23,7 @@ class CleanupStorageTask extends AbstractTask
|
|||
try {
|
||||
/** @var Entity\Station $station */
|
||||
$this->cleanStationTempFiles($station);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'station' => (string)$station,
|
||||
]);
|
||||
|
@ -34,7 +35,7 @@ class CleanupStorageTask extends AbstractTask
|
|||
try {
|
||||
/** @var Entity\StorageLocation $storageLocation */
|
||||
$this->cleanMediaStorageLocation($storageLocation);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'storageLocation' => (string)$storageLocation,
|
||||
]);
|
||||
|
@ -80,7 +81,7 @@ class CleanupStorageTask extends AbstractTask
|
|||
|
||||
if (0 === count($allUniqueIds)) {
|
||||
$this->logger->notice(
|
||||
sprintf('Skipping storage location %s: no media found.', (string)$storageLocation)
|
||||
sprintf('Skipping storage location %s: no media found.', $storageLocation)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Doctrine\ReloadableEntityManagerInterface;
|
|||
use App\Entity;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Throwable;
|
||||
|
||||
class MoveBroadcastsTask extends AbstractTask
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ class MoveBroadcastsTask extends AbstractTask
|
|||
try {
|
||||
/** @var Entity\StorageLocation $storageLocation */
|
||||
$this->processForStorageLocation($storageLocation);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'storageLocation' => (string)$storageLocation,
|
||||
]);
|
||||
|
|
|
@ -12,6 +12,7 @@ use League\Flysystem\StorageAttributes;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use Supervisor\SupervisorInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Throwable;
|
||||
|
||||
class RotateLogsTask extends AbstractTask
|
||||
{
|
||||
|
@ -43,7 +44,7 @@ class RotateLogsTask extends AbstractTask
|
|||
|
||||
try {
|
||||
$this->rotateStationLogs($station);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error($e->getMessage(), [
|
||||
'station' => (string)$station,
|
||||
]);
|
||||
|
|
|
@ -8,6 +8,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests;
|
||||
|
||||
use App\AppFactory;
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Enums\ApplicationEnvironment;
|
||||
use App\Environment;
|
||||
|
@ -38,13 +39,7 @@ class Module extends Framework implements DoctrineProvider
|
|||
|
||||
public function _initialize(): void
|
||||
{
|
||||
/** @var string $container_class The fully qualified name of the container class. */
|
||||
$container_class = $this->config['container'];
|
||||
|
||||
$autoloader = $GLOBALS['autoloader'];
|
||||
|
||||
$this->app = $container_class::createApp(
|
||||
$autoloader,
|
||||
$this->app = AppFactory::createApp(
|
||||
[
|
||||
Environment::BASE_DIR => Configuration::projectDir(),
|
||||
Environment::APP_ENV => ApplicationEnvironment::Testing->value,
|
||||
|
|
|
@ -8,8 +8,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Xml;
|
||||
|
||||
use RuntimeException;
|
||||
use XMLReader;
|
||||
|
||||
use const LIBXML_XINCLUDE;
|
||||
|
||||
/**
|
||||
* XML config reader.
|
||||
*/
|
||||
|
@ -32,14 +35,14 @@ class Reader
|
|||
}
|
||||
|
||||
/** @var XMLReader|false $reader */
|
||||
$reader = XMLReader::XML($string, null, \LIBXML_XINCLUDE);
|
||||
$reader = XMLReader::XML($string, null, LIBXML_XINCLUDE);
|
||||
if (false === $reader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_error_handler(
|
||||
function ($error, $message = '') {
|
||||
throw new \RuntimeException(
|
||||
throw new RuntimeException(
|
||||
sprintf('Error reading XML string: %s', $message),
|
||||
$error
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Xml;
|
||||
|
||||
use RuntimeException;
|
||||
use XMLWriter;
|
||||
|
||||
class Writer
|
||||
|
@ -71,7 +72,7 @@ class Writer
|
|||
$branchType = 'string';
|
||||
}
|
||||
} elseif ($branchType !== (is_numeric($key) ? 'numeric' : 'string')) {
|
||||
throw new \RuntimeException('Mixing of string and numeric keys is not allowed');
|
||||
throw new RuntimeException('Mixing of string and numeric keys is not allowed');
|
||||
}
|
||||
|
||||
if ($branchType === 'numeric') {
|
||||
|
|
|
@ -2,8 +2,7 @@ actor: FunctionalTester
|
|||
suite_namespace: \Functional
|
||||
modules:
|
||||
enabled:
|
||||
- \App\Tests\Module:
|
||||
container: \App\AppFactory
|
||||
- \App\Tests\Module
|
||||
- Doctrine2:
|
||||
depends: \App\Tests\Module
|
||||
- REST:
|
||||
|
|
|
@ -2,7 +2,6 @@ actor: UnitTester
|
|||
suite_namespace: \Unit
|
||||
modules:
|
||||
enabled:
|
||||
- \App\Tests\Module:
|
||||
container: \App\AppFactory
|
||||
- \App\Tests\Module
|
||||
|
||||
error_level: "E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED"
|
||||
|
|
|
@ -5,12 +5,8 @@ $autoloader->addClassMap([
|
|||
'Functional\CestAbstract' => __DIR__ . '/Functional/CestAbstract.php',
|
||||
]);
|
||||
|
||||
\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$autoloader, 'loadClass']);
|
||||
|
||||
$GLOBALS['autoloader'] = $autoloader;
|
||||
|
||||
if (!function_exists('__')) {
|
||||
\PhpMyAdmin\MoTranslator\Loader::loadFunctions();
|
||||
PhpMyAdmin\MoTranslator\Loader::loadFunctions();
|
||||
}
|
||||
|
||||
// Clear output directory
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
const AZURACAST_VERSION = App\Version::FALLBACK_VERSION;
|
||||
const AZURACAST_API_URL = 'https://localhost/api';
|
||||
const AZURACAST_API_NAME = 'Testing API';
|
||||
|
||||
App\AppFactory::createCli(
|
||||
$autoloader,
|
||||
[
|
||||
App\Environment::BASE_DIR => dirname(__DIR__),
|
||||
]
|
||||
|
|
|
@ -6,9 +6,9 @@ use App\Environment;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$di = App\AppFactory::buildContainer($autoloader,
|
||||
$di = App\AppFactory::buildContainer(
|
||||
[
|
||||
App\Environment::BASE_DIR => dirname(__DIR__),
|
||||
App\Environment::LOG_LEVEL => LogLevel::DEBUG,
|
||||
|
|
|
@ -5,10 +5,9 @@ declare(strict_types=1);
|
|||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
$autoloader = require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
$app = App\AppFactory::createApp(
|
||||
$autoloader,
|
||||
[
|
||||
App\Environment::BASE_DIR => dirname(__DIR__),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue