Bug fixes, Repo and CustomAsset cleanup.
This commit is contained in:
parent
3c1bec857b
commit
b6767e1bc3
|
@ -10,11 +10,6 @@ use Psr\Http\Message\UriInterface;
|
||||||
|
|
||||||
abstract class AbstractCustomAsset implements CustomAssetInterface
|
abstract class AbstractCustomAsset implements CustomAssetInterface
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
protected Environment $environment
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected function getPattern(): string;
|
abstract protected function getPattern(): string;
|
||||||
|
|
||||||
abstract protected function getDefaultUrl(): string;
|
abstract protected function getDefaultUrl(): string;
|
||||||
|
@ -22,7 +17,7 @@ abstract class AbstractCustomAsset implements CustomAssetInterface
|
||||||
public function getPath(): string
|
public function getPath(): string
|
||||||
{
|
{
|
||||||
$pattern = sprintf($this->getPattern(), '');
|
$pattern = sprintf($this->getPattern(), '');
|
||||||
return $this->environment->getUploadsDirectory() . '/' . $pattern;
|
return Environment::getInstance()->getUploadsDirectory() . '/' . $pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl(): string
|
public function getUrl(): string
|
||||||
|
@ -32,7 +27,7 @@ abstract class AbstractCustomAsset implements CustomAssetInterface
|
||||||
$pattern = $this->getPattern();
|
$pattern = $this->getPattern();
|
||||||
$mtime = filemtime($path);
|
$mtime = filemtime($path);
|
||||||
|
|
||||||
return $this->environment->getAssetUrl() . self::UPLOADS_URL_PREFIX . '/' . sprintf(
|
return Environment::getInstance()->getAssetUrl() . self::UPLOADS_URL_PREFIX . '/' . sprintf(
|
||||||
$pattern,
|
$pattern,
|
||||||
'.' . $mtime
|
'.' . $mtime
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Assets;
|
namespace App\Assets;
|
||||||
|
|
||||||
|
use App\Environment;
|
||||||
use Intervention\Image\Constraint;
|
use Intervention\Image\Constraint;
|
||||||
use Intervention\Image\Image;
|
use Intervention\Image\Image;
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ class AlbumArtCustomAsset extends AbstractCustomAsset
|
||||||
|
|
||||||
protected function getDefaultUrl(): string
|
protected function getDefaultUrl(): string
|
||||||
{
|
{
|
||||||
return $this->environment->getAssetUrl() . '/img/generic_song.jpg';
|
return Environment::getInstance()->getAssetUrl() . '/img/generic_song.jpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upload(Image $image): void
|
public function upload(Image $image): void
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Assets;
|
|
||||||
|
|
||||||
use App\Environment;
|
|
||||||
use InvalidArgumentException;
|
|
||||||
|
|
||||||
class AssetFactory
|
|
||||||
{
|
|
||||||
public const TYPE_ALBUM_ART = 'album_art';
|
|
||||||
public const TYPE_BACKGROUND = 'background';
|
|
||||||
public const TYPE_BROWSER_ICON = 'browser_icon';
|
|
||||||
|
|
||||||
public static function createAlbumArt(Environment $environment): AlbumArtCustomAsset
|
|
||||||
{
|
|
||||||
return new AlbumArtCustomAsset($environment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createBackground(Environment $environment): BackgroundCustomAsset
|
|
||||||
{
|
|
||||||
return new BackgroundCustomAsset($environment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createBrowserIcon(Environment $environment): BrowserIconCustomAsset
|
|
||||||
{
|
|
||||||
return new BrowserIconCustomAsset($environment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createForType(Environment $environment, string $type): CustomAssetInterface
|
|
||||||
{
|
|
||||||
return match ($type) {
|
|
||||||
self::TYPE_ALBUM_ART => self::createAlbumArt($environment),
|
|
||||||
self::TYPE_BACKGROUND => self::createBackground($environment),
|
|
||||||
self::TYPE_BROWSER_ICON => self::createBrowserIcon($environment),
|
|
||||||
default => throw new InvalidArgumentException('Invalid type specified.')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// phpcs:ignoreFile
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Assets;
|
||||||
|
|
||||||
|
enum AssetTypes: string
|
||||||
|
{
|
||||||
|
case AlbumArt = 'album_art';
|
||||||
|
case Background = 'background';
|
||||||
|
case BrowserIcon = 'browser_icon';
|
||||||
|
|
||||||
|
public function createObject(): CustomAssetInterface
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::AlbumArt => new AlbumArtCustomAsset(),
|
||||||
|
self::Background => new BackgroundCustomAsset(),
|
||||||
|
self::BrowserIcon => new BrowserIconCustomAsset(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Assets;
|
namespace App\Assets;
|
||||||
|
|
||||||
|
use App\Environment;
|
||||||
use Intervention\Image\Constraint;
|
use Intervention\Image\Constraint;
|
||||||
use Intervention\Image\Image;
|
use Intervention\Image\Image;
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ class BackgroundCustomAsset extends AbstractCustomAsset
|
||||||
|
|
||||||
protected function getDefaultUrl(): string
|
protected function getDefaultUrl(): string
|
||||||
{
|
{
|
||||||
return $this->environment->getAssetUrl() . '/img/hexbg.png';
|
return Environment::getInstance()->getAssetUrl() . '/img/hexbg.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upload(Image $image): void
|
public function upload(Image $image): void
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Assets;
|
namespace App\Assets;
|
||||||
|
|
||||||
|
use App\Environment;
|
||||||
use Intervention\Image\Image;
|
use Intervention\Image\Image;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
|
||||||
|
@ -34,13 +35,15 @@ class BrowserIconCustomAsset extends AbstractCustomAsset
|
||||||
|
|
||||||
protected function getDefaultUrl(): string
|
protected function getDefaultUrl(): string
|
||||||
{
|
{
|
||||||
$assetUrl = $this->environment->getAssetUrl();
|
$env = Environment::getInstance();
|
||||||
return $assetUrl . '/icons/' . $this->environment->getAppEnvironmentEnum()->value . '/original.png';
|
|
||||||
|
$assetUrl = $env->getAssetUrl();
|
||||||
|
return $assetUrl . '/icons/' . $env->getAppEnvironmentEnum()->value . '/original.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upload(Image $image): void
|
public function upload(Image $image): void
|
||||||
{
|
{
|
||||||
$uploadsDir = $this->environment->getUploadsDirectory() . '/browser_icon';
|
$uploadsDir = Environment::getInstance()->getUploadsDirectory() . '/browser_icon';
|
||||||
(new Filesystem())->mkdir($uploadsDir);
|
(new Filesystem())->mkdir($uploadsDir);
|
||||||
|
|
||||||
$newImage = clone $image;
|
$newImage = clone $image;
|
||||||
|
@ -56,15 +59,16 @@ class BrowserIconCustomAsset extends AbstractCustomAsset
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
{
|
{
|
||||||
$uploadsDir = $this->environment->getUploadsDirectory() . '/browser_icon';
|
$uploadsDir = Environment::getInstance()->getUploadsDirectory() . '/browser_icon';
|
||||||
(new Filesystem())->remove($uploadsDir);
|
(new Filesystem())->remove($uploadsDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlForSize(int $size): string
|
public function getUrlForSize(int $size): string
|
||||||
{
|
{
|
||||||
$assetUrl = $this->environment->getAssetUrl();
|
$env = Environment::getInstance();
|
||||||
|
$assetUrl = $env->getAssetUrl();
|
||||||
|
|
||||||
$uploadsDir = $this->environment->getUploadsDirectory();
|
$uploadsDir = $env->getUploadsDirectory();
|
||||||
$iconPath = $uploadsDir . '/browser_icon/' . $size . '.png';
|
$iconPath = $uploadsDir . '/browser_icon/' . $size . '.png';
|
||||||
|
|
||||||
if (is_file($iconPath)) {
|
if (is_file($iconPath)) {
|
||||||
|
@ -72,6 +76,6 @@ class BrowserIconCustomAsset extends AbstractCustomAsset
|
||||||
return $assetUrl . '/uploads/browser_icon/' . $size . '.' . $mtime . '.png';
|
return $assetUrl . '/uploads/browser_icon/' . $size . '.' . $mtime . '.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $assetUrl . '/icons/' . $this->environment->getAppEnvironmentEnum()->value . '/' . $size . '.png';
|
return $assetUrl . '/icons/' . $env->getAppEnvironmentEnum()->value . '/' . $size . '.png';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\AssetTypes;
|
||||||
use App\Entity\Settings;
|
use App\Entity\Settings;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
|
@ -28,13 +28,13 @@ final class BrandingAction
|
||||||
'group' => Settings::GROUP_BRANDING,
|
'group' => Settings::GROUP_BRANDING,
|
||||||
]),
|
]),
|
||||||
'browserIconApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
'browserIconApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
||||||
'type' => AssetFactory::TYPE_BROWSER_ICON,
|
'type' => AssetTypes::BrowserIcon->value,
|
||||||
]),
|
]),
|
||||||
'backgroundApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
'backgroundApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
||||||
'type' => AssetFactory::TYPE_BACKGROUND,
|
'type' => AssetTypes::Background->value,
|
||||||
]),
|
]),
|
||||||
'albumArtApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
'albumArtApiUrl' => (string)$router->named('api:admin:custom_assets', [
|
||||||
'type' => AssetFactory::TYPE_ALBUM_ART,
|
'type' => AssetTypes::AlbumArt->value,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -89,7 +89,7 @@ final class LogsController extends AbstractLogViewerController
|
||||||
public function viewAction(
|
public function viewAction(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string|int $station_id,
|
string $station_id,
|
||||||
string $log
|
string $log
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
if ('global' === $station_id) {
|
if ('global' === $station_id) {
|
||||||
|
|
|
@ -4,27 +4,20 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Admin\CustomAssets;
|
namespace App\Controller\Api\Admin\CustomAssets;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\AssetTypes;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class DeleteCustomAssetAction
|
final class DeleteCustomAssetAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
private readonly Environment $environment,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $type
|
string $type
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$customAsset = AssetFactory::createForType($this->environment, $type);
|
$customAsset = AssetTypes::from($type)->createObject();
|
||||||
|
|
||||||
$customAsset->delete();
|
$customAsset->delete();
|
||||||
|
|
||||||
return $response->withJson(Entity\Api\Status::success());
|
return $response->withJson(Entity\Api\Status::success());
|
||||||
|
|
|
@ -4,25 +4,19 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Admin\CustomAssets;
|
namespace App\Controller\Api\Admin\CustomAssets;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\AssetTypes;
|
||||||
use App\Environment;
|
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class GetCustomAssetAction
|
final class GetCustomAssetAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
private readonly Environment $environment,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $type
|
string $type
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$customAsset = AssetFactory::createForType($this->environment, $type);
|
$customAsset = AssetTypes::from($type)->createObject();
|
||||||
|
|
||||||
return $response->withJson(
|
return $response->withJson(
|
||||||
[
|
[
|
||||||
|
|
|
@ -4,9 +4,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Admin\CustomAssets;
|
namespace App\Controller\Api\Admin\CustomAssets;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\AssetTypes;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Media\AlbumArt;
|
use App\Media\AlbumArt;
|
||||||
|
@ -15,17 +14,12 @@ use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class PostCustomAssetAction
|
final class PostCustomAssetAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
|
||||||
private readonly Environment $environment
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $type
|
string $type
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$customAsset = AssetFactory::createForType($this->environment, $type);
|
$customAsset = AssetTypes::from($type)->createObject();
|
||||||
|
|
||||||
$flowResponse = Flow::process($request, $response);
|
$flowResponse = Flow::process($request, $response);
|
||||||
if ($flowResponse instanceof ResponseInterface) {
|
if ($flowResponse instanceof ResponseInterface) {
|
||||||
|
|
|
@ -53,12 +53,7 @@ final class DeleteArtAction
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
|
|
||||||
$media = $this->mediaRepo->findForStation($media_id, $station);
|
$media = $this->mediaRepo->requireForStation($media_id, $station);
|
||||||
if (!($media instanceof Entity\StationMedia)) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->mediaRepo->removeAlbumArt($media);
|
$this->mediaRepo->removeAlbumArt($media);
|
||||||
|
|
||||||
return $response->withJson(Entity\Api\Status::deleted());
|
return $response->withJson(Entity\Api\Status::deleted());
|
||||||
|
|
|
@ -56,11 +56,7 @@ final class PostArtAction
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
|
|
||||||
$media = $this->mediaRepo->findForStation($media_id, $station);
|
$media = $this->mediaRepo->requireForStation($media_id, $station);
|
||||||
if (!($media instanceof Entity\StationMedia)) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
$flowResponse = Flow::process($request, $response, $station->getRadioTempDir());
|
$flowResponse = Flow::process($request, $response, $station->getRadioTempDir());
|
||||||
if ($flowResponse instanceof ResponseInterface) {
|
if ($flowResponse instanceof ResponseInterface) {
|
||||||
|
|
|
@ -27,12 +27,7 @@ final class PlayAction
|
||||||
|
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
|
|
||||||
$media = $this->mediaRepo->findForStation($id, $station);
|
$media = $this->mediaRepo->requireForStation($id, $station);
|
||||||
|
|
||||||
if (!$media instanceof Entity\StationMedia) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,8 @@ final class DeleteIntroAction
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
$mount = $this->mountRepo->findForStation($id, $station);
|
|
||||||
|
|
||||||
if (null === $mount) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$mount = $this->mountRepo->requireForStation($id, $station);
|
||||||
$this->mountRepo->clearIntro($mount);
|
$this->mountRepo->clearIntro($mount);
|
||||||
|
|
||||||
return $response->withJson(Entity\Api\Status::deleted());
|
return $response->withJson(Entity\Api\Status::deleted());
|
||||||
|
|
|
@ -55,12 +55,7 @@ final class PostIntroAction
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $id) {
|
if (null !== $id) {
|
||||||
$mount = $this->mountRepo->findForStation($id, $station);
|
$mount = $this->mountRepo->requireForStation($id, $station);
|
||||||
if (null === $mount) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->mountRepo->setIntro($mount, $flowResponse);
|
$this->mountRepo->setIntro($mount, $flowResponse);
|
||||||
|
|
||||||
return $response->withJson(Entity\Api\Status::updated());
|
return $response->withJson(Entity\Api\Status::updated());
|
||||||
|
|
|
@ -31,12 +31,7 @@ final class DownloadAction
|
||||||
->withJson(new Entity\Api\Error(403, __('This station does not support on-demand streaming.')));
|
->withJson(new Entity\Api\Error(403, __('This station does not support on-demand streaming.')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$media = $this->mediaRepo->findByUniqueId($media_id, $station);
|
$media = $this->mediaRepo->requireByUniqueId($media_id, $station);
|
||||||
|
|
||||||
if (!($media instanceof Entity\StationMedia)) {
|
|
||||||
return $response->withStatus(404)
|
|
||||||
->withJson(Entity\Api\Error::notFound());
|
|
||||||
}
|
|
||||||
|
|
||||||
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
$fsMedia = (new StationFilesystems($station))->getMediaFilesystem();
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
|
||||||
|
|
||||||
use App\Entity;
|
|
||||||
use App\Exception\NotFoundException;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
|
|
||||||
abstract class AbstractPlaylistsAction
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
protected EntityManagerInterface $em
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function requireRecord(Entity\Station $station, int|string $id): Entity\StationPlaylist
|
|
||||||
{
|
|
||||||
$record = $this->em->getRepository(Entity\StationPlaylist::class)->findOneBy(
|
|
||||||
[
|
|
||||||
'station' => $station,
|
|
||||||
'id' => (int)$id,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$record instanceof Entity\StationPlaylist) {
|
|
||||||
throw new NotFoundException(__('Playlist not found.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $record;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,22 +4,34 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
|
use App\Entity\Api\Status;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
|
use App\Entity\StationPlaylist;
|
||||||
|
use App\Entity\StationPlaylistFolder;
|
||||||
|
use App\Entity\StationPlaylistMedia;
|
||||||
|
use App\Entity\StationSchedule;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use DeepCopy;
|
use DeepCopy;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class CloneAction extends AbstractPlaylistsAction
|
final class CloneAction
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
|
private readonly ReloadableEntityManagerInterface $em,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$data = (array)$request->getParsedBody();
|
$data = (array)$request->getParsedBody();
|
||||||
|
|
||||||
|
@ -43,10 +55,10 @@ final class CloneAction extends AbstractPlaylistsAction
|
||||||
);
|
);
|
||||||
$copier->addFilter(
|
$copier->addFilter(
|
||||||
new DeepCopy\Filter\KeepFilter(),
|
new DeepCopy\Filter\KeepFilter(),
|
||||||
new DeepCopy\Matcher\PropertyMatcher(Entity\StationPlaylistMedia::class, 'media')
|
new DeepCopy\Matcher\PropertyMatcher(StationPlaylistMedia::class, 'media')
|
||||||
);
|
);
|
||||||
|
|
||||||
/** @var Entity\StationPlaylist $newRecord */
|
/** @var StationPlaylist $newRecord */
|
||||||
$newRecord = $copier->copy($record);
|
$newRecord = $copier->copy($record);
|
||||||
|
|
||||||
$newRecord->setName($data['name'] ?? ($record->getName() . ' - Copy'));
|
$newRecord->setName($data['name'] ?? ($record->getName() . ' - Copy'));
|
||||||
|
@ -57,7 +69,7 @@ final class CloneAction extends AbstractPlaylistsAction
|
||||||
|
|
||||||
if (in_array('schedule', $toClone, true)) {
|
if (in_array('schedule', $toClone, true)) {
|
||||||
foreach ($record->getScheduleItems() as $oldScheduleItem) {
|
foreach ($record->getScheduleItems() as $oldScheduleItem) {
|
||||||
/** @var Entity\StationSchedule $newScheduleItem */
|
/** @var StationSchedule $newScheduleItem */
|
||||||
$newScheduleItem = $copier->copy($oldScheduleItem);
|
$newScheduleItem = $copier->copy($oldScheduleItem);
|
||||||
$newScheduleItem->setPlaylist($newRecord);
|
$newScheduleItem->setPlaylist($newRecord);
|
||||||
|
|
||||||
|
@ -67,14 +79,14 @@ final class CloneAction extends AbstractPlaylistsAction
|
||||||
|
|
||||||
if (in_array('media', $toClone, true)) {
|
if (in_array('media', $toClone, true)) {
|
||||||
foreach ($record->getFolders() as $oldPlaylistFolder) {
|
foreach ($record->getFolders() as $oldPlaylistFolder) {
|
||||||
/** @var Entity\StationPlaylistFolder $newPlaylistFolder */
|
/** @var StationPlaylistFolder $newPlaylistFolder */
|
||||||
$newPlaylistFolder = $copier->copy($oldPlaylistFolder);
|
$newPlaylistFolder = $copier->copy($oldPlaylistFolder);
|
||||||
$newPlaylistFolder->setPlaylist($newRecord);
|
$newPlaylistFolder->setPlaylist($newRecord);
|
||||||
$this->em->persist($newPlaylistFolder);
|
$this->em->persist($newPlaylistFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($record->getMediaItems() as $oldMediaItem) {
|
foreach ($record->getMediaItems() as $oldMediaItem) {
|
||||||
/** @var Entity\StationPlaylistMedia $newMediaItem */
|
/** @var StationPlaylistMedia $newMediaItem */
|
||||||
$newMediaItem = $copier->copy($oldMediaItem);
|
$newMediaItem = $copier->copy($oldMediaItem);
|
||||||
|
|
||||||
$newMediaItem->setPlaylist($newRecord);
|
$newMediaItem->setPlaylist($newRecord);
|
||||||
|
@ -84,6 +96,6 @@ final class CloneAction extends AbstractPlaylistsAction
|
||||||
|
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
||||||
return $response->withJson(Entity\Api\Status::created());
|
return $response->withJson(Status::created());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,19 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity\Api\Status;
|
||||||
|
use App\Entity\Repository\StationPlaylistMediaRepository;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class DeleteQueueAction extends AbstractPlaylistsAction
|
final class DeleteQueueAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
private readonly Entity\Repository\StationPlaylistMediaRepository $spmRepo,
|
private readonly StationPlaylistMediaRepository $spmRepo,
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -25,12 +25,12 @@ final class DeleteQueueAction extends AbstractPlaylistsAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$this->spmRepo->resetQueue($record);
|
$this->spmRepo->resetQueue($record);
|
||||||
|
|
||||||
return $response->withJson(
|
return $response->withJson(
|
||||||
new Entity\Api\Status(
|
new Status(
|
||||||
true,
|
true,
|
||||||
__('Playlist queue cleared.')
|
__('Playlist queue cleared.')
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,13 +4,19 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class ExportAction extends AbstractPlaylistsAction
|
final class ExportAction
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationPlaylistRepository $playlistRepo
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
|
@ -18,7 +24,7 @@ final class ExportAction extends AbstractPlaylistsAction
|
||||||
string $id,
|
string $id,
|
||||||
string $format = 'pls'
|
string $format = 'pls'
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$exportFileName = 'playlist_' . $record->getShortName() . '.' . $format;
|
$exportFileName = 'playlist_' . $record->getShortName() . '.' . $format;
|
||||||
$exportLines = [];
|
$exportLines = [];
|
||||||
|
|
|
@ -4,14 +4,23 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
|
use App\Entity\Enums\PlaylistOrders;
|
||||||
|
use App\Entity\Enums\PlaylistSources;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Exception;
|
use App\Exception;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class GetOrderAction extends AbstractPlaylistsAction
|
final class GetOrderAction
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
|
private readonly ReloadableEntityManagerInterface $em,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
|
@ -19,11 +28,11 @@ final class GetOrderAction extends AbstractPlaylistsAction
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
$record = $this->requireRecord($station, $id);
|
$record = $this->playlistRepo->requireForStation($id, $station);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Entity\Enums\PlaylistSources::Songs !== $record->getSourceEnum()
|
PlaylistSources::Songs !== $record->getSourceEnum()
|
||||||
|| Entity\Enums\PlaylistOrders::Sequential !== $record->getOrderEnum()
|
|| PlaylistOrders::Sequential !== $record->getOrderEnum()
|
||||||
) {
|
) {
|
||||||
throw new Exception(__('This playlist is not a sequential playlist.'));
|
throw new Exception(__('This playlist is not a sequential playlist.'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,22 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity\Enums\PlaylistOrders;
|
||||||
|
use App\Entity\Enums\PlaylistSources;
|
||||||
|
use App\Entity\Repository\StationPlaylistMediaRepository;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Paginator;
|
use App\Paginator;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class GetQueueAction extends AbstractPlaylistsAction
|
final class GetQueueAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
private readonly Entity\Repository\StationPlaylistMediaRepository $spmRepo
|
private readonly StationPlaylistMediaRepository $spmRepo
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -27,13 +28,13 @@ final class GetQueueAction extends AbstractPlaylistsAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
if (Entity\Enums\PlaylistSources::Songs !== $record->getSourceEnum()) {
|
if (PlaylistSources::Songs !== $record->getSourceEnum()) {
|
||||||
throw new InvalidArgumentException('This playlist does not have songs as its primary source.');
|
throw new InvalidArgumentException('This playlist does not have songs as its primary source.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Entity\Enums\PlaylistOrders::Random === $record->getOrderEnum()) {
|
if (PlaylistOrders::Random === $record->getOrderEnum()) {
|
||||||
throw new InvalidArgumentException('This playlist is always shuffled and has no visible queue.');
|
throw new InvalidArgumentException('This playlist is always shuffled and has no visible queue.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,22 +4,26 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
|
use App\Entity\Api\Error;
|
||||||
|
use App\Entity\Api\StationPlaylistImportResult;
|
||||||
|
use App\Entity\Repository\StationPlaylistMediaRepository;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
|
use App\Entity\StationMedia;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Radio\PlaylistParser;
|
use App\Radio\PlaylistParser;
|
||||||
use App\Utilities\File;
|
use App\Utilities\File;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\UploadedFileInterface;
|
use Psr\Http\Message\UploadedFileInterface;
|
||||||
|
|
||||||
final class ImportAction extends AbstractPlaylistsAction
|
final class ImportAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
private readonly Entity\Repository\StationPlaylistMediaRepository $spmRepo,
|
private readonly StationPlaylistMediaRepository $spmRepo,
|
||||||
|
private readonly ReloadableEntityManagerInterface $em,
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -28,13 +32,13 @@ final class ImportAction extends AbstractPlaylistsAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$playlist = $this->requireRecord($request->getStation(), $id);
|
$playlist = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$files = $request->getUploadedFiles();
|
$files = $request->getUploadedFiles();
|
||||||
|
|
||||||
if (empty($files['playlist_file'])) {
|
if (empty($files['playlist_file'])) {
|
||||||
return $response->withStatus(500)
|
return $response->withStatus(500)
|
||||||
->withJson(new Entity\Api\Error(500, 'No "playlist_file" provided.'));
|
->withJson(new Error(500, 'No "playlist_file" provided.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var UploadedFileInterface $file */
|
/** @var UploadedFileInterface $file */
|
||||||
|
@ -42,7 +46,7 @@ final class ImportAction extends AbstractPlaylistsAction
|
||||||
|
|
||||||
if (UPLOAD_ERR_OK !== $file->getError()) {
|
if (UPLOAD_ERR_OK !== $file->getError()) {
|
||||||
return $response->withStatus(500)
|
return $response->withStatus(500)
|
||||||
->withJson(Entity\Api\Error::fromFileError($file->getError()));
|
->withJson(Error::fromFileError($file->getError()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$playlistFile = $file->getStream()->getContents();
|
$playlistFile = $file->getStream()->getContents();
|
||||||
|
@ -137,10 +141,10 @@ final class ImportAction extends AbstractPlaylistsAction
|
||||||
->setParameter('matched_ids', $matches)
|
->setParameter('matched_ids', $matches)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
/** @var Entity\StationMedia[] $mediaById */
|
/** @var StationMedia[] $mediaById */
|
||||||
$mediaById = [];
|
$mediaById = [];
|
||||||
foreach ($matchedMediaRaw as $row) {
|
foreach ($matchedMediaRaw as $row) {
|
||||||
/** @var Entity\StationMedia $row */
|
/** @var StationMedia $row */
|
||||||
$mediaById[$row->getId()] = $row;
|
$mediaById[$row->getId()] = $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +165,7 @@ final class ImportAction extends AbstractPlaylistsAction
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->withJson(
|
return $response->withJson(
|
||||||
new Entity\Api\StationPlaylistImportResult(
|
new StationPlaylistImportResult(
|
||||||
true,
|
true,
|
||||||
sprintf(
|
sprintf(
|
||||||
__('Playlist successfully imported; %d of %d files were successfully matched.'),
|
__('Playlist successfully imported; %d of %d files were successfully matched.'),
|
||||||
|
|
|
@ -4,20 +4,21 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity\Enums\PlaylistOrders;
|
||||||
|
use App\Entity\Enums\PlaylistSources;
|
||||||
|
use App\Entity\Repository\StationPlaylistMediaRepository;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Exception;
|
use App\Exception;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class PutOrderAction extends AbstractPlaylistsAction
|
final class PutOrderAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
private readonly Entity\Repository\StationPlaylistMediaRepository $spmRepo,
|
private readonly StationPlaylistMediaRepository $spmRepo
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -26,11 +27,11 @@ final class PutOrderAction extends AbstractPlaylistsAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Entity\Enums\PlaylistSources::Songs !== $record->getSourceEnum()
|
PlaylistSources::Songs !== $record->getSourceEnum()
|
||||||
|| Entity\Enums\PlaylistOrders::Sequential !== $record->getOrderEnum()
|
|| PlaylistOrders::Sequential !== $record->getOrderEnum()
|
||||||
) {
|
) {
|
||||||
throw new Exception(__('This playlist is not a sequential playlist.'));
|
throw new Exception(__('This playlist is not a sequential playlist.'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,19 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity\Api\Status;
|
||||||
|
use App\Entity\Repository\StationPlaylistMediaRepository;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class ReshuffleAction extends AbstractPlaylistsAction
|
final class ReshuffleAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationPlaylistRepository $playlistRepo,
|
||||||
private readonly Entity\Repository\StationPlaylistMediaRepository $spmRepo,
|
private readonly StationPlaylistMediaRepository $spmRepo
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -25,12 +25,12 @@ final class ReshuffleAction extends AbstractPlaylistsAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$this->spmRepo->resetQueue($record);
|
$this->spmRepo->resetQueue($record);
|
||||||
|
|
||||||
return $response->withJson(
|
return $response->withJson(
|
||||||
new Entity\Api\Status(
|
new Status(
|
||||||
true,
|
true,
|
||||||
__('Playlist reshuffled.')
|
__('Playlist reshuffled.')
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,31 +4,38 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Playlists;
|
namespace App\Controller\Api\Stations\Playlists;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity\Api\Status;
|
||||||
|
use App\Entity\Repository\StationPlaylistRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class ToggleAction extends AbstractPlaylistsAction
|
final class ToggleAction
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationPlaylistRepository $playlistRepo
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->playlistRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$new_value = !$record->getIsEnabled();
|
$new_value = !$record->getIsEnabled();
|
||||||
|
|
||||||
$record->setIsEnabled($new_value);
|
$record->setIsEnabled($new_value);
|
||||||
$this->em->persist($record);
|
|
||||||
$this->em->flush();
|
$em = $this->playlistRepo->getEntityManager();
|
||||||
|
$em->persist($record);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
$flash_message = ($new_value)
|
$flash_message = ($new_value)
|
||||||
? __('Playlist enabled.')
|
? __('Playlist enabled.')
|
||||||
: __('Playlist disabled.');
|
: __('Playlist disabled.');
|
||||||
|
|
||||||
return $response->withJson(new Entity\Api\Status(true, $flash_message));
|
return $response->withJson(new Status(true, $flash_message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ final class BroadcastsController extends AbstractApiCrudController
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $station_id,
|
string $station_id,
|
||||||
int $broadcast_id
|
string $broadcast_id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
$broadcast = $this->getRecord($station, $broadcast_id);
|
$broadcast = $this->getRecord($station, $broadcast_id);
|
||||||
|
@ -158,7 +158,7 @@ final class BroadcastsController extends AbstractApiCrudController
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $station_id,
|
string $station_id,
|
||||||
int $broadcast_id
|
string $broadcast_id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$station = $request->getStation();
|
$station = $request->getStation();
|
||||||
$broadcast = $this->getRecord($station, $broadcast_id);
|
$broadcast = $this->getRecord($station, $broadcast_id);
|
||||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Waveform;
|
namespace App\Controller\Api\Stations\Waveform;
|
||||||
|
|
||||||
use App\Entity\Api\Error;
|
|
||||||
use App\Entity\Repository\StationMediaRepository;
|
use App\Entity\Repository\StationMediaRepository;
|
||||||
use App\Entity\StationMedia;
|
use App\Entity\StationMedia;
|
||||||
use App\Flysystem\StationFilesystems;
|
use App\Flysystem\StationFilesystems;
|
||||||
|
@ -41,10 +40,7 @@ final class GetWaveformAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$media = $this->mediaRepo->findByUniqueId($media_id, $station);
|
$media = $this->mediaRepo->requireByUniqueId($media_id, $station);
|
||||||
if (!($media instanceof StationMedia)) {
|
|
||||||
return $response->withStatus(500)->withJson(new Error(500, 'Media not found.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$waveformPath = StationMedia::getWaveformPath($media->getUniqueId());
|
$waveformPath = StationMedia::getWaveformPath($media->getUniqueId());
|
||||||
if (!$fsMedia->fileExists($waveformPath)) {
|
if (!$fsMedia->fileExists($waveformPath)) {
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Webhooks;
|
|
||||||
|
|
||||||
use App\Entity;
|
|
||||||
use App\Exception\NotFoundException;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
|
|
||||||
abstract class AbstractWebhooksAction
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
protected EntityManagerInterface $em
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function requireRecord(Entity\Station $station, int|string $id): Entity\StationWebhook
|
|
||||||
{
|
|
||||||
$record = $this->em->getRepository(Entity\StationWebhook::class)->findOneBy(
|
|
||||||
[
|
|
||||||
'station' => $station,
|
|
||||||
'id' => (int)$id,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$record instanceof Entity\StationWebhook) {
|
|
||||||
throw new NotFoundException(__('Web hook not found.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $record;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,21 +4,20 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Api\Stations\Webhooks;
|
namespace App\Controller\Api\Stations\Webhooks;
|
||||||
|
|
||||||
|
use App\Entity\Repository\StationWebhookRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Message\TestWebhookMessage;
|
use App\Message\TestWebhookMessage;
|
||||||
use App\Utilities\File;
|
use App\Utilities\File;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Symfony\Component\Messenger\MessageBus;
|
use Symfony\Component\Messenger\MessageBus;
|
||||||
|
|
||||||
final class TestAction extends AbstractWebhooksAction
|
final class TestAction
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EntityManagerInterface $em,
|
private readonly StationWebhookRepository $webhookRepo,
|
||||||
private readonly MessageBus $messageBus
|
private readonly MessageBus $messageBus
|
||||||
) {
|
) {
|
||||||
parent::__construct($em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
|
@ -27,7 +26,7 @@ final class TestAction extends AbstractWebhooksAction
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$webhook = $this->requireRecord($request->getStation(), $id);
|
$webhook = $this->webhookRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$tempFile = File::generateTempPath('webhook_test_' . $id . '.log');
|
$tempFile = File::generateTempPath('webhook_test_' . $id . '.log');
|
||||||
touch($tempFile);
|
touch($tempFile);
|
||||||
|
|
|
@ -6,15 +6,21 @@ namespace App\Controller\Api\Stations\Webhooks;
|
||||||
|
|
||||||
use App\Controller\Api\Traits\HasLogViewer;
|
use App\Controller\Api\Traits\HasLogViewer;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
|
use App\Entity\Repository\StationWebhookRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Utilities\File;
|
use App\Utilities\File;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class TestLogAction extends AbstractWebhooksAction
|
final class TestLogAction
|
||||||
{
|
{
|
||||||
use HasLogViewer;
|
use HasLogViewer;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationWebhookRepository $webhookRepo
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
|
@ -22,7 +28,7 @@ final class TestLogAction extends AbstractWebhooksAction
|
||||||
string $id,
|
string $id,
|
||||||
string $path
|
string $path
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$this->requireRecord($request->getStation(), $id);
|
$this->webhookRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$logPathPortion = 'webhook_test_' . $id;
|
$logPathPortion = 'webhook_test_' . $id;
|
||||||
if (!str_contains($path, $logPathPortion)) {
|
if (!str_contains($path, $logPathPortion)) {
|
||||||
|
|
|
@ -5,25 +5,32 @@ declare(strict_types=1);
|
||||||
namespace App\Controller\Api\Stations\Webhooks;
|
namespace App\Controller\Api\Stations\Webhooks;
|
||||||
|
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
|
use App\Entity\Repository\StationWebhookRepository;
|
||||||
use App\Http\Response;
|
use App\Http\Response;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
final class ToggleAction extends AbstractWebhooksAction
|
final class ToggleAction
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly StationWebhookRepository $webhookRepo
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public function __invoke(
|
public function __invoke(
|
||||||
ServerRequest $request,
|
ServerRequest $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
string $station_id,
|
string $station_id,
|
||||||
string $id
|
string $id
|
||||||
): ResponseInterface {
|
): ResponseInterface {
|
||||||
$record = $this->requireRecord($request->getStation(), $id);
|
$record = $this->webhookRepo->requireForStation($id, $request->getStation());
|
||||||
|
|
||||||
$newValue = !$record->getIsEnabled();
|
$newValue = !$record->getIsEnabled();
|
||||||
$record->setIsEnabled($newValue);
|
$record->setIsEnabled($newValue);
|
||||||
|
|
||||||
$this->em->persist($record);
|
$em = $this->webhookRepo->getEntityManager();
|
||||||
$this->em->flush();
|
$em->persist($record);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
$flash_message = ($newValue)
|
$flash_message = ($newValue)
|
||||||
? __('Web hook enabled.')
|
? __('Web hook enabled.')
|
||||||
|
|
|
@ -4,7 +4,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\BackgroundCustomAsset;
|
||||||
|
use App\Assets\BrowserIconCustomAsset;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Enums\SupportedLocales;
|
use App\Enums\SupportedLocales;
|
||||||
use App\Enums\SupportedThemes;
|
use App\Enums\SupportedThemes;
|
||||||
|
@ -108,7 +109,7 @@ class Customization
|
||||||
{
|
{
|
||||||
$publicCss = $this->settings->getPublicCustomCss() ?? '';
|
$publicCss = $this->settings->getPublicCustomCss() ?? '';
|
||||||
|
|
||||||
$background = AssetFactory::createBackground($this->environment);
|
$background = new BackgroundCustomAsset();
|
||||||
if ($background->isUploaded()) {
|
if ($background->isUploaded()) {
|
||||||
$backgroundUrl = $background->getUrl();
|
$backgroundUrl = $background->getUrl();
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ class Customization
|
||||||
|
|
||||||
public function getBrowserIconUrl(int $size = 256): string
|
public function getBrowserIconUrl(int $size = 256): string
|
||||||
{
|
{
|
||||||
return AssetFactory::createBrowserIcon($this->environment)->getUrlForSize($size);
|
return (new BrowserIconCustomAsset())->getUrlForSize($size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,14 +4,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Doctrine;
|
namespace App\Doctrine;
|
||||||
|
|
||||||
use App\Environment;
|
|
||||||
use App\Exception\NotFoundException;
|
use App\Exception\NotFoundException;
|
||||||
use Azura\Normalizer\DoctrineEntityNormalizer;
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template TEntity as object
|
* @template TEntity as object
|
||||||
|
@ -25,10 +20,7 @@ class Repository
|
||||||
protected ObjectRepository $repository;
|
protected ObjectRepository $repository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected ReloadableEntityManagerInterface $em,
|
protected ReloadableEntityManagerInterface $em
|
||||||
protected Serializer $serializer,
|
|
||||||
protected Environment $environment,
|
|
||||||
protected LoggerInterface $logger
|
|
||||||
) {
|
) {
|
||||||
if (!isset($this->entityClass)) {
|
if (!isset($this->entityClass)) {
|
||||||
/** @var class-string<TEntity> $defaultClass */
|
/** @var class-string<TEntity> $defaultClass */
|
||||||
|
@ -135,42 +127,4 @@ class Repository
|
||||||
|
|
||||||
return $select;
|
return $select;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* FromArray (A Doctrine 1 Classic)
|
|
||||||
*
|
|
||||||
* @param object $entity
|
|
||||||
* @param array $source
|
|
||||||
*/
|
|
||||||
public function fromArray(object $entity, array $source): object
|
|
||||||
{
|
|
||||||
return $this->serializer->denormalize(
|
|
||||||
$source,
|
|
||||||
get_class($entity),
|
|
||||||
null,
|
|
||||||
[
|
|
||||||
AbstractNormalizer::OBJECT_TO_POPULATE => $entity,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ToArray (A Doctrine 1 Classic)
|
|
||||||
*
|
|
||||||
* @param object $entity
|
|
||||||
* @param bool $deep Iterate through collections associated with this item.
|
|
||||||
* @param bool $form_mode Return values in a format suitable for ZendForm setDefault function.
|
|
||||||
*
|
|
||||||
* @return mixed[]
|
|
||||||
*/
|
|
||||||
public function toArray(object $entity, bool $deep = false, bool $form_mode = false): array
|
|
||||||
{
|
|
||||||
return (array)$this->serializer->normalize(
|
|
||||||
$entity,
|
|
||||||
null,
|
|
||||||
[
|
|
||||||
DoctrineEntityNormalizer::NORMALIZE_TO_IDENTIFIERS => $form_mode,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use DateTimeInterface;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Analytics>
|
* @extends Repository<Entity\Analytics>
|
||||||
*/
|
*/
|
||||||
class AnalyticsRepository extends Repository
|
final class AnalyticsRepository extends Repository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return mixed[]
|
* @return mixed[]
|
||||||
|
|
|
@ -9,6 +9,6 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractSplitTokenRepository<Entity\ApiKey>
|
* @extends AbstractSplitTokenRepository<Entity\ApiKey>
|
||||||
*/
|
*/
|
||||||
class ApiKeyRepository extends AbstractSplitTokenRepository
|
final class ApiKeyRepository extends AbstractSplitTokenRepository
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\CustomField>
|
* @extends Repository<Entity\CustomField>
|
||||||
*/
|
*/
|
||||||
class CustomFieldRepository extends Repository
|
final class CustomFieldRepository extends Repository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Entity\CustomField[]
|
* @return Entity\CustomField[]
|
||||||
|
|
|
@ -7,37 +7,32 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Service\DeviceDetector;
|
use App\Service\DeviceDetector;
|
||||||
use App\Service\IpGeolocation;
|
use App\Service\IpGeolocation;
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use Doctrine\DBAL\Connection;
|
use Doctrine\DBAL\Connection;
|
||||||
|
use Monolog\Registry;
|
||||||
use NowPlaying\Result\Client;
|
use NowPlaying\Result\Client;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Listener>
|
* @extends Repository<Entity\Listener>
|
||||||
*/
|
*/
|
||||||
class ListenerRepository extends Repository
|
final class ListenerRepository extends Repository
|
||||||
{
|
{
|
||||||
use Entity\Traits\TruncateStrings;
|
use Entity\Traits\TruncateStrings;
|
||||||
|
|
||||||
protected string $tableName;
|
private string $tableName;
|
||||||
|
|
||||||
protected Connection $conn;
|
private Connection $conn;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected DeviceDetector $deviceDetector,
|
|
||||||
protected IpGeolocation $ipGeolocation,
|
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly DeviceDetector $deviceDetector,
|
||||||
Environment $environment,
|
private readonly IpGeolocation $ipGeolocation
|
||||||
LoggerInterface $logger
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
|
|
||||||
$this->tableName = $this->em->getClassMetadata(Entity\Listener::class)->getTableName();
|
$this->tableName = $this->em->getClassMetadata(Entity\Listener::class)->getTableName();
|
||||||
$this->conn = $this->em->getConnection();
|
$this->conn = $this->em->getConnection();
|
||||||
|
@ -190,7 +185,7 @@ class ListenerRepository extends Repository
|
||||||
$record['device_browser_family'] = $this->truncateNullableString($browserResult->browserFamily, 150);
|
$record['device_browser_family'] = $this->truncateNullableString($browserResult->browserFamily, 150);
|
||||||
$record['device_os_family'] = $this->truncateNullableString($browserResult->osFamily, 150);
|
$record['device_os_family'] = $this->truncateNullableString($browserResult->osFamily, 150);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
$this->logger->error('Device Detector error: ' . $e->getMessage(), [
|
Registry::getInstance('app')->error('Device Detector error: ' . $e->getMessage(), [
|
||||||
'user_agent' => $userAgent,
|
'user_agent' => $userAgent,
|
||||||
'exception' => $e,
|
'exception' => $e,
|
||||||
]);
|
]);
|
||||||
|
@ -213,7 +208,7 @@ class ListenerRepository extends Repository
|
||||||
$record['location_lat'] = $ipInfo->lat;
|
$record['location_lat'] = $ipInfo->lat;
|
||||||
$record['location_lon'] = $ipInfo->lon;
|
$record['location_lon'] = $ipInfo->lon;
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
$this->logger->error('IP Geolocation error: ' . $e->getMessage(), [
|
Registry::getInstance('app')->error('IP Geolocation error: ' . $e->getMessage(), [
|
||||||
'ip' => $ip,
|
'ip' => $ip,
|
||||||
'exception' => $e,
|
'exception' => $e,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Exception\InvalidPodcastMediaFileException;
|
use App\Exception\InvalidPodcastMediaFileException;
|
||||||
use App\Exception\StorageLocationFullException;
|
use App\Exception\StorageLocationFullException;
|
||||||
use App\Media\AlbumArt;
|
use App\Media\AlbumArt;
|
||||||
|
@ -15,22 +14,17 @@ use App\Media\MetadataManager;
|
||||||
use Azura\Files\ExtendedFilesystemInterface;
|
use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use League\Flysystem\UnableToDeleteFile;
|
use League\Flysystem\UnableToDeleteFile;
|
||||||
use League\Flysystem\UnableToRetrieveMetadata;
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\PodcastEpisode>
|
* @extends Repository<Entity\PodcastEpisode>
|
||||||
*/
|
*/
|
||||||
class PodcastEpisodeRepository extends Repository
|
final class PodcastEpisodeRepository extends Repository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected MetadataManager $metadataManager,
|
|
||||||
ReloadableEntityManagerInterface $entityManager,
|
ReloadableEntityManagerInterface $entityManager,
|
||||||
Serializer $serializer,
|
private readonly MetadataManager $metadataManager
|
||||||
Environment $environment,
|
|
||||||
LoggerInterface $logger
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($entityManager, $serializer, $environment, $logger);
|
parent::__construct($entityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fetchEpisodeForStation(Entity\Station $station, string $episodeId): ?Entity\PodcastEpisode
|
public function fetchEpisodeForStation(Entity\Station $station, string $episodeId): ?Entity\PodcastEpisode
|
||||||
|
|
|
@ -7,28 +7,22 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Exception\StorageLocationFullException;
|
use App\Exception\StorageLocationFullException;
|
||||||
use App\Media\AlbumArt;
|
use App\Media\AlbumArt;
|
||||||
use Azura\Files\ExtendedFilesystemInterface;
|
use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use League\Flysystem\UnableToDeleteFile;
|
use League\Flysystem\UnableToDeleteFile;
|
||||||
use League\Flysystem\UnableToRetrieveMetadata;
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Podcast>
|
* @extends Repository<Entity\Podcast>
|
||||||
*/
|
*/
|
||||||
class PodcastRepository extends Repository
|
final class PodcastRepository extends Repository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $entityManager,
|
ReloadableEntityManagerInterface $entityManager,
|
||||||
Serializer $serializer,
|
private readonly PodcastEpisodeRepository $podcastEpisodeRepo,
|
||||||
Environment $environment,
|
|
||||||
LoggerInterface $logger,
|
|
||||||
protected PodcastEpisodeRepository $podcastEpisodeRepo,
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($entityManager, $serializer, $environment, $logger);
|
parent::__construct($entityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fetchPodcastForStation(Entity\Station $station, string $podcastId): ?Entity\Podcast
|
public function fetchPodcastForStation(Entity\Station $station, string $podcastId): ?Entity\Podcast
|
||||||
|
|
|
@ -11,7 +11,7 @@ use App\Enums\GlobalPermissions;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\RolePermission>
|
* @extends Repository<Entity\RolePermission>
|
||||||
*/
|
*/
|
||||||
class RolePermissionRepository extends Repository
|
final class RolePermissionRepository extends Repository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Entity\Role $role
|
* @param Entity\Role $role
|
||||||
|
|
|
@ -10,6 +10,6 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Role>
|
* @extends Repository<Entity\Role>
|
||||||
*/
|
*/
|
||||||
class RoleRepository extends Repository
|
final class RoleRepository extends Repository
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,31 +7,24 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Exception\ValidationException;
|
use App\Exception\ValidationException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
use Symfony\Component\Serializer\Serializer;
|
use Symfony\Component\Serializer\Serializer;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Settings>
|
* @extends Repository<Entity\Settings>
|
||||||
*/
|
*/
|
||||||
class SettingsRepository extends Repository
|
final class SettingsRepository extends Repository
|
||||||
{
|
{
|
||||||
protected ValidatorInterface $validator;
|
|
||||||
|
|
||||||
protected string $entityClass = Entity\Settings::class;
|
protected string $entityClass = Entity\Settings::class;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly Serializer $serializer,
|
||||||
Environment $environment,
|
private readonly ValidatorInterface $validator
|
||||||
LoggerInterface $logger,
|
|
||||||
ValidatorInterface $validator
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
|
|
||||||
$this->validator = $validator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readSettings(): Entity\Settings
|
public function readSettings(): Entity\Settings
|
||||||
|
@ -78,4 +71,23 @@ class SettingsRepository extends Repository
|
||||||
$this->em->persist($settings);
|
$this->em->persist($settings);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fromArray(Entity\Settings $entity, array $source): Entity\Settings
|
||||||
|
{
|
||||||
|
return $this->serializer->denormalize(
|
||||||
|
$source,
|
||||||
|
Entity\Settings::class,
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
AbstractNormalizer::OBJECT_TO_POPULATE => $entity,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(Entity\Settings $entity): array
|
||||||
|
{
|
||||||
|
return (array)$this->serializer->normalize(
|
||||||
|
$entity
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,28 +6,22 @@ namespace App\Entity\Repository;
|
||||||
|
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Radio\Backend\Liquidsoap\Command\FeedbackCommand;
|
use App\Radio\Backend\Liquidsoap\Command\FeedbackCommand;
|
||||||
use App\Radio\Enums\BackendAdapters;
|
use App\Radio\Enums\BackendAdapters;
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\SongHistory>
|
* @extends AbstractStationBasedRepository<Entity\SongHistory>
|
||||||
*/
|
*/
|
||||||
class SongHistoryRepository extends AbstractStationBasedRepository
|
final class SongHistoryRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly ListenerRepository $listenerRepository,
|
||||||
Environment $environment,
|
private readonly StationQueueRepository $stationQueueRepository,
|
||||||
LoggerInterface $logger,
|
private readonly FeedbackCommand $liquidsoapFeedback,
|
||||||
protected ListenerRepository $listenerRepository,
|
|
||||||
protected StationQueueRepository $stationQueueRepository,
|
|
||||||
protected FeedbackCommand $liquidsoapFeedback,
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,8 +7,8 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Exception\CannotProcessMediaException;
|
use App\Exception\CannotProcessMediaException;
|
||||||
|
use App\Exception\NotFoundException;
|
||||||
use App\Media\AlbumArt;
|
use App\Media\AlbumArt;
|
||||||
use App\Media\MetadataManager;
|
use App\Media\MetadataManager;
|
||||||
use App\Media\RemoteAlbumArt;
|
use App\Media\RemoteAlbumArt;
|
||||||
|
@ -17,8 +17,7 @@ use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Generator;
|
use Generator;
|
||||||
use League\Flysystem\FilesystemException;
|
use League\Flysystem\FilesystemException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Monolog\Registry;
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
use const JSON_PRETTY_PRINT;
|
use const JSON_PRETTY_PRINT;
|
||||||
use const JSON_THROW_ON_ERROR;
|
use const JSON_THROW_ON_ERROR;
|
||||||
|
@ -27,21 +26,17 @@ use const JSON_UNESCAPED_SLASHES;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\StationMedia>
|
* @extends Repository<Entity\StationMedia>
|
||||||
*/
|
*/
|
||||||
class StationMediaRepository extends Repository
|
final class StationMediaRepository extends Repository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly MetadataManager $metadataManager,
|
||||||
Environment $environment,
|
private readonly RemoteAlbumArt $remoteAlbumArt,
|
||||||
LoggerInterface $logger,
|
private readonly CustomFieldRepository $customFieldRepo,
|
||||||
protected MetadataManager $metadataManager,
|
private readonly StationPlaylistMediaRepository $spmRepo,
|
||||||
protected RemoteAlbumArt $remoteAlbumArt,
|
private readonly UnprocessableMediaRepository $unprocessableMediaRepo
|
||||||
protected CustomFieldRepository $customFieldRepo,
|
|
||||||
protected StationPlaylistMediaRepository $spmRepo,
|
|
||||||
protected StorageLocationRepository $storageLocationRepo,
|
|
||||||
protected UnprocessableMediaRepository $unprocessableMediaRepo
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findForStation(int|string $id, Entity\Station $station): ?Entity\StationMedia
|
public function findForStation(int|string $id, Entity\Station $station): ?Entity\StationMedia
|
||||||
|
@ -66,6 +61,15 @@ class StationMediaRepository extends Repository
|
||||||
return $media;
|
return $media;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function requireForStation(int|string $id, Entity\Station $station): Entity\StationMedia
|
||||||
|
{
|
||||||
|
$record = $this->findForStation($id, $station);
|
||||||
|
if (null === $record) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param Entity\Station|Entity\StorageLocation $source
|
* @param Entity\Station|Entity\StorageLocation $source
|
||||||
|
@ -120,6 +124,17 @@ class StationMediaRepository extends Repository
|
||||||
return $media;
|
return $media;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function requireByUniqueId(
|
||||||
|
string $uniqueId,
|
||||||
|
Entity\Station|Entity\StorageLocation $source
|
||||||
|
): Entity\StationMedia {
|
||||||
|
$record = $this->findByUniqueId($uniqueId, $source);
|
||||||
|
if (null === $record) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getStorageLocation(Entity\Station|Entity\StorageLocation $source): Entity\StorageLocation
|
protected function getStorageLocation(Entity\Station|Entity\StorageLocation $source): Entity\StorageLocation
|
||||||
{
|
{
|
||||||
if ($source instanceof Entity\Station) {
|
if ($source instanceof Entity\Station) {
|
||||||
|
@ -277,7 +292,7 @@ class StationMediaRepository extends Repository
|
||||||
try {
|
try {
|
||||||
$this->writeAlbumArt($media, $artwork, $fs);
|
$this->writeAlbumArt($media, $artwork, $fs);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
$this->logger->error(
|
Registry::getInstance('app')->error(
|
||||||
sprintf(
|
sprintf(
|
||||||
'Album Artwork for "%s" could not be processed: "%s"',
|
'Album Artwork for "%s" could not be processed: "%s"',
|
||||||
$filePath,
|
$filePath,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use Azura\Files\ExtendedFilesystemInterface;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationMount>
|
* @extends AbstractStationBasedRepository<Entity\StationMount>
|
||||||
*/
|
*/
|
||||||
class StationMountRepository extends AbstractStationBasedRepository
|
final class StationMountRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
public function setIntro(
|
public function setIntro(
|
||||||
Entity\StationMount $mount,
|
Entity\StationMount $mount,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationPlaylistFolder>
|
* @extends AbstractStationBasedRepository<Entity\StationPlaylistFolder>
|
||||||
*/
|
*/
|
||||||
class StationPlaylistFolderRepository extends AbstractStationBasedRepository
|
final class StationPlaylistFolderRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Entity\Station $station
|
* @param Entity\Station $station
|
||||||
|
|
|
@ -7,33 +7,23 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Carbon\CarbonInterface;
|
use Carbon\CarbonInterface;
|
||||||
use Doctrine\ORM\NoResultException;
|
use Doctrine\ORM\NoResultException;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\StationPlaylistMedia>
|
* @extends Repository<Entity\StationPlaylistMedia>
|
||||||
*/
|
*/
|
||||||
class StationPlaylistMediaRepository extends Repository
|
final class StationPlaylistMediaRepository extends Repository
|
||||||
{
|
{
|
||||||
protected StationQueueRepository $queueRepo;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly StationQueueRepository $queueRepo
|
||||||
Environment $environment,
|
|
||||||
LoggerInterface $logger,
|
|
||||||
StationQueueRepository $queueRepo
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
|
|
||||||
$this->queueRepo = $queueRepo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationPlaylist>
|
* @extends AbstractStationBasedRepository<Entity\StationPlaylist>
|
||||||
*/
|
*/
|
||||||
class StationPlaylistRepository extends AbstractStationBasedRepository
|
final class StationPlaylistRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Entity\StationPlaylist[]
|
* @return Entity\StationPlaylist[]
|
||||||
|
|
|
@ -13,7 +13,7 @@ use Doctrine\ORM\QueryBuilder;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationQueue>
|
* @extends AbstractStationBasedRepository<Entity\StationQueue>
|
||||||
*/
|
*/
|
||||||
class StationQueueRepository extends AbstractStationBasedRepository
|
final class StationQueueRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
public function clearForMediaAndPlaylist(Entity\StationMedia $media, Entity\StationPlaylist $playlist): void
|
public function clearForMediaAndPlaylist(Entity\StationMedia $media, Entity\StationPlaylist $playlist): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationRemote>
|
* @extends AbstractStationBasedRepository<Entity\StationRemote>
|
||||||
*/
|
*/
|
||||||
class StationRemoteRepository extends AbstractStationBasedRepository
|
final class StationRemoteRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Entity\Station $station
|
* @param Entity\Station $station
|
||||||
|
|
|
@ -4,33 +4,27 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity\Repository;
|
namespace App\Entity\Repository;
|
||||||
|
|
||||||
use App\Assets\AssetFactory;
|
use App\Assets\AlbumArtCustomAsset;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Flysystem\StationFilesystems;
|
use App\Flysystem\StationFilesystems;
|
||||||
use App\Radio\Frontend\AbstractFrontend;
|
use App\Radio\Frontend\AbstractFrontend;
|
||||||
use App\Service\Flow\UploadedFile;
|
use App\Service\Flow\UploadedFile;
|
||||||
use Azura\Files\ExtendedFilesystemInterface;
|
use Azura\Files\ExtendedFilesystemInterface;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Psr\Http\Message\UriInterface;
|
use Psr\Http\Message\UriInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\Station>
|
* @extends Repository<Entity\Station>
|
||||||
*/
|
*/
|
||||||
class StationRepository extends Repository
|
final class StationRepository extends Repository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected SettingsRepository $settingsRepo,
|
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly SettingsRepository $settingsRepo
|
||||||
Environment $environment,
|
|
||||||
LoggerInterface $logger
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,11 +97,8 @@ class StationRepository extends Repository
|
||||||
// Create default mountpoints if station supports them.
|
// Create default mountpoints if station supports them.
|
||||||
if ($frontend_adapter->supportsMounts()) {
|
if ($frontend_adapter->supportsMounts()) {
|
||||||
// Create default mount points.
|
// Create default mount points.
|
||||||
foreach ($frontend_adapter->getDefaultMounts() as $mount_point) {
|
foreach ($frontend_adapter->getDefaultMounts($station) as $mount) {
|
||||||
$mount_record = new Entity\StationMount($station);
|
$this->em->persist($mount);
|
||||||
$this->fromArray($mount_record, $mount_point);
|
|
||||||
|
|
||||||
$this->em->persist($mount_record);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +156,7 @@ class StationRepository extends Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
$customUrl = $this->settingsRepo->readSettings()->getDefaultAlbumArtUrlAsUri();
|
$customUrl = $this->settingsRepo->readSettings()->getDefaultAlbumArtUrlAsUri();
|
||||||
return $customUrl ?? AssetFactory::createAlbumArt($this->environment)->getUri();
|
return $customUrl ?? (new AlbumArtCustomAsset())->getUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFallback(
|
public function setFallback(
|
||||||
|
|
|
@ -6,32 +6,26 @@ namespace App\Entity\Repository;
|
||||||
|
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Exception;
|
use App\Exception;
|
||||||
use App\Radio\AutoDJ;
|
use App\Radio\AutoDJ;
|
||||||
use App\Radio\Frontend\Blocklist\BlocklistParser;
|
use App\Radio\Frontend\Blocklist\BlocklistParser;
|
||||||
use App\Service\DeviceDetector;
|
use App\Service\DeviceDetector;
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Carbon\CarbonInterface;
|
use Carbon\CarbonInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationRequest>
|
* @extends AbstractStationBasedRepository<Entity\StationRequest>
|
||||||
*/
|
*/
|
||||||
class StationRequestRepository extends AbstractStationBasedRepository
|
final class StationRequestRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly StationMediaRepository $mediaRepo,
|
||||||
Environment $environment,
|
private readonly DeviceDetector $deviceDetector,
|
||||||
LoggerInterface $logger,
|
private readonly BlocklistParser $blocklistParser,
|
||||||
protected StationMediaRepository $mediaRepo,
|
private readonly AutoDJ\DuplicatePrevention $duplicatePrevention,
|
||||||
protected DeviceDetector $deviceDetector,
|
|
||||||
protected BlocklistParser $blocklistParser,
|
|
||||||
protected AutoDJ\DuplicatePrevention $duplicatePrevention,
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPendingRequest(int|string $id, Entity\Station $station): ?Entity\StationRequest
|
public function getPendingRequest(int|string $id, Entity\Station $station): ?Entity\StationRequest
|
||||||
|
|
|
@ -7,27 +7,21 @@ namespace App\Entity\Repository;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Doctrine\Repository;
|
use App\Doctrine\Repository;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Radio\AutoDJ\Scheduler;
|
use App\Radio\AutoDJ\Scheduler;
|
||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Carbon\CarbonInterface;
|
use Carbon\CarbonInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\StationSchedule>
|
* @extends Repository<Entity\StationSchedule>
|
||||||
*/
|
*/
|
||||||
class StationScheduleRepository extends Repository
|
final class StationScheduleRepository extends Repository
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly Scheduler $scheduler,
|
||||||
Environment $environment,
|
private readonly Entity\ApiGenerator\ScheduleApiGenerator $scheduleApiGenerator
|
||||||
LoggerInterface $logger,
|
|
||||||
protected Scheduler $scheduler,
|
|
||||||
protected Entity\ApiGenerator\ScheduleApiGenerator $scheduleApiGenerator
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Carbon\CarbonImmutable;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\StationStreamerBroadcast>
|
* @extends Repository<Entity\StationStreamerBroadcast>
|
||||||
*/
|
*/
|
||||||
class StationStreamerBroadcastRepository extends Repository
|
final class StationStreamerBroadcastRepository extends Repository
|
||||||
{
|
{
|
||||||
public function getLatestBroadcast(Entity\Station $station): ?Entity\StationStreamerBroadcast
|
public function getLatestBroadcast(Entity\Station $station): ?Entity\StationStreamerBroadcast
|
||||||
{
|
{
|
||||||
|
@ -58,7 +58,7 @@ class StationStreamerBroadcastRepository extends Repository
|
||||||
public function getActiveBroadcasts(Entity\Station $station): array
|
public function getActiveBroadcasts(Entity\Station $station): array
|
||||||
{
|
{
|
||||||
return $this->repository->findBy([
|
return $this->repository->findBy([
|
||||||
'station' => $station,
|
'station' => $station,
|
||||||
'timestampEnd' => 0,
|
'timestampEnd' => 0,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,34 +6,21 @@ namespace App\Entity\Repository;
|
||||||
|
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Entity;
|
use App\Entity;
|
||||||
use App\Environment;
|
|
||||||
use App\Flysystem\StationFilesystems;
|
use App\Flysystem\StationFilesystems;
|
||||||
use App\Media\AlbumArt;
|
use App\Media\AlbumArt;
|
||||||
use App\Radio\AutoDJ\Scheduler;
|
use App\Radio\AutoDJ\Scheduler;
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends AbstractStationBasedRepository<Entity\StationStreamer>
|
* @extends AbstractStationBasedRepository<Entity\StationStreamer>
|
||||||
*/
|
*/
|
||||||
class StationStreamerRepository extends AbstractStationBasedRepository
|
final class StationStreamerRepository extends AbstractStationBasedRepository
|
||||||
{
|
{
|
||||||
protected Scheduler $scheduler;
|
|
||||||
|
|
||||||
protected StationStreamerBroadcastRepository $broadcastRepo;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ReloadableEntityManagerInterface $em,
|
ReloadableEntityManagerInterface $em,
|
||||||
Serializer $serializer,
|
private readonly Scheduler $scheduler,
|
||||||
Environment $environment,
|
private readonly StationStreamerBroadcastRepository $broadcastRepo
|
||||||
LoggerInterface $logger,
|
|
||||||
Scheduler $scheduler,
|
|
||||||
StationStreamerBroadcastRepository $broadcastRepo
|
|
||||||
) {
|
) {
|
||||||
parent::__construct($em, $serializer, $environment, $logger);
|
parent::__construct($em);
|
||||||
|
|
||||||
$this->scheduler = $scheduler;
|
|
||||||
$this->broadcastRepo = $broadcastRepo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity\Repository;
|
||||||
|
|
||||||
|
use App\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends AbstractStationBasedRepository<Entity\StationWebhook>
|
||||||
|
*/
|
||||||
|
final class StationWebhookRepository extends AbstractStationBasedRepository
|
||||||
|
{
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ use Brick\Math\BigInteger;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\StorageLocation>
|
* @extends Repository<Entity\StorageLocation>
|
||||||
*/
|
*/
|
||||||
class StorageLocationRepository extends Repository
|
final class StorageLocationRepository extends Repository
|
||||||
{
|
{
|
||||||
public function findByType(
|
public function findByType(
|
||||||
string|Entity\Enums\StorageLocationTypes $type,
|
string|Entity\Enums\StorageLocationTypes $type,
|
||||||
|
@ -24,7 +24,7 @@ class StorageLocationRepository extends Repository
|
||||||
return $this->repository->findOneBy(
|
return $this->repository->findOneBy(
|
||||||
[
|
[
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Generator;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\UnprocessableMedia>
|
* @extends Repository<Entity\UnprocessableMedia>
|
||||||
*/
|
*/
|
||||||
class UnprocessableMediaRepository extends Repository
|
final class UnprocessableMediaRepository extends Repository
|
||||||
{
|
{
|
||||||
public function findByPath(string $path, Entity\StorageLocation $storageLocation): ?Entity\UnprocessableMedia
|
public function findByPath(string $path, Entity\StorageLocation $storageLocation): ?Entity\UnprocessableMedia
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ use App\Security\SplitToken;
|
||||||
/**
|
/**
|
||||||
* @extends AbstractSplitTokenRepository<Entity\UserLoginToken>
|
* @extends AbstractSplitTokenRepository<Entity\UserLoginToken>
|
||||||
*/
|
*/
|
||||||
class UserLoginTokenRepository extends AbstractSplitTokenRepository
|
final class UserLoginTokenRepository extends AbstractSplitTokenRepository
|
||||||
{
|
{
|
||||||
public function createToken(Entity\User $user): SplitToken
|
public function createToken(Entity\User $user): SplitToken
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ use App\Entity;
|
||||||
/**
|
/**
|
||||||
* @extends Repository<Entity\User>
|
* @extends Repository<Entity\User>
|
||||||
*/
|
*/
|
||||||
class UserRepository extends Repository
|
final class UserRepository extends Repository
|
||||||
{
|
{
|
||||||
public function findByEmail(string $email): ?Entity\User
|
public function findByEmail(string $email): ?Entity\User
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity;
|
||||||
use App\Environment;
|
use App\Environment;
|
||||||
use App\Http\Router;
|
use App\Http\Router;
|
||||||
use App\Radio\AbstractAdapter;
|
use App\Radio\AbstractAdapter;
|
||||||
|
use App\Radio\Enums\StreamFormats;
|
||||||
use App\Xml\Reader;
|
use App\Xml\Reader;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
@ -50,19 +51,18 @@ abstract class AbstractFrontend extends AbstractAdapter
|
||||||
/**
|
/**
|
||||||
* Get the default mounts when resetting or initializing a station.
|
* Get the default mounts when resetting or initializing a station.
|
||||||
*
|
*
|
||||||
* @return mixed[]
|
* @return Entity\StationMount[]
|
||||||
*/
|
*/
|
||||||
public function getDefaultMounts(): array
|
public function getDefaultMounts(Entity\Station $station): array
|
||||||
{
|
{
|
||||||
return [
|
$record = new Entity\StationMount($station);
|
||||||
[
|
$record->setName('/radio.mp3');
|
||||||
'name' => '/radio.mp3',
|
$record->setIsDefault(true);
|
||||||
'is_default' => 1,
|
$record->setEnableAutodj(true);
|
||||||
'enable_autodj' => 1,
|
$record->setAutodjFormat(StreamFormats::Mp3->value);
|
||||||
'autodj_format' => 'mp3',
|
$record->setAutodjBitrate(128);
|
||||||
'autodj_bitrate' => 128,
|
|
||||||
],
|
return [$record];
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue