More code cleanup.
This commit is contained in:
parent
26d9a5e66a
commit
a320c1a6a0
|
@ -88,6 +88,7 @@
|
||||||
"codeception/module-phpbrowser": "^1.0",
|
"codeception/module-phpbrowser": "^1.0",
|
||||||
"codeception/module-rest": "^1.0",
|
"codeception/module-rest": "^1.0",
|
||||||
"filp/whoops": "^2",
|
"filp/whoops": "^2",
|
||||||
|
"jetbrains/phpstorm-attributes": "^1.0",
|
||||||
"mockery/mockery": "^1.0",
|
"mockery/mockery": "^1.0",
|
||||||
"php-parallel-lint/php-console-highlighter": "^0.5.0",
|
"php-parallel-lint/php-console-highlighter": "^0.5.0",
|
||||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5293039041c75026b99de9bd015e4ede",
|
"content-hash": "419126bd4b8437a667508f7085775a4e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
|
@ -9868,6 +9868,48 @@
|
||||||
},
|
},
|
||||||
"time": "2020-07-09T08:09:16+00:00"
|
"time": "2020-07-09T08:09:16+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "jetbrains/phpstorm-attributes",
|
||||||
|
"version": "1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/JetBrains/phpstorm-attributes.git",
|
||||||
|
"reference": "a7a83ae5df4dd3c0875484483de19de8edf60a9f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/JetBrains/phpstorm-attributes/zipball/a7a83ae5df4dd3c0875484483de19de8edf60a9f",
|
||||||
|
"reference": "a7a83ae5df4dd3c0875484483de19de8edf60a9f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"JetBrains\\PhpStorm\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "JetBrains",
|
||||||
|
"homepage": "https://www.jetbrains.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PhpStorm specific attributes",
|
||||||
|
"keywords": [
|
||||||
|
"attributes",
|
||||||
|
"jetbrains",
|
||||||
|
"phpstorm"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://youtrack.jetbrains.com/newIssue?project=WI",
|
||||||
|
"source": "https://github.com/JetBrains/phpstorm-attributes/tree/1.0"
|
||||||
|
},
|
||||||
|
"time": "2020-11-17T11:09:47+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "justinrainbow/json-schema",
|
"name": "justinrainbow/json-schema",
|
||||||
"version": "5.2.10",
|
"version": "5.2.10",
|
||||||
|
|
|
@ -106,6 +106,7 @@ class SetupCommand extends CommandAbstract
|
||||||
} else {
|
} else {
|
||||||
$public_ip = $acCentral->getIp(false);
|
$public_ip = $acCentral->getIp(false);
|
||||||
|
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$io->success(
|
$io->success(
|
||||||
[
|
[
|
||||||
__('AzuraCast installation complete!'),
|
__('AzuraCast installation complete!'),
|
||||||
|
|
|
@ -114,6 +114,7 @@ class RelaysController
|
||||||
$base_url = $body['base_url'];
|
$base_url = $body['base_url'];
|
||||||
} else {
|
} else {
|
||||||
$serverParams = $request->getServerParams();
|
$serverParams = $request->getServerParams();
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$base_url = 'http://' . $serverParams('REMOTE_ADDR');
|
$base_url = 'http://' . $serverParams('REMOTE_ADDR');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,8 @@ class ChartsAction
|
||||||
// Generate unique cache ID for stations.
|
// Generate unique cache ID for stations.
|
||||||
$stationIds = [];
|
$stationIds = [];
|
||||||
foreach ($stations as $station) {
|
foreach ($stations as $station) {
|
||||||
$stationIds[$station->getId()] = $station->getId();
|
$stationId = $station->getId();
|
||||||
|
$stationIds[$stationId] = $stationId;
|
||||||
}
|
}
|
||||||
$cacheName = 'homepage_metrics_' . implode(',', $stationIds);
|
$cacheName = 'homepage_metrics_' . implode(',', $stationIds);
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ class BatchAction
|
||||||
|
|
||||||
foreach ($toMove as $iterator) {
|
foreach ($toMove as $iterator) {
|
||||||
foreach ($iterator as $record) {
|
foreach ($iterator as $record) {
|
||||||
/** @var \App\Entity\Interfaces\PathAwareInterface $record */
|
/** @var Entity\Interfaces\PathAwareInterface $record */
|
||||||
$oldPath = $record->getPath();
|
$oldPath = $record->getPath();
|
||||||
$newPath = File::renameDirectoryInPath($oldPath, $from, $to);
|
$newPath = File::renameDirectoryInPath($oldPath, $from, $to);
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ class BatchAction
|
||||||
|
|
||||||
foreach ($toMove as $iterator) {
|
foreach ($toMove as $iterator) {
|
||||||
foreach ($iterator as $record) {
|
foreach ($iterator as $record) {
|
||||||
/** @var \App\Entity\Interfaces\PathAwareInterface $record */
|
/** @var Entity\Interfaces\PathAwareInterface $record */
|
||||||
try {
|
try {
|
||||||
$record->setPath(
|
$record->setPath(
|
||||||
File::renameDirectoryInPath($record->getPath(), $from, $to)
|
File::renameDirectoryInPath($record->getPath(), $from, $to)
|
||||||
|
|
|
@ -11,6 +11,7 @@ use App\Flysystem\StationFilesystems;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\UploadedFileInterface;
|
use Psr\Http\Message\UploadedFileInterface;
|
||||||
use Symfony\Component\Serializer\Serializer;
|
use Symfony\Component\Serializer\Serializer;
|
||||||
|
@ -266,7 +267,7 @@ class PodcastEpisodesController extends AbstractApiCrudController
|
||||||
protected function viewRecord(object $record, ServerRequest $request): mixed
|
protected function viewRecord(object $record, ServerRequest $request): mixed
|
||||||
{
|
{
|
||||||
if (!($record instanceof Entity\PodcastEpisode)) {
|
if (!($record instanceof Entity\PodcastEpisode)) {
|
||||||
throw new \InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
$isInternal = ('true' === $request->getParam('internal', 'false'));
|
$isInternal = ('true' === $request->getParam('internal', 'false'));
|
||||||
|
|
|
@ -11,6 +11,7 @@ use App\Flysystem\StationFilesystems;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\UploadedFileInterface;
|
use Psr\Http\Message\UploadedFileInterface;
|
||||||
|
@ -221,7 +222,7 @@ class PodcastsController extends AbstractApiCrudController
|
||||||
protected function viewRecord(object $record, ServerRequest $request): mixed
|
protected function viewRecord(object $record, ServerRequest $request): mixed
|
||||||
{
|
{
|
||||||
if (!($record instanceof Entity\Podcast)) {
|
if (!($record instanceof Entity\Podcast)) {
|
||||||
throw new \InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
throw new InvalidArgumentException(sprintf('Record must be an instance of %s.', $this->entityClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
$isInternal = ('true' === $request->getParam('internal', 'false'));
|
$isInternal = ('true' === $request->getParam('internal', 'false'));
|
||||||
|
|
|
@ -7,6 +7,7 @@ use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class ChartsAction
|
class ChartsAction
|
||||||
{
|
{
|
||||||
|
@ -38,7 +39,7 @@ class ChartsAction
|
||||||
$statisticsThreshold
|
$statisticsThreshold
|
||||||
);
|
);
|
||||||
|
|
||||||
$daily_chart = new \stdClass();
|
$daily_chart = new stdClass();
|
||||||
$daily_chart->label = __('Listeners by Day');
|
$daily_chart->label = __('Listeners by Day');
|
||||||
$daily_chart->type = 'line';
|
$daily_chart->type = 'line';
|
||||||
$daily_chart->fill = false;
|
$daily_chart->fill = false;
|
||||||
|
@ -56,7 +57,7 @@ class ChartsAction
|
||||||
$statTime = $stat['moment'];
|
$statTime = $stat['moment'];
|
||||||
$statTime = $statTime->shiftTimezone($station_tz);
|
$statTime = $statTime->shiftTimezone($station_tz);
|
||||||
|
|
||||||
$avg_row = new \stdClass();
|
$avg_row = new stdClass();
|
||||||
$avg_row->t = $statTime->getTimestamp() * 1000;
|
$avg_row->t = $statTime->getTimestamp() * 1000;
|
||||||
$avg_row->y = round($stat['number_avg'], 2);
|
$avg_row->y = round($stat['number_avg'], 2);
|
||||||
$daily_averages[] = $avg_row;
|
$daily_averages[] = $avg_row;
|
||||||
|
@ -79,7 +80,7 @@ class ChartsAction
|
||||||
'alt' => implode('', $daily_alt),
|
'alt' => implode('', $daily_alt),
|
||||||
];
|
];
|
||||||
|
|
||||||
$day_of_week_chart = new \stdClass();
|
$day_of_week_chart = new stdClass();
|
||||||
$day_of_week_chart->label = __('Listeners by Day of Week');
|
$day_of_week_chart->label = __('Listeners by Day of Week');
|
||||||
|
|
||||||
$day_of_week_alt = [
|
$day_of_week_alt = [
|
||||||
|
@ -134,12 +135,12 @@ class ChartsAction
|
||||||
$statTime = $stat['moment'];
|
$statTime = $stat['moment'];
|
||||||
$statTime = $statTime->shiftTimezone($station_tz);
|
$statTime = $statTime->shiftTimezone($station_tz);
|
||||||
|
|
||||||
$hour = (int)$statTime->hour;
|
$hour = $statTime->hour;
|
||||||
$totals_by_hour[$hour][] = $stat['number_avg'];
|
$totals_by_hour[$hour][] = $stat['number_avg'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$hourly_labels = [];
|
$hourly_labels = [];
|
||||||
$hourly_chart = new \stdClass();
|
$hourly_chart = new stdClass();
|
||||||
$hourly_chart->label = __('Listeners by Hour');
|
$hourly_chart->label = __('Listeners by Hour');
|
||||||
|
|
||||||
$hourly_rows = [];
|
$hourly_rows = [];
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PodcastEpisodesController
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
$podcastsLink = (string)$router->fromHere(
|
$podcastsLink = $router->fromHere(
|
||||||
'public:podcasts',
|
'public:podcasts',
|
||||||
[
|
[
|
||||||
'station_id' => $station->getId(),
|
'station_id' => $station->getId(),
|
||||||
|
|
|
@ -16,6 +16,7 @@ use App\Flysystem\StationFilesystems;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\RouterInterface;
|
use App\Http\RouterInterface;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
|
use DateTime;
|
||||||
use GuzzleHttp\Psr7\UriResolver;
|
use GuzzleHttp\Psr7\UriResolver;
|
||||||
use MarcW\RssWriter\Extension\Atom\AtomLink;
|
use MarcW\RssWriter\Extension\Atom\AtomLink;
|
||||||
use MarcW\RssWriter\Extension\Atom\AtomWriter;
|
use MarcW\RssWriter\Extension\Atom\AtomWriter;
|
||||||
|
@ -124,7 +125,7 @@ class PodcastFeedController
|
||||||
$channel = new RssChannel();
|
$channel = new RssChannel();
|
||||||
|
|
||||||
$channel->setTtl(5);
|
$channel->setTtl(5);
|
||||||
$channel->setLastBuildDate(new \DateTime());
|
$channel->setLastBuildDate(new DateTime());
|
||||||
|
|
||||||
$channel->setTitle($podcast->getTitle());
|
$channel->setTitle($podcast->getTitle());
|
||||||
$channel->setDescription($podcast->getDescription());
|
$channel->setDescription($podcast->getDescription());
|
||||||
|
@ -265,10 +266,10 @@ class PodcastFeedController
|
||||||
|
|
||||||
$rssItem->setLink($episodeLink);
|
$rssItem->setLink($episodeLink);
|
||||||
|
|
||||||
$publishAtDateTime = (new \DateTime())->setTimestamp($episode->getCreatedAt());
|
$publishAtDateTime = (new DateTime())->setTimestamp($episode->getCreatedAt());
|
||||||
|
|
||||||
if ($episode->getPublishAt() !== null) {
|
if ($episode->getPublishAt() !== null) {
|
||||||
$publishAtDateTime = (new \DateTime())->setTimestamp($episode->getPublishAt());
|
$publishAtDateTime = (new DateTime())->setTimestamp($episode->getPublishAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
$rssItem->setPubDate($publishAtDateTime);
|
$rssItem->setPubDate($publishAtDateTime);
|
||||||
|
|
|
@ -13,9 +13,11 @@ use Doctrine\ORM\Mapping\ClassMetadataInfo;
|
||||||
use Doctrine\ORM\PersistentCollection;
|
use Doctrine\ORM\PersistentCollection;
|
||||||
use Doctrine\ORM\Proxy\Proxy;
|
use Doctrine\ORM\Proxy\Proxy;
|
||||||
use Doctrine\ORM\UnitOfWork;
|
use Doctrine\ORM\UnitOfWork;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
use ProxyManager\Proxy\GhostObjectInterface;
|
use ProxyManager\Proxy\GhostObjectInterface;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionObject;
|
use ReflectionObject;
|
||||||
|
use Stringable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook into Doctrine's event listener to write changes to "Auditable"
|
* A hook into Doctrine's event listener to write changes to "Auditable"
|
||||||
|
@ -247,7 +249,7 @@ class AuditLog implements EventSubscriber
|
||||||
return !$em->getMetadataFactory()->isTransient($class);
|
return !$em->getMetadataFactory()->isTransient($class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isAuditable(ReflectionClass $refl): bool
|
#[Pure] protected function isAuditable(ReflectionClass $refl): bool
|
||||||
{
|
{
|
||||||
$auditable = $refl->getAttributes(Auditable::class);
|
$auditable = $refl->getAttributes(Auditable::class);
|
||||||
return !empty($auditable);
|
return !empty($auditable);
|
||||||
|
@ -260,7 +262,7 @@ class AuditLog implements EventSubscriber
|
||||||
*/
|
*/
|
||||||
protected function getIdentifier(object $entity): ?string
|
protected function getIdentifier(object $entity): ?string
|
||||||
{
|
{
|
||||||
if ($entity instanceof \Stringable) {
|
if ($entity instanceof Stringable) {
|
||||||
return (string)$entity;
|
return (string)$entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Error
|
||||||
|
|
||||||
public static function fromException(Throwable $e, bool $includeTrace = false): self
|
public static function fromException(Throwable $e, bool $includeTrace = false): self
|
||||||
{
|
{
|
||||||
$code = (int)$e->getCode();
|
$code = $e->getCode();
|
||||||
if (0 === $code) {
|
if (0 === $code) {
|
||||||
$code = 500;
|
$code = 500;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,27 +56,27 @@ class Station implements ResolvableUrlInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public URL of the station.
|
* The public URL of the station.
|
||||||
* @OA\Property(example="http://example.com/")
|
* @OA\Property(example="https://example.com/")
|
||||||
*/
|
*/
|
||||||
public ?string $url = null;
|
public ?string $url = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The public player URL for the station.
|
* The public player URL for the station.
|
||||||
* @OA\Property(example="http://example.com/public/example_station")
|
* @OA\Property(example="https://example.com/public/example_station")
|
||||||
* @var string|UriInterface
|
* @var string|UriInterface
|
||||||
*/
|
*/
|
||||||
public $public_player_url;
|
public $public_player_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The playlist download URL in PLS format.
|
* The playlist download URL in PLS format.
|
||||||
* @OA\Property(example="http://example.com/public/example_station/playlist.pls")
|
* @OA\Property(example="https://example.com/public/example_station/playlist.pls")
|
||||||
* @var string|UriInterface
|
* @var string|UriInterface
|
||||||
*/
|
*/
|
||||||
public $playlist_pls_url;
|
public $playlist_pls_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The playlist download URL in M3U format.
|
* The playlist download URL in M3U format.
|
||||||
* @OA\Property(example="http://example.com/public/example_station/playlist.m3u")
|
* @OA\Property(example="https://example.com/public/example_station/playlist.m3u")
|
||||||
* @var string|UriInterface
|
* @var string|UriInterface
|
||||||
*/
|
*/
|
||||||
public $playlist_m3u_url;
|
public $playlist_m3u_url;
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace App\Entity;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
|
use Stringable;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/** @OA\Schema(type="object") */
|
/** @OA\Schema(type="object") */
|
||||||
|
@ -14,7 +15,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
ORM\Table(name: 'custom_field'),
|
ORM\Table(name: 'custom_field'),
|
||||||
Attributes\Auditable
|
Attributes\Auditable
|
||||||
]
|
]
|
||||||
class CustomField implements \Stringable
|
class CustomField implements Stringable
|
||||||
{
|
{
|
||||||
use Traits\HasAutoIncrementId;
|
use Traits\HasAutoIncrementId;
|
||||||
use Traits\TruncateStrings;
|
use Traits\TruncateStrings;
|
||||||
|
|
|
@ -10,9 +10,9 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class Analytics extends AbstractFixture implements DependentFixtureInterface
|
class Analytics extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$stations = $em->getRepository(Entity\Station::class)->findAll();
|
$stations = $manager->getRepository(Entity\Station::class)->findAll();
|
||||||
|
|
||||||
$midnight_utc = CarbonImmutable::now('UTC')->setTime(0, 0);
|
$midnight_utc = CarbonImmutable::now('UTC')->setTime(0, 0);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class Analytics extends AbstractFixture implements DependentFixtureInterface
|
||||||
$station_listeners,
|
$station_listeners,
|
||||||
$station_unique
|
$station_unique
|
||||||
);
|
);
|
||||||
$em->persist($stationPoint);
|
$manager->persist($stationPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
$totalPoint = new Entity\Analytics(
|
$totalPoint = new Entity\Analytics(
|
||||||
|
@ -58,10 +58,10 @@ class Analytics extends AbstractFixture implements DependentFixtureInterface
|
||||||
$day_listeners,
|
$day_listeners,
|
||||||
$day_unique
|
$day_unique
|
||||||
);
|
);
|
||||||
$em->persist($totalPoint);
|
$manager->persist($totalPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$demo_api_key = getenv('INIT_DEMO_API_KEY');
|
$demo_api_key = getenv('INIT_DEMO_API_KEY');
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
||||||
$api_key = new Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
|
$api_key = new Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
|
||||||
$api_key->setComment('Demo User');
|
$api_key->setComment('Demo User');
|
||||||
|
|
||||||
$em->persist($api_key);
|
$manager->persist($api_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
$admin_api_key = getenv('INIT_ADMIN_API_KEY');
|
$admin_api_key = getenv('INIT_ADMIN_API_KEY');
|
||||||
|
@ -33,10 +33,10 @@ class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
||||||
$api_key = new Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
|
$api_key = new Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
|
||||||
$api_key->setComment('Administrator');
|
$api_key->setComment('Administrator');
|
||||||
|
|
||||||
$em->persist($api_key);
|
$manager->persist($api_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class Podcast extends AbstractFixture implements DependentFixtureInterface
|
class Podcast extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
/** @var Entity\Station $station */
|
/** @var Entity\Station $station */
|
||||||
$station = $this->getReference('station');
|
$station = $this->getReference('station');
|
||||||
|
@ -22,12 +22,12 @@ class Podcast extends AbstractFixture implements DependentFixtureInterface
|
||||||
$podcast->setLink('https://demo.azuracast.com');
|
$podcast->setLink('https://demo.azuracast.com');
|
||||||
$podcast->setLanguage('en');
|
$podcast->setLanguage('en');
|
||||||
$podcast->setDescription('The unofficial testing podcast for the AzuraCast development team.');
|
$podcast->setDescription('The unofficial testing podcast for the AzuraCast development team.');
|
||||||
$em->persist($podcast);
|
$manager->persist($podcast);
|
||||||
|
|
||||||
$category = new Entity\PodcastCategory($podcast, 'Technology');
|
$category = new Entity\PodcastCategory($podcast, 'Technology');
|
||||||
$em->persist($category);
|
$manager->persist($category);
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
|
|
||||||
$this->setReference('podcast', $podcast);
|
$this->setReference('podcast', $podcast);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class PodcastEpisode extends AbstractFixture implements DependentFixtureInterfac
|
||||||
$this->mediaRepo = $mediaRepo;
|
$this->mediaRepo = $mediaRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$podcastsSkeletonDir = getenv('INIT_PODCASTS_PATH');
|
$podcastsSkeletonDir = getenv('INIT_PODCASTS_PATH');
|
||||||
|
|
||||||
|
@ -68,8 +68,8 @@ class PodcastEpisode extends AbstractFixture implements DependentFixtureInterfac
|
||||||
$episode->setDescription('Another great episode!');
|
$episode->setDescription('Another great episode!');
|
||||||
$episode->setExplicit(false);
|
$episode->setExplicit(false);
|
||||||
|
|
||||||
$em->persist($episode);
|
$manager->persist($episode);
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
|
|
||||||
$this->mediaRepo->upload(
|
$this->mediaRepo->upload(
|
||||||
$episode,
|
$episode,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class Role extends AbstractFixture
|
class Role extends AbstractFixture
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$admin_role = new Entity\Role();
|
$admin_role = new Entity\Role();
|
||||||
$admin_role->setName('Super Administrator');
|
$admin_role->setName('Super Administrator');
|
||||||
|
@ -16,9 +16,9 @@ class Role extends AbstractFixture
|
||||||
$demo_role = new Entity\Role();
|
$demo_role = new Entity\Role();
|
||||||
$demo_role->setName('Demo Account');
|
$demo_role->setName('Demo Account');
|
||||||
|
|
||||||
$em->persist($admin_role);
|
$manager->persist($admin_role);
|
||||||
$em->persist($demo_role);
|
$manager->persist($demo_role);
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
|
|
||||||
$this->addReference('admin_role', $admin_role);
|
$this->addReference('admin_role', $admin_role);
|
||||||
$this->addReference('demo_role', $demo_role);
|
$this->addReference('demo_role', $demo_role);
|
||||||
|
|
|
@ -10,7 +10,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class RolePermission extends AbstractFixture implements DependentFixtureInterface
|
class RolePermission extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
/** @var Entity\Station $station */
|
/** @var Entity\Station $station */
|
||||||
$station = $this->getReference('station');
|
$station = $this->getReference('station');
|
||||||
|
@ -38,11 +38,11 @@ class RolePermission extends AbstractFixture implements DependentFixtureInterfac
|
||||||
|
|
||||||
foreach ($perm_names as $perm_name) {
|
foreach ($perm_names as $perm_name) {
|
||||||
$rp = new Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
|
$rp = new Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
|
||||||
$em->persist($rp);
|
$manager->persist($rp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,10 +8,10 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class Settings extends AbstractFixture
|
class Settings extends AbstractFixture
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
foreach ($em->getRepository(Entity\Settings::class)->findAll() as $row) {
|
foreach ($manager->getRepository(Entity\Settings::class)->findAll() as $row) {
|
||||||
$em->remove($row);
|
$manager->remove($row);
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings = new Entity\Settings();
|
$settings = new Entity\Settings();
|
||||||
|
@ -43,7 +43,7 @@ class Settings extends AbstractFixture
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->persist($settings);
|
$manager->persist($settings);
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class Station extends AbstractFixture
|
class Station extends AbstractFixture
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$station = new Entity\Station();
|
$station = new Entity\Station();
|
||||||
$station->setName('AzuraTest Radio');
|
$station->setName('AzuraTest Radio');
|
||||||
|
@ -32,12 +32,12 @@ class Station extends AbstractFixture
|
||||||
$podcastsStorage->setStorageQuota($stationQuota);
|
$podcastsStorage->setStorageQuota($stationQuota);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->persist($station);
|
$manager->persist($station);
|
||||||
$em->persist($mediaStorage);
|
$manager->persist($mediaStorage);
|
||||||
$em->persist($recordingsStorage);
|
$manager->persist($recordingsStorage);
|
||||||
$em->persist($podcastsStorage);
|
$manager->persist($podcastsStorage);
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
|
|
||||||
$this->addReference('station', $station);
|
$this->addReference('station', $station);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class StationMedia extends AbstractFixture implements DependentFixtureInterface
|
||||||
$this->mediaRepo = $mediaRepo;
|
$this->mediaRepo = $mediaRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$musicSkeletonDir = getenv('INIT_MUSIC_PATH');
|
$musicSkeletonDir = getenv('INIT_MUSIC_PATH');
|
||||||
|
|
||||||
|
@ -47,15 +47,15 @@ class StationMedia extends AbstractFixture implements DependentFixtureInterface
|
||||||
$fs->upload($filePath, '/' . $fileBaseName);
|
$fs->upload($filePath, '/' . $fileBaseName);
|
||||||
|
|
||||||
$mediaRow = $this->mediaRepo->getOrCreate($mediaStorage, $fileBaseName);
|
$mediaRow = $this->mediaRepo->getOrCreate($mediaStorage, $fileBaseName);
|
||||||
$em->persist($mediaRow);
|
$manager->persist($mediaRow);
|
||||||
|
|
||||||
// Add the file to the playlist.
|
// Add the file to the playlist.
|
||||||
$spmRow = new Entity\StationPlaylistMedia($playlist, $mediaRow);
|
$spmRow = new Entity\StationPlaylistMedia($playlist, $mediaRow);
|
||||||
$spmRow->setWeight(1);
|
$spmRow->setWeight(1);
|
||||||
$em->persist($spmRow);
|
$manager->persist($spmRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class StationMount extends AbstractFixture implements DependentFixtureInterface
|
class StationMount extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
/** @var Entity\Station $station */
|
/** @var Entity\Station $station */
|
||||||
$station = $this->getReference('station');
|
$station = $this->getReference('station');
|
||||||
|
@ -17,14 +17,14 @@ class StationMount extends AbstractFixture implements DependentFixtureInterface
|
||||||
$mount_radio = new Entity\StationMount($station);
|
$mount_radio = new Entity\StationMount($station);
|
||||||
$mount_radio->setName('/radio.mp3');
|
$mount_radio->setName('/radio.mp3');
|
||||||
$mount_radio->setIsDefault(true);
|
$mount_radio->setIsDefault(true);
|
||||||
$em->persist($mount_radio);
|
$manager->persist($mount_radio);
|
||||||
|
|
||||||
$mount_mobile = new Entity\StationMount($station);
|
$mount_mobile = new Entity\StationMount($station);
|
||||||
$mount_mobile->setName('/mobile.mp3');
|
$mount_mobile->setName('/mobile.mp3');
|
||||||
$mount_mobile->setAutodjBitrate(64);
|
$mount_mobile->setAutodjBitrate(64);
|
||||||
$em->persist($mount_mobile);
|
$manager->persist($mount_mobile);
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,15 +9,15 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class StationPlaylist extends AbstractFixture implements DependentFixtureInterface
|
class StationPlaylist extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
/** @var Entity\Station $station */
|
/** @var Entity\Station $station */
|
||||||
$station = $this->getReference('station');
|
$station = $this->getReference('station');
|
||||||
|
|
||||||
$playlist = new Entity\StationPlaylist($station);
|
$playlist = new Entity\StationPlaylist($station);
|
||||||
$playlist->setName('default');
|
$playlist->setName('default');
|
||||||
$em->persist($playlist);
|
$manager->persist($playlist);
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
|
|
||||||
$this->addReference('station_playlist', $playlist);
|
$this->addReference('station_playlist', $playlist);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,14 @@ use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
class User extends AbstractFixture implements DependentFixtureInterface
|
class User extends AbstractFixture implements DependentFixtureInterface
|
||||||
{
|
{
|
||||||
public function load(ObjectManager $em): void
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
$demo_user = new Entity\User();
|
$demo_user = new Entity\User();
|
||||||
$demo_user->setEmail('demo@azuracast.com');
|
$demo_user->setEmail('demo@azuracast.com');
|
||||||
$demo_user->setNewPassword('demo');
|
$demo_user->setNewPassword('demo');
|
||||||
$demo_user->setName('AzuraCast Demo User');
|
$demo_user->setName('AzuraCast Demo User');
|
||||||
$demo_user->getRoles()->add($this->getReference('demo_role'));
|
$demo_user->getRoles()->add($this->getReference('demo_role'));
|
||||||
$em->persist($demo_user);
|
$manager->persist($demo_user);
|
||||||
|
|
||||||
$this->addReference('demo_user', $demo_user);
|
$this->addReference('demo_user', $demo_user);
|
||||||
|
|
||||||
|
@ -37,12 +37,12 @@ class User extends AbstractFixture implements DependentFixtureInterface
|
||||||
$admin_user->setTwoFactorSecret($admin_2fa_secret);
|
$admin_user->setTwoFactorSecret($admin_2fa_secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->persist($admin_user);
|
$manager->persist($admin_user);
|
||||||
|
|
||||||
$this->addReference('admin_user', $admin_user);
|
$this->addReference('admin_user', $admin_user);
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,7 +18,7 @@ final class Version20170829030442 extends AbstractMigration
|
||||||
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
|
$this->changeCharset('utf8mb4', 'utf8mb4_unicode_ci');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function changeCharset($charset, $collate): void
|
private function changeCharset($charset, $collate): void
|
||||||
{
|
{
|
||||||
$db_name = $this->connection->getDatabase();
|
$db_name = $this->connection->getDatabase();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ final class Version20180425050351 extends AbstractMigration
|
||||||
$this->changeCharset('utf8mb4', 'utf8mb4_bin');
|
$this->changeCharset('utf8mb4', 'utf8mb4_bin');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function changeCharset($charset, $collate): void
|
private function changeCharset($charset, $collate): void
|
||||||
{
|
{
|
||||||
$sqlLines = [
|
$sqlLines = [
|
||||||
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
|
'ALTER TABLE `station_media` DROP FOREIGN KEY FK_32AADE3AA0BDB2F3',
|
||||||
|
|
|
@ -20,7 +20,7 @@ final class Version20180826043500 extends AbstractMigration
|
||||||
$this->changeCharset('utf8mb4', 'utf8mb4_general_ci');
|
$this->changeCharset('utf8mb4', 'utf8mb4_general_ci');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function changeCharset($charset, $collate): void
|
private function changeCharset($charset, $collate): void
|
||||||
{
|
{
|
||||||
$db_name = $this->connection->getDatabase();
|
$db_name = $this->connection->getDatabase();
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ final class Version20190513163051 extends AbstractMigration
|
||||||
* @return int
|
* @return int
|
||||||
* @noinspection SummerTimeUnsafeTimeManipulationInspection
|
* @noinspection SummerTimeUnsafeTimeManipulationInspection
|
||||||
*/
|
*/
|
||||||
protected function applyOffset(mixed $time_code, int $offset_hours): int
|
private function applyOffset(mixed $time_code, int $offset_hours): int
|
||||||
{
|
{
|
||||||
$hours = (int)floor($time_code / 100);
|
$hours = (int)floor($time_code / 100);
|
||||||
$mins = $time_code % 100;
|
$mins = $time_code % 100;
|
||||||
|
|
|
@ -84,12 +84,12 @@ final class Version20201204043539 extends AbstractMigration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function toInt($value): ?int
|
private function toInt($value): ?int
|
||||||
{
|
{
|
||||||
return (null === $value) ? null : (int)$value;
|
return (null === $value) ? null : (int)$value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function toBool($value): ?bool
|
private function toBool($value): ?bool
|
||||||
{
|
{
|
||||||
return (null === $value) ? null : (bool)$value;
|
return (null === $value) ? null : (bool)$value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use App\Entity\Traits;
|
use App\Entity\Traits;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use App\Entity\Traits;
|
use App\Entity\Traits;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Relay
|
||||||
use Traits\HasAutoIncrementId;
|
use Traits\HasAutoIncrementId;
|
||||||
use Traits\TruncateStrings;
|
use Traits\TruncateStrings;
|
||||||
|
|
||||||
/** @OA\Property(example="http://custom-url.example.com") */
|
/** @OA\Property(example="https://custom-url.example.com") */
|
||||||
#[ORM\Column(length: 255)]
|
#[ORM\Column(length: 255)]
|
||||||
protected string $base_url;
|
protected string $base_url;
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ class SongHistoryRepository extends Repository
|
||||||
// Pull the most recent history item for this station.
|
// Pull the most recent history item for this station.
|
||||||
$last_sh = $this->getCurrent($station);
|
$last_sh = $this->getCurrent($station);
|
||||||
|
|
||||||
$listeners = (int)$np->listeners->current;
|
$listeners = $np->listeners->current;
|
||||||
|
|
||||||
if ($last_sh instanceof Entity\SongHistory) {
|
if ($last_sh instanceof Entity\SongHistory) {
|
||||||
if ($last_sh->getSongId() === $song->getSongId()) {
|
if ($last_sh->getSongId() === $song->getSongId()) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ class StationStreamerBroadcastRepository extends Repository
|
||||||
->setParameter('streamer', $currentStreamer)
|
->setParameter('streamer', $currentStreamer)
|
||||||
->setMaxResults(1)
|
->setMaxResults(1)
|
||||||
->getSingleResult();
|
->getSingleResult();
|
||||||
|
|
||||||
return $latestBroadcast;
|
return $latestBroadcast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,8 @@ class StationStreamerRepository extends Repository
|
||||||
$this->em->persist($record);
|
$this->em->persist($record);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
||||||
$fsStations = new StationFilesystems($station);
|
return (new StationFilesystems($station))->getTempFilesystem()
|
||||||
return $fsStations->getTempFilesystem()->getLocalPath($recordingPath);
|
->getLocalPath($recordingPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use App\Customization;
|
use App\Customization;
|
||||||
use App\Doctrine\Generator\UuidV6Generator;
|
use App\Doctrine\Generator\UuidV6Generator;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
|
|
|
@ -13,6 +13,7 @@ use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Exception;
|
use Exception;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/** @OA\Schema(type="object") */
|
/** @OA\Schema(type="object") */
|
||||||
|
@ -207,7 +208,7 @@ class StationMedia implements SongInterface, ProcessableMediaInterface, PathAwar
|
||||||
public function getUniqueId(): string
|
public function getUniqueId(): string
|
||||||
{
|
{
|
||||||
if (!isset($this->unique_id)) {
|
if (!isset($this->unique_id)) {
|
||||||
throw new \RuntimeException('Unique ID has not been generated yet.');
|
throw new RuntimeException('Unique ID has not been generated yet.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->unique_id;
|
return $this->unique_id;
|
||||||
|
|
|
@ -10,6 +10,7 @@ use App\Radio\Frontend\AbstractFrontend;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
use Psr\Http\Message\UriInterface;
|
use Psr\Http\Message\UriInterface;
|
||||||
|
use Stringable;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/** @OA\Schema(type="object") */
|
/** @OA\Schema(type="object") */
|
||||||
|
@ -18,7 +19,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
ORM\Table(name: 'station_mounts'),
|
ORM\Table(name: 'station_mounts'),
|
||||||
Attributes\Auditable
|
Attributes\Auditable
|
||||||
]
|
]
|
||||||
class StationMount implements \Stringable, Interfaces\StationMountInterface, Interfaces\StationCloneAwareInterface
|
class StationMount implements Stringable, Interfaces\StationMountInterface, Interfaces\StationCloneAwareInterface
|
||||||
{
|
{
|
||||||
use Traits\HasAutoIncrementId;
|
use Traits\HasAutoIncrementId;
|
||||||
use Traits\TruncateStrings;
|
use Traits\TruncateStrings;
|
||||||
|
@ -55,7 +56,7 @@ class StationMount implements \Stringable, Interfaces\StationMountInterface, Int
|
||||||
#[ORM\Column(length: 100, nullable: true)]
|
#[ORM\Column(length: 100, nullable: true)]
|
||||||
protected ?string $fallback_mount = null;
|
protected ?string $fallback_mount = null;
|
||||||
|
|
||||||
/** @OA\Property(example="http://radio.example.com:8000/radio.mp3") */
|
/** @OA\Property(example="https://radio.example.com:8000/radio.mp3") */
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
protected ?string $relay_url = null;
|
protected ?string $relay_url = null;
|
||||||
|
|
||||||
|
@ -335,7 +336,7 @@ class StationMount implements \Stringable, Interfaces\StationMountInterface, Int
|
||||||
$response->id = $this->id;
|
$response->id = $this->id;
|
||||||
$response->name = $this->getDisplayName();
|
$response->name = $this->getDisplayName();
|
||||||
$response->path = $this->getName();
|
$response->path = $this->getName();
|
||||||
$response->is_default = (bool)$this->is_default;
|
$response->is_default = $this->is_default;
|
||||||
$response->url = $fa->getUrlForMount($this->station, $this, $base_url);
|
$response->url = $fa->getUrlForMount($this->station, $this, $base_url);
|
||||||
|
|
||||||
$response->listeners = new Api\NowPlayingListeners(
|
$response->listeners = new Api\NowPlayingListeners(
|
||||||
|
|
|
@ -82,7 +82,7 @@ class StationPlaylist implements Stringable, Interfaces\StationCloneAwareInterfa
|
||||||
#[Assert\Choice(choices: [self::ORDER_RANDOM, self::ORDER_SHUFFLE, self::ORDER_SEQUENTIAL])]
|
#[Assert\Choice(choices: [self::ORDER_RANDOM, self::ORDER_SHUFFLE, self::ORDER_SEQUENTIAL])]
|
||||||
protected string $order = self::ORDER_SHUFFLE;
|
protected string $order = self::ORDER_SHUFFLE;
|
||||||
|
|
||||||
/** @OA\Property(example="http://remote-url.example.com/stream.mp3") */
|
/** @OA\Property(example="https://remote-url.example.com/stream.mp3") */
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
protected ?string $remote_url = null;
|
protected ?string $remote_url = null;
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ class StationPlaylistMedia implements JsonSerializable
|
||||||
return [
|
return [
|
||||||
'id' => $this->playlist->getId(),
|
'id' => $this->playlist->getId(),
|
||||||
'name' => $this->playlist->getName(),
|
'name' => $this->playlist->getName(),
|
||||||
'weight' => (int)$this->weight,
|
'weight' => $this->weight,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class StationRemote implements Stringable, Interfaces\StationMountInterface, Int
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
protected ?string $custom_listen_url = null;
|
protected ?string $custom_listen_url = null;
|
||||||
|
|
||||||
/** @OA\Property(example="http://custom-url.example.com") */
|
/** @OA\Property(example="https://custom-url.example.com") */
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
protected ?string $url = null;
|
protected ?string $url = null;
|
||||||
|
|
||||||
|
@ -310,6 +310,7 @@ class StationRemote implements Stringable, Interfaces\StationMountInterface, Int
|
||||||
public function setUrl(?string $url): void
|
public function setUrl(?string $url): void
|
||||||
{
|
{
|
||||||
if (!empty($url) && !str_starts_with($url, 'http')) {
|
if (!empty($url) && !str_starts_with($url, 'http')) {
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$url = 'http://' . $url;
|
$url = 'http://' . $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class StationSchedule
|
||||||
|
|
||||||
public function getStartTime(): int
|
public function getStartTime(): int
|
||||||
{
|
{
|
||||||
return (int)$this->start_time;
|
return $this->start_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStartTime(int $start_time): void
|
public function setStartTime(int $start_time): void
|
||||||
|
@ -85,7 +85,7 @@ class StationSchedule
|
||||||
|
|
||||||
public function getEndTime(): int
|
public function getEndTime(): int
|
||||||
{
|
{
|
||||||
return (int)$this->end_time;
|
return $this->end_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEndTime(int $end_time): void
|
public function setEndTime(int $end_time): void
|
||||||
|
|
|
@ -11,6 +11,7 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
|
use Stringable;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ use const PASSWORD_ARGON2ID;
|
||||||
UniqueEntity(fields: ['station', 'streamer_username']),
|
UniqueEntity(fields: ['station', 'streamer_username']),
|
||||||
Attributes\Auditable
|
Attributes\Auditable
|
||||||
]
|
]
|
||||||
class StationStreamer implements \Stringable, Interfaces\StationCloneAwareInterface
|
class StationStreamer implements Stringable, Interfaces\StationCloneAwareInterface
|
||||||
{
|
{
|
||||||
use Traits\HasAutoIncrementId;
|
use Traits\HasAutoIncrementId;
|
||||||
use Traits\TruncateStrings;
|
use Traits\TruncateStrings;
|
||||||
|
@ -79,7 +80,7 @@ class StationStreamer implements \Stringable, Interfaces\StationCloneAwareInterf
|
||||||
* @OA\Items()
|
* @OA\Items()
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
#[ORM\OneToMany(targetEntity: StationSchedule::class, mappedBy: 'streamer')]
|
#[ORM\OneToMany(mappedBy: 'streamer', targetEntity: StationSchedule::class)]
|
||||||
#[DeepNormalize(true)]
|
#[DeepNormalize(true)]
|
||||||
#[Serializer\MaxDepth(1)]
|
#[Serializer\MaxDepth(1)]
|
||||||
protected Collection $schedule_items;
|
protected Collection $schedule_items;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use OpenApi\Annotations as OA;
|
use OpenApi\Annotations as OA;
|
||||||
use Stringable;
|
use Stringable;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use App\Radio\Quota;
|
use App\Radio\Quota;
|
||||||
use App\Validator\Constraints as AppAssert;
|
use App\Validator\Constraints as AppAssert;
|
||||||
use Aws\S3\S3Client;
|
use Aws\S3\S3Client;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Entity\Traits;
|
namespace App\Entity\Traits;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
use App\Entity;
|
||||||
use App\Security\SplitToken;
|
use App\Security\SplitToken;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ trait HasSplitTokenFields
|
||||||
protected string $id;
|
protected string $id;
|
||||||
|
|
||||||
#[ORM\Column(length: 128)]
|
#[ORM\Column(length: 128)]
|
||||||
#[\App\Entity\Attributes\AuditIgnore]
|
#[Entity\Attributes\AuditIgnore]
|
||||||
protected string $verifier;
|
protected string $verifier;
|
||||||
|
|
||||||
protected function setFromToken(SplitToken $token): void
|
protected function setFromToken(SplitToken $token): void
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use App\Annotations\AuditLog;
|
|
||||||
use App\Auth;
|
use App\Auth;
|
||||||
use App\Normalizer\Attributes\DeepNormalize;
|
use App\Normalizer\Attributes\DeepNormalize;
|
||||||
use App\Validator\Constraints\UniqueEntity;
|
use App\Validator\Constraints\UniqueEntity;
|
||||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Http;
|
||||||
|
|
||||||
use Azura\Files\Adapter\LocalAdapterInterface;
|
use Azura\Files\Adapter\LocalAdapterInterface;
|
||||||
use Azura\Files\ExtendedFilesystemInterface;
|
use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use Azura\Files\FilesystemInterface;
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use League\Flysystem\FileAttributes;
|
use League\Flysystem\FileAttributes;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
|
@ -42,6 +42,7 @@ class Router implements RouterInterface
|
||||||
$settingsBaseUrl = $settings->getBaseUrl();
|
$settingsBaseUrl = $settings->getBaseUrl();
|
||||||
if (!empty($settingsBaseUrl)) {
|
if (!empty($settingsBaseUrl)) {
|
||||||
if (!str_starts_with($settingsBaseUrl, 'http')) {
|
if (!str_starts_with($settingsBaseUrl, 'http')) {
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$settingsBaseUrl = 'http://' . $settingsBaseUrl;
|
$settingsBaseUrl = 'http://' . $settingsBaseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ final class ServerRequest extends \Slim\Http\ServerRequest
|
||||||
*
|
*
|
||||||
* @throws Exception\InvalidRequestAttribute
|
* @throws Exception\InvalidRequestAttribute
|
||||||
*/
|
*/
|
||||||
protected function getAttributeOfClass(string $attr, string $class_name): mixed
|
private function getAttributeOfClass(string $attr, string $class_name): mixed
|
||||||
{
|
{
|
||||||
$object = $this->serverRequest->getAttribute($attr);
|
$object = $this->serverRequest->getAttribute($attr);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use App\Entity;
|
||||||
use App\Utilities\File;
|
use App\Utilities\File;
|
||||||
use Azura\Files\ExtendedFilesystemInterface;
|
use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class BatchUtilities
|
class BatchUtilities
|
||||||
{
|
{
|
||||||
|
@ -35,7 +36,7 @@ class BatchUtilities
|
||||||
|
|
||||||
foreach ($toRename as $iterator) {
|
foreach ($toRename as $iterator) {
|
||||||
foreach ($iterator as $record) {
|
foreach ($iterator as $record) {
|
||||||
/** @var \App\Entity\Interfaces\PathAwareInterface $record */
|
/** @var Entity\Interfaces\PathAwareInterface $record */
|
||||||
$record->setPath(
|
$record->setPath(
|
||||||
File::renameDirectoryInPath($record->getPath(), $from, $to)
|
File::renameDirectoryInPath($record->getPath(), $from, $to)
|
||||||
);
|
);
|
||||||
|
@ -88,7 +89,7 @@ class BatchUtilities
|
||||||
$affectedPlaylists[$playlistId] = $playlist;
|
$affectedPlaylists[$playlistId] = $playlist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable) {
|
} catch (Throwable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
|
||||||
|
use const JSON_THROW_ON_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When sending data using multipart forms (that also include uploaded files, for example),
|
* When sending data using multipart forms (that also include uploaded files, for example),
|
||||||
* it isn't possible to encode JSON values (i.e. booleans) in the other submitted values.
|
* it isn't possible to encode JSON values (i.e. booleans) in the other submitted values.
|
||||||
|
@ -34,7 +36,7 @@ class HandleMultipartJson implements MiddlewareInterface
|
||||||
if (1 === count($parsedBody)) {
|
if (1 === count($parsedBody)) {
|
||||||
$bodyField = current($parsedBody);
|
$bodyField = current($parsedBody);
|
||||||
if (is_string($bodyField)) {
|
if (is_string($bodyField)) {
|
||||||
$parsedBody = json_decode($bodyField, true, 512, \JSON_THROW_ON_ERROR);
|
$parsedBody = json_decode($bodyField, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
$request = $request->withParsedBody($parsedBody);
|
$request = $request->withParsedBody($parsedBody);
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,17 +113,17 @@ class DoctrineEntityNormalizer extends AbstractNormalizer
|
||||||
* Replicates the "fromArray" functionality previously present in Doctrine 1.
|
* Replicates the "fromArray" functionality previously present in Doctrine 1.
|
||||||
*
|
*
|
||||||
* @param mixed $data
|
* @param mixed $data
|
||||||
* @param string $class
|
* @param string $type
|
||||||
* @param string|null $format
|
* @param string|null $format
|
||||||
* @param array $context
|
* @param array $context
|
||||||
*/
|
*/
|
||||||
public function denormalize($data, string $class, string $format = null, array $context = []): object
|
public function denormalize($data, string $type, string $format = null, array $context = []): object
|
||||||
{
|
{
|
||||||
$object = $this->instantiateObject($data, $class, $context, new ReflectionClass($class), false, $format);
|
$object = $this->instantiateObject($data, $type, $context, new ReflectionClass($type), false, $format);
|
||||||
|
|
||||||
$class = get_class($object);
|
$type = get_class($object);
|
||||||
|
|
||||||
$context[self::CLASS_METADATA] = $this->em->getMetadataFactory()->getMetadataFor($class);
|
$context[self::CLASS_METADATA] = $this->em->getMetadataFactory()->getMetadataFor($type);
|
||||||
$context[self::ASSOCIATION_MAPPINGS] = [];
|
$context[self::ASSOCIATION_MAPPINGS] = [];
|
||||||
|
|
||||||
if ($context[self::CLASS_METADATA]->associationMappings) {
|
if ($context[self::CLASS_METADATA]->associationMappings) {
|
||||||
|
|
|
@ -6,9 +6,11 @@ use App\Http\Response;
|
||||||
use App\Http\Router;
|
use App\Http\Router;
|
||||||
use App\Http\RouterInterface;
|
use App\Http\RouterInterface;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
|
use Countable;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Query;
|
use Doctrine\ORM\Query;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use IteratorAggregate;
|
||||||
use Pagerfanta\Adapter\ArrayAdapter;
|
use Pagerfanta\Adapter\ArrayAdapter;
|
||||||
use Pagerfanta\Doctrine\Collections\CollectionAdapter;
|
use Pagerfanta\Doctrine\Collections\CollectionAdapter;
|
||||||
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
use Pagerfanta\Doctrine\ORM\QueryAdapter;
|
||||||
|
@ -17,7 +19,7 @@ use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
|
|
||||||
class Paginator implements \IteratorAggregate, \Countable
|
class Paginator implements IteratorAggregate, Countable
|
||||||
{
|
{
|
||||||
protected RouterInterface $router;
|
protected RouterInterface $router;
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ class Scheduler
|
||||||
Entity\StationPlaylist $playlist,
|
Entity\StationPlaylist $playlist,
|
||||||
CarbonInterface $now
|
CarbonInterface $now
|
||||||
): bool {
|
): bool {
|
||||||
$current_minute = (int)$now->minute;
|
$current_minute = $now->minute;
|
||||||
$target_minute = $playlist->getPlayPerHourMinute();
|
$target_minute = $playlist->getPlayPerHourMinute();
|
||||||
|
|
||||||
if ($current_minute < $target_minute) {
|
if ($current_minute < $target_minute) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Radio\Backend;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Radio\AbstractAdapter;
|
use App\Radio\AbstractAdapter;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
|
|
||||||
abstract class AbstractBackend extends AbstractAdapter
|
abstract class AbstractBackend extends AbstractAdapter
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,7 @@ abstract class AbstractBackend extends AbstractAdapter
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProgramName(Entity\Station $station): string
|
#[Pure] public function getProgramName(Entity\Station $station): string
|
||||||
{
|
{
|
||||||
return 'station_' . $station->getId() . ':station_' . $station->getId() . '_backend';
|
return 'station_' . $station->getId() . ':station_' . $station->getId() . '_backend';
|
||||||
}
|
}
|
||||||
|
|
|
@ -683,6 +683,8 @@ class ConfigWriter implements EventSubscriberInterface
|
||||||
$params['api_auth'] = '!azuracast_api_auth';
|
$params['api_auth'] = '!azuracast_api_auth';
|
||||||
|
|
||||||
$service_uri = ($this->environment->isDockerRevisionAtLeast(5)) ? 'web' : 'nginx';
|
$service_uri = ($this->environment->isDockerRevisionAtLeast(5)) ? 'web' : 'nginx';
|
||||||
|
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$api_url = 'http://' . $service_uri . '/api/internal/' . $station->getId() . '/' . $endpoint;
|
$api_url = 'http://' . $service_uri . '/api/internal/' . $station->getId() . '/' . $endpoint;
|
||||||
$command = 'curl -s --request POST --url ' . $api_url;
|
$command = 'curl -s --request POST --url ' . $api_url;
|
||||||
foreach ($params as $paramKey => $paramVal) {
|
foreach ($params as $paramKey => $paramVal) {
|
||||||
|
@ -991,11 +993,6 @@ class ConfigWriter implements EventSubscriberInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given outbound broadcast information, produce a suitable LiquidSoap configuration line for the stream.
|
* Given outbound broadcast information, produce a suitable LiquidSoap configuration line for the stream.
|
||||||
*
|
|
||||||
* @param Entity\Station $station
|
|
||||||
* @param \App\Entity\Interfaces\StationMountInterface $mount
|
|
||||||
* @param string $idPrefix
|
|
||||||
* @param int $id
|
|
||||||
*/
|
*/
|
||||||
protected function getOutputString(
|
protected function getOutputString(
|
||||||
Entity\Station $station,
|
Entity\Station $station,
|
||||||
|
|
|
@ -9,6 +9,7 @@ use App\Http\Router;
|
||||||
use App\Radio\AbstractAdapter;
|
use App\Radio\AbstractAdapter;
|
||||||
use App\Xml\Reader;
|
use App\Xml\Reader;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Exception;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Psr7\Uri;
|
use GuzzleHttp\Psr7\Uri;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
@ -177,7 +178,7 @@ abstract class AbstractFrontend extends AbstractAdapter
|
||||||
if (str_starts_with($custom_config_raw, '<')) {
|
if (str_starts_with($custom_config_raw, '<')) {
|
||||||
return (new Reader())->fromString('<custom_config>' . $custom_config_raw . '</custom_config>');
|
return (new Reader())->fromString('<custom_config>' . $custom_config_raw . '</custom_config>');
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->logger->error(
|
$this->logger->error(
|
||||||
'Could not parse custom configuration.',
|
'Could not parse custom configuration.',
|
||||||
[
|
[
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Icecast extends AbstractFrontend
|
||||||
$feConfig = $station->getFrontendConfig();
|
$feConfig = $station->getFrontendConfig();
|
||||||
$radioPort = $feConfig->getPort();
|
$radioPort = $feConfig->getPort();
|
||||||
|
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$baseUrl = 'http://' . ($this->environment->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
|
$baseUrl = 'http://' . ($this->environment->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
|
||||||
|
|
||||||
$npAdapter = $this->adapterFactory->getIcecastAdapter($baseUrl);
|
$npAdapter = $this->adapterFactory->getIcecastAdapter($baseUrl);
|
||||||
|
@ -91,6 +92,7 @@ class Icecast extends AbstractFrontend
|
||||||
|
|
||||||
$settingsBaseUrl = $settings->getBaseUrl() ?: 'http://localhost';
|
$settingsBaseUrl = $settings->getBaseUrl() ?: 'http://localhost';
|
||||||
if (!str_starts_with($settingsBaseUrl, 'http')) {
|
if (!str_starts_with($settingsBaseUrl, 'http')) {
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$settingsBaseUrl = 'http://' . $settingsBaseUrl;
|
$settingsBaseUrl = 'http://' . $settingsBaseUrl;
|
||||||
}
|
}
|
||||||
$baseUrl = new Uri($settingsBaseUrl);
|
$baseUrl = new Uri($settingsBaseUrl);
|
||||||
|
|
|
@ -59,6 +59,8 @@ class SHOUTcast extends AbstractFrontend
|
||||||
{
|
{
|
||||||
$feConfig = $station->getFrontendConfig();
|
$feConfig = $station->getFrontendConfig();
|
||||||
$radioPort = $feConfig->getPort();
|
$radioPort = $feConfig->getPort();
|
||||||
|
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$baseUrl = 'http://' . ($this->environment->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
|
$baseUrl = 'http://' . ($this->environment->isDocker() ? 'stations' : 'localhost') . ':' . $radioPort;
|
||||||
|
|
||||||
$npAdapter = $this->adapterFactory->getShoutcast2Adapter($baseUrl);
|
$npAdapter = $this->adapterFactory->getShoutcast2Adapter($baseUrl);
|
||||||
|
|
|
@ -44,8 +44,8 @@ class NChan
|
||||||
{
|
{
|
||||||
$vars = [];
|
$vars = [];
|
||||||
|
|
||||||
if (0 === stripos(PHP_OS, 'linux')) {
|
if ('Linux' === PHP_OS_FAMILY) {
|
||||||
foreach (glob('/etc/*-release') as $file) {
|
foreach (glob(' /etc/*-release', GLOB_NOSORT) as $file) {
|
||||||
$lines = array_filter(
|
$lines = array_filter(
|
||||||
array_map(
|
array_map(
|
||||||
static function ($line) {
|
static function ($line) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use App\EventDispatcher;
|
||||||
use App\LockFactory;
|
use App\LockFactory;
|
||||||
use App\Message;
|
use App\Message;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Exception;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Monolog\Handler\StreamHandler;
|
use Monolog\Handler\StreamHandler;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
@ -92,7 +93,7 @@ class Runner
|
||||||
foreach ($event->getTasks() as $taskClass => $task) {
|
foreach ($event->getTasks() as $taskClass => $task) {
|
||||||
try {
|
try {
|
||||||
$lock->refresh($syncInfo['timeout']);
|
$lock->refresh($syncInfo['timeout']);
|
||||||
} catch (\Exception) {
|
} catch (Exception) {
|
||||||
// Noop
|
// Noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@ class File
|
||||||
*/
|
*/
|
||||||
public static function sanitizePathPrefix(string $path): string
|
public static function sanitizePathPrefix(string $path): string
|
||||||
{
|
{
|
||||||
$pattern = '/.*:\/\//i';
|
$pattern = '/:\/\//';
|
||||||
|
|
||||||
$path = preg_replace($pattern, '', $path);
|
$path = preg_replace($pattern, '', $path);
|
||||||
|
|
||||||
if (preg_match($pattern, $path)) {
|
if (preg_match($pattern, $path)) {
|
||||||
|
|
|
@ -104,6 +104,7 @@ class Strings
|
||||||
*/
|
*/
|
||||||
public static function truncateUrl(string $url, $length = 40): string
|
public static function truncateUrl(string $url, $length = 40): string
|
||||||
{
|
{
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
$url = str_replace(['http://', 'https://', 'www.'], '', $url);
|
$url = str_replace(['http://', 'https://', 'www.'], '', $url);
|
||||||
|
|
||||||
return self::truncateText(rtrim($url, '/'), $length);
|
return self::truncateText(rtrim($url, '/'), $length);
|
||||||
|
|
|
@ -17,17 +17,17 @@ class StationPortCheckerValidator extends ConstraintValidator
|
||||||
$this->configuration = $configuration;
|
$this->configuration = $configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate($station, Constraint $constraint): void
|
public function validate($value, Constraint $constraint): void
|
||||||
{
|
{
|
||||||
if (!$constraint instanceof StationPortChecker) {
|
if (!$constraint instanceof StationPortChecker) {
|
||||||
throw new UnexpectedTypeException($constraint, StationPortChecker::class);
|
throw new UnexpectedTypeException($constraint, StationPortChecker::class);
|
||||||
}
|
}
|
||||||
if (!$station instanceof Entity\Station) {
|
if (!$value instanceof Entity\Station) {
|
||||||
throw new UnexpectedTypeException($station, Entity\Station::class);
|
throw new UnexpectedTypeException($value, Entity\Station::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
$frontend_config = $station->getFrontendConfig();
|
$frontend_config = $value->getFrontendConfig();
|
||||||
$backend_config = $station->getBackendConfig();
|
$backend_config = $value->getBackendConfig();
|
||||||
|
|
||||||
$ports_to_check = [
|
$ports_to_check = [
|
||||||
'frontend_config_port' => $frontend_config->getPort(),
|
'frontend_config_port' => $frontend_config->getPort(),
|
||||||
|
@ -35,16 +35,16 @@ class StationPortCheckerValidator extends ConstraintValidator
|
||||||
'backend_config_telnet_port' => $backend_config->getTelnetPort(),
|
'backend_config_telnet_port' => $backend_config->getTelnetPort(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$used_ports = $this->configuration->getUsedPorts($station);
|
$used_ports = $this->configuration->getUsedPorts($value);
|
||||||
|
|
||||||
$message = __('The port %s is in use by another station.', '{{ port }}');
|
$message = __('The port %s is in use by another station.', '{{ port }}');
|
||||||
|
|
||||||
foreach ($ports_to_check as $port_path => $value) {
|
foreach ($ports_to_check as $port_path => $port) {
|
||||||
if (null === $value) {
|
if (null === $port) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$port = (int)$value;
|
$port = (int)$port;
|
||||||
if (isset($used_ports[$port])) {
|
if (isset($used_ports[$port])) {
|
||||||
$this->context->buildViolation($message)
|
$this->context->buildViolation($message)
|
||||||
->setParameter('{{ port }}', (string)$port)
|
->setParameter('{{ port }}', (string)$port)
|
||||||
|
|
|
@ -18,19 +18,19 @@ class StorageLocationValidator extends ConstraintValidator
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate($storageLocation, Constraint $constraint): void
|
public function validate($value, Constraint $constraint): void
|
||||||
{
|
{
|
||||||
if (!$constraint instanceof StorageLocation) {
|
if (!$constraint instanceof StorageLocation) {
|
||||||
throw new UnexpectedTypeException($constraint, StorageLocation::class);
|
throw new UnexpectedTypeException($constraint, StorageLocation::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!($storageLocation instanceof Entity\StorageLocation)) {
|
if (!($value instanceof Entity\StorageLocation)) {
|
||||||
throw new UnexpectedTypeException($storageLocation, Entity\StorageLocation::class);
|
throw new UnexpectedTypeException($value, Entity\StorageLocation::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure this storage location validates.
|
// Ensure this storage location validates.
|
||||||
try {
|
try {
|
||||||
$storageLocation->validate();
|
$value->validate();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$message = __(
|
$message = __(
|
||||||
'Storage location %s could not be validated: %s',
|
'Storage location %s could not be validated: %s',
|
||||||
|
@ -39,7 +39,7 @@ class StorageLocationValidator extends ConstraintValidator
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->context->buildViolation($message)
|
$this->context->buildViolation($message)
|
||||||
->setParameter('{{ storageLocation }}', (string)$storageLocation)
|
->setParameter('{{ storageLocation }}', (string)$value)
|
||||||
->setParameter('{{ error }}', $e->getMessage())
|
->setParameter('{{ error }}', $e->getMessage())
|
||||||
->addViolation();
|
->addViolation();
|
||||||
}
|
}
|
||||||
|
@ -49,16 +49,16 @@ class StorageLocationValidator extends ConstraintValidator
|
||||||
->select('sl')
|
->select('sl')
|
||||||
->from(Entity\StorageLocation::class, 'sl')
|
->from(Entity\StorageLocation::class, 'sl')
|
||||||
->where('sl.type = :type')
|
->where('sl.type = :type')
|
||||||
->setParameter('type', $storageLocation->getType())
|
->setParameter('type', $value->getType())
|
||||||
->andWhere('sl.adapter = :adapter')
|
->andWhere('sl.adapter = :adapter')
|
||||||
->setParameter('adapter', $storageLocation->getAdapter());
|
->setParameter('adapter', $value->getAdapter());
|
||||||
|
|
||||||
if (null !== $storageLocation->getId()) {
|
if (null !== $value->getId()) {
|
||||||
$qb->andWhere('sl.id != :id')
|
$qb->andWhere('sl.id != :id')
|
||||||
->setParameter('id', $storageLocation->getId());
|
->setParameter('id', $value->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$storageLocationUri = $storageLocation->getUri();
|
$storageLocationUri = $value->getUri();
|
||||||
|
|
||||||
/** @var Entity\StorageLocation $row */
|
/** @var Entity\StorageLocation $row */
|
||||||
foreach ($qb->getQuery()->toIterable() as $row) {
|
foreach ($qb->getQuery()->toIterable() as $row) {
|
||||||
|
@ -69,7 +69,7 @@ class StorageLocationValidator extends ConstraintValidator
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->context->buildViolation($message)
|
$this->context->buildViolation($message)
|
||||||
->setParameter('{{ storageLocation }}', (string)$storageLocation)
|
->setParameter('{{ storageLocation }}', (string)$value)
|
||||||
->addViolation();
|
->addViolation();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -42,12 +42,12 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param object $entity
|
* @param object $value
|
||||||
*
|
*
|
||||||
* @throws UnexpectedTypeException
|
* @throws UnexpectedTypeException
|
||||||
* @throws ConstraintDefinitionException
|
* @throws ConstraintDefinitionException
|
||||||
*/
|
*/
|
||||||
public function validate($entity, Constraint $constraint): void
|
public function validate($value, Constraint $constraint): void
|
||||||
{
|
{
|
||||||
if (!$constraint instanceof UniqueEntity) {
|
if (!$constraint instanceof UniqueEntity) {
|
||||||
throw new UnexpectedTypeException($constraint, UniqueEntity::class);
|
throw new UnexpectedTypeException($constraint, UniqueEntity::class);
|
||||||
|
@ -67,11 +67,11 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
throw new ConstraintDefinitionException('At least one field has to be specified.');
|
throw new ConstraintDefinitionException('At least one field has to be specified.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $entity) {
|
if (null === $value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = $this->em->getClassMetadata(get_class($entity));
|
$class = $this->em->getClassMetadata(get_class($value));
|
||||||
|
|
||||||
$criteria = [];
|
$criteria = [];
|
||||||
$hasNullValue = false;
|
$hasNullValue = false;
|
||||||
|
@ -86,7 +86,7 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fieldValue = $class->reflFields[$fieldName]->getValue($entity);
|
$fieldValue = $class->reflFields[$fieldName]->getValue($value);
|
||||||
|
|
||||||
if (null === $fieldValue) {
|
if (null === $fieldValue) {
|
||||||
$hasNullValue = true;
|
$hasNullValue = true;
|
||||||
|
@ -126,7 +126,7 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
$repository = $this->em->getRepository($constraint->entityClass);
|
$repository = $this->em->getRepository($constraint->entityClass);
|
||||||
$supportedClass = $repository->getClassName();
|
$supportedClass = $repository->getClassName();
|
||||||
|
|
||||||
if (!$entity instanceof $supportedClass) {
|
if (!$value instanceof $supportedClass) {
|
||||||
throw new ConstraintDefinitionException(
|
throw new ConstraintDefinitionException(
|
||||||
sprintf(
|
sprintf(
|
||||||
'The "%s" entity repository does not support the "%s" entity. The entity should be '
|
'The "%s" entity repository does not support the "%s" entity. The entity should be '
|
||||||
|
@ -138,7 +138,7 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$repository = $this->em->getRepository(get_class($entity));
|
$repository = $this->em->getRepository(get_class($value));
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $repository->{$constraint->repositoryMethod}($criteria);
|
$result = $repository->{$constraint->repositoryMethod}($criteria);
|
||||||
|
@ -168,7 +168,7 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||||
* which is the same as the entity being validated, the criteria is
|
* which is the same as the entity being validated, the criteria is
|
||||||
* unique.
|
* unique.
|
||||||
*/
|
*/
|
||||||
if (!$result || (1 === count($result) && current($result) === $entity)) {
|
if (!$result || (1 === count($result) && current($result) === $value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Webhook\Connector;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Utilities;
|
use App\Utilities;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
|
use JetBrains\PhpStorm\Pure;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use Symfony\Component\Validator\Constraints\UrlValidator;
|
use Symfony\Component\Validator\Constraints\UrlValidator;
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ abstract class AbstractConnector implements ConnectorInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function webhookShouldTrigger(Entity\StationWebhook $webhook, array $triggers = []): bool
|
#[Pure] protected function webhookShouldTrigger(Entity\StationWebhook $webhook, array $triggers = []): bool
|
||||||
{
|
{
|
||||||
$webhookTriggers = $webhook->getTriggers();
|
$webhookTriggers = $webhook->getTriggers();
|
||||||
if (empty($webhookTriggers)) {
|
if (empty($webhookTriggers)) {
|
||||||
|
@ -105,7 +106,7 @@ abstract class AbstractConnector implements ConnectorInterface
|
||||||
protected function getValidUrl(?string $url_string = null): ?string
|
protected function getValidUrl(?string $url_string = null): ?string
|
||||||
{
|
{
|
||||||
$url = trim($url_string);
|
$url = trim($url_string);
|
||||||
$pattern = sprintf(UrlValidator::PATTERN, implode('|', ['http', 'https']));
|
$pattern = sprintf(UrlValidator::PATTERN, 'http|https');
|
||||||
return (preg_match($pattern, $url)) ? $url : null;
|
return (preg_match($pattern, $url)) ? $url : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Webhook\Connector;
|
namespace App\Webhook\Connector;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Event\SendWebhooks;
|
|
||||||
|
|
||||||
interface ConnectorInterface
|
interface ConnectorInterface
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,6 +152,7 @@ class Discord extends AbstractConnector
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @noinspection HttpUrlsUsage */
|
||||||
protected function getImageUrl(?string $url = null): ?string
|
protected function getImageUrl(?string $url = null): ?string
|
||||||
{
|
{
|
||||||
$url = $this->getValidUrl($url);
|
$url = $this->getValidUrl($url);
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Webhook\Connector;
|
namespace App\Webhook\Connector;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Event\SendWebhooks;
|
|
||||||
use App\Radio\Adapters;
|
use App\Radio\Adapters;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Webhook\Connector;
|
namespace App\Webhook\Connector;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Event\SendWebhooks;
|
|
||||||
use GuzzleHttp\Exception\TransferException;
|
use GuzzleHttp\Exception\TransferException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Webhook\Connector;
|
namespace App\Webhook\Connector;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Event\SendWebhooks;
|
|
||||||
use GuzzleHttp\Exception\TransferException;
|
use GuzzleHttp\Exception\TransferException;
|
||||||
|
|
||||||
class TuneIn extends AbstractConnector
|
class TuneIn extends AbstractConnector
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Webhook\Connector;
|
namespace App\Webhook\Connector;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Event\SendWebhooks;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Exception\TransferException;
|
use GuzzleHttp\Exception\TransferException;
|
||||||
|
|
Loading…
Reference in New Issue