Removing "App\Entity" imports, part 3
This commit is contained in:
parent
13d19511a9
commit
6314fa7a09
|
@ -46,10 +46,6 @@
|
|||
</rule>
|
||||
|
||||
<rule ref="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly">
|
||||
<properties>
|
||||
<property name="allowPartialUses" value="false"/>
|
||||
</properties>
|
||||
|
||||
<exclude-pattern>config/*$</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace App\Controller\Api\Stations\Files;
|
|||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Controller\Api\Traits\CanSortResults;
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\RouterInterface;
|
||||
|
@ -20,6 +19,11 @@ use League\Flysystem\StorageAttributes;
|
|||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\Api\FileList;
|
||||
use App\Entity\Api\FileListMedia;
|
||||
use App\Entity\Station;
|
||||
|
||||
final class ListAction
|
||||
{
|
||||
|
@ -64,7 +68,7 @@ final class ListAction
|
|||
$flushCache = (bool)$request->getParam('flushCache', false);
|
||||
|
||||
if (!$flushCache && $this->cache->has($cacheKey)) {
|
||||
/** @var array<int, Entity\Api\FileList> $result */
|
||||
/** @var array<int, \App\Entity\Api\FileList> $result */
|
||||
$result = $this->cache->get($cacheKey);
|
||||
} else {
|
||||
$pathLike = (empty($currentDir))
|
||||
|
@ -73,7 +77,7 @@ final class ListAction
|
|||
|
||||
$mediaQueryBuilder = $this->em->createQueryBuilder()
|
||||
->select('sm')
|
||||
->from(Entity\StationMedia::class, 'sm')
|
||||
->from(StationMedia::class, 'sm')
|
||||
->where('sm.storage_location = :storageLocation')
|
||||
->andWhere('sm.path LIKE :path')
|
||||
->setParameter('storageLocation', $station->getMediaStorageLocation())
|
||||
|
@ -83,7 +87,7 @@ final class ListAction
|
|||
$foldersInDirQuery = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT spf, sp
|
||||
FROM App\Entity\StationPlaylistFolder spf
|
||||
FROM App\\App\Entity\StationPlaylistFolder spf
|
||||
JOIN spf.playlist sp
|
||||
WHERE spf.station = :station
|
||||
AND spf.path LIKE :path
|
||||
|
@ -94,7 +98,7 @@ final class ListAction
|
|||
$unprocessableMediaQuery = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT upm
|
||||
FROM App\Entity\UnprocessableMedia upm
|
||||
FROM App\\App\Entity\UnprocessableMedia upm
|
||||
WHERE upm.storage_location = :storageLocation
|
||||
AND upm.path LIKE :path
|
||||
DQL
|
||||
|
@ -116,7 +120,7 @@ final class ListAction
|
|||
'sm.song_id',
|
||||
<<<'DQL'
|
||||
SELECT sm2.song_id FROM
|
||||
App\Entity\StationMedia sm2
|
||||
App\\App\Entity\StationMedia sm2
|
||||
WHERE sm2.storage_location = :storageLocation
|
||||
GROUP BY sm2.song_id
|
||||
HAVING COUNT(sm2.id) > 1
|
||||
|
@ -125,14 +129,14 @@ final class ListAction
|
|||
);
|
||||
} elseif ('special:unassigned' === $searchPhrase) {
|
||||
$mediaQueryBuilder->andWhere(
|
||||
'sm.id NOT IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2)'
|
||||
'sm.id NOT IN (SELECT spm2.media_id FROM App\\App\Entity\StationPlaylistMedia spm2)'
|
||||
);
|
||||
} else {
|
||||
[$searchPhrase, $playlist] = $this->parseSearchQuery($station, $searchPhrase);
|
||||
|
||||
if (null !== $playlist) {
|
||||
$mediaQueryBuilder->andWhere(
|
||||
'sm.id IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2 '
|
||||
'sm.id IN (SELECT spm2.media_id FROM App\\App\Entity\StationPlaylistMedia spm2 '
|
||||
. 'WHERE spm2.playlist = :playlist)'
|
||||
)->setParameter('playlist', $playlist);
|
||||
}
|
||||
|
@ -174,7 +178,7 @@ final class ListAction
|
|||
$foldersInDir[$folderRow['path']]['playlists'][] = [
|
||||
'id' => $folderRow['playlist']['id'],
|
||||
'name' => $folderRow['playlist']['name'],
|
||||
'short_name' => Entity\StationPlaylist::generateShortName(
|
||||
'short_name' => StationPlaylist::generateShortName(
|
||||
$folderRow['playlist']['name']
|
||||
),
|
||||
];
|
||||
|
@ -195,9 +199,9 @@ final class ListAction
|
|||
}
|
||||
} else {
|
||||
$protectedPaths = [
|
||||
Entity\StationMedia::DIR_ALBUM_ART,
|
||||
Entity\StationMedia::DIR_WAVEFORMS,
|
||||
Entity\StationMedia::DIR_FOLDER_COVERS,
|
||||
StationMedia::DIR_ALBUM_ART,
|
||||
StationMedia::DIR_WAVEFORMS,
|
||||
StationMedia::DIR_FOLDER_COVERS,
|
||||
];
|
||||
|
||||
$files = $fs->listContents($currentDir, false)->filter(
|
||||
|
@ -211,7 +215,7 @@ final class ListAction
|
|||
|
||||
$result = [];
|
||||
foreach ($files as $file) {
|
||||
$row = new Entity\Api\FileList();
|
||||
$row = new FileList();
|
||||
|
||||
if ($file instanceof StorageAttributes) {
|
||||
$row->path = $file->path();
|
||||
|
@ -235,7 +239,7 @@ final class ListAction
|
|||
}
|
||||
$row->path_short = $shortname;
|
||||
|
||||
$row->media = new Entity\Api\FileListMedia();
|
||||
$row->media = new FileListMedia();
|
||||
|
||||
if (isset($mediaInDir[$row->path])) {
|
||||
$row->media = $mediaInDir[$row->path]['media'];
|
||||
|
@ -272,7 +276,7 @@ final class ListAction
|
|||
|
||||
usort(
|
||||
$result,
|
||||
static fn(Entity\Api\FileList $a, Entity\Api\FileList $b) => self::sortRows(
|
||||
static fn(FileList $a, FileList $b) => self::sortRows(
|
||||
$a,
|
||||
$b,
|
||||
$propertyAccessor,
|
||||
|
@ -288,14 +292,14 @@ final class ListAction
|
|||
$stationId = $station->getIdRequired();
|
||||
|
||||
$paginator->setPostprocessor(
|
||||
static fn(Entity\Api\FileList $row) => self::postProcessRow($row, $router, $stationId)
|
||||
static fn(FileList $row) => self::postProcessRow($row, $router, $stationId)
|
||||
);
|
||||
|
||||
return $paginator->write($response);
|
||||
}
|
||||
|
||||
private function parseSearchQuery(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
string $query
|
||||
): array {
|
||||
$playlist = null;
|
||||
|
@ -310,14 +314,14 @@ final class ListAction
|
|||
$playlistNameLookupRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sp.id, sp.name
|
||||
FROM App\Entity\StationPlaylist sp
|
||||
FROM App\\App\Entity\StationPlaylist sp
|
||||
WHERE sp.station = :station
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
->getArrayResult();
|
||||
|
||||
foreach ($playlistNameLookupRaw as $playlistRow) {
|
||||
$shortName = Entity\StationPlaylist::generateShortName($playlistRow['name']);
|
||||
$shortName = StationPlaylist::generateShortName($playlistRow['name']);
|
||||
if ($shortName === $playlistId) {
|
||||
$playlistId = $playlistRow['id'];
|
||||
break;
|
||||
|
@ -325,7 +329,7 @@ final class ListAction
|
|||
}
|
||||
}
|
||||
|
||||
$playlist = $this->em->getRepository(Entity\StationPlaylist::class)
|
||||
$playlist = $this->em->getRepository(StationPlaylist::class)
|
||||
->findOneBy(
|
||||
[
|
||||
'station' => $station,
|
||||
|
@ -345,7 +349,7 @@ final class ListAction
|
|||
}
|
||||
|
||||
private function processMediaInDir(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?QueryBuilder $qb = null
|
||||
): array {
|
||||
if (null === $qb) {
|
||||
|
@ -375,7 +379,7 @@ final class ListAction
|
|||
$customFieldsRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT smcf.media_id, smcf.field_id, smcf.value
|
||||
FROM App\Entity\StationMediaCustomField smcf
|
||||
FROM App\\App\Entity\StationMediaCustomField smcf
|
||||
WHERE smcf.media_id IN (:ids)
|
||||
DQL
|
||||
)->setParameter('ids', $mediaIds)
|
||||
|
@ -391,7 +395,7 @@ final class ListAction
|
|||
$allPlaylistsRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT spm.media_id, spm.playlist_id, sp.name
|
||||
FROM App\Entity\StationPlaylistMedia spm
|
||||
FROM App\\App\Entity\StationPlaylistMedia spm
|
||||
JOIN spm.playlist sp
|
||||
WHERE sp.station = :station AND spm.media_id IN (:ids)
|
||||
DQL
|
||||
|
@ -408,7 +412,7 @@ final class ListAction
|
|||
$mediaInDir = [];
|
||||
foreach ($mediaInDirRaw as $row) {
|
||||
$id = $row['id'];
|
||||
$media = new Entity\Api\FileListMedia();
|
||||
$media = new FileListMedia();
|
||||
|
||||
$media->id = (string)$row['song_id'];
|
||||
$media->title = (string)$row['title'];
|
||||
|
@ -436,7 +440,7 @@ final class ListAction
|
|||
$playlists[$playlistId] = [
|
||||
'id' => $playlistId,
|
||||
'name' => $playlistName,
|
||||
'short_name' => Entity\StationPlaylist::generateShortName($playlistName),
|
||||
'short_name' => StationPlaylist::generateShortName($playlistName),
|
||||
'count' => 1,
|
||||
];
|
||||
}
|
||||
|
@ -452,8 +456,8 @@ final class ListAction
|
|||
}
|
||||
|
||||
private static function sortRows(
|
||||
Entity\Api\FileList $a,
|
||||
Entity\Api\FileList $b,
|
||||
FileList $a,
|
||||
FileList $b,
|
||||
PropertyAccessorInterface $propertyAccessor,
|
||||
?string $searchPhrase = null,
|
||||
?string $sort = null,
|
||||
|
@ -478,10 +482,10 @@ final class ListAction
|
|||
}
|
||||
|
||||
private static function postProcessRow(
|
||||
Entity\Api\FileList $row,
|
||||
FileList $row,
|
||||
RouterInterface $router,
|
||||
int $stationId
|
||||
): Entity\Api\FileList {
|
||||
): FileList {
|
||||
if (null !== $row->media->media_id) {
|
||||
$artMediaId = $row->media->unique_id;
|
||||
if (0 !== $row->media->art_updated_at) {
|
||||
|
|
|
@ -4,12 +4,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\StationMedia;
|
||||
|
||||
final class ListDirectoriesAction
|
||||
{
|
||||
|
@ -30,9 +30,9 @@ final class ListDirectoriesAction
|
|||
$fsMedia = $this->stationFilesystems->getMediaFilesystem($station);
|
||||
|
||||
$protectedPaths = [
|
||||
Entity\StationMedia::DIR_ALBUM_ART,
|
||||
Entity\StationMedia::DIR_WAVEFORMS,
|
||||
Entity\StationMedia::DIR_FOLDER_COVERS,
|
||||
StationMedia::DIR_ALBUM_ART,
|
||||
StationMedia::DIR_WAVEFORMS,
|
||||
StationMedia::DIR_FOLDER_COVERS,
|
||||
];
|
||||
|
||||
$directoriesRaw = $fsMedia->listContents($currentDir, false)->filter(
|
||||
|
|
|
@ -4,12 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use League\Flysystem\UnableToCreateDirectory;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class MakeDirectoryAction
|
||||
{
|
||||
|
@ -28,7 +29,7 @@ final class MakeDirectoryAction
|
|||
|
||||
if (empty($newDirName)) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Error(400, __('No directory specified')));
|
||||
->withJson(new Error(400, __('No directory specified')));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
@ -41,9 +42,9 @@ final class MakeDirectoryAction
|
|||
$fsMedia->createDirectory($newDir);
|
||||
} catch (UnableToCreateDirectory $e) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Error(400, $e->getMessage()));
|
||||
->withJson(new Error(400, $e->getMessage()));
|
||||
}
|
||||
|
||||
return $response->withJson(Entity\Api\Status::created());
|
||||
return $response->withJson(Status::created());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMediaRepository;
|
||||
|
||||
final class PlayAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMediaRepository $mediaRepo,
|
||||
private readonly StationMediaRepository $mediaRepo,
|
||||
private readonly StationFilesystems $stationFilesystems
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -4,12 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Files;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Media\BatchUtilities;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class RenameAction
|
||||
{
|
||||
|
@ -27,18 +28,18 @@ final class RenameAction
|
|||
$from = $request->getParam('file');
|
||||
if (empty($from)) {
|
||||
return $response->withStatus(500)
|
||||
->withJson(new Entity\Api\Error(500, __('File not specified.')));
|
||||
->withJson(new Error(500, __('File not specified.')));
|
||||
}
|
||||
|
||||
$to = $request->getParam('newPath');
|
||||
if (empty($to)) {
|
||||
return $response->withStatus(500)
|
||||
->withJson(new Entity\Api\Error(500, __('New path not specified.')));
|
||||
->withJson(new Error(500, __('New path not specified.')));
|
||||
}
|
||||
|
||||
// No-op if paths match
|
||||
if ($from === $to) {
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
@ -49,6 +50,6 @@ final class RenameAction
|
|||
|
||||
$this->batchUtilities->handleRename($from, $to, $storageLocation, $fsMedia);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\LiquidsoapConfig;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Event\Radio\WriteLiquidsoapConfiguration;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -34,7 +33,7 @@ final class PutAction
|
|||
$station = $this->em->refetch($request->getStation());
|
||||
|
||||
$backendConfig = $station->getBackendConfig();
|
||||
foreach (Entity\StationBackendConfiguration::getCustomConfigurationSections() as $field) {
|
||||
foreach (\App\Entity\StationBackendConfiguration::getCustomConfigurationSections() as $field) {
|
||||
if (isset($body[$field])) {
|
||||
$backendConfig->setCustomConfigurationSection($field, $body[$field]);
|
||||
}
|
||||
|
@ -52,9 +51,9 @@ final class PutAction
|
|||
$config = $event->buildConfiguration();
|
||||
$this->liquidsoap->verifyConfig($config);
|
||||
} catch (Throwable $e) {
|
||||
return $response->withStatus(500)->withJson(Entity\Api\Error::fromException($e));
|
||||
return $response->withStatus(500)->withJson(\App\Entity\Api\Error::fromException($e));
|
||||
}
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(\App\Entity\Api\Status::updated());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Mounts\Intro;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMountRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/station/{station_id}/mount/{id}/intro',
|
||||
|
@ -36,7 +37,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class DeleteIntroAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo,
|
||||
private readonly StationMountRepository $mountRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -51,6 +52,6 @@ final class DeleteIntroAction
|
|||
$mount = $this->mountRepo->requireForStation($id, $station);
|
||||
$this->mountRepo->clearIntro($mount);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Mounts\Intro;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMountRepository;
|
||||
use App\Entity\StationMount;
|
||||
use App\Entity\Api\Error;
|
||||
|
||||
#[OA\Get(
|
||||
path: '/station/{station_id}/mount/{id}/intro',
|
||||
|
@ -40,7 +42,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class GetIntroAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo,
|
||||
private readonly StationMountRepository $mountRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -55,7 +57,7 @@ final class GetIntroAction
|
|||
$station = $request->getStation();
|
||||
$mount = $this->mountRepo->findForStation($id, $station);
|
||||
|
||||
if ($mount instanceof Entity\StationMount) {
|
||||
if ($mount instanceof StationMount) {
|
||||
$introPath = $mount->getIntroPath();
|
||||
|
||||
if (!empty($introPath)) {
|
||||
|
@ -71,6 +73,6 @@ final class GetIntroAction
|
|||
}
|
||||
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Mounts\Intro;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Service\Flow;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMountRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Post(
|
||||
path: '/station/{station_id}/mount/{id}/intro',
|
||||
|
@ -37,7 +38,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class PostIntroAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo,
|
||||
private readonly StationMountRepository $mountRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -58,7 +59,7 @@ final class PostIntroAction
|
|||
$mount = $this->mountRepo->requireForStation($id, $station);
|
||||
$this->mountRepo->setIntro($mount, $flowResponse);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
return $response->withJson($flowResponse);
|
||||
|
|
|
@ -4,16 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\OnDemand;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMediaRepository;
|
||||
use App\Entity\Api\Error;
|
||||
|
||||
final class DownloadAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMediaRepository $mediaRepo,
|
||||
private readonly StationMediaRepository $mediaRepo,
|
||||
private readonly StationFilesystems $stationFilesystems,
|
||||
) {
|
||||
}
|
||||
|
@ -29,7 +30,7 @@ final class DownloadAction
|
|||
// Verify that the station supports on-demand streaming.
|
||||
if (!$station->getEnableOnDemand()) {
|
||||
return $response->withStatus(403)
|
||||
->withJson(new Entity\Api\Error(403, __('This station does not support on-demand streaming.')));
|
||||
->withJson(new Error(403, __('This station does not support on-demand streaming.')));
|
||||
}
|
||||
|
||||
$media = $this->mediaRepo->requireByUniqueId($media_id, $station);
|
||||
|
|
|
@ -5,12 +5,14 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Podcasts\Art;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastRepository;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/art',
|
||||
|
@ -39,7 +41,7 @@ final class DeleteArtAction
|
|||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastRepository $podcastRepo,
|
||||
private readonly PodcastRepository $podcastRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -56,7 +58,7 @@ final class DeleteArtAction
|
|||
if ($podcast === null) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(
|
||||
new Entity\Api\Error(
|
||||
new Error(
|
||||
404,
|
||||
__('Podcast not found!')
|
||||
)
|
||||
|
@ -67,6 +69,6 @@ final class DeleteArtAction
|
|||
$this->em->persist($podcast);
|
||||
$this->em->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Podcasts\Art;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\Podcast;
|
||||
|
||||
#[OA\Get(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/art',
|
||||
|
@ -40,7 +41,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class GetArtAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRepository $stationRepo,
|
||||
private readonly StationRepository $stationRepo,
|
||||
private readonly StationFilesystems $stationFilesystems,
|
||||
) {
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ final class GetArtAction
|
|||
// If a timestamp delimiter is added, strip it automatically.
|
||||
$podcast_id = explode('|', $podcast_id, 2)[0];
|
||||
|
||||
$podcastPath = Entity\Podcast::getArtPath($podcast_id);
|
||||
$podcastPath = Podcast::getArtPath($podcast_id);
|
||||
|
||||
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);
|
||||
|
||||
|
|
|
@ -5,13 +5,15 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Podcasts\Art;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Service\Flow;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastRepository;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Post(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/art',
|
||||
|
@ -40,7 +42,7 @@ final class PostArtAction
|
|||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastRepository $podcastRepo,
|
||||
private readonly PodcastRepository $podcastRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -65,7 +67,7 @@ final class PostArtAction
|
|||
|
||||
if (null === $podcast) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$this->podcastRepo->writePodcastArt(
|
||||
|
@ -75,7 +77,7 @@ final class PostArtAction
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
return $response->withJson($flowResponse);
|
||||
|
|
|
@ -5,12 +5,14 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
|
||||
|
@ -57,7 +59,7 @@ final class DeleteArtAction
|
|||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly PodcastEpisodeRepository $episodeRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -73,13 +75,13 @@ final class DeleteArtAction
|
|||
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
|
||||
if ($episode === null) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$this->episodeRepo->removeEpisodeArt($episode);
|
||||
$this->em->persist($episode);
|
||||
$this->em->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\PodcastEpisode;
|
||||
use App\Entity\Podcast;
|
||||
|
||||
#[OA\Get(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
|
||||
|
@ -47,7 +49,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class GetArtAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRepository $stationRepo,
|
||||
private readonly StationRepository $stationRepo,
|
||||
private readonly StationFilesystems $stationFilesystems
|
||||
) {
|
||||
}
|
||||
|
@ -64,7 +66,7 @@ final class GetArtAction
|
|||
// If a timestamp delimiter is added, strip it automatically.
|
||||
$episode_id = explode('|', $episode_id, 2)[0];
|
||||
|
||||
$episodeArtPath = Entity\PodcastEpisode::getArtPath($episode_id);
|
||||
$episodeArtPath = PodcastEpisode::getArtPath($episode_id);
|
||||
|
||||
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);
|
||||
if ($fsPodcasts->fileExists($episodeArtPath)) {
|
||||
|
@ -72,7 +74,7 @@ final class GetArtAction
|
|||
->streamFilesystemFile($fsPodcasts, $episodeArtPath, null, 'inline', false);
|
||||
}
|
||||
|
||||
$podcastArtPath = Entity\Podcast::getArtPath($podcast_id);
|
||||
$podcastArtPath = Podcast::getArtPath($podcast_id);
|
||||
|
||||
if ($fsPodcasts->fileExists($podcastArtPath)) {
|
||||
return $response->withCacheLifetime(Response::CACHE_ONE_DAY)
|
||||
|
|
|
@ -5,13 +5,15 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Art;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Service\Flow;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Post(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/art',
|
||||
|
@ -47,7 +49,7 @@ final class PostArtAction
|
|||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly PodcastEpisodeRepository $episodeRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -70,7 +72,7 @@ final class PostArtAction
|
|||
|
||||
if (null === $episode) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$this->episodeRepo->writeEpisodeArt(
|
||||
|
@ -80,7 +82,7 @@ final class PostArtAction
|
|||
|
||||
$this->em->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
return $response->withJson($flowResponse);
|
||||
|
|
|
@ -4,12 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\PodcastEpisode;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\PodcastMedia;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
|
||||
|
@ -43,7 +47,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class DeleteMediaAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly PodcastEpisodeRepository $episodeRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -57,17 +61,17 @@ final class DeleteMediaAction
|
|||
$station = $request->getStation();
|
||||
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
|
||||
|
||||
if (!($episode instanceof Entity\PodcastEpisode)) {
|
||||
if (!($episode instanceof PodcastEpisode)) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$podcastMedia = $episode->getMedia();
|
||||
|
||||
if ($podcastMedia instanceof Entity\PodcastMedia) {
|
||||
if ($podcastMedia instanceof PodcastMedia) {
|
||||
$this->episodeRepo->deleteMedia($podcastMedia);
|
||||
}
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\PodcastEpisode;
|
||||
use App\Entity\PodcastMedia;
|
||||
use App\Entity\Api\Error;
|
||||
|
||||
#[OA\Get(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
|
||||
|
@ -47,7 +50,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class GetMediaAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly StationFilesystems $stationFilesystems,
|
||||
) {
|
||||
}
|
||||
|
@ -64,10 +67,10 @@ final class GetMediaAction
|
|||
$station = $request->getStation();
|
||||
$episode = $this->episodeRepo->fetchEpisodeForStation($station, $episode_id);
|
||||
|
||||
if ($episode instanceof Entity\PodcastEpisode) {
|
||||
if ($episode instanceof PodcastEpisode) {
|
||||
$podcastMedia = $episode->getMedia();
|
||||
|
||||
if ($podcastMedia instanceof Entity\PodcastMedia) {
|
||||
if ($podcastMedia instanceof PodcastMedia) {
|
||||
$fsPodcasts = $this->stationFilesystems->getPodcastsFilesystem($station);
|
||||
|
||||
$path = $podcastMedia->getPath();
|
||||
|
@ -83,6 +86,6 @@ final class GetMediaAction
|
|||
}
|
||||
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Podcasts\Episodes\Media;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -12,6 +11,9 @@ use App\OpenApi;
|
|||
use App\Service\Flow;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Post(
|
||||
path: '/station/{station_id}/podcast/{podcast_id}/episode/{episode_id}/media',
|
||||
|
@ -45,7 +47,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class PostMediaAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly PodcastEpisodeRepository $episodeRepo,
|
||||
private readonly StationFilesystems $stationFilesystems
|
||||
) {
|
||||
}
|
||||
|
@ -69,7 +71,7 @@ final class PostMediaAction
|
|||
|
||||
if (null === $episode) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$this->episodeRepo->uploadMedia(
|
||||
|
@ -79,7 +81,7 @@ final class PostMediaAction
|
|||
$this->stationFilesystems->getPodcastsFilesystem($station)
|
||||
);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
return $response->withJson($flowResponse);
|
||||
|
|
|
@ -4,17 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Utilities\DateRange;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\ApiGenerator\SongApiGenerator;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\Api\Status;
|
||||
use App\Entity\SongHistory;
|
||||
use App\Entity\Song;
|
||||
|
||||
final class BestAndWorstAction extends AbstractReportAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\ApiGenerator\SongApiGenerator $songApiGenerator,
|
||||
Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SongApiGenerator $songApiGenerator,
|
||||
SettingsRepository $settingsRepo
|
||||
) {
|
||||
parent::__construct($settingsRepo);
|
||||
}
|
||||
|
@ -27,7 +31,7 @@ final class BestAndWorstAction extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$dateRange = $this->getDateRange($request, $request->getStation()->getTimezoneObject());
|
||||
|
@ -47,7 +51,7 @@ final class BestAndWorstAction extends AbstractReportAction
|
|||
// Get all songs played in timeline.
|
||||
$baseQuery = $this->em->createQueryBuilder()
|
||||
->select('sh')
|
||||
->from(Entity\SongHistory::class, 'sh')
|
||||
->from(SongHistory::class, 'sh')
|
||||
->where('sh.station = :station')
|
||||
->setParameter('station', $station)
|
||||
->andWhere('sh.timestamp_start <= :end AND sh.timestamp_end >= :start')
|
||||
|
@ -71,7 +75,7 @@ final class BestAndWorstAction extends AbstractReportAction
|
|||
foreach ($rawStats as $category => $rawRows) {
|
||||
$stats[$category] = array_map(
|
||||
function ($row) use ($station, $baseUrl) {
|
||||
$song = ($this->songApiGenerator)(Entity\Song::createFromArray($row), $station);
|
||||
$song = ($this->songApiGenerator)(Song::createFromArray($row), $station);
|
||||
$song->resolveUrls($baseUrl);
|
||||
|
||||
return [
|
||||
|
@ -97,7 +101,7 @@ final class BestAndWorstAction extends AbstractReportAction
|
|||
$rawRows = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sh.song_id, sh.text, sh.artist, sh.title, COUNT(sh.id) AS records
|
||||
FROM App\Entity\SongHistory sh
|
||||
FROM App\\App\Entity\SongHistory sh
|
||||
WHERE sh.station = :station
|
||||
AND sh.is_visible = 1
|
||||
AND sh.timestamp_start <= :end
|
||||
|
@ -115,7 +119,7 @@ final class BestAndWorstAction extends AbstractReportAction
|
|||
|
||||
return array_map(
|
||||
function ($row) use ($station, $baseUrl) {
|
||||
$song = ($this->songApiGenerator)(Entity\Song::createFromArray($row), $station);
|
||||
$song = ($this->songApiGenerator)(Song::createFromArray($row), $station);
|
||||
$song->resolveUrls($baseUrl);
|
||||
|
||||
return [
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ByBrowser extends AbstractReportAction
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ final class ByBrowser extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAllAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ByClient extends AbstractReportAction
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ final class ByClient extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAllAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
|
|
@ -4,11 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Intl\Countries;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ByCountry extends AbstractReportAction
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ final class ByCountry extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAllAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ByListeningTime extends AbstractReportAction
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ final class ByListeningTime extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
|
|
@ -4,18 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationMountRepository;
|
||||
use App\Entity\Repository\StationRemoteRepository;
|
||||
use App\Entity\Repository\StationHlsStreamRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ByStream extends AbstractReportAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationMountRepository $mountRepo,
|
||||
private readonly Entity\Repository\StationRemoteRepository $remoteRepo,
|
||||
private readonly Entity\Repository\StationHlsStreamRepository $hlsStreamRepo,
|
||||
private readonly StationMountRepository $mountRepo,
|
||||
private readonly StationRemoteRepository $remoteRepo,
|
||||
private readonly StationHlsStreamRepository $hlsStreamRepo,
|
||||
SettingsRepository $settingsRepo,
|
||||
) {
|
||||
parent::__construct($settingsRepo);
|
||||
|
@ -29,7 +32,7 @@ final class ByStream extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
|
|
@ -4,18 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Reports\Overview;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use stdClass;
|
||||
use App\Entity\Repository\AnalyticsRepository;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\Api\Status;
|
||||
use App\Entity\Enums\AnalyticsIntervals;
|
||||
|
||||
final class ChartsAction extends AbstractReportAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\AnalyticsRepository $analyticsRepo,
|
||||
Entity\Repository\SettingsRepository $settingsRepo,
|
||||
private readonly AnalyticsRepository $analyticsRepo,
|
||||
SettingsRepository $settingsRepo,
|
||||
) {
|
||||
parent::__construct($settingsRepo);
|
||||
}
|
||||
|
@ -28,7 +31,7 @@ final class ChartsAction extends AbstractReportAction
|
|||
// Get current analytics level.
|
||||
if (!$this->isAnalyticsEnabled()) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
->withJson(new Status(false, 'Reporting is restricted due to system analytics level.'));
|
||||
}
|
||||
|
||||
$station = $request->getStation();
|
||||
|
@ -141,7 +144,7 @@ final class ChartsAction extends AbstractReportAction
|
|||
$hourlyStats = $this->analyticsRepo->findForStationInRange(
|
||||
$station,
|
||||
$dateRange,
|
||||
Entity\Enums\AnalyticsIntervals::Hourly
|
||||
AnalyticsIntervals::Hourly
|
||||
);
|
||||
|
||||
$totals_by_hour = [];
|
||||
|
|
|
@ -5,19 +5,21 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Reports;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Paginator;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRequestRepository;
|
||||
use App\Entity\StationRequest;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class RequestsController
|
||||
{
|
||||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRequestRepository $requestRepo
|
||||
private readonly StationRequestRepository $requestRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -30,7 +32,7 @@ final class RequestsController
|
|||
|
||||
$qb = $this->em->createQueryBuilder()
|
||||
->select('sr, sm')
|
||||
->from(Entity\StationRequest::class, 'sr')
|
||||
->from(StationRequest::class, 'sr')
|
||||
->join('sr.track', 'sm')
|
||||
->where('sr.station = :station')
|
||||
->setParameter('station', $station)
|
||||
|
@ -73,12 +75,12 @@ final class RequestsController
|
|||
$station = $request->getStation();
|
||||
$media = $this->requestRepo->getPendingRequest($request_id, $station);
|
||||
|
||||
if ($media instanceof Entity\StationRequest) {
|
||||
if ($media instanceof StationRequest) {
|
||||
$this->em->remove($media);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
|
||||
public function clearAction(
|
||||
|
@ -89,6 +91,6 @@ final class RequestsController
|
|||
$station = $request->getStation();
|
||||
$this->requestRepo->clearPendingRequests($station);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Reports;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Service\MusicBrainz;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
use App\Entity\Song;
|
||||
|
||||
/**
|
||||
* Produce a report in SoundExchange (the US webcaster licensing agency) format.
|
||||
|
@ -68,7 +68,7 @@ final class SoundExchangeAction
|
|||
$all_media = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sm, spm, sp, smcf
|
||||
FROM App\Entity\StationMedia sm
|
||||
FROM App\\App\Entity\StationMedia sm
|
||||
LEFT JOIN sm.custom_fields smcf
|
||||
LEFT JOIN sm.playlists spm
|
||||
LEFT JOIN spm.playlist sp
|
||||
|
@ -85,7 +85,7 @@ final class SoundExchangeAction
|
|||
<<<'DQL'
|
||||
SELECT sh.song_id AS song_id, sh.text, sh.artist, sh.title, sh.media_id, COUNT(sh.id) AS plays,
|
||||
SUM(sh.unique_listeners) AS unique_listeners
|
||||
FROM App\Entity\SongHistory sh
|
||||
FROM App\\App\Entity\SongHistory sh
|
||||
WHERE sh.station = :station
|
||||
AND sh.timestamp_start <= :time_end
|
||||
AND sh.timestamp_end >= :time_start
|
||||
|
@ -100,7 +100,7 @@ final class SoundExchangeAction
|
|||
$history_rows_by_id = array_column($history_rows, null, 'media_id');
|
||||
|
||||
// Remove any reference to the "Stream Offline" song.
|
||||
$offline_song_hash = Entity\Song::createOffline()->getSongId();
|
||||
$offline_song_hash = Song::createOffline()->getSongId();
|
||||
unset($history_rows_by_id[$offline_song_hash]);
|
||||
|
||||
// Assemble report items
|
||||
|
@ -108,7 +108,7 @@ final class SoundExchangeAction
|
|||
|
||||
$set_isrc_query = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationMedia sm
|
||||
UPDATE App\\App\Entity\StationMedia sm
|
||||
SET sm.isrc = :isrc
|
||||
WHERE sm.id = :media_id
|
||||
DQL
|
||||
|
@ -163,7 +163,7 @@ final class SoundExchangeAction
|
|||
|
||||
private function findISRC(array $song_row): ?string
|
||||
{
|
||||
$song = Entity\Song::createFromArray($song_row);
|
||||
$song = Song::createFromArray($song_row);
|
||||
|
||||
try {
|
||||
foreach ($this->musicBrainz->findRecordingsForSong($song, 'isrcs') as $recording) {
|
||||
|
|
|
@ -4,12 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\StereoTool;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Delete(
|
||||
path: '/station/{station_id}/stereo-tool-configuration',
|
||||
|
@ -29,7 +30,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class DeleteStereoToolConfigurationAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRepository $stationRepo
|
||||
private readonly StationRepository $stationRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,6 @@ final class DeleteStereoToolConfigurationAction
|
|||
|
||||
$this->stationRepo->clearStereoToolConfiguration($station);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\StereoTool;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Error;
|
||||
|
||||
#[OA\Get(
|
||||
path: '/station/{station_id}/stereo-tool-configuration',
|
||||
|
@ -55,6 +55,6 @@ final class GetStereoToolConfigurationAction
|
|||
}
|
||||
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\StereoTool;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\OpenApi;
|
||||
use App\Service\Flow;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
#[OA\Post(
|
||||
path: '/station/{station_id}/stereo-tool-configuration',
|
||||
|
@ -30,7 +31,7 @@ use Psr\Http\Message\ResponseInterface;
|
|||
final class PostStereoToolConfigurationAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRepository $stationRepo
|
||||
private readonly StationRepository $stationRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,6 @@ final class PostStereoToolConfigurationAction
|
|||
|
||||
$this->stationRepo->setStereoToolConfiguration($station, $flowResponse);
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Streamers\Art;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\StationStreamer;
|
||||
|
||||
final class GetArtAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationRepository $stationRepo,
|
||||
private readonly StationRepository $stationRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -28,7 +29,7 @@ final class GetArtAction
|
|||
|
||||
$station = $request->getStation();
|
||||
|
||||
$artworkPath = Entity\StationStreamer::getArtworkPath($id);
|
||||
$artworkPath = StationStreamer::getArtworkPath($id);
|
||||
|
||||
$fsConfig = StationFilesystems::buildConfigFilesystem($station);
|
||||
if ($fsConfig->fileExists($artworkPath)) {
|
||||
|
|
|
@ -4,16 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Streamers\Art;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Service\Flow;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\StationStreamerRepository;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class PostArtAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\StationStreamerRepository $streamerRepo,
|
||||
private readonly StationStreamerRepository $streamerRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,7 @@ final class PostArtAction
|
|||
$this->streamerRepo->getEntityManager()
|
||||
->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::updated());
|
||||
return $response->withJson(Status::updated());
|
||||
}
|
||||
|
||||
return $response->withJson($flowResponse);
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Streamers;
|
||||
|
||||
use App\Controller\Api\AbstractApiCrudController;
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
|
@ -14,13 +13,18 @@ use App\Utilities\File;
|
|||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use App\Entity\StationStreamerBroadcast;
|
||||
use App\Entity\Api\Error;
|
||||
use App\Entity\Api\Status;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationStreamer;
|
||||
|
||||
/**
|
||||
* @extends AbstractApiCrudController<Entity\StationStreamerBroadcast>
|
||||
* @extends AbstractApiCrudController<\App\Entity\StationStreamerBroadcast>
|
||||
*/
|
||||
final class BroadcastsController extends AbstractApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\StationStreamerBroadcast::class;
|
||||
protected string $entityClass = StationStreamerBroadcast::class;
|
||||
|
||||
public function __construct(
|
||||
private readonly StationFilesystems $stationFilesystems,
|
||||
|
@ -43,13 +47,13 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
|
||||
if (null === $streamer) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$query = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssb
|
||||
FROM App\Entity\StationStreamerBroadcast ssb
|
||||
FROM App\\App\Entity\StationStreamerBroadcast ssb
|
||||
WHERE ssb.station = :station AND ssb.streamer = :streamer
|
||||
ORDER BY ssb.timestampStart DESC
|
||||
DQL
|
||||
|
@ -59,7 +63,7 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
$query = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssb, ss
|
||||
FROM App\Entity\StationStreamerBroadcast ssb
|
||||
FROM App\\App\Entity\StationStreamerBroadcast ssb
|
||||
JOIN ssb.streamer ss
|
||||
WHERE ssb.station = :station
|
||||
ORDER BY ssb.timestampStart DESC
|
||||
|
@ -139,14 +143,14 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
|
||||
if (null === $broadcast) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$recordingPath = $broadcast->getRecordingPath();
|
||||
|
||||
if (empty($recordingPath)) {
|
||||
return $response->withStatus(400)
|
||||
->withJson(new Entity\Api\Error(400, __('No recording available.')));
|
||||
->withJson(new Error(400, __('No recording available.')));
|
||||
}
|
||||
|
||||
$filename = basename($recordingPath);
|
||||
|
@ -172,7 +176,7 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
|
||||
if (null === $broadcast) {
|
||||
return $response->withStatus(404)
|
||||
->withJson(Entity\Api\Error::notFound());
|
||||
->withJson(Error::notFound());
|
||||
}
|
||||
|
||||
$recordingPath = $broadcast->getRecordingPath();
|
||||
|
@ -185,13 +189,13 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
$this->em->remove($broadcast);
|
||||
$this->em->flush();
|
||||
|
||||
return $response->withJson(Entity\Api\Status::deleted());
|
||||
return $response->withJson(Status::deleted());
|
||||
}
|
||||
|
||||
private function getRecord(Entity\Station $station, int|string $id): ?Entity\StationStreamerBroadcast
|
||||
private function getRecord(Station $station, int|string $id): ?StationStreamerBroadcast
|
||||
{
|
||||
/** @var Entity\StationStreamerBroadcast|null $broadcast */
|
||||
$broadcast = $this->em->getRepository(Entity\StationStreamerBroadcast::class)->findOneBy(
|
||||
/** @var \App\Entity\StationStreamerBroadcast|null $broadcast */
|
||||
$broadcast = $this->em->getRepository(StationStreamerBroadcast::class)->findOneBy(
|
||||
[
|
||||
'id' => (int)$id,
|
||||
'station' => $station,
|
||||
|
@ -200,10 +204,10 @@ final class BroadcastsController extends AbstractApiCrudController
|
|||
return $broadcast;
|
||||
}
|
||||
|
||||
private function getStreamer(Entity\Station $station, int|string $id): ?Entity\StationStreamer
|
||||
private function getStreamer(Station $station, int|string $id): ?StationStreamer
|
||||
{
|
||||
/** @var Entity\StationStreamer|null $streamer */
|
||||
$streamer = $this->em->getRepository(Entity\StationStreamer::class)->findOneBy(
|
||||
/** @var \App\Entity\StationStreamer|null $streamer */
|
||||
$streamer = $this->em->getRepository(StationStreamer::class)->findOneBy(
|
||||
[
|
||||
'id' => (int)$id,
|
||||
'station' => $station,
|
||||
|
|
|
@ -5,12 +5,12 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Api\Stations\Webhooks;
|
||||
|
||||
use App\Controller\Api\Traits\HasLogViewer;
|
||||
use App\Entity;
|
||||
use App\Entity\Repository\StationWebhookRepository;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Utilities\File;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Error;
|
||||
|
||||
final class TestLogAction
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ final class TestLogAction
|
|||
if (!str_contains($path, $logPathPortion)) {
|
||||
return $response
|
||||
->withStatus(403)
|
||||
->withJson(new Entity\Api\Error(403, 'Invalid log path.'));
|
||||
->withJson(new Error(403, 'Invalid log path.'));
|
||||
}
|
||||
|
||||
$tempPath = File::validateTempPath($path);
|
||||
|
|
|
@ -4,11 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Stations\Webhooks;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Repository\StationWebhookRepository;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Api\Status;
|
||||
|
||||
final class ToggleAction
|
||||
{
|
||||
|
@ -36,6 +36,6 @@ final class ToggleAction
|
|||
? __('Web hook enabled.')
|
||||
: __('Web hook disabled.');
|
||||
|
||||
return $response->withJson(new Entity\Api\Status(true, $flash_message));
|
||||
return $response->withJson(new Status(true, $flash_message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Api\Traits;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\AutoDJ\Scheduler;
|
||||
use App\Utilities\DateRange;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Entity\StationSchedule;
|
||||
|
||||
trait HasScheduleDisplay
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ trait HasScheduleDisplay
|
|||
$endDate = $dateRange->getEnd();
|
||||
|
||||
foreach ($scheduleItems as $scheduleItem) {
|
||||
/** @var Entity\StationSchedule $scheduleItem */
|
||||
/** @var \App\Entity\StationSchedule $scheduleItem */
|
||||
$i = $startDate;
|
||||
|
||||
while ($i <= $endDate) {
|
||||
|
@ -48,8 +48,8 @@ trait HasScheduleDisplay
|
|||
$scheduler->shouldSchedulePlayOnCurrentDate($scheduleItem, $i)
|
||||
&& $scheduler->isScheduleScheduledToPlayToday($scheduleItem, $dayOfWeek)
|
||||
) {
|
||||
$rowStart = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
|
||||
$rowEnd = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
|
||||
$rowStart = StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
|
||||
$rowEnd = StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
|
||||
|
||||
// Handle overnight schedule items
|
||||
if ($rowEnd < $rowStart) {
|
||||
|
|
|
@ -4,19 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend\Account;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\RateLimitExceededException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\RateLimit;
|
||||
use App\Service\Mail;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\UserRepository;
|
||||
use App\Entity\Repository\UserLoginTokenRepository;
|
||||
use App\Entity\User;
|
||||
|
||||
final class ForgotPasswordAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\UserRepository $userRepo,
|
||||
private readonly Entity\Repository\UserLoginTokenRepository $loginTokenRepo,
|
||||
private readonly UserRepository $userRepo,
|
||||
private readonly UserLoginTokenRepository $loginTokenRepo,
|
||||
private readonly RateLimit $rateLimit,
|
||||
private readonly Mail $mail
|
||||
) {
|
||||
|
@ -54,7 +56,7 @@ final class ForgotPasswordAction
|
|||
$email = $request->getParsedBodyParam('email', '');
|
||||
$user = $this->userRepo->findByEmail($email);
|
||||
|
||||
if ($user instanceof Entity\User) {
|
||||
if ($user instanceof User) {
|
||||
$email = $this->mail->createMessage();
|
||||
$email->to($user->getEmail());
|
||||
|
||||
|
|
|
@ -5,13 +5,14 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Frontend\Account;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Exception\RateLimitExceededException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\RateLimit;
|
||||
use Mezzio\Session\SessionCookiePersistenceInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\User;
|
||||
|
||||
final class LoginAction
|
||||
{
|
||||
|
@ -19,7 +20,7 @@ final class LoginAction
|
|||
|
||||
public function __construct(
|
||||
private readonly RateLimit $rateLimit,
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SettingsRepository $settingsRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -36,7 +37,7 @@ final class LoginAction
|
|||
if (!$settings->isSetupComplete()) {
|
||||
$num_users = (int)$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(u.id) FROM App\Entity\User u
|
||||
SELECT COUNT(u.id) FROM App\\App\Entity\User u
|
||||
DQL
|
||||
)->getSingleScalarResult();
|
||||
|
||||
|
@ -68,7 +69,7 @@ final class LoginAction
|
|||
|
||||
$user = $auth->authenticate($request->getParam('username'), $request->getParam('password'));
|
||||
|
||||
if ($user instanceof Entity\User) {
|
||||
if ($user instanceof User) {
|
||||
$session = $request->getSession();
|
||||
|
||||
// If user selects "remember me", extend the cookie/session lifetime.
|
||||
|
|
|
@ -4,18 +4,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend\Account;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\UserRepository;
|
||||
use App\Entity\User;
|
||||
|
||||
final class MasqueradeAction
|
||||
{
|
||||
public const CSRF_NAMESPACE = 'user_masquerade';
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\UserRepository $userRepo,
|
||||
private readonly UserRepository $userRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ final class MasqueradeAction
|
|||
|
||||
$user = $this->userRepo->find($id);
|
||||
|
||||
if (!($user instanceof Entity\User)) {
|
||||
if (!($user instanceof User)) {
|
||||
throw new NotFoundException(__('User not found.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,19 +5,20 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Frontend\Account;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
use App\Entity\Repository\UserLoginTokenRepository;
|
||||
use App\Entity\User;
|
||||
|
||||
final class RecoverAction
|
||||
{
|
||||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\UserLoginTokenRepository $loginTokenRepo,
|
||||
private readonly UserLoginTokenRepository $loginTokenRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ final class RecoverAction
|
|||
$user = $this->loginTokenRepo->authenticate($token);
|
||||
$flash = $request->getFlash();
|
||||
|
||||
if (!$user instanceof Entity\User) {
|
||||
if (!$user instanceof User) {
|
||||
$flash->error(
|
||||
sprintf(
|
||||
'<b>%s</b>',
|
||||
|
|
|
@ -4,16 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend;
|
||||
|
||||
use App\Entity;
|
||||
use App\Enums\GlobalPermissions;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
|
||||
final class DashboardAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SettingsRepository $settingsRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\User;
|
||||
|
||||
final class IndexAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SettingsRepository $settingsRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ final class IndexAction
|
|||
// Redirect to login screen if the user isn't logged in.
|
||||
$user = $request->getAttribute(ServerRequest::ATTR_USER);
|
||||
|
||||
if (!($user instanceof Entity\User)) {
|
||||
if (!($user instanceof User)) {
|
||||
// Redirect to a custom homepage URL if specified in settings.
|
||||
$homepageRedirect = $settings->getHomepageRedirectUrl();
|
||||
if (null !== $homepageRedirect) {
|
||||
|
|
|
@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend\PublicPages;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\StationNotFoundException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\VueComponent\NowPlayingComponent;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\CustomFieldRepository;
|
||||
|
||||
final class PlayerAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo,
|
||||
private readonly CustomFieldRepository $customFieldRepo,
|
||||
private readonly NowPlayingComponent $nowPlayingComponent
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend\PublicPages;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Radio\Adapters;
|
||||
|
@ -31,7 +30,7 @@ final class PlaylistAction
|
|||
$fa = $this->adapters->getFrontendAdapter($station);
|
||||
if (null !== $fa) {
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
/** @var Entity\StationMount $mount */
|
||||
/** @var \App\Entity\StationMount $mount */
|
||||
if (!$mount->getIsVisibleOnPublicPages()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Frontend\PublicPages;
|
||||
|
||||
use App\Entity;
|
||||
use App\Exception\StationNotFoundException;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\CustomFieldRepository;
|
||||
|
||||
final class RequestsAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo
|
||||
private readonly CustomFieldRepository $customFieldRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace App\Controller\Frontend;
|
|||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Container\EnvironmentAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Exception\NotLoggedInException;
|
||||
use App\Exception\ValidationException;
|
||||
use App\Http\Response;
|
||||
|
@ -17,6 +16,10 @@ use InvalidArgumentException;
|
|||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Throwable;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\Repository\RolePermissionRepository;
|
||||
use App\Entity\User;
|
||||
use App\Entity\Settings;
|
||||
|
||||
final class SetupController
|
||||
{
|
||||
|
@ -24,8 +27,8 @@ final class SetupController
|
|||
use EnvironmentAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo,
|
||||
private readonly Entity\Repository\RolePermissionRepository $permissionRepo,
|
||||
private readonly SettingsRepository $settingsRepo,
|
||||
private readonly RolePermissionRepository $permissionRepo,
|
||||
private readonly ValidatorInterface $validator,
|
||||
private readonly StationFormComponent $stationFormComponent,
|
||||
private readonly Version $version
|
||||
|
@ -77,7 +80,7 @@ final class SetupController
|
|||
$role = $this->permissionRepo->ensureSuperAdministratorRole();
|
||||
|
||||
// Create user account.
|
||||
$user = new Entity\User();
|
||||
$user = new User();
|
||||
$user->setEmail($data['username']);
|
||||
$user->setNewPassword($data['password']);
|
||||
$user->getRoles()->add($role);
|
||||
|
@ -170,7 +173,7 @@ final class SetupController
|
|||
title: __('System Settings'),
|
||||
props: [
|
||||
'apiUrl' => $router->named('api:admin:settings', [
|
||||
'group' => Entity\Settings::GROUP_GENERAL,
|
||||
'group' => Settings::GROUP_GENERAL,
|
||||
]),
|
||||
'releaseChannel' => $this->version->getReleaseChannelEnum()->value,
|
||||
'continueUrl' => $router->named('dashboard'),
|
||||
|
@ -208,7 +211,7 @@ final class SetupController
|
|||
// Step 1: Register
|
||||
$num_users = (int)$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(u.id) FROM App\Entity\User u
|
||||
SELECT COUNT(u.id) FROM App\\App\Entity\User u
|
||||
DQL
|
||||
)->getSingleScalarResult();
|
||||
|
||||
|
@ -225,7 +228,7 @@ final class SetupController
|
|||
// Step 2: Set up Station
|
||||
$num_stations = (int)$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(s.id) FROM App\Entity\Station s
|
||||
SELECT COUNT(s.id) FROM App\\App\Entity\Station s
|
||||
DQL
|
||||
)->getSingleScalarResult();
|
||||
|
||||
|
|
|
@ -5,19 +5,21 @@ declare(strict_types=1);
|
|||
namespace App\Controller\Stations;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Enums\StationFeatures;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Media\MimeType;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\CustomFieldRepository;
|
||||
use App\Entity\Enums\PlaylistSources;
|
||||
use App\Entity\Enums\StorageLocationTypes;
|
||||
|
||||
final class FilesAction
|
||||
{
|
||||
use EntityManagerAwareTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo
|
||||
private readonly CustomFieldRepository $customFieldRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -31,12 +33,12 @@ final class FilesAction
|
|||
$playlists = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sp.id, sp.name
|
||||
FROM App\Entity\StationPlaylist sp
|
||||
FROM App\\App\Entity\StationPlaylist sp
|
||||
WHERE sp.station_id = :station_id AND sp.source = :source
|
||||
ORDER BY sp.name ASC
|
||||
DQL
|
||||
)->setParameter('station_id', $station->getId())
|
||||
->setParameter('source', Entity\Enums\PlaylistSources::Songs->value)
|
||||
->setParameter('source', PlaylistSources::Songs->value)
|
||||
->getArrayResult();
|
||||
|
||||
$router = $request->getRouter();
|
||||
|
@ -56,7 +58,7 @@ final class FilesAction
|
|||
'mkdirUrl' => $router->fromHere('api:stations:files:mkdir'),
|
||||
'renameUrl' => $router->fromHere('api:stations:files:rename'),
|
||||
'quotaUrl' => $router->fromHere('api:stations:quota', [
|
||||
'type' => Entity\Enums\StorageLocationTypes::StationMedia->value,
|
||||
'type' => StorageLocationTypes::StationMedia->value,
|
||||
]),
|
||||
'initialPlaylists' => $playlists,
|
||||
'customFields' => $this->customFieldRepo->fetchArray(),
|
||||
|
|
|
@ -4,11 +4,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Stations;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Intl\Languages;
|
||||
use App\Entity\PodcastCategory;
|
||||
use App\Entity\Enums\StorageLocationTypes;
|
||||
|
||||
final class PodcastsAction
|
||||
{
|
||||
|
@ -24,7 +25,7 @@ final class PodcastsAction
|
|||
$userLocale = $locale->value;
|
||||
|
||||
$languageOptions = Languages::getNames($userLocale);
|
||||
$categoriesOptions = Entity\PodcastCategory::getAvailableCategories();
|
||||
$categoriesOptions = PodcastCategory::getAvailableCategories();
|
||||
|
||||
return $request->getView()->renderVuePage(
|
||||
response: $response,
|
||||
|
@ -36,7 +37,7 @@ final class PodcastsAction
|
|||
'newArtUrl' => $router->fromHere('api:stations:podcasts:new-art'),
|
||||
'stationUrl' => $router->fromHere('stations:index:index'),
|
||||
'quotaUrl' => $router->fromHere('api:stations:quota', [
|
||||
'type' => Entity\Enums\StorageLocationTypes::StationPodcasts->value,
|
||||
'type' => StorageLocationTypes::StationPodcasts->value,
|
||||
]),
|
||||
'locale' => substr($locale->value, 0, 2),
|
||||
'stationTimeZone' => $station->getTimezone(),
|
||||
|
|
|
@ -4,15 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Stations\Reports;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
use App\Entity\Enums\AnalyticsLevel;
|
||||
|
||||
final class OverviewAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SettingsRepository $settingsRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -39,7 +40,7 @@ final class OverviewAction
|
|||
title: __('Station Statistics'),
|
||||
props: [
|
||||
'stationTz' => $request->getStation()->getTimezone(),
|
||||
'showFullAnalytics' => Entity\Enums\AnalyticsLevel::All === $analyticsLevel,
|
||||
'showFullAnalytics' => AnalyticsLevel::All === $analyticsLevel,
|
||||
'listenersByTimePeriodUrl' => $router->fromHere('api:stations:reports:overview-charts'),
|
||||
'bestAndWorstUrl' => $router->fromHere('api:stations:reports:best-and-worst'),
|
||||
'byStreamUrl' => $router->fromHere('api:stations:reports:by-stream'),
|
||||
|
|
|
@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller\Stations;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Service\AzuraCastCentral;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use App\Entity\Repository\SettingsRepository;
|
||||
|
||||
final class StreamersAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AzuraCastCentral $acCentral,
|
||||
private readonly Entity\Repository\SettingsRepository $settingsRepo
|
||||
private readonly SettingsRepository $settingsRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Doctrine\Event;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Attributes\Auditable;
|
||||
use App\Entity\Attributes\AuditIgnore;
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
|
@ -17,6 +16,8 @@ use Doctrine\ORM\UnitOfWork;
|
|||
use ReflectionClass;
|
||||
use ReflectionObject;
|
||||
use Stringable;
|
||||
use App\Entity\Enums\AuditLogOperations;
|
||||
use App\Entity\Interfaces\IdentifiableEntityInterface;
|
||||
|
||||
/**
|
||||
* A hook into Doctrine's event listener to write changes to "Auditable"
|
||||
|
@ -47,7 +48,7 @@ final class AuditLog implements EventSubscriber
|
|||
$newAuditLogs = array_merge($singleAuditLogs, $collectionAuditLogs);
|
||||
|
||||
if (!empty($newAuditLogs)) {
|
||||
$auditLogMetadata = $em->getClassMetadata(Entity\AuditLog::class);
|
||||
$auditLogMetadata = $em->getClassMetadata(\App\Entity\AuditLog::class);
|
||||
foreach ($newAuditLogs as $auditLog) {
|
||||
$uow->persist($auditLog);
|
||||
$uow->computeChangeSet($auditLogMetadata, $auditLog);
|
||||
|
@ -55,7 +56,7 @@ final class AuditLog implements EventSubscriber
|
|||
}
|
||||
}
|
||||
|
||||
/** @return Entity\AuditLog[] */
|
||||
/** @return \App\Entity\AuditLog[] */
|
||||
private function handleSingleUpdates(
|
||||
EntityManagerInterface $em,
|
||||
UnitOfWork $uow
|
||||
|
@ -64,15 +65,15 @@ final class AuditLog implements EventSubscriber
|
|||
|
||||
$collections = [
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Insert,
|
||||
AuditLogOperations::Insert,
|
||||
$uow->getScheduledEntityInsertions(),
|
||||
],
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Update,
|
||||
AuditLogOperations::Update,
|
||||
$uow->getScheduledEntityUpdates(),
|
||||
],
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Delete,
|
||||
AuditLogOperations::Delete,
|
||||
$uow->getScheduledEntityDeletions(),
|
||||
],
|
||||
];
|
||||
|
@ -114,14 +115,14 @@ final class AuditLog implements EventSubscriber
|
|||
$changes[$changeField] = [$fieldPrev, $fieldNow];
|
||||
}
|
||||
|
||||
if (Entity\Enums\AuditLogOperations::Update === $changeType && empty($changes)) {
|
||||
if (AuditLogOperations::Update === $changeType && empty($changes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the identifier method or property.
|
||||
$identifier = $this->getIdentifier($entity);
|
||||
|
||||
$newRecords[] = new Entity\AuditLog(
|
||||
$newRecords[] = new \App\Entity\AuditLog(
|
||||
$changeType,
|
||||
get_class($entity),
|
||||
$identifier,
|
||||
|
@ -135,7 +136,7 @@ final class AuditLog implements EventSubscriber
|
|||
return $newRecords;
|
||||
}
|
||||
|
||||
/** @return Entity\AuditLog[] */
|
||||
/** @return \App\Entity\AuditLog[] */
|
||||
private function handleCollectionUpdates(
|
||||
UnitOfWork $uow
|
||||
): array {
|
||||
|
@ -215,8 +216,8 @@ final class AuditLog implements EventSubscriber
|
|||
}
|
||||
|
||||
foreach ($associated as [$owner, $ownerIdentifier, $entity, $entityIdentifier]) {
|
||||
$newRecords[] = new Entity\AuditLog(
|
||||
Entity\Enums\AuditLogOperations::Insert,
|
||||
$newRecords[] = new \App\Entity\AuditLog(
|
||||
AuditLogOperations::Insert,
|
||||
get_class($owner),
|
||||
$ownerIdentifier,
|
||||
(string)get_class($entity),
|
||||
|
@ -226,8 +227,8 @@ final class AuditLog implements EventSubscriber
|
|||
}
|
||||
|
||||
foreach ($disassociated as [$owner, $ownerIdentifier, $entity, $entityIdentifier]) {
|
||||
$newRecords[] = new Entity\AuditLog(
|
||||
Entity\Enums\AuditLogOperations::Delete,
|
||||
$newRecords[] = new \App\Entity\AuditLog(
|
||||
AuditLogOperations::Delete,
|
||||
get_class($owner),
|
||||
$ownerIdentifier,
|
||||
(string)get_class($entity),
|
||||
|
@ -282,7 +283,7 @@ final class AuditLog implements EventSubscriber
|
|||
return $entity->getName();
|
||||
}
|
||||
|
||||
if ($entity instanceof Entity\Interfaces\IdentifiableEntityInterface) {
|
||||
if ($entity instanceof IdentifiableEntityInterface) {
|
||||
$entityId = $entity->getId();
|
||||
if (null !== $entityId) {
|
||||
return (string)$entityId;
|
||||
|
|
|
@ -4,12 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Doctrine\Event;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Attributes\AuditIgnore;
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
use ReflectionObject;
|
||||
use App\Entity\Enums\AuditLogOperations;
|
||||
use App\Entity\StationMount;
|
||||
use App\Entity\StationHlsStream;
|
||||
use App\Entity\StationRemote;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\Station;
|
||||
|
||||
/**
|
||||
* A hook into Doctrine's event listener to mark a station as
|
||||
|
@ -34,15 +39,15 @@ final class StationRequiresRestart implements EventSubscriber
|
|||
|
||||
$collections_to_check = [
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Insert,
|
||||
AuditLogOperations::Insert,
|
||||
$uow->getScheduledEntityInsertions(),
|
||||
],
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Update,
|
||||
AuditLogOperations::Update,
|
||||
$uow->getScheduledEntityUpdates(),
|
||||
],
|
||||
[
|
||||
Entity\Enums\AuditLogOperations::Delete,
|
||||
AuditLogOperations::Delete,
|
||||
$uow->getScheduledEntityDeletions(),
|
||||
],
|
||||
];
|
||||
|
@ -52,12 +57,12 @@ final class StationRequiresRestart implements EventSubscriber
|
|||
foreach ($collections_to_check as [$change_type, $collection]) {
|
||||
foreach ($collection as $entity) {
|
||||
if (
|
||||
($entity instanceof Entity\StationMount)
|
||||
|| ($entity instanceof Entity\StationHlsStream)
|
||||
|| ($entity instanceof Entity\StationRemote && $entity->isEditable())
|
||||
|| ($entity instanceof Entity\StationPlaylist && $entity->getStation()->useManualAutoDJ())
|
||||
($entity instanceof StationMount)
|
||||
|| ($entity instanceof StationHlsStream)
|
||||
|| ($entity instanceof StationRemote && $entity->isEditable())
|
||||
|| ($entity instanceof StationPlaylist && $entity->getStation()->useManualAutoDJ())
|
||||
) {
|
||||
if (Entity\Enums\AuditLogOperations::Update === $change_type) {
|
||||
if (AuditLogOperations::Update === $change_type) {
|
||||
$changes = $uow->getEntityChangeSet($entity);
|
||||
|
||||
// Look for the @AuditIgnore annotation on a property.
|
||||
|
@ -87,7 +92,7 @@ final class StationRequiresRestart implements EventSubscriber
|
|||
$station->setNeedsRestart(true);
|
||||
$em->persist($station);
|
||||
|
||||
$station_meta = $em->getClassMetadata(Entity\Station::class);
|
||||
$station_meta = $em->getClassMetadata(Station::class);
|
||||
$uow->recomputeSingleEntityChangeSet($station_meta, $station);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\Api\ResolvableUrlInterface;
|
||||
|
||||
#[OA\Schema(
|
||||
schema: 'Api_Admin_Relay',
|
||||
type: 'object'
|
||||
)]
|
||||
final class Relay implements Entity\Api\ResolvableUrlInterface
|
||||
final class Relay implements ResolvableUrlInterface
|
||||
{
|
||||
#[OA\Property(
|
||||
description: 'Station ID',
|
||||
|
@ -74,7 +74,7 @@ final class Relay implements Entity\Api\ResolvableUrlInterface
|
|||
)]
|
||||
public string $admin_pw;
|
||||
|
||||
/** @var Entity\Api\NowPlaying\StationMount[] */
|
||||
/** @var \App\Entity\Api\NowPlaying\StationMount[] */
|
||||
#[OA\Property]
|
||||
public array $mounts = [];
|
||||
|
||||
|
@ -86,7 +86,7 @@ final class Relay implements Entity\Api\ResolvableUrlInterface
|
|||
public function resolveUrls(UriInterface $base): void
|
||||
{
|
||||
foreach ($this->mounts as $mount) {
|
||||
if ($mount instanceof Entity\Api\ResolvableUrlInterface) {
|
||||
if ($mount instanceof ResolvableUrlInterface) {
|
||||
$mount->resolveUrls($base);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
use App\Traits\LoadFromParentObject;
|
||||
use OpenApi\Attributes as OA;
|
||||
use App\Entity\Api\Traits\HasLinks;
|
||||
|
||||
#[OA\Schema(
|
||||
schema: 'Api_Admin_StorageLocation',
|
||||
|
@ -14,7 +14,7 @@ use OpenApi\Attributes as OA;
|
|||
)]
|
||||
final class StorageLocation
|
||||
{
|
||||
use Entity\Api\Traits\HasLinks;
|
||||
use HasLinks;
|
||||
use LoadFromParentObject;
|
||||
|
||||
#[OA\Property(example: 1)]
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Api\NowPlaying;
|
||||
|
||||
use App\Entity;
|
||||
use App\Traits\LoadFromParentObject;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
|
@ -33,7 +32,7 @@ final class CurrentSong extends SongHistory
|
|||
*/
|
||||
public function recalculate(): void
|
||||
{
|
||||
$this->elapsed = time() + Entity\SongHistory::PLAYBACK_DELAY_SECONDS - $this->played_at;
|
||||
$this->elapsed = time() + \App\Entity\SongHistory::PLAYBACK_DELAY_SECONDS - $this->played_at;
|
||||
if ($this->elapsed < 0) {
|
||||
$this->elapsed = 0;
|
||||
}
|
||||
|
|
|
@ -4,18 +4,20 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\ApiGenerator;
|
||||
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Entity\StationSchedule;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\StationStreamer;
|
||||
|
||||
final class ScheduleApiGenerator
|
||||
{
|
||||
public function __invoke(
|
||||
Entity\StationSchedule $scheduleItem,
|
||||
StationSchedule $scheduleItem,
|
||||
?CarbonInterface $start,
|
||||
?CarbonInterface $end,
|
||||
?CarbonInterface $now
|
||||
): Entity\Api\StationSchedule {
|
||||
): \App\Entity\Api\StationSchedule {
|
||||
$playlist = $scheduleItem->getPlaylist();
|
||||
$streamer = $scheduleItem->getStreamer();
|
||||
|
||||
|
@ -32,8 +34,8 @@ final class ScheduleApiGenerator
|
|||
}
|
||||
|
||||
if (null === $start || null === $end) {
|
||||
$start = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $now);
|
||||
$end = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $now);
|
||||
$start = StationSchedule::getDateTime($scheduleItem->getStartTime(), $now);
|
||||
$end = StationSchedule::getDateTime($scheduleItem->getEndTime(), $now);
|
||||
|
||||
// Handle overnight schedule items
|
||||
if ($end < $start) {
|
||||
|
@ -41,7 +43,7 @@ final class ScheduleApiGenerator
|
|||
}
|
||||
}
|
||||
|
||||
$row = new Entity\Api\StationSchedule();
|
||||
$row = new \App\Entity\Api\StationSchedule();
|
||||
$row->id = $scheduleItem->getIdRequired();
|
||||
$row->start_timestamp = $start->getTimestamp();
|
||||
$row->start = $start->toIso8601String();
|
||||
|
@ -49,13 +51,13 @@ final class ScheduleApiGenerator
|
|||
$row->end = $end->toIso8601String();
|
||||
$row->is_now = ($start <= $now && $end >= $now);
|
||||
|
||||
if ($playlist instanceof Entity\StationPlaylist) {
|
||||
$row->type = Entity\Api\StationSchedule::TYPE_PLAYLIST;
|
||||
if ($playlist instanceof StationPlaylist) {
|
||||
$row->type = \App\Entity\Api\StationSchedule::TYPE_PLAYLIST;
|
||||
$row->name = $playlist->getName();
|
||||
$row->title = $row->name;
|
||||
$row->description = sprintf(__('Playlist: %s'), $row->name);
|
||||
} elseif ($streamer instanceof Entity\StationStreamer) {
|
||||
$row->type = Entity\Api\StationSchedule::TYPE_STREAMER;
|
||||
} elseif ($streamer instanceof StationStreamer) {
|
||||
$row->type = \App\Entity\Api\StationSchedule::TYPE_STREAMER;
|
||||
$row->name = $streamer->getDisplayName();
|
||||
$row->title = $row->name;
|
||||
$row->description = sprintf(__('Streamer: %s'), $row->name);
|
||||
|
|
|
@ -5,12 +5,17 @@ declare(strict_types=1);
|
|||
namespace App\Entity\ApiGenerator;
|
||||
|
||||
use App\Container\EntityManagerAwareTrait;
|
||||
use App\Entity;
|
||||
use App\Http\Router;
|
||||
use App\Media\RemoteAlbumArt;
|
||||
use GuzzleHttp\Psr7\UriResolver;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\Repository\StationRepository;
|
||||
use App\Entity\Repository\CustomFieldRepository;
|
||||
use App\Entity\Interfaces\SongInterface;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Api\Song;
|
||||
use App\Entity\StationMedia;
|
||||
|
||||
final class SongApiGenerator
|
||||
{
|
||||
|
@ -18,26 +23,26 @@ final class SongApiGenerator
|
|||
|
||||
public function __construct(
|
||||
private readonly Router $router,
|
||||
private readonly Entity\Repository\StationRepository $stationRepo,
|
||||
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo,
|
||||
private readonly StationRepository $stationRepo,
|
||||
private readonly CustomFieldRepository $customFieldRepo,
|
||||
private readonly RemoteAlbumArt $remoteAlbumArt
|
||||
) {
|
||||
}
|
||||
|
||||
public function __invoke(
|
||||
Entity\Interfaces\SongInterface $song,
|
||||
?Entity\Station $station = null,
|
||||
SongInterface $song,
|
||||
?Station $station = null,
|
||||
?UriInterface $baseUri = null,
|
||||
bool $allowRemoteArt = false,
|
||||
bool $isNowPlaying = false,
|
||||
): Entity\Api\Song {
|
||||
$response = new Entity\Api\Song();
|
||||
): Song {
|
||||
$response = new Song();
|
||||
$response->id = $song->getSongId();
|
||||
$response->text = $song->getText() ?? '';
|
||||
$response->artist = $song->getArtist() ?? '';
|
||||
$response->title = $song->getTitle() ?? '';
|
||||
|
||||
if ($song instanceof Entity\StationMedia) {
|
||||
if ($song instanceof StationMedia) {
|
||||
$response->album = $song->getAlbum() ?? '';
|
||||
$response->genre = $song->getGenre() ?? '';
|
||||
$response->isrc = $song->getIsrc() ?? '';
|
||||
|
@ -57,12 +62,12 @@ final class SongApiGenerator
|
|||
}
|
||||
|
||||
private function getAlbumArtUrl(
|
||||
Entity\Interfaces\SongInterface $song,
|
||||
?Entity\Station $station = null,
|
||||
SongInterface $song,
|
||||
?Station $station = null,
|
||||
bool $allowRemoteArt = false,
|
||||
bool $isNowPlaying = false,
|
||||
): UriInterface {
|
||||
if (null !== $station && $song instanceof Entity\StationMedia) {
|
||||
if (null !== $station && $song instanceof StationMedia) {
|
||||
$mediaUpdatedTimestamp = $song->getArtUpdatedAt();
|
||||
$mediaId = $song->getUniqueId();
|
||||
if (0 !== $mediaUpdatedTimestamp) {
|
||||
|
@ -117,7 +122,7 @@ final class SongApiGenerator
|
|||
$mediaFieldsRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT smcf.field_id, smcf.value
|
||||
FROM App\Entity\StationMediaCustomField smcf
|
||||
FROM App\\App\Entity\StationMediaCustomField smcf
|
||||
WHERE smcf.media_id = :media_id
|
||||
DQL
|
||||
)->setParameter('media_id', $media_id)
|
||||
|
|
|
@ -4,9 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\ApiGenerator;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Api\NowPlaying\SongHistory;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\StationStreamer;
|
||||
use App\Entity\Api\DetailedSongHistory;
|
||||
|
||||
final class SongHistoryApiGenerator
|
||||
{
|
||||
|
@ -16,7 +18,7 @@ final class SongHistoryApiGenerator
|
|||
}
|
||||
|
||||
public function __invoke(
|
||||
Entity\SongHistory $record,
|
||||
\App\Entity\SongHistory $record,
|
||||
?UriInterface $baseUri = null,
|
||||
bool $allowRemoteArt = false,
|
||||
bool $isNowPlaying = false,
|
||||
|
@ -25,16 +27,16 @@ final class SongHistoryApiGenerator
|
|||
$response->sh_id = $record->getIdRequired();
|
||||
$response->played_at = (0 === $record->getTimestampStart())
|
||||
? 0
|
||||
: $record->getTimestampStart() + Entity\SongHistory::PLAYBACK_DELAY_SECONDS;
|
||||
: $record->getTimestampStart() + \App\Entity\SongHistory::PLAYBACK_DELAY_SECONDS;
|
||||
$response->duration = (int)$record->getDuration();
|
||||
$response->is_request = ($record->getRequest() !== null);
|
||||
if ($record->getPlaylist() instanceof Entity\StationPlaylist) {
|
||||
if ($record->getPlaylist() instanceof StationPlaylist) {
|
||||
$response->playlist = $record->getPlaylist()->getName();
|
||||
} else {
|
||||
$response->playlist = '';
|
||||
}
|
||||
|
||||
if ($record->getStreamer() instanceof Entity\StationStreamer) {
|
||||
if ($record->getStreamer() instanceof StationStreamer) {
|
||||
$response->streamer = $record->getStreamer()->getDisplayName();
|
||||
} else {
|
||||
$response->streamer = '';
|
||||
|
@ -62,7 +64,7 @@ final class SongHistoryApiGenerator
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\SongHistory[] $records
|
||||
* @param \App\Entity\SongHistory[] $records
|
||||
* @param UriInterface|null $baseUri
|
||||
* @param bool $allowRemoteArt
|
||||
*
|
||||
|
@ -80,10 +82,12 @@ final class SongHistoryApiGenerator
|
|||
return $apiRecords;
|
||||
}
|
||||
|
||||
public function detailed(Entity\SongHistory $record, ?UriInterface $baseUri = null): Entity\Api\DetailedSongHistory
|
||||
{
|
||||
public function detailed(
|
||||
\App\Entity\SongHistory $record,
|
||||
?UriInterface $baseUri = null
|
||||
): DetailedSongHistory {
|
||||
$apiHistory = ($this)($record, $baseUri);
|
||||
$response = new Entity\Api\DetailedSongHistory();
|
||||
$response = new DetailedSongHistory();
|
||||
$response->fromParentObject($apiHistory);
|
||||
$response->listeners_start = (int)$record->getListenersStart();
|
||||
$response->listeners_end = (int)$record->getListenersEnd();
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\ApiGenerator;
|
||||
|
||||
use App\Entity;
|
||||
use App\Http\Router;
|
||||
use App\Radio\Adapters;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\Station;
|
||||
|
||||
final class StationApiGenerator
|
||||
{
|
||||
|
@ -18,14 +18,14 @@ final class StationApiGenerator
|
|||
}
|
||||
|
||||
public function __invoke(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?UriInterface $baseUri = null,
|
||||
bool $showAllMounts = false
|
||||
): Entity\Api\NowPlaying\Station {
|
||||
): \App\Entity\Api\NowPlaying\Station {
|
||||
$frontend = $this->adapters->getFrontendAdapter($station);
|
||||
$backend = $this->adapters->getBackendAdapter($station);
|
||||
|
||||
$response = new Entity\Api\NowPlaying\Station();
|
||||
$response = new \App\Entity\Api\NowPlaying\Station();
|
||||
$response->id = (int)$station->getId();
|
||||
$response->name = (string)$station->getName();
|
||||
$response->shortcode = $station->getShortName();
|
||||
|
|
|
@ -4,8 +4,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\ApiGenerator;
|
||||
|
||||
use App\Entity;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\StationQueue;
|
||||
use App\Entity\StationPlaylist;
|
||||
|
||||
final class StationQueueApiGenerator
|
||||
{
|
||||
|
@ -15,17 +16,17 @@ final class StationQueueApiGenerator
|
|||
}
|
||||
|
||||
public function __invoke(
|
||||
Entity\StationQueue $record,
|
||||
StationQueue $record,
|
||||
?UriInterface $baseUri = null,
|
||||
bool $allowRemoteArt = false
|
||||
): Entity\Api\NowPlaying\StationQueue {
|
||||
$response = new Entity\Api\NowPlaying\StationQueue();
|
||||
): \App\Entity\Api\NowPlaying\StationQueue {
|
||||
$response = new \App\Entity\Api\NowPlaying\StationQueue();
|
||||
$response->cued_at = $record->getTimestampCued();
|
||||
$response->played_at = $record->getTimestampPlayed();
|
||||
$response->duration = (int)$record->getDuration();
|
||||
$response->is_request = $record->getRequest() !== null;
|
||||
|
||||
if ($record->getPlaylist() instanceof Entity\StationPlaylist) {
|
||||
if ($record->getPlaylist() instanceof StationPlaylist) {
|
||||
$response->playlist = $record->getPlaylist()->getName();
|
||||
} else {
|
||||
$response->playlist = '';
|
||||
|
|
|
@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use App\Entity\Enums\AnalyticsIntervals;
|
||||
|
||||
final class Analytics extends AbstractFixture implements DependentFixtureInterface
|
||||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$stations = $manager->getRepository(Entity\Station::class)->findAll();
|
||||
$stations = $manager->getRepository(\App\Entity\Station::class)->findAll();
|
||||
|
||||
$midnight_utc = CarbonImmutable::now('UTC')->setTime(0, 0);
|
||||
|
||||
|
@ -27,7 +27,7 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
|
|||
$day_unique = 0;
|
||||
|
||||
foreach ($stations as $station) {
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station_listeners = random_int(10, 50);
|
||||
$station_min = random_int(1, $station_listeners);
|
||||
$station_max = random_int($station_listeners, 150);
|
||||
|
@ -39,10 +39,10 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
|
|||
$day_listeners += $station_listeners;
|
||||
$day_unique += $station_unique;
|
||||
|
||||
$stationPoint = new Entity\Analytics(
|
||||
$stationPoint = new \App\Entity\Analytics(
|
||||
$day,
|
||||
$station,
|
||||
Entity\Enums\AnalyticsIntervals::Daily,
|
||||
AnalyticsIntervals::Daily,
|
||||
$station_min,
|
||||
$station_max,
|
||||
$station_listeners,
|
||||
|
@ -51,10 +51,10 @@ final class Analytics extends AbstractFixture implements DependentFixtureInterfa
|
|||
$manager->persist($stationPoint);
|
||||
}
|
||||
|
||||
$totalPoint = new Entity\Analytics(
|
||||
$totalPoint = new \App\Entity\Analytics(
|
||||
$day,
|
||||
null,
|
||||
Entity\Enums\AnalyticsIntervals::Daily,
|
||||
AnalyticsIntervals::Daily,
|
||||
$day_min,
|
||||
$day_max,
|
||||
$day_listeners,
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Security\SplitToken;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
|
@ -17,10 +16,10 @@ final class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
|||
$demo_api_key = getenv('INIT_DEMO_API_KEY');
|
||||
|
||||
if (!empty($demo_api_key) && $this->hasReference('demo_user')) {
|
||||
/** @var Entity\User $demo_user */
|
||||
/** @var \App\Entity\User $demo_user */
|
||||
$demo_user = $this->getReference('demo_user');
|
||||
|
||||
$api_key = new Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
|
||||
$api_key = new \App\Entity\ApiKey($demo_user, SplitToken::fromKeyString($demo_api_key));
|
||||
$api_key->setComment('Demo User');
|
||||
|
||||
$manager->persist($api_key);
|
||||
|
@ -29,10 +28,10 @@ final class ApiKey extends AbstractFixture implements DependentFixtureInterface
|
|||
$admin_api_key = getenv('INIT_ADMIN_API_KEY');
|
||||
|
||||
if (!empty($admin_api_key) && $this->hasReference('admin_user')) {
|
||||
/** @var Entity\User $admin_user */
|
||||
/** @var \App\Entity\User $admin_user */
|
||||
$admin_user = $this->getReference('admin_user');
|
||||
|
||||
$api_key = new Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
|
||||
$api_key = new \App\Entity\ApiKey($admin_user, SplitToken::fromKeyString($admin_api_key));
|
||||
$api_key->setComment('Administrator');
|
||||
|
||||
$manager->persist($api_key);
|
||||
|
|
|
@ -4,21 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use App\Entity\PodcastCategory;
|
||||
|
||||
final class Podcast extends AbstractFixture implements DependentFixtureInterface
|
||||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$podcastStorage = $station->getPodcastsStorageLocation();
|
||||
|
||||
$podcast = new Entity\Podcast($podcastStorage);
|
||||
$podcast = new \App\Entity\Podcast($podcastStorage);
|
||||
|
||||
$podcast->setTitle('The AzuraTest Podcast');
|
||||
$podcast->setLink('https://demo.azuracast.com');
|
||||
|
@ -28,7 +28,7 @@ final class Podcast extends AbstractFixture implements DependentFixtureInterface
|
|||
$podcast->setEmail('demo@azuracast.com');
|
||||
$manager->persist($podcast);
|
||||
|
||||
$category = new Entity\PodcastCategory($podcast, 'Technology');
|
||||
$category = new PodcastCategory($podcast, 'Technology');
|
||||
$manager->persist($category);
|
||||
|
||||
$manager->flush();
|
||||
|
|
|
@ -4,17 +4,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use App\Entity\Repository\PodcastEpisodeRepository;
|
||||
use App\Entity\Repository\StorageLocationRepository;
|
||||
|
||||
final class PodcastEpisode extends AbstractFixture implements DependentFixtureInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected Entity\Repository\PodcastEpisodeRepository $episodeRepo,
|
||||
protected Entity\Repository\StorageLocationRepository $storageLocationRepo
|
||||
protected PodcastEpisodeRepository $episodeRepo,
|
||||
protected StorageLocationRepository $storageLocationRepo
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -26,7 +27,7 @@ final class PodcastEpisode extends AbstractFixture implements DependentFixtureIn
|
|||
return;
|
||||
}
|
||||
|
||||
/** @var Entity\Podcast $podcast */
|
||||
/** @var \App\Entity\Podcast $podcast */
|
||||
$podcast = $this->getReference('podcast');
|
||||
|
||||
$fs = $this->storageLocationRepo->getAdapter($podcast->getStorageLocation())
|
||||
|
@ -61,7 +62,7 @@ final class PodcastEpisode extends AbstractFixture implements DependentFixtureIn
|
|||
copy($filePath, $tempPath);
|
||||
|
||||
// Create an episode and associate it with the podcast/media.
|
||||
$episode = new Entity\PodcastEpisode($podcast);
|
||||
$episode = new \App\Entity\PodcastEpisode($podcast);
|
||||
|
||||
/** @noinspection NonSecureArrayRandUsageInspection */
|
||||
$podcastName = $podcastNames[array_rand($podcastNames)];
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
|
@ -12,10 +11,10 @@ final class Role extends AbstractFixture
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$admin_role = new Entity\Role();
|
||||
$admin_role = new \App\Entity\Role();
|
||||
$admin_role->setName('Super Administrator');
|
||||
|
||||
$demo_role = new Entity\Role();
|
||||
$demo_role = new \App\Entity\Role();
|
||||
$demo_role->setName('Demo Account');
|
||||
|
||||
$manager->persist($admin_role);
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Enums\GlobalPermissions;
|
||||
use App\Enums\StationPermissions;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
|
@ -15,7 +14,7 @@ final class RolePermission extends AbstractFixture implements DependentFixtureIn
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$permissions = [
|
||||
|
@ -35,11 +34,11 @@ final class RolePermission extends AbstractFixture implements DependentFixtureIn
|
|||
];
|
||||
|
||||
foreach ($permissions as $role_reference => $perm_names) {
|
||||
/** @var Entity\Role $role */
|
||||
/** @var \App\Entity\Role $role */
|
||||
$role = $this->getReference($role_reference);
|
||||
|
||||
foreach ($perm_names as $perm_name) {
|
||||
$rp = new Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
|
||||
$rp = new \App\Entity\RolePermission($role, $perm_name[1], $perm_name[0]);
|
||||
$manager->persist($rp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use App\Entity\Enums\AnalyticsLevel;
|
||||
|
||||
final class Settings extends AbstractFixture
|
||||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
foreach ($manager->getRepository(Entity\Settings::class)->findAll() as $row) {
|
||||
foreach ($manager->getRepository(\App\Entity\Settings::class)->findAll() as $row) {
|
||||
$manager->remove($row);
|
||||
}
|
||||
|
||||
$settings = new Entity\Settings();
|
||||
$settings = new \App\Entity\Settings();
|
||||
$settings->setBaseUrl((string)(getenv('INIT_BASE_URL') ?: 'http://docker.local'));
|
||||
$settings->setInstanceName((string)(getenv('INIT_INSTANCE_NAME') ?: 'local test'));
|
||||
$settings->setGeoliteLicenseKey((string)(getenv('INIT_GEOLITE_LICENSE_KEY') ?: ''));
|
||||
|
@ -29,7 +29,7 @@ final class Settings extends AbstractFixture
|
|||
$settings->setEnableAdvancedFeatures(true);
|
||||
|
||||
if (!empty(getenv('INIT_DEMO_API_KEY') ?: '')) {
|
||||
$settings->setAnalytics(Entity\Enums\AnalyticsLevel::NoIp);
|
||||
$settings->setAnalytics(AnalyticsLevel::NoIp);
|
||||
$settings->setCheckForUpdates(false);
|
||||
|
||||
$settings->setPublicCustomJs(
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Radio\Enums\BackendAdapters;
|
||||
use App\Radio\Enums\FrontendAdapters;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
|
@ -14,7 +13,7 @@ final class Station extends AbstractFixture
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$station = new Entity\Station();
|
||||
$station = new \App\Entity\Station();
|
||||
$station->setName('AzuraTest Radio');
|
||||
$station->setDescription('A test radio station.');
|
||||
$station->setEnableRequests(true);
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
|
@ -14,22 +13,22 @@ final class StationHlsStream extends AbstractFixture implements DependentFixture
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$mountLofi = new Entity\StationHlsStream($station);
|
||||
$mountLofi = new \App\Entity\StationHlsStream($station);
|
||||
$mountLofi->setName('aac_lofi');
|
||||
$mountLofi->setFormat(StreamFormats::Aac);
|
||||
$mountLofi->setBitrate(64);
|
||||
$manager->persist($mountLofi);
|
||||
|
||||
$mountMidfi = new Entity\StationHlsStream($station);
|
||||
$mountMidfi = new \App\Entity\StationHlsStream($station);
|
||||
$mountMidfi->setName('aac_midfi');
|
||||
$mountMidfi->setFormat(StreamFormats::Aac);
|
||||
$mountMidfi->setBitrate(128);
|
||||
$manager->persist($mountMidfi);
|
||||
|
||||
$mountHifi = new Entity\StationHlsStream($station);
|
||||
$mountHifi = new \App\Entity\StationHlsStream($station);
|
||||
$mountHifi->setName('aac_hifi');
|
||||
$mountHifi->setFormat(StreamFormats::Aac);
|
||||
$mountHifi->setBitrate(256);
|
||||
|
|
|
@ -4,18 +4,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Media\MediaProcessor;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use App\Entity\Repository\StorageLocationRepository;
|
||||
use App\Entity\StationPlaylistMedia;
|
||||
|
||||
final class StationMedia extends AbstractFixture implements DependentFixtureInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly MediaProcessor $mediaProcessor,
|
||||
private readonly Entity\Repository\StorageLocationRepository $storageLocationRepo,
|
||||
private readonly StorageLocationRepository $storageLocationRepo,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -27,13 +28,13 @@ final class StationMedia extends AbstractFixture implements DependentFixtureInte
|
|||
return;
|
||||
}
|
||||
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$mediaStorage = $station->getMediaStorageLocation();
|
||||
$fs = $this->storageLocationRepo->getAdapter($mediaStorage)->getFilesystem();
|
||||
|
||||
/** @var Entity\StationPlaylist $playlist */
|
||||
/** @var \App\Entity\StationPlaylist $playlist */
|
||||
$playlist = $this->getReference('station_playlist');
|
||||
|
||||
$finder = (new Finder())
|
||||
|
@ -56,7 +57,7 @@ final class StationMedia extends AbstractFixture implements DependentFixtureInte
|
|||
$manager->persist($mediaRow);
|
||||
|
||||
// Add the file to the playlist.
|
||||
$spmRow = new Entity\StationPlaylistMedia($playlist, $mediaRow);
|
||||
$spmRow = new StationPlaylistMedia($playlist, $mediaRow);
|
||||
$spmRow->setWeight(1);
|
||||
$manager->persist($spmRow);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
@ -13,15 +12,15 @@ final class StationMount extends AbstractFixture implements DependentFixtureInte
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$mount_radio = new Entity\StationMount($station);
|
||||
$mount_radio = new \App\Entity\StationMount($station);
|
||||
$mount_radio->setName('/radio.mp3');
|
||||
$mount_radio->setIsDefault(true);
|
||||
$manager->persist($mount_radio);
|
||||
|
||||
$mount_mobile = new Entity\StationMount($station);
|
||||
$mount_mobile = new \App\Entity\StationMount($station);
|
||||
$mount_mobile->setName('/mobile.mp3');
|
||||
$mount_mobile->setAutodjBitrate(64);
|
||||
$manager->persist($mount_mobile);
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
@ -13,10 +12,10 @@ final class StationPlaylist extends AbstractFixture implements DependentFixtureI
|
|||
{
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
/** @var Entity\Station $station */
|
||||
/** @var \App\Entity\Station $station */
|
||||
$station = $this->getReference('station');
|
||||
|
||||
$playlist = new Entity\StationPlaylist($station);
|
||||
$playlist = new \App\Entity\StationPlaylist($station);
|
||||
$playlist->setName('default');
|
||||
$manager->persist($playlist);
|
||||
$manager->flush();
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Fixture;
|
||||
|
||||
use App\Entity;
|
||||
use App\Enums\SupportedThemes;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||
|
@ -18,12 +17,12 @@ final class User extends AbstractFixture implements DependentFixtureInterface
|
|||
$admin_password = getenv('INIT_ADMIN_PASSWORD');
|
||||
|
||||
if (!empty($admin_email) && !empty($admin_password)) {
|
||||
$demo_user = new Entity\User();
|
||||
$demo_user = new \App\Entity\User();
|
||||
$demo_user->setEmail('demo@azuracast.com');
|
||||
$demo_user->setNewPassword('demo');
|
||||
$demo_user->setName('AzuraCast Demo User');
|
||||
|
||||
/** @var Entity\Role $demoRole */
|
||||
/** @var \App\Entity\Role $demoRole */
|
||||
$demoRole = $this->getReference('demo_role');
|
||||
$demo_user->getRoles()->add($demoRole);
|
||||
|
||||
|
@ -31,13 +30,13 @@ final class User extends AbstractFixture implements DependentFixtureInterface
|
|||
|
||||
$this->addReference('demo_user', $demo_user);
|
||||
|
||||
$admin_user = new Entity\User();
|
||||
$admin_user = new \App\Entity\User();
|
||||
$admin_user->setEmail($admin_email);
|
||||
$admin_user->setName('System Administrator');
|
||||
$admin_user->setNewPassword($admin_password);
|
||||
$admin_user->setTheme(SupportedThemes::Browser);
|
||||
|
||||
/** @var Entity\Role $adminRole */
|
||||
/** @var \App\Entity\Role $adminRole */
|
||||
$adminRole = $this->getReference('admin_role');
|
||||
$admin_user->getRoles()->add($adminRole);
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Interfaces;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
|
||||
interface StationCloneAwareInterface extends StationAwareInterface
|
||||
{
|
||||
public function setStation(Entity\Station $station): void;
|
||||
public function setStation(Station $station): void;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Security\SplitToken;
|
||||
use App\Entity\User;
|
||||
|
||||
/**
|
||||
* @template TEntity of Entity\ApiKey|Entity\UserLoginToken
|
||||
* @template TEntity of \App\Entity\ApiKey|\App\Entity\UserLoginToken
|
||||
* @extends Repository<TEntity>
|
||||
*/
|
||||
abstract class AbstractSplitTokenRepository extends Repository
|
||||
|
@ -19,7 +19,7 @@ abstract class AbstractSplitTokenRepository extends Repository
|
|||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function authenticate(string $key): ?Entity\User
|
||||
public function authenticate(string $key): ?User
|
||||
{
|
||||
$userSuppliedToken = SplitToken::fromKeyString($key);
|
||||
|
||||
|
|
|
@ -5,13 +5,14 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Utilities\DateRange;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Enums\AnalyticsIntervals;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Analytics>
|
||||
* @extends Repository<\App\Entity\Analytics>
|
||||
*/
|
||||
final class AnalyticsRepository extends Repository
|
||||
{
|
||||
|
@ -19,13 +20,13 @@ final class AnalyticsRepository extends Repository
|
|||
* @return mixed[]
|
||||
*/
|
||||
public function findForStationInRange(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
DateRange $dateRange,
|
||||
Entity\Enums\AnalyticsIntervals $type = Entity\Enums\AnalyticsIntervals::Daily
|
||||
AnalyticsIntervals $type = AnalyticsIntervals::Daily
|
||||
): array {
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT a FROM App\Entity\Analytics a
|
||||
SELECT a FROM App\\App\Entity\Analytics a
|
||||
WHERE a.station = :station AND a.type = :type AND a.moment BETWEEN :start AND :end
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
|
@ -39,7 +40,7 @@ final class AnalyticsRepository extends Repository
|
|||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Analytics a
|
||||
DELETE FROM App\\App\Entity\Analytics a
|
||||
DQL
|
||||
)->execute();
|
||||
}
|
||||
|
@ -51,23 +52,23 @@ final class AnalyticsRepository extends Repository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Analytics a
|
||||
DELETE FROM App\\App\Entity\Analytics a
|
||||
WHERE a.type = :type AND a.moment <= :threshold
|
||||
DQL
|
||||
)->setParameter('type', Entity\Enums\AnalyticsIntervals::Hourly)
|
||||
)->setParameter('type', AnalyticsIntervals::Hourly)
|
||||
->setParameter('threshold', $hourlyRetention)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public function clearSingleMetric(
|
||||
Entity\Enums\AnalyticsIntervals $type,
|
||||
AnalyticsIntervals $type,
|
||||
CarbonInterface $moment,
|
||||
?Entity\Station $station = null
|
||||
?Station $station = null
|
||||
): void {
|
||||
if (null === $station) {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Analytics a
|
||||
DELETE FROM App\\App\Entity\Analytics a
|
||||
WHERE a.station IS NULL AND a.type = :type AND a.moment = :moment
|
||||
DQL
|
||||
)->setParameter('type', $type)
|
||||
|
@ -76,7 +77,7 @@ final class AnalyticsRepository extends Repository
|
|||
} else {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Analytics a
|
||||
DELETE FROM App\\App\Entity\Analytics a
|
||||
WHERE a.station = :station AND a.type = :type AND a.moment = :moment
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\ApiKey;
|
||||
|
||||
/**
|
||||
* @extends AbstractSplitTokenRepository<Entity\ApiKey>
|
||||
* @extends AbstractSplitTokenRepository<ApiKey>
|
||||
*/
|
||||
final class ApiKeyRepository extends AbstractSplitTokenRepository
|
||||
{
|
||||
|
|
|
@ -5,22 +5,25 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\CustomField;
|
||||
use App\Entity\StationMediaCustomField;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\CustomField>
|
||||
* @extends Repository<\App\Entity\CustomField>
|
||||
*/
|
||||
final class CustomFieldRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* @return Entity\CustomField[]
|
||||
* @return \App\Entity\CustomField[]
|
||||
*/
|
||||
public function getAutoAssignableFields(): array
|
||||
{
|
||||
$fields = [];
|
||||
|
||||
foreach ($this->repository->findAll() as $field) {
|
||||
/** @var Entity\CustomField $field */
|
||||
/** @var \App\Entity\CustomField $field */
|
||||
if (!$field->hasAutoAssign()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -43,13 +46,13 @@ final class CustomFieldRepository extends Repository
|
|||
$fieldsRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT cf.id, cf.name, cf.short_name
|
||||
FROM App\Entity\CustomField cf
|
||||
FROM App\\App\Entity\CustomField cf
|
||||
ORDER BY cf.name ASC
|
||||
DQL
|
||||
)->getArrayResult();
|
||||
|
||||
foreach ($fieldsRaw as $row) {
|
||||
$fields[$row['id']] = $row['short_name'] ?? Entity\Station::generateShortName($row['name']);
|
||||
$fields[$row['id']] = $row['short_name'] ?? Station::generateShortName($row['name']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,16 +62,16 @@ final class CustomFieldRepository extends Repository
|
|||
/**
|
||||
* Retrieve a key-value representation of all custom metadata for the specified media.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param \App\Entity\StationMedia $media
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getCustomFields(Entity\StationMedia $media): array
|
||||
public function getCustomFields(StationMedia $media): array
|
||||
{
|
||||
$metadata_raw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT cf.short_name, e.value
|
||||
FROM App\Entity\StationMediaCustomField e JOIN e.field cf
|
||||
FROM App\\App\Entity\StationMediaCustomField e JOIN e.field cf
|
||||
WHERE e.media_id = :media_id
|
||||
DQL
|
||||
)->setParameter('media_id', $media->getId())
|
||||
|
@ -85,25 +88,25 @@ final class CustomFieldRepository extends Repository
|
|||
/**
|
||||
* Set the custom metadata for a specified station based on a provided key-value array.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param array $custom_fields
|
||||
*/
|
||||
public function setCustomFields(Entity\StationMedia $media, array $custom_fields): void
|
||||
public function setCustomFields(StationMedia $media, array $custom_fields): void
|
||||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationMediaCustomField e WHERE e.media_id = :media_id
|
||||
DELETE FROM App\\App\Entity\StationMediaCustomField e WHERE e.media_id = :media_id
|
||||
DQL
|
||||
)->setParameter('media_id', $media->getId())
|
||||
->execute();
|
||||
|
||||
foreach ($custom_fields as $field_id => $field_value) {
|
||||
$field = is_numeric($field_id)
|
||||
? $this->em->find(Entity\CustomField::class, $field_id)
|
||||
: $this->em->getRepository(Entity\CustomField::class)->findOneBy(['short_name' => $field_id]);
|
||||
? $this->em->find(CustomField::class, $field_id)
|
||||
: $this->em->getRepository(CustomField::class)->findOneBy(['short_name' => $field_id]);
|
||||
|
||||
if ($field instanceof Entity\CustomField) {
|
||||
$record = new Entity\StationMediaCustomField($media, $field);
|
||||
if ($field instanceof CustomField) {
|
||||
$record = new StationMediaCustomField($media, $field);
|
||||
$record->setValue($field_value);
|
||||
$this->em->persist($record);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace App\Entity\Repository;
|
|||
use App\Container\LoggerAwareTrait;
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Service\DeviceDetector;
|
||||
use App\Service\IpGeolocation;
|
||||
use App\Utilities\File;
|
||||
|
@ -18,14 +17,17 @@ use League\Csv\Writer;
|
|||
use NowPlaying\Result\Client;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Throwable;
|
||||
use App\Entity\Traits\TruncateStrings;
|
||||
use App\Entity\Listener;
|
||||
use App\Entity\Station;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Listener>
|
||||
* @extends Repository<\App\Entity\Listener>
|
||||
*/
|
||||
final class ListenerRepository extends Repository
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use Entity\Traits\TruncateStrings;
|
||||
use TruncateStrings;
|
||||
|
||||
private string $tableName;
|
||||
|
||||
|
@ -38,19 +40,19 @@ final class ListenerRepository extends Repository
|
|||
) {
|
||||
parent::__construct($em);
|
||||
|
||||
$this->tableName = $this->em->getClassMetadata(Entity\Listener::class)->getTableName();
|
||||
$this->tableName = $this->em->getClassMetadata(Listener::class)->getTableName();
|
||||
$this->conn = $this->em->getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of unique listeners for a station during a specified time period.
|
||||
*
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param DateTimeInterface|int $start
|
||||
* @param DateTimeInterface|int $end
|
||||
*/
|
||||
public function getUniqueListeners(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
DateTimeInterface|int $start,
|
||||
DateTimeInterface|int $end
|
||||
): int {
|
||||
|
@ -64,7 +66,7 @@ final class ListenerRepository extends Repository
|
|||
return (int)$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(DISTINCT l.listener_hash)
|
||||
FROM App\Entity\Listener l
|
||||
FROM App\\App\Entity\Listener l
|
||||
WHERE l.station_id = :station_id
|
||||
AND l.timestamp_start <= :time_end
|
||||
AND l.timestamp_end >= :time_start
|
||||
|
@ -75,12 +77,12 @@ final class ListenerRepository extends Repository
|
|||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function iterateLiveListenersArray(Entity\Station $station): iterable
|
||||
public function iterateLiveListenersArray(Station $station): iterable
|
||||
{
|
||||
$query = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT l
|
||||
FROM App\Entity\Listener l
|
||||
FROM App\\App\Entity\Listener l
|
||||
WHERE l.station = :station
|
||||
AND l.timestamp_end = 0
|
||||
ORDER BY l.timestamp_start ASC
|
||||
|
@ -93,17 +95,17 @@ final class ListenerRepository extends Repository
|
|||
/**
|
||||
* Update listener data for a station.
|
||||
*
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param Client[] $clients
|
||||
*/
|
||||
public function update(Entity\Station $station, array $clients): void
|
||||
public function update(Station $station, array $clients): void
|
||||
{
|
||||
$this->em->wrapInTransaction(
|
||||
function () use ($station, $clients): void {
|
||||
$existingClientsRaw = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT l.id, l.listener_hash
|
||||
FROM App\Entity\Listener l
|
||||
FROM App\\App\Entity\Listener l
|
||||
WHERE l.station = :station
|
||||
AND l.timestamp_end = 0
|
||||
DQL
|
||||
|
@ -125,7 +127,7 @@ final class ListenerRepository extends Repository
|
|||
if (!empty($existingClients)) {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\Listener l
|
||||
UPDATE App\\App\Entity\Listener l
|
||||
SET l.timestamp_end = :time
|
||||
WHERE l.id IN (:ids)
|
||||
DQL
|
||||
|
@ -138,7 +140,7 @@ final class ListenerRepository extends Repository
|
|||
}
|
||||
|
||||
private function batchAddClients(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
array &$clients,
|
||||
array &$existingClients
|
||||
): void {
|
||||
|
@ -162,7 +164,7 @@ final class ListenerRepository extends Repository
|
|||
$csvColumns = null;
|
||||
|
||||
foreach ($clients as $client) {
|
||||
$identifier = Entity\Listener::calculateListenerHash($client);
|
||||
$identifier = Listener::calculateListenerHash($client);
|
||||
|
||||
// Check for an existing record for this client.
|
||||
if (isset($existingClients[$identifier])) {
|
||||
|
@ -215,7 +217,7 @@ final class ListenerRepository extends Repository
|
|||
$this->ipGeolocation->saveCache();
|
||||
}
|
||||
|
||||
private function batchAddRow(Entity\Station $station, Client $client): array
|
||||
private function batchAddRow(Station $station, Client $client): array
|
||||
{
|
||||
$record = [
|
||||
'station_id' => $station->getId(),
|
||||
|
@ -224,7 +226,7 @@ final class ListenerRepository extends Repository
|
|||
'listener_uid' => (int)$client->uid,
|
||||
'listener_user_agent' => $this->truncateString($client->userAgent ?? ''),
|
||||
'listener_ip' => $client->ip,
|
||||
'listener_hash' => Entity\Listener::calculateListenerHash($client),
|
||||
'listener_hash' => Listener::calculateListenerHash($client),
|
||||
'mount_id' => null,
|
||||
'remote_id' => null,
|
||||
'hls_stream_id' => null,
|
||||
|
@ -308,7 +310,7 @@ final class ListenerRepository extends Repository
|
|||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Listener l
|
||||
DELETE FROM App\\App\Entity\Listener l
|
||||
DQL
|
||||
)->execute();
|
||||
}
|
||||
|
@ -321,7 +323,7 @@ final class ListenerRepository extends Repository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\Listener sh
|
||||
DELETE FROM App\\App\Entity\Listener sh
|
||||
WHERE sh.timestamp_start != 0
|
||||
AND sh.timestamp_start <= :threshold
|
||||
DQL
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Exception\InvalidPodcastMediaFileException;
|
||||
use App\Exception\StorageLocationFullException;
|
||||
use App\Flysystem\ExtendedFilesystemInterface;
|
||||
|
@ -14,9 +13,14 @@ use App\Media\AlbumArt;
|
|||
use App\Media\MetadataManager;
|
||||
use League\Flysystem\UnableToDeleteFile;
|
||||
use League\Flysystem\UnableToRetrieveMetadata;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\PodcastEpisode;
|
||||
use App\Entity\StorageLocation;
|
||||
use App\Entity\Podcast;
|
||||
use App\Entity\PodcastMedia;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\PodcastEpisode>
|
||||
* @extends Repository<\App\Entity\PodcastEpisode>
|
||||
*/
|
||||
final class PodcastEpisodeRepository extends Repository
|
||||
{
|
||||
|
@ -28,7 +32,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
parent::__construct($entityManager);
|
||||
}
|
||||
|
||||
public function fetchEpisodeForStation(Entity\Station $station, string $episodeId): ?Entity\PodcastEpisode
|
||||
public function fetchEpisodeForStation(Station $station, string $episodeId): ?PodcastEpisode
|
||||
{
|
||||
return $this->fetchEpisodeForStorageLocation(
|
||||
$station->getPodcastsStorageLocation(),
|
||||
|
@ -37,13 +41,13 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
public function fetchEpisodeForStorageLocation(
|
||||
Entity\StorageLocation $storageLocation,
|
||||
StorageLocation $storageLocation,
|
||||
string $episodeId
|
||||
): ?Entity\PodcastEpisode {
|
||||
): ?PodcastEpisode {
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT pe
|
||||
FROM App\Entity\PodcastEpisode pe
|
||||
FROM App\\App\Entity\PodcastEpisode pe
|
||||
JOIN pe.podcast p
|
||||
WHERE pe.id = :id
|
||||
AND p.storage_location = :storageLocation
|
||||
|
@ -54,13 +58,13 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Entity\PodcastEpisode[]
|
||||
* @return \App\Entity\PodcastEpisode[]
|
||||
*/
|
||||
public function fetchPublishedEpisodesForPodcast(Entity\Podcast $podcast): array
|
||||
public function fetchPublishedEpisodesForPodcast(Podcast $podcast): array
|
||||
{
|
||||
$episodes = $this->em->createQueryBuilder()
|
||||
->select('pe')
|
||||
->from(Entity\PodcastEpisode::class, 'pe')
|
||||
->from(PodcastEpisode::class, 'pe')
|
||||
->where('pe.podcast = :podcast')
|
||||
->setParameter('podcast', $podcast)
|
||||
->orderBy('pe.created_at', 'DESC')
|
||||
|
@ -69,14 +73,14 @@ final class PodcastEpisodeRepository extends Repository
|
|||
|
||||
return array_filter(
|
||||
$episodes,
|
||||
static function (Entity\PodcastEpisode $episode) {
|
||||
static function (PodcastEpisode $episode) {
|
||||
return $episode->isPublished();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function writeEpisodeArt(
|
||||
Entity\PodcastEpisode $episode,
|
||||
PodcastEpisode $episode,
|
||||
string $rawArtworkString
|
||||
): void {
|
||||
$episodeArtworkString = AlbumArt::resize($rawArtworkString);
|
||||
|
@ -90,7 +94,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
throw new StorageLocationFullException();
|
||||
}
|
||||
|
||||
$episodeArtworkPath = Entity\PodcastEpisode::getArtPath($episode->getIdRequired());
|
||||
$episodeArtworkPath = PodcastEpisode::getArtPath($episode->getIdRequired());
|
||||
$fs->write($episodeArtworkPath, $episodeArtworkString);
|
||||
|
||||
$storageLocation->addStorageUsed($episodeArtworkSize);
|
||||
|
@ -101,10 +105,10 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
public function removeEpisodeArt(
|
||||
Entity\PodcastEpisode $episode,
|
||||
PodcastEpisode $episode,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$artworkPath = Entity\PodcastEpisode::getArtPath($episode->getIdRequired());
|
||||
$artworkPath = PodcastEpisode::getArtPath($episode->getIdRequired());
|
||||
|
||||
$storageLocation = $episode->getPodcast()->getStorageLocation();
|
||||
$fs ??= $this->storageLocationRepo->getAdapter($storageLocation)
|
||||
|
@ -129,7 +133,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
public function uploadMedia(
|
||||
Entity\PodcastEpisode $episode,
|
||||
PodcastEpisode $episode,
|
||||
string $originalPath,
|
||||
string $uploadPath,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
|
@ -155,7 +159,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
$existingMedia = $episode->getMedia();
|
||||
if ($existingMedia instanceof Entity\PodcastMedia) {
|
||||
if ($existingMedia instanceof PodcastMedia) {
|
||||
$this->deleteMedia($existingMedia, $fs);
|
||||
$episode->setMedia(null);
|
||||
}
|
||||
|
@ -163,7 +167,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
$ext = pathinfo($originalPath, PATHINFO_EXTENSION);
|
||||
$path = $podcast->getId() . '/' . $episode->getId() . '.' . $ext;
|
||||
|
||||
$podcastMedia = new Entity\PodcastMedia($storageLocation);
|
||||
$podcastMedia = new PodcastMedia($storageLocation);
|
||||
$podcastMedia->setPath($path);
|
||||
$podcastMedia->setOriginalName(basename($originalPath));
|
||||
|
||||
|
@ -195,7 +199,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
public function deleteMedia(
|
||||
Entity\PodcastMedia $media,
|
||||
PodcastMedia $media,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$storageLocation = $media->getStorageLocation();
|
||||
|
@ -223,7 +227,7 @@ final class PodcastEpisodeRepository extends Repository
|
|||
}
|
||||
|
||||
public function delete(
|
||||
Entity\PodcastEpisode $episode,
|
||||
PodcastEpisode $episode,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->storageLocationRepo->getAdapter($episode->getPodcast()->getStorageLocation())
|
||||
|
|
|
@ -6,15 +6,17 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Exception\StorageLocationFullException;
|
||||
use App\Flysystem\ExtendedFilesystemInterface;
|
||||
use App\Media\AlbumArt;
|
||||
use League\Flysystem\UnableToDeleteFile;
|
||||
use League\Flysystem\UnableToRetrieveMetadata;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Podcast;
|
||||
use App\Entity\StorageLocation;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Podcast>
|
||||
* @extends Repository<\App\Entity\Podcast>
|
||||
*/
|
||||
final class PodcastRepository extends Repository
|
||||
{
|
||||
|
@ -26,15 +28,15 @@ final class PodcastRepository extends Repository
|
|||
parent::__construct($entityManager);
|
||||
}
|
||||
|
||||
public function fetchPodcastForStation(Entity\Station $station, string $podcastId): ?Entity\Podcast
|
||||
public function fetchPodcastForStation(Station $station, string $podcastId): ?Podcast
|
||||
{
|
||||
return $this->fetchPodcastForStorageLocation($station->getPodcastsStorageLocation(), $podcastId);
|
||||
}
|
||||
|
||||
public function fetchPodcastForStorageLocation(
|
||||
Entity\StorageLocation $storageLocation,
|
||||
StorageLocation $storageLocation,
|
||||
string $podcastId
|
||||
): ?Entity\Podcast {
|
||||
): ?Podcast {
|
||||
return $this->repository->findOneBy(
|
||||
[
|
||||
'id' => $podcastId,
|
||||
|
@ -44,14 +46,14 @@ final class PodcastRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Entity\Podcast[]
|
||||
* @return \App\Entity\Podcast[]
|
||||
*/
|
||||
public function fetchPublishedPodcastsForStation(Entity\Station $station): array
|
||||
public function fetchPublishedPodcastsForStation(Station $station): array
|
||||
{
|
||||
$podcasts = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT p, pe
|
||||
FROM App\Entity\Podcast p
|
||||
FROM App\\App\Entity\Podcast p
|
||||
LEFT JOIN p.episodes pe
|
||||
WHERE p.storage_location = :storageLocation
|
||||
DQL
|
||||
|
@ -60,7 +62,7 @@ final class PodcastRepository extends Repository
|
|||
|
||||
return array_filter(
|
||||
$podcasts,
|
||||
static function (Entity\Podcast $podcast) {
|
||||
static function (Podcast $podcast) {
|
||||
foreach ($podcast->getEpisodes() as $episode) {
|
||||
if ($episode->isPublished()) {
|
||||
return true;
|
||||
|
@ -73,7 +75,7 @@ final class PodcastRepository extends Repository
|
|||
}
|
||||
|
||||
public function writePodcastArt(
|
||||
Entity\Podcast $podcast,
|
||||
Podcast $podcast,
|
||||
string $rawArtworkString,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
|
@ -87,7 +89,7 @@ final class PodcastRepository extends Repository
|
|||
throw new StorageLocationFullException();
|
||||
}
|
||||
|
||||
$podcastArtworkPath = Entity\Podcast::getArtPath($podcast->getIdRequired());
|
||||
$podcastArtworkPath = Podcast::getArtPath($podcast->getIdRequired());
|
||||
$fs->write($podcastArtworkPath, $podcastArtworkString);
|
||||
|
||||
$storageLocation->addStorageUsed($podcastArtworkSize);
|
||||
|
@ -98,13 +100,13 @@ final class PodcastRepository extends Repository
|
|||
}
|
||||
|
||||
public function removePodcastArt(
|
||||
Entity\Podcast $podcast,
|
||||
Podcast $podcast,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$storageLocation = $podcast->getStorageLocation();
|
||||
$fs ??= $this->storageLocationRepo->getAdapter($storageLocation)->getFilesystem();
|
||||
|
||||
$artworkPath = Entity\Podcast::getArtPath($podcast->getIdRequired());
|
||||
$artworkPath = Podcast::getArtPath($podcast->getIdRequired());
|
||||
|
||||
try {
|
||||
$size = $fs->fileSize($artworkPath);
|
||||
|
@ -125,7 +127,7 @@ final class PodcastRepository extends Repository
|
|||
}
|
||||
|
||||
public function delete(
|
||||
Entity\Podcast $podcast,
|
||||
Podcast $podcast,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->storageLocationRepo->getAdapter($podcast->getStorageLocation())
|
||||
|
|
|
@ -5,25 +5,26 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Enums\GlobalPermissions;
|
||||
use App\Entity\Role;
|
||||
use App\Entity\RolePermission;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\RolePermission>
|
||||
* @extends Repository<\App\Entity\RolePermission>
|
||||
*/
|
||||
final class RolePermissionRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* @param Entity\Role $role
|
||||
* @param \App\Entity\Role $role
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getActionsForRole(Entity\Role $role): array
|
||||
public function getActionsForRole(Role $role): array
|
||||
{
|
||||
$role_has_action = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT e
|
||||
FROM App\Entity\RolePermission e
|
||||
FROM App\\App\Entity\RolePermission e
|
||||
WHERE e.role_id = :role_id
|
||||
DQL
|
||||
)->setParameter('role_id', $role->getId())
|
||||
|
@ -41,27 +42,27 @@ final class RolePermissionRepository extends Repository
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function ensureSuperAdministratorRole(): Entity\Role
|
||||
public function ensureSuperAdministratorRole(): Role
|
||||
{
|
||||
$superAdminRole = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT r FROM
|
||||
App\Entity\Role r LEFT JOIN r.permissions rp
|
||||
App\\App\Entity\Role r LEFT JOIN r.permissions rp
|
||||
WHERE rp.station IS NULL AND rp.action_name = :action
|
||||
DQL
|
||||
)->setParameter('action', GlobalPermissions::All->value)
|
||||
->setMaxResults(1)
|
||||
->getOneOrNullResult();
|
||||
|
||||
if ($superAdminRole instanceof Entity\Role) {
|
||||
if ($superAdminRole instanceof Role) {
|
||||
return $superAdminRole;
|
||||
}
|
||||
|
||||
$newRole = new Entity\Role();
|
||||
$newRole = new Role();
|
||||
$newRole->setName('Super Administrator');
|
||||
$this->em->persist($newRole);
|
||||
|
||||
$newPerm = new Entity\RolePermission($newRole, null, GlobalPermissions::All);
|
||||
$newPerm = new RolePermission($newRole, null, GlobalPermissions::All);
|
||||
$this->em->persist($newPerm);
|
||||
|
||||
$this->em->flush();
|
||||
|
|
|
@ -5,10 +5,10 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Entity\Role;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Role>
|
||||
* @extends Repository<Role>
|
||||
*/
|
||||
final class RoleRepository extends Repository
|
||||
{
|
||||
|
|
|
@ -6,18 +6,18 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Exception\ValidationException;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use App\Entity\Settings;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Settings>
|
||||
* @extends Repository<\App\Entity\Settings>
|
||||
*/
|
||||
final class SettingsRepository extends Repository
|
||||
{
|
||||
protected string $entityClass = Entity\Settings::class;
|
||||
protected string $entityClass = Settings::class;
|
||||
|
||||
public function __construct(
|
||||
ReloadableEntityManagerInterface $em,
|
||||
|
@ -27,21 +27,21 @@ final class SettingsRepository extends Repository
|
|||
parent::__construct($em);
|
||||
}
|
||||
|
||||
public function readSettings(): Entity\Settings
|
||||
public function readSettings(): Settings
|
||||
{
|
||||
static $settingsId = null;
|
||||
|
||||
if (null !== $settingsId) {
|
||||
$settings = $this->repository->find($settingsId);
|
||||
if ($settings instanceof Entity\Settings) {
|
||||
if ($settings instanceof Settings) {
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
$settings = $this->repository->findOneBy([]);
|
||||
|
||||
if (!($settings instanceof Entity\Settings)) {
|
||||
$settings = new Entity\Settings();
|
||||
if (!($settings instanceof Settings)) {
|
||||
$settings = new Settings();
|
||||
$this->em->persist($settings);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ final class SettingsRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Settings|array $settingsObj
|
||||
* @param \App\Entity\Settings|array $settingsObj
|
||||
*/
|
||||
public function writeSettings(Entity\Settings|array $settingsObj): void
|
||||
public function writeSettings(Settings|array $settingsObj): void
|
||||
{
|
||||
if (is_array($settingsObj)) {
|
||||
$settings = $this->readSettings();
|
||||
|
@ -72,11 +72,11 @@ final class SettingsRepository extends Repository
|
|||
$this->em->flush();
|
||||
}
|
||||
|
||||
public function fromArray(Entity\Settings $entity, array $source): Entity\Settings
|
||||
public function fromArray(Settings $entity, array $source): Settings
|
||||
{
|
||||
return $this->serializer->denormalize(
|
||||
$source,
|
||||
Entity\Settings::class,
|
||||
Settings::class,
|
||||
null,
|
||||
[
|
||||
AbstractNormalizer::OBJECT_TO_POPULATE => $entity,
|
||||
|
@ -84,7 +84,7 @@ final class SettingsRepository extends Repository
|
|||
);
|
||||
}
|
||||
|
||||
public function toArray(Entity\Settings $entity): array
|
||||
public function toArray(Settings $entity): array
|
||||
{
|
||||
return (array)$this->serializer->normalize(
|
||||
$entity
|
||||
|
|
|
@ -5,12 +5,14 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use RuntimeException;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Interfaces\SongInterface;
|
||||
use App\Entity\SongHistory;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\SongHistory>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\SongHistory>
|
||||
*/
|
||||
final class SongHistoryRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
|
@ -23,12 +25,12 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @return Entity\SongHistory[]
|
||||
* @return \App\Entity\SongHistory[]
|
||||
*/
|
||||
public function getVisibleHistory(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?int $numEntries = null
|
||||
): array {
|
||||
$numEntries ??= $station->getApiHistoryItems();
|
||||
|
@ -38,7 +40,7 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sh FROM App\Entity\SongHistory sh
|
||||
SELECT sh FROM App\\App\Entity\SongHistory sh
|
||||
LEFT JOIN sh.media sm
|
||||
WHERE sh.station = :station
|
||||
AND sh.is_visible = 1
|
||||
|
@ -50,8 +52,8 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function updateSongFromNowPlaying(
|
||||
Entity\Station $station,
|
||||
Entity\Interfaces\SongInterface $song
|
||||
Station $station,
|
||||
SongInterface $song
|
||||
): void {
|
||||
if (!$this->isDifferentFromCurrentSong($station, $song)) {
|
||||
return;
|
||||
|
@ -61,18 +63,18 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
$upcomingTrack = $this->stationQueueRepository->findRecentlyCuedSong($station, $song);
|
||||
if (null !== $upcomingTrack) {
|
||||
$this->stationQueueRepository->trackPlayed($station, $upcomingTrack);
|
||||
$newSong = Entity\SongHistory::fromQueue($upcomingTrack);
|
||||
$newSong = SongHistory::fromQueue($upcomingTrack);
|
||||
} else {
|
||||
$newSong = new Entity\SongHistory($station, $song);
|
||||
$newSong = new SongHistory($station, $song);
|
||||
}
|
||||
|
||||
$this->changeCurrentSong($station, $newSong);
|
||||
}
|
||||
|
||||
public function updateListenersFromNowPlaying(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
int $listeners
|
||||
): Entity\SongHistory {
|
||||
): SongHistory {
|
||||
$currentSong = $station->getCurrentSong();
|
||||
if (null === $currentSong) {
|
||||
throw new RuntimeException('No track to update.');
|
||||
|
@ -86,17 +88,17 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function isDifferentFromCurrentSong(
|
||||
Entity\Station $station,
|
||||
Entity\Interfaces\SongInterface $toCompare
|
||||
Station $station,
|
||||
SongInterface $toCompare
|
||||
): bool {
|
||||
$currentSong = $station->getCurrentSong();
|
||||
return !(null !== $currentSong) || $currentSong->getSongId() !== $toCompare->getSongId();
|
||||
}
|
||||
|
||||
public function changeCurrentSong(
|
||||
Entity\Station $station,
|
||||
Entity\SongHistory $newCurrentSong
|
||||
): Entity\SongHistory {
|
||||
Station $station,
|
||||
SongHistory $newCurrentSong
|
||||
): SongHistory {
|
||||
$previousCurrentSong = $station->getCurrentSong();
|
||||
|
||||
if (null !== $previousCurrentSong) {
|
||||
|
@ -132,19 +134,19 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param int $start
|
||||
* @param int $end
|
||||
*
|
||||
* @return mixed[] [int $minimumListeners, int $maximumListeners, float $averageListeners]
|
||||
*/
|
||||
public function getStatsByTimeRange(Entity\Station $station, int $start, int $end): array
|
||||
public function getStatsByTimeRange(Station $station, int $start, int $end): array
|
||||
{
|
||||
$historyTotals = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT AVG(sh.listeners_end) AS listeners_avg, MAX(sh.listeners_end) AS listeners_max,
|
||||
MIN(sh.listeners_end) AS listeners_min
|
||||
FROM App\Entity\SongHistory sh
|
||||
FROM App\\App\Entity\SongHistory sh
|
||||
WHERE sh.station = :station
|
||||
AND sh.timestamp_end >= :start
|
||||
AND sh.timestamp_start <= :end
|
||||
|
@ -169,7 +171,7 @@ final class SongHistoryRepository extends AbstractStationBasedRepository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\SongHistory sh
|
||||
DELETE FROM App\\App\Entity\SongHistory sh
|
||||
WHERE sh.timestamp_start != 0
|
||||
AND sh.timestamp_start <= :threshold
|
||||
DQL
|
||||
|
|
|
@ -4,25 +4,25 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationHlsStream>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationHlsStream>
|
||||
*/
|
||||
final class StationHlsStreamRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getDisplayNames(Entity\Station $station): array
|
||||
public function getDisplayNames(Station $station): array
|
||||
{
|
||||
$streams = $this->repository->findBy(['station' => $station]);
|
||||
|
||||
$displayNames = [];
|
||||
|
||||
/** @var Entity\StationHlsStream $stream */
|
||||
/** @var \App\Entity\StationHlsStream $stream */
|
||||
foreach ($streams as $stream) {
|
||||
$displayNames[$stream->getIdRequired()] = 'HLS: ' . $stream->getName();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace App\Entity\Repository;
|
|||
use App\Container\LoggerAwareTrait;
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Exception\NotFoundException;
|
||||
use App\Flysystem\ExtendedFilesystemInterface;
|
||||
use App\Media\AlbumArt;
|
||||
|
@ -22,8 +21,14 @@ use const JSON_PRETTY_PRINT;
|
|||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\StorageLocation;
|
||||
use App\Entity\StationMediaCustomField;
|
||||
use App\Entity\Song;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\StationMedia>
|
||||
* @extends Repository<\App\Entity\StationMedia>
|
||||
*/
|
||||
final class StationMediaRepository extends Repository
|
||||
{
|
||||
|
@ -40,18 +45,18 @@ final class StationMediaRepository extends Repository
|
|||
parent::__construct($em);
|
||||
}
|
||||
|
||||
public function findForStation(int|string $id, Entity\Station $station): ?Entity\StationMedia
|
||||
public function findForStation(int|string $id, Station $station): ?StationMedia
|
||||
{
|
||||
if (!is_numeric($id) && Entity\StationMedia::UNIQUE_ID_LENGTH === strlen($id)) {
|
||||
if (!is_numeric($id) && StationMedia::UNIQUE_ID_LENGTH === strlen($id)) {
|
||||
$media = $this->findByUniqueId($id, $station);
|
||||
if ($media instanceof Entity\StationMedia) {
|
||||
if ($media instanceof StationMedia) {
|
||||
return $media;
|
||||
}
|
||||
}
|
||||
|
||||
$storageLocation = $this->getStorageLocation($station);
|
||||
|
||||
/** @var Entity\StationMedia|null $media */
|
||||
/** @var \App\Entity\StationMedia|null $media */
|
||||
$media = $this->repository->findOneBy(
|
||||
[
|
||||
'storage_location' => $storageLocation,
|
||||
|
@ -62,7 +67,7 @@ final class StationMediaRepository extends Repository
|
|||
return $media;
|
||||
}
|
||||
|
||||
public function requireForStation(int|string $id, Entity\Station $station): Entity\StationMedia
|
||||
public function requireForStation(int|string $id, Station $station): StationMedia
|
||||
{
|
||||
$record = $this->findForStation($id, $station);
|
||||
if (null === $record) {
|
||||
|
@ -73,14 +78,16 @@ final class StationMediaRepository extends Repository
|
|||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param Entity\Station|Entity\StorageLocation $source
|
||||
* @param \App\Entity\Station|\App\Entity\StorageLocation $source
|
||||
*
|
||||
*/
|
||||
public function findByPath(string $path, Entity\Station|Entity\StorageLocation $source): ?Entity\StationMedia
|
||||
{
|
||||
public function findByPath(
|
||||
string $path,
|
||||
Station|StorageLocation $source
|
||||
): ?StationMedia {
|
||||
$storageLocation = $this->getStorageLocation($source);
|
||||
|
||||
/** @var Entity\StationMedia|null $media */
|
||||
/** @var \App\Entity\StationMedia|null $media */
|
||||
$media = $this->repository->findOneBy(
|
||||
[
|
||||
'storage_location' => $storageLocation,
|
||||
|
@ -91,13 +98,13 @@ final class StationMediaRepository extends Repository
|
|||
return $media;
|
||||
}
|
||||
|
||||
public function iteratePaths(array $paths, Entity\Station|Entity\StorageLocation $source): Generator
|
||||
public function iteratePaths(array $paths, Station|StorageLocation $source): Generator
|
||||
{
|
||||
$storageLocation = $this->getStorageLocation($source);
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$media = $this->findByPath($path, $storageLocation);
|
||||
if ($media instanceof Entity\StationMedia) {
|
||||
if ($media instanceof StationMedia) {
|
||||
yield $path => $media;
|
||||
}
|
||||
}
|
||||
|
@ -105,16 +112,16 @@ final class StationMediaRepository extends Repository
|
|||
|
||||
/**
|
||||
* @param string $uniqueId
|
||||
* @param Entity\Station|Entity\StorageLocation $source
|
||||
* @param \App\Entity\Station|\App\Entity\StorageLocation $source
|
||||
*
|
||||
*/
|
||||
public function findByUniqueId(
|
||||
string $uniqueId,
|
||||
Entity\Station|Entity\StorageLocation $source
|
||||
): ?Entity\StationMedia {
|
||||
Station|StorageLocation $source
|
||||
): ?StationMedia {
|
||||
$storageLocation = $this->getStorageLocation($source);
|
||||
|
||||
/** @var Entity\StationMedia|null $media */
|
||||
/** @var \App\Entity\StationMedia|null $media */
|
||||
$media = $this->repository->findOneBy(
|
||||
[
|
||||
'storage_location' => $storageLocation,
|
||||
|
@ -127,8 +134,8 @@ final class StationMediaRepository extends Repository
|
|||
|
||||
public function requireByUniqueId(
|
||||
string $uniqueId,
|
||||
Entity\Station|Entity\StorageLocation $source
|
||||
): Entity\StationMedia {
|
||||
Station|StorageLocation $source
|
||||
): StationMedia {
|
||||
$record = $this->findByUniqueId($uniqueId, $source);
|
||||
if (null === $record) {
|
||||
throw new NotFoundException();
|
||||
|
@ -136,9 +143,9 @@ final class StationMediaRepository extends Repository
|
|||
return $record;
|
||||
}
|
||||
|
||||
private function getStorageLocation(Entity\Station|Entity\StorageLocation $source): Entity\StorageLocation
|
||||
private function getStorageLocation(Station|StorageLocation $source): StorageLocation
|
||||
{
|
||||
if ($source instanceof Entity\Station) {
|
||||
if ($source instanceof Station) {
|
||||
return $source->getMediaStorageLocation();
|
||||
}
|
||||
|
||||
|
@ -148,12 +155,12 @@ final class StationMediaRepository extends Repository
|
|||
/**
|
||||
* Process metadata information from media file.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param string $filePath
|
||||
* @param ExtendedFilesystemInterface|null $fs
|
||||
*/
|
||||
public function loadFromFile(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
string $filePath,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
|
@ -168,7 +175,7 @@ final class StationMediaRepository extends Repository
|
|||
// Clear existing auto-assigned custom fields.
|
||||
$fieldCollection = $media->getCustomFields();
|
||||
foreach ($fieldCollection as $existingCustomField) {
|
||||
/** @var Entity\StationMediaCustomField $existingCustomField */
|
||||
/** @var \App\Entity\StationMediaCustomField $existingCustomField */
|
||||
if ($existingCustomField->getField()->hasAutoAssign()) {
|
||||
$this->em->remove($existingCustomField);
|
||||
$fieldCollection->removeElement($existingCustomField);
|
||||
|
@ -179,7 +186,7 @@ final class StationMediaRepository extends Repository
|
|||
$tags = $metadata->getTags();
|
||||
foreach ($customFieldsToSet as $tag => $customFieldKey) {
|
||||
if (!empty($tags[$tag])) {
|
||||
$customFieldRow = new Entity\StationMediaCustomField($media, $customFieldKey);
|
||||
$customFieldRow = new StationMediaCustomField($media, $customFieldKey);
|
||||
$customFieldRow->setValue($tags[$tag]);
|
||||
$this->em->persist($customFieldRow);
|
||||
|
||||
|
@ -216,7 +223,7 @@ final class StationMediaRepository extends Repository
|
|||
$filename = pathinfo($media->getPath(), PATHINFO_FILENAME);
|
||||
$filename = str_replace('_', ' ', $filename);
|
||||
|
||||
$songObj = Entity\Song::createFromText($filename);
|
||||
$songObj = Song::createFromText($filename);
|
||||
$media->setSong($songObj);
|
||||
}
|
||||
|
||||
|
@ -228,7 +235,7 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
public function updateAlbumArt(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
string $rawArtString
|
||||
): bool {
|
||||
$fs = $this->getFilesystem($media);
|
||||
|
@ -238,7 +245,7 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
public function writeAlbumArt(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
string $rawArtString,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
|
@ -247,19 +254,19 @@ final class StationMediaRepository extends Repository
|
|||
$media->setArtUpdatedAt(time());
|
||||
$this->em->persist($media);
|
||||
|
||||
$albumArtPath = Entity\StationMedia::getArtPath($media->getUniqueId());
|
||||
$albumArtPath = StationMedia::getArtPath($media->getUniqueId());
|
||||
$albumArtString = AlbumArt::resize($rawArtString);
|
||||
|
||||
$fs->write($albumArtPath, $albumArtString);
|
||||
}
|
||||
|
||||
public function removeAlbumArt(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
$currentAlbumArtPath = Entity\StationMedia::getArtPath($media->getUniqueId());
|
||||
$currentAlbumArtPath = StationMedia::getArtPath($media->getUniqueId());
|
||||
$fs->delete($currentAlbumArtPath);
|
||||
|
||||
$media->setArtUpdatedAt(0);
|
||||
|
@ -270,14 +277,14 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
public function writeToFile(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): bool {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
$metadata = $media->toMetadata();
|
||||
|
||||
$art_path = Entity\StationMedia::getArtPath($media->getUniqueId());
|
||||
$art_path = StationMedia::getArtPath($media->getUniqueId());
|
||||
if ($fs->fileExists($art_path)) {
|
||||
$metadata->setArtwork($fs->read($art_path));
|
||||
}
|
||||
|
@ -296,7 +303,7 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
public function updateWaveform(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
@ -309,14 +316,14 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
public function writeWaveform(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
string $path,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= $this->getFilesystem($media);
|
||||
|
||||
$waveform = AudioWaveform::getWaveformFor($path);
|
||||
$waveformPath = Entity\StationMedia::getWaveformPath($media->getUniqueId());
|
||||
$waveformPath = StationMedia::getWaveformPath($media->getUniqueId());
|
||||
|
||||
$fs->write(
|
||||
$waveformPath,
|
||||
|
@ -328,14 +335,14 @@ final class StationMediaRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\StationMedia $media
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param bool $deleteFile Whether to remove the media file itself (disabled for batch operations).
|
||||
* @param ExtendedFilesystemInterface|null $fs
|
||||
*
|
||||
* @return Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
|
||||
* @return \App\Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
|
||||
*/
|
||||
public function remove(
|
||||
Entity\StationMedia $media,
|
||||
StationMedia $media,
|
||||
bool $deleteFile = false,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): array {
|
||||
|
@ -366,7 +373,7 @@ final class StationMediaRepository extends Repository
|
|||
return $affectedPlaylists;
|
||||
}
|
||||
|
||||
private function getFilesystem(Entity\StationMedia $media): ExtendedFilesystemInterface
|
||||
private function getFilesystem(StationMedia $media): ExtendedFilesystemInterface
|
||||
{
|
||||
return $this->storageLocationRepo->getAdapter($media->getStorageLocation())
|
||||
->getFilesystem();
|
||||
|
|
|
@ -4,20 +4,23 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Enums\PlaylistSources;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\StationPlaylistFolder;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationPlaylistFolder>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationPlaylistFolder>
|
||||
*/
|
||||
final class StationPlaylistFolderRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param Entity\StationPlaylist[] $playlists
|
||||
* @param \App\Entity\Station $station
|
||||
* @param \App\Entity\StationPlaylist[] $playlists
|
||||
* @param string $path
|
||||
*/
|
||||
public function setPlaylistsForFolder(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
array $playlists,
|
||||
string $path
|
||||
): void {
|
||||
|
@ -27,7 +30,7 @@ final class StationPlaylistFolderRepository extends AbstractStationBasedReposito
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationPlaylistFolder spf
|
||||
DELETE FROM App\\App\Entity\StationPlaylistFolder spf
|
||||
WHERE spf.station = :station AND spf.path = :path
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
|
@ -35,11 +38,11 @@ final class StationPlaylistFolderRepository extends AbstractStationBasedReposito
|
|||
->execute();
|
||||
|
||||
foreach ($playlists as $playlistId => $playlistRecord) {
|
||||
if (Entity\Enums\PlaylistSources::Songs === $playlistRecord->getSource()) {
|
||||
/** @var Entity\StationPlaylist $playlist */
|
||||
$playlist = $this->em->getReference(Entity\StationPlaylist::class, $playlistId);
|
||||
if (PlaylistSources::Songs === $playlistRecord->getSource()) {
|
||||
/** @var \App\Entity\StationPlaylist $playlist */
|
||||
$playlist = $this->em->getReference(StationPlaylist::class, $playlistId);
|
||||
|
||||
$newRecord = new Entity\StationPlaylistFolder($station, $playlist, $path);
|
||||
$newRecord = new StationPlaylistFolder($station, $playlist, $path);
|
||||
$this->em->persist($newRecord);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,22 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\Enums\PlaylistSources;
|
||||
use App\Entity\Enums\PlaylistOrders;
|
||||
use App\Entity\StationPlaylistMedia;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Api\StationPlaylistQueue;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\StationPlaylistMedia>
|
||||
* @extends Repository<\App\Entity\StationPlaylistMedia>
|
||||
*/
|
||||
final class StationPlaylistMediaRepository extends Repository
|
||||
{
|
||||
|
@ -30,23 +36,23 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
* Add the specified media to the specified playlist.
|
||||
* Must flush the EntityManager after using.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param Entity\StationPlaylist $playlist
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param \App\Entity\StationPlaylist $playlist
|
||||
* @param int $weight
|
||||
*
|
||||
* @return int The weight assigned to the newly added record.
|
||||
*/
|
||||
public function addMediaToPlaylist(
|
||||
Entity\StationMedia $media,
|
||||
Entity\StationPlaylist $playlist,
|
||||
StationMedia $media,
|
||||
StationPlaylist $playlist,
|
||||
int $weight = 0
|
||||
): int {
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
throw new RuntimeException('This playlist is not meant to contain songs!');
|
||||
}
|
||||
|
||||
// Only update existing record for random-order playlists.
|
||||
$isNonSequential = Entity\Enums\PlaylistOrders::Sequential !== $playlist->getOrder();
|
||||
$isNonSequential = PlaylistOrders::Sequential !== $playlist->getOrder();
|
||||
|
||||
$record = ($isNonSequential)
|
||||
? $this->repository->findOneBy(
|
||||
|
@ -56,7 +62,7 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
]
|
||||
) : null;
|
||||
|
||||
if ($record instanceof Entity\StationPlaylistMedia) {
|
||||
if ($record instanceof StationPlaylistMedia) {
|
||||
if (0 !== $weight) {
|
||||
$record->setWeight($weight);
|
||||
$this->em->persist($record);
|
||||
|
@ -69,7 +75,7 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
$weight = random_int(1, $weight);
|
||||
}
|
||||
|
||||
$record = new Entity\StationPlaylistMedia($playlist, $media);
|
||||
$record = new StationPlaylistMedia($playlist, $media);
|
||||
$record->setWeight($weight);
|
||||
$this->em->persist($record);
|
||||
}
|
||||
|
@ -77,13 +83,13 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
return $weight;
|
||||
}
|
||||
|
||||
public function getHighestSongWeight(Entity\StationPlaylist $playlist): int
|
||||
public function getHighestSongWeight(StationPlaylist $playlist): int
|
||||
{
|
||||
try {
|
||||
$highest_weight = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT MAX(e.weight)
|
||||
FROM App\Entity\StationPlaylistMedia e
|
||||
FROM App\\App\Entity\StationPlaylistMedia e
|
||||
WHERE e.playlist_id = :playlist_id
|
||||
DQL
|
||||
)->setParameter('playlist_id', $playlist->getId())
|
||||
|
@ -98,21 +104,21 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
/**
|
||||
* Remove all playlist associations from the specified media object.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param Entity\Station|null $station
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param \App\Entity\Station|null $station
|
||||
*
|
||||
* @return Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
|
||||
* @return \App\Entity\StationPlaylist[] The IDs as keys and records as values for all affected playlists.
|
||||
*/
|
||||
public function clearPlaylistsFromMedia(
|
||||
Entity\StationMedia $media,
|
||||
?Entity\Station $station = null
|
||||
StationMedia $media,
|
||||
?Station $station = null
|
||||
): array {
|
||||
$affectedPlaylists = [];
|
||||
|
||||
$playlists = $media->getPlaylists();
|
||||
if (null !== $station) {
|
||||
$playlists = $playlists->filter(
|
||||
function (Entity\StationPlaylistMedia $spm) use ($station) {
|
||||
function (StationPlaylistMedia $spm) use ($station) {
|
||||
return $spm->getPlaylist()->getStation()->getId() === $station->getId();
|
||||
}
|
||||
);
|
||||
|
@ -137,14 +143,14 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
* ...
|
||||
* ]
|
||||
*
|
||||
* @param Entity\StationPlaylist $playlist
|
||||
* @param \App\Entity\StationPlaylist $playlist
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function setMediaOrder(Entity\StationPlaylist $playlist, array $mapping): void
|
||||
public function setMediaOrder(StationPlaylist $playlist, array $mapping): void
|
||||
{
|
||||
$update_query = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationPlaylistMedia e
|
||||
UPDATE App\\App\Entity\StationPlaylistMedia e
|
||||
SET e.weight = :weight
|
||||
WHERE e.playlist_id = :playlist_id
|
||||
AND e.id = :id
|
||||
|
@ -162,28 +168,28 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
);
|
||||
}
|
||||
|
||||
public function resetQueue(Entity\StationPlaylist $playlist, CarbonInterface $now = null): void
|
||||
public function resetQueue(StationPlaylist $playlist, CarbonInterface $now = null): void
|
||||
{
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
throw new InvalidArgumentException('Playlist must contain songs.');
|
||||
}
|
||||
|
||||
if (Entity\Enums\PlaylistOrders::Sequential === $playlist->getOrder()) {
|
||||
if (PlaylistOrders::Sequential === $playlist->getOrder()) {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationPlaylistMedia spm
|
||||
UPDATE App\\App\Entity\StationPlaylistMedia spm
|
||||
SET spm.is_queued = 1
|
||||
WHERE spm.playlist = :playlist
|
||||
DQL
|
||||
)->setParameter('playlist', $playlist)
|
||||
->execute();
|
||||
} elseif (Entity\Enums\PlaylistOrders::Shuffle === $playlist->getOrder()) {
|
||||
} elseif (PlaylistOrders::Shuffle === $playlist->getOrder()) {
|
||||
$this->em->wrapInTransaction(
|
||||
function () use ($playlist): void {
|
||||
$allSpmRecordsQuery = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT spm.id
|
||||
FROM App\Entity\StationPlaylistMedia spm
|
||||
FROM App\\App\Entity\StationPlaylistMedia spm
|
||||
WHERE spm.playlist = :playlist
|
||||
ORDER BY RAND()
|
||||
DQL
|
||||
|
@ -191,7 +197,7 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
|
||||
$updateSpmWeightQuery = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationPlaylistMedia spm
|
||||
UPDATE App\\App\Entity\StationPlaylistMedia spm
|
||||
SET spm.weight=:weight, spm.is_queued=1
|
||||
WHERE spm.id = :id
|
||||
DQL
|
||||
|
@ -218,12 +224,12 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
$this->em->flush();
|
||||
}
|
||||
|
||||
public function resetAllQueues(Entity\Station $station): void
|
||||
public function resetAllQueues(Station $station): void
|
||||
{
|
||||
$now = CarbonImmutable::now($station->getTimezoneObject());
|
||||
|
||||
foreach ($station->getPlaylists() as $playlist) {
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -232,22 +238,22 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Entity\Api\StationPlaylistQueue[]
|
||||
* @return \App\Entity\Api\StationPlaylistQueue[]
|
||||
*/
|
||||
public function getQueue(Entity\StationPlaylist $playlist): array
|
||||
public function getQueue(StationPlaylist $playlist): array
|
||||
{
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
throw new InvalidArgumentException('Playlist must contain songs.');
|
||||
}
|
||||
|
||||
$queuedMediaQuery = $this->em->createQueryBuilder()
|
||||
->select(['spm.id AS spm_id', 'sm.id', 'sm.song_id', 'sm.artist', 'sm.title'])
|
||||
->from(Entity\StationMedia::class, 'sm')
|
||||
->from(StationMedia::class, 'sm')
|
||||
->join('sm.playlists', 'spm')
|
||||
->where('spm.playlist = :playlist')
|
||||
->setParameter('playlist', $playlist);
|
||||
|
||||
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
if (PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
$queuedMediaQuery = $queuedMediaQuery->orderBy('RAND()');
|
||||
} else {
|
||||
$queuedMediaQuery = $queuedMediaQuery->andWhere('spm.is_queued = 1')
|
||||
|
@ -257,8 +263,8 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
$queuedMedia = $queuedMediaQuery->getQuery()->getArrayResult();
|
||||
|
||||
return array_map(
|
||||
static function ($val): Entity\Api\StationPlaylistQueue {
|
||||
$record = new Entity\Api\StationPlaylistQueue();
|
||||
static function ($val): StationPlaylistQueue {
|
||||
$record = new StationPlaylistQueue();
|
||||
$record->spm_id = $val['spm_id'];
|
||||
$record->media_id = $val['id'];
|
||||
$record->song_id = $val['song_id'];
|
||||
|
@ -271,13 +277,13 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
);
|
||||
}
|
||||
|
||||
public function isQueueCompletelyFilled(Entity\StationPlaylist $playlist): bool
|
||||
public function isQueueCompletelyFilled(StationPlaylist $playlist): bool
|
||||
{
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
if (PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -289,13 +295,13 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
return $notQueuedMediaCount === 0;
|
||||
}
|
||||
|
||||
public function isQueueEmpty(Entity\StationPlaylist $playlist): bool
|
||||
public function isQueueEmpty(StationPlaylist $playlist): bool
|
||||
{
|
||||
if (Entity\Enums\PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
if (PlaylistSources::Songs !== $playlist->getSource()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Entity\Enums\PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
if (PlaylistOrders::Random === $playlist->getOrder()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -311,11 +317,11 @@ final class StationPlaylistMediaRepository extends Repository
|
|||
return $notQueuedMediaCount === $totalMediaCount;
|
||||
}
|
||||
|
||||
private function getCountPlaylistMediaBaseQuery(Entity\StationPlaylist $playlist): QueryBuilder
|
||||
private function getCountPlaylistMediaBaseQuery(StationPlaylist $playlist): QueryBuilder
|
||||
{
|
||||
return $this->em->createQueryBuilder()
|
||||
->select('count(spm.id)')
|
||||
->from(Entity\StationMedia::class, 'sm')
|
||||
->from(StationMedia::class, 'sm')
|
||||
->join('sm.playlists', 'spm')
|
||||
->where('spm.playlist = :playlist')
|
||||
->setParameter('playlist', $playlist);
|
||||
|
|
|
@ -4,37 +4,38 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\Enums\PlaylistSources;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationPlaylist>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationPlaylist>
|
||||
*/
|
||||
final class StationPlaylistRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
/**
|
||||
* @return Entity\StationPlaylist[]
|
||||
* @return \App\Entity\StationPlaylist[]
|
||||
*/
|
||||
public function getAllForStation(Entity\Station $station): array
|
||||
public function getAllForStation(Station $station): array
|
||||
{
|
||||
return $this->repository->findBy([
|
||||
'station' => $station,
|
||||
]);
|
||||
}
|
||||
|
||||
public function stationHasActivePlaylists(Entity\Station $station): bool
|
||||
public function stationHasActivePlaylists(Station $station): bool
|
||||
{
|
||||
foreach ($station->getPlaylists() as $playlist) {
|
||||
if (!$playlist->getIsEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Entity\Enums\PlaylistSources::RemoteUrl === $playlist->getSource()) {
|
||||
if (PlaylistSources::RemoteUrl === $playlist->getSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$mediaCount = $this->em->createQuery(
|
||||
<<<DQL
|
||||
SELECT COUNT(spm.id) FROM App\Entity\StationPlaylistMedia spm
|
||||
SELECT COUNT(spm.id) FROM App\\App\Entity\StationPlaylistMedia spm
|
||||
JOIN spm.playlist sp
|
||||
WHERE sp.station = :station
|
||||
DQL
|
||||
|
|
|
@ -4,22 +4,28 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationQueue;
|
||||
use App\Entity\Interfaces\SongInterface;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationQueue>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationQueue>
|
||||
*/
|
||||
final class StationQueueRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
public function clearForMediaAndPlaylist(Entity\StationMedia $media, Entity\StationPlaylist $playlist): void
|
||||
{
|
||||
public function clearForMediaAndPlaylist(
|
||||
StationMedia $media,
|
||||
StationPlaylist $playlist
|
||||
): void {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationQueue sq
|
||||
DELETE FROM App\\App\Entity\StationQueue sq
|
||||
WHERE sq.media = :media
|
||||
AND sq.playlist = :playlist
|
||||
AND sq.is_played = 0
|
||||
|
@ -29,7 +35,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
->execute();
|
||||
}
|
||||
|
||||
public function getNextVisible(Entity\Station $station): ?Entity\StationQueue
|
||||
public function getNextVisible(Station $station): ?StationQueue
|
||||
{
|
||||
return $this->getUnplayedBaseQuery($station)
|
||||
->andWhere('sq.is_visible = 1')
|
||||
|
@ -39,12 +45,12 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function trackPlayed(
|
||||
Entity\Station $station,
|
||||
Entity\StationQueue $row
|
||||
Station $station,
|
||||
StationQueue $row
|
||||
): void {
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationQueue sq
|
||||
UPDATE App\\App\Entity\StationQueue sq
|
||||
SET sq.timestamp_played = :timestamp
|
||||
WHERE sq.station = :station
|
||||
AND sq.id = :id
|
||||
|
@ -56,7 +62,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationQueue sq
|
||||
UPDATE App\\App\Entity\StationQueue sq
|
||||
SET sq.is_played=1, sq.sent_to_autodj=1
|
||||
WHERE sq.station = :station
|
||||
AND sq.is_played = 0
|
||||
|
@ -69,7 +75,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function isPlaylistRecentlyPlayed(
|
||||
Entity\StationPlaylist $playlist,
|
||||
StationPlaylist $playlist,
|
||||
?int $playPerSongs = null
|
||||
): bool {
|
||||
$playPerSongs ??= $playlist->getPlayPerSongs();
|
||||
|
@ -77,7 +83,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
$recentPlayedQuery = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sq.playlist_id
|
||||
FROM App\Entity\StationQueue sq
|
||||
FROM App\\App\Entity\StationQueue sq
|
||||
WHERE sq.station = :station
|
||||
AND sq.playlist_id IS NOT NULL
|
||||
AND (sq.playlist = :playlist OR sq.is_visible = 1)
|
||||
|
@ -96,7 +102,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
* @return mixed[]
|
||||
*/
|
||||
public function getRecentlyPlayedByTimeRange(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
CarbonInterface $now,
|
||||
int $minutes
|
||||
): array {
|
||||
|
@ -105,7 +111,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sq.song_id, sq.timestamp_played, sq.title, sq.artist
|
||||
FROM App\Entity\StationQueue sq
|
||||
FROM App\\App\Entity\StationQueue sq
|
||||
WHERE sq.station = :station
|
||||
AND (sq.is_played = 0 OR sq.timestamp_played >= :threshold)
|
||||
ORDER BY sq.timestamp_played DESC
|
||||
|
@ -116,24 +122,24 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @return Entity\StationQueue[]
|
||||
* @param \App\Entity\Station $station
|
||||
* @return \App\Entity\StationQueue[]
|
||||
*/
|
||||
public function getUnplayedQueue(Entity\Station $station): array
|
||||
public function getUnplayedQueue(Station $station): array
|
||||
{
|
||||
return $this->getUnplayedQuery($station)->execute();
|
||||
}
|
||||
|
||||
public function getUnplayedQuery(Entity\Station $station): Query
|
||||
public function getUnplayedQuery(Station $station): Query
|
||||
{
|
||||
return $this->getUnplayedBaseQuery($station)->getQuery();
|
||||
}
|
||||
|
||||
public function clearUpcomingQueue(Entity\Station $station): void
|
||||
public function clearUpcomingQueue(Station $station): void
|
||||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationQueue sq
|
||||
DELETE FROM App\\App\Entity\StationQueue sq
|
||||
WHERE sq.station = :station
|
||||
AND sq.sent_to_autodj = 0
|
||||
DQL
|
||||
|
@ -141,7 +147,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
->execute();
|
||||
}
|
||||
|
||||
public function getNextToSendToAutoDj(Entity\Station $station): ?Entity\StationQueue
|
||||
public function getNextToSendToAutoDj(Station $station): ?StationQueue
|
||||
{
|
||||
return $this->getBaseQuery($station)
|
||||
->andWhere('sq.sent_to_autodj = 0')
|
||||
|
@ -152,9 +158,9 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function findRecentlyCuedSong(
|
||||
Entity\Station $station,
|
||||
Entity\Interfaces\SongInterface $song
|
||||
): ?Entity\StationQueue {
|
||||
Station $station,
|
||||
SongInterface $song
|
||||
): ?StationQueue {
|
||||
return $this->getUnplayedBaseQuery($station)
|
||||
->andWhere('sq.sent_to_autodj = 1')
|
||||
->andWhere('sq.song_id = :song_id')
|
||||
|
@ -164,7 +170,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
->getOneOrNullResult();
|
||||
}
|
||||
|
||||
public function hasCuedPlaylistMedia(Entity\StationPlaylist $playlist): bool
|
||||
public function hasCuedPlaylistMedia(StationPlaylist $playlist): bool
|
||||
{
|
||||
$station = $playlist->getStation();
|
||||
|
||||
|
@ -178,7 +184,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
return $cuedPlaylistContentCount > 0;
|
||||
}
|
||||
|
||||
private function getUnplayedBaseQuery(Entity\Station $station): QueryBuilder
|
||||
private function getUnplayedBaseQuery(Station $station): QueryBuilder
|
||||
{
|
||||
return $this->getBaseQuery($station)
|
||||
->andWhere('sq.is_played = 0')
|
||||
|
@ -186,21 +192,21 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
->addOrderBy('sq.timestamp_cued', 'ASC');
|
||||
}
|
||||
|
||||
private function getBaseQuery(Entity\Station $station): QueryBuilder
|
||||
private function getBaseQuery(Station $station): QueryBuilder
|
||||
{
|
||||
return $this->em->createQueryBuilder()
|
||||
->select('sq, sm, sp')
|
||||
->from(Entity\StationQueue::class, 'sq')
|
||||
->from(StationQueue::class, 'sq')
|
||||
->leftJoin('sq.media', 'sm')
|
||||
->leftJoin('sq.playlist', 'sp')
|
||||
->where('sq.station = :station')
|
||||
->setParameter('station', $station);
|
||||
}
|
||||
|
||||
public function clearUnplayed(?Entity\Station $station = null): void
|
||||
public function clearUnplayed(?Station $station = null): void
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder()
|
||||
->delete(Entity\StationQueue::class, 'sq')
|
||||
->delete(StationQueue::class, 'sq')
|
||||
->where('sq.is_played = 0');
|
||||
|
||||
if (null !== $station) {
|
||||
|
@ -219,7 +225,7 @@ final class StationQueueRepository extends AbstractStationBasedRepository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationQueue sq
|
||||
DELETE FROM App\\App\Entity\StationQueue sq
|
||||
WHERE sq.timestamp_cued <= :threshold
|
||||
DQL
|
||||
)->setParameter('threshold', $threshold)
|
||||
|
|
|
@ -4,26 +4,26 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\Station;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationRemote>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationRemote>
|
||||
*/
|
||||
final class StationRemoteRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getDisplayNames(Entity\Station $station): array
|
||||
public function getDisplayNames(Station $station): array
|
||||
{
|
||||
$remotes = $this->repository->findBy(['station' => $station]);
|
||||
|
||||
$displayNames = [];
|
||||
|
||||
foreach ($remotes as $remote) {
|
||||
/** @var Entity\StationRemote $remote */
|
||||
/** @var \App\Entity\StationRemote $remote */
|
||||
$displayNames[$remote->getId()] = $remote->getDisplayName();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,16 +8,18 @@ use App\Assets\AssetTypes;
|
|||
use App\Container\EnvironmentAwareTrait;
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Flysystem\ExtendedFilesystemInterface;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use App\Service\Flow\UploadedFile;
|
||||
use Closure;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationMount;
|
||||
use App\Entity\StationHlsStream;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\Station>
|
||||
* @extends Repository<\App\Entity\Station>
|
||||
*/
|
||||
final class StationRepository extends Repository
|
||||
{
|
||||
|
@ -33,7 +35,7 @@ final class StationRepository extends Repository
|
|||
/**
|
||||
* @param string $identifier A numeric or string identifier for a station.
|
||||
*/
|
||||
public function findByIdentifier(string $identifier): ?Entity\Station
|
||||
public function findByIdentifier(string $identifier): ?Station
|
||||
{
|
||||
return is_numeric($identifier)
|
||||
? $this->repository->find($identifier)
|
||||
|
@ -44,19 +46,19 @@ final class StationRepository extends Repository
|
|||
{
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(s.id) FROM App\Entity\Station s WHERE s.is_enabled = 1
|
||||
SELECT COUNT(s.id) FROM App\\App\Entity\Station s WHERE s.is_enabled = 1
|
||||
DQL
|
||||
)->getSingleScalarResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array-key, Entity\Station>
|
||||
* @return array<array-key, \App\Entity\Station>
|
||||
*/
|
||||
public function fetchAll(): mixed
|
||||
{
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT s FROM App\Entity\Station s ORDER BY s.name ASC
|
||||
SELECT s FROM App\\App\Entity\Station s ORDER BY s.name ASC
|
||||
DQL
|
||||
)->execute();
|
||||
}
|
||||
|
@ -88,13 +90,13 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @return iterable<Entity\Station>
|
||||
* @return iterable<\App\Entity\Station>
|
||||
*/
|
||||
public function iterateEnabledStations(): iterable
|
||||
{
|
||||
return $this->em->createQuery(
|
||||
<<<DQL
|
||||
SELECT s FROM App\Entity\Station s WHERE s.is_enabled = 1
|
||||
SELECT s FROM App\\App\Entity\Station s WHERE s.is_enabled = 1
|
||||
DQL
|
||||
)->toIterable();
|
||||
}
|
||||
|
@ -102,7 +104,7 @@ final class StationRepository extends Repository
|
|||
/**
|
||||
* Reset mount points to their adapter defaults (in the event of an adapter change).
|
||||
*/
|
||||
public function resetMounts(Entity\Station $station): void
|
||||
public function resetMounts(Station $station): void
|
||||
{
|
||||
foreach ($station->getMounts() as $mount) {
|
||||
$this->em->remove($mount);
|
||||
|
@ -110,7 +112,7 @@ final class StationRepository extends Repository
|
|||
|
||||
// Create default mountpoints if station supports them.
|
||||
if ($station->getFrontendType()->supportsMounts()) {
|
||||
$record = new Entity\StationMount($station);
|
||||
$record = new StationMount($station);
|
||||
$record->setName('/radio.mp3');
|
||||
$record->setIsDefault(true);
|
||||
$record->setEnableAutodj(true);
|
||||
|
@ -123,7 +125,7 @@ final class StationRepository extends Repository
|
|||
$this->em->refresh($station);
|
||||
}
|
||||
|
||||
public function resetHls(Entity\Station $station): void
|
||||
public function resetHls(Station $station): void
|
||||
{
|
||||
foreach ($station->getHlsStreams() as $hlsStream) {
|
||||
$this->em->remove($hlsStream);
|
||||
|
@ -137,7 +139,7 @@ final class StationRepository extends Repository
|
|||
];
|
||||
|
||||
foreach ($streams as $name => $bitrate) {
|
||||
$record = new Entity\StationHlsStream($station);
|
||||
$record = new StationHlsStream($station);
|
||||
$record->setName($name);
|
||||
$record->setFormat(StreamFormats::Aac);
|
||||
$record->setBitrate($bitrate);
|
||||
|
@ -149,11 +151,11 @@ final class StationRepository extends Repository
|
|||
$this->em->refresh($station);
|
||||
}
|
||||
|
||||
public function flushRelatedMedia(Entity\Station $station): void
|
||||
public function flushRelatedMedia(Station $station): void
|
||||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\SongHistory sh SET sh.media = null
|
||||
UPDATE App\\App\Entity\SongHistory sh SET sh.media = null
|
||||
WHERE sh.station = :station
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
|
@ -161,9 +163,9 @@ final class StationRepository extends Repository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationPlaylistMedia spm
|
||||
DELETE FROM App\\App\Entity\StationPlaylistMedia spm
|
||||
WHERE spm.playlist_id IN (
|
||||
SELECT sp.id FROM App\Entity\StationPlaylist sp WHERE sp.station = :station
|
||||
SELECT sp.id FROM App\\App\Entity\StationPlaylist sp WHERE sp.station = :station
|
||||
)
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
|
@ -171,14 +173,14 @@ final class StationRepository extends Repository
|
|||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationQueue sq WHERE sq.station = :station
|
||||
DELETE FROM App\\App\Entity\StationQueue sq WHERE sq.station = :station
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
->execute();
|
||||
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationRequest sr WHERE sr.station = :station
|
||||
DELETE FROM App\\App\Entity\StationRequest sr WHERE sr.station = :station
|
||||
DQL
|
||||
)->setParameter('station', $station)
|
||||
->execute();
|
||||
|
@ -187,9 +189,9 @@ final class StationRepository extends Repository
|
|||
/**
|
||||
* Return the URL to use for songs with no specified album artwork, when artwork is displayed.
|
||||
*
|
||||
* @param Entity\Station|null $station
|
||||
* @param \App\Entity\Station|null $station
|
||||
*/
|
||||
public function getDefaultAlbumArtUrl(?Entity\Station $station = null): UriInterface
|
||||
public function getDefaultAlbumArtUrl(?Station $station = null): UriInterface
|
||||
{
|
||||
if (null !== $station) {
|
||||
$stationAlbumArt = AssetTypes::AlbumArt->createObject($this->environment, $station);
|
||||
|
@ -208,7 +210,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function setFallback(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
UploadedFile $file,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
|
@ -231,7 +233,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function doDeleteFallback(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$fs ??= StationFilesystems::buildConfigFilesystem($station);
|
||||
|
@ -245,7 +247,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function clearFallback(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$this->doDeleteFallback($station, $fs);
|
||||
|
@ -256,7 +258,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function setStereoToolConfiguration(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
UploadedFile $file,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
|
@ -280,7 +282,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function doDeleteStereoToolConfiguration(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$backendConfig = $station->getBackendConfig();
|
||||
|
@ -293,7 +295,7 @@ final class StationRepository extends Repository
|
|||
}
|
||||
|
||||
public function clearStereoToolConfiguration(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?ExtendedFilesystemInterface $fs = null
|
||||
): void {
|
||||
$this->doDeleteStereoToolConfiguration($station, $fs);
|
||||
|
|
|
@ -5,16 +5,19 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Entity;
|
||||
use App\Exception;
|
||||
use App\Radio\AutoDJ;
|
||||
use App\Radio\Frontend\Blocklist\BlocklistParser;
|
||||
use App\Service\DeviceDetector;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationRequest;
|
||||
use App\Entity\StationMedia;
|
||||
use App\Entity\Api\StationPlaylistQueue;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationRequest>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationRequest>
|
||||
*/
|
||||
final class StationRequestRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
|
@ -28,7 +31,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
parent::__construct($em);
|
||||
}
|
||||
|
||||
public function getPendingRequest(int|string $id, Entity\Station $station): ?Entity\StationRequest
|
||||
public function getPendingRequest(int|string $id, Station $station): ?StationRequest
|
||||
{
|
||||
return $this->repository->findOneBy(
|
||||
[
|
||||
|
@ -39,11 +42,11 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
);
|
||||
}
|
||||
|
||||
public function clearPendingRequests(Entity\Station $station): void
|
||||
public function clearPendingRequests(Station $station): void
|
||||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
DELETE FROM App\Entity\StationRequest sr
|
||||
DELETE FROM App\\App\Entity\StationRequest sr
|
||||
WHERE sr.station = :station
|
||||
AND sr.played_at = 0
|
||||
DQL
|
||||
|
@ -52,7 +55,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function submit(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
string $trackId,
|
||||
bool $isAuthenticated,
|
||||
string $ip,
|
||||
|
@ -100,7 +103,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
|
||||
$recentRequests = (int)$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT COUNT(sr.id) FROM App\Entity\StationRequest sr
|
||||
SELECT COUNT(sr.id) FROM App\\App\Entity\StationRequest sr
|
||||
WHERE sr.ip = :user_ip
|
||||
AND sr.timestamp >= :threshold
|
||||
DQL
|
||||
|
@ -116,7 +119,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
// Save request locally.
|
||||
$record = new Entity\StationRequest($station, $media_item, $ip);
|
||||
$record = new StationRequest($station, $media_item, $ip);
|
||||
$this->em->persist($record);
|
||||
$this->em->flush();
|
||||
|
||||
|
@ -126,12 +129,12 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
/**
|
||||
* Check if the song is already enqueued as a request.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkPendingRequest(Entity\StationMedia $media, Entity\Station $station): bool
|
||||
public function checkPendingRequest(StationMedia $media, Station $station): bool
|
||||
{
|
||||
$pending_request_threshold = time() - (60 * 10);
|
||||
|
||||
|
@ -139,7 +142,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
$pending_request = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sr.timestamp
|
||||
FROM App\Entity\StationRequest sr
|
||||
FROM App\\App\Entity\StationRequest sr
|
||||
WHERE sr.track_id = :track_id
|
||||
AND sr.station_id = :station_id
|
||||
AND (sr.timestamp >= :threshold OR sr.played_at = 0)
|
||||
|
@ -162,16 +165,16 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function getNextPlayableRequest(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
?CarbonInterface $now = null
|
||||
): ?Entity\StationRequest {
|
||||
): ?StationRequest {
|
||||
$now ??= CarbonImmutable::now($station->getTimezoneObject());
|
||||
|
||||
// Look up all requests that have at least waited as long as the threshold.
|
||||
$requests = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sr, sm
|
||||
FROM App\Entity\StationRequest sr JOIN sr.track sm
|
||||
FROM App\\App\Entity\StationRequest sr JOIN sr.track sm
|
||||
WHERE sr.played_at = 0
|
||||
AND sr.station = :station
|
||||
ORDER BY sr.skip_delay DESC, sr.id ASC
|
||||
|
@ -180,7 +183,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
->execute();
|
||||
|
||||
foreach ($requests as $request) {
|
||||
/** @var Entity\StationRequest $request */
|
||||
/** @var \App\Entity\StationRequest $request */
|
||||
if ($request->shouldPlayNow($now)) {
|
||||
try {
|
||||
$this->checkRecentPlay($request->getTrack(), $station);
|
||||
|
@ -198,12 +201,12 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
/**
|
||||
* Check the most recent song history.
|
||||
*
|
||||
* @param Entity\StationMedia $media
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\StationMedia $media
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkRecentPlay(Entity\StationMedia $media, Entity\Station $station): bool
|
||||
public function checkRecentPlay(StationMedia $media, Station $station): bool
|
||||
{
|
||||
$lastPlayThresholdMins = ($station->getRequestThreshold() ?? 15);
|
||||
|
||||
|
@ -215,7 +218,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
|
||||
$recentTracks = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT sh FROM App\Entity\SongHistory sh
|
||||
SELECT sh FROM App\\App\Entity\SongHistory sh
|
||||
WHERE sh.station = :station
|
||||
AND sh.timestamp_start >= :threshold
|
||||
ORDER BY sh.timestamp_start DESC
|
||||
|
@ -224,7 +227,7 @@ final class StationRequestRepository extends AbstractStationBasedRepository
|
|||
->setParameter('threshold', $lastPlayThreshold)
|
||||
->getArrayResult();
|
||||
|
||||
$eligibleTrack = new Entity\Api\StationPlaylistQueue();
|
||||
$eligibleTrack = new StationPlaylistQueue();
|
||||
$eligibleTrack->media_id = $media->getIdRequired();
|
||||
$eligibleTrack->song_id = $media->getSongId();
|
||||
$eligibleTrack->title = $media->getTitle() ?? '';
|
||||
|
|
|
@ -6,30 +6,36 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use App\Radio\AutoDJ\Scheduler;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use App\Entity\ApiGenerator\ScheduleApiGenerator;
|
||||
use App\Entity\StationPlaylist;
|
||||
use App\Entity\StationStreamer;
|
||||
use App\Entity\StationSchedule;
|
||||
use App\Entity\Station;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\StationSchedule>
|
||||
* @extends Repository<\App\Entity\StationSchedule>
|
||||
*/
|
||||
final class StationScheduleRepository extends Repository
|
||||
{
|
||||
public function __construct(
|
||||
ReloadableEntityManagerInterface $em,
|
||||
private readonly Scheduler $scheduler,
|
||||
private readonly Entity\ApiGenerator\ScheduleApiGenerator $scheduleApiGenerator
|
||||
private readonly ScheduleApiGenerator $scheduleApiGenerator
|
||||
) {
|
||||
parent::__construct($em);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\StationPlaylist|Entity\StationStreamer $relation
|
||||
* @param \App\Entity\StationPlaylist|\App\Entity\StationStreamer $relation
|
||||
* @param array $items
|
||||
*/
|
||||
public function setScheduleItems(Entity\StationPlaylist|Entity\StationStreamer $relation, array $items = []): void
|
||||
{
|
||||
public function setScheduleItems(
|
||||
StationPlaylist|StationStreamer $relation,
|
||||
array $items = []
|
||||
): void {
|
||||
$rawScheduleItems = $this->findByRelation($relation);
|
||||
|
||||
$scheduleItems = [];
|
||||
|
@ -42,7 +48,7 @@ final class StationScheduleRepository extends Repository
|
|||
$record = $scheduleItems[$item['id']];
|
||||
unset($scheduleItems[$item['id']]);
|
||||
} else {
|
||||
$record = new Entity\StationSchedule($relation);
|
||||
$record = new StationSchedule($relation);
|
||||
}
|
||||
|
||||
$record->setStartTime((int)$item['start_time']);
|
||||
|
@ -63,13 +69,13 @@ final class StationScheduleRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\StationPlaylist|Entity\StationStreamer $relation
|
||||
* @param \App\Entity\StationPlaylist|\App\Entity\StationStreamer $relation
|
||||
*
|
||||
* @return Entity\StationSchedule[]
|
||||
* @return \App\Entity\StationSchedule[]
|
||||
*/
|
||||
public function findByRelation(Entity\StationPlaylist|Entity\StationStreamer $relation): array
|
||||
public function findByRelation(StationPlaylist|StationStreamer $relation): array
|
||||
{
|
||||
if ($relation instanceof Entity\StationPlaylist) {
|
||||
if ($relation instanceof StationPlaylist) {
|
||||
return $this->repository->findBy(['playlist' => $relation]);
|
||||
}
|
||||
|
||||
|
@ -77,16 +83,16 @@ final class StationScheduleRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @return Entity\StationSchedule[]
|
||||
* @return \App\Entity\StationSchedule[]
|
||||
*/
|
||||
public function getAllScheduledItemsForStation(Entity\Station $station): array
|
||||
public function getAllScheduledItemsForStation(Station $station): array
|
||||
{
|
||||
return $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssc, sp, sst
|
||||
FROM App\Entity\StationSchedule ssc
|
||||
FROM App\\App\Entity\StationSchedule ssc
|
||||
LEFT JOIN ssc.playlist sp
|
||||
LEFT JOIN ssc.streamer sst
|
||||
WHERE (sp.station = :station AND sp.is_jingle = 0 AND sp.is_enabled = 1)
|
||||
|
@ -97,12 +103,12 @@ final class StationScheduleRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param CarbonInterface|null $now
|
||||
*
|
||||
* @return Entity\Api\StationSchedule[]
|
||||
* @return \App\Entity\Api\StationSchedule[]
|
||||
*/
|
||||
public function getUpcomingSchedule(Entity\Station $station, CarbonInterface $now = null): array
|
||||
public function getUpcomingSchedule(Station $station, CarbonInterface $now = null): array
|
||||
{
|
||||
if (null === $now) {
|
||||
$now = CarbonImmutable::now($station->getTimezoneObject());
|
||||
|
@ -114,7 +120,7 @@ final class StationScheduleRepository extends Repository
|
|||
$events = [];
|
||||
|
||||
foreach ($this->getAllScheduledItemsForStation($station) as $scheduleItem) {
|
||||
/** @var Entity\StationSchedule $scheduleItem */
|
||||
/** @var \App\Entity\StationSchedule $scheduleItem */
|
||||
$i = $startDate;
|
||||
|
||||
while ($i <= $endDate) {
|
||||
|
@ -124,8 +130,8 @@ final class StationScheduleRepository extends Repository
|
|||
$this->scheduler->shouldSchedulePlayOnCurrentDate($scheduleItem, $i)
|
||||
&& $this->scheduler->isScheduleScheduledToPlayToday($scheduleItem, $dayOfWeek)
|
||||
) {
|
||||
$start = Entity\StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
|
||||
$end = Entity\StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
|
||||
$start = StationSchedule::getDateTime($scheduleItem->getStartTime(), $i);
|
||||
$end = StationSchedule::getDateTime($scheduleItem->getEndTime(), $i);
|
||||
|
||||
// Handle overnight schedule items
|
||||
if ($end < $start) {
|
||||
|
|
|
@ -5,26 +5,28 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationStreamerBroadcast;
|
||||
use App\Entity\StationStreamer;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\StationStreamerBroadcast>
|
||||
* @extends Repository<\App\Entity\StationStreamerBroadcast>
|
||||
*/
|
||||
final class StationStreamerBroadcastRepository extends Repository
|
||||
{
|
||||
public function getLatestBroadcast(Entity\Station $station): ?Entity\StationStreamerBroadcast
|
||||
public function getLatestBroadcast(Station $station): ?StationStreamerBroadcast
|
||||
{
|
||||
$currentStreamer = $station->getCurrentStreamer();
|
||||
if (null === $currentStreamer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Entity\StationStreamerBroadcast|null $latestBroadcast */
|
||||
/** @var \App\Entity\StationStreamerBroadcast|null $latestBroadcast */
|
||||
$latestBroadcast = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssb
|
||||
FROM App\Entity\StationStreamerBroadcast ssb
|
||||
FROM App\\App\Entity\StationStreamerBroadcast ssb
|
||||
WHERE ssb.station = :station AND ssb.streamer = :streamer
|
||||
ORDER BY ssb.timestampStart DESC
|
||||
DQL
|
||||
|
@ -36,11 +38,11 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
return $latestBroadcast;
|
||||
}
|
||||
|
||||
public function endAllActiveBroadcasts(Entity\Station $station): void
|
||||
public function endAllActiveBroadcasts(Station $station): void
|
||||
{
|
||||
$this->em->createQuery(
|
||||
<<<'DQL'
|
||||
UPDATE App\Entity\StationStreamerBroadcast ssb
|
||||
UPDATE App\\App\Entity\StationStreamerBroadcast ssb
|
||||
SET ssb.timestampEnd = :time
|
||||
WHERE ssb.station = :station
|
||||
AND ssb.timestampEnd = 0
|
||||
|
@ -51,11 +53,11 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
*
|
||||
* @return Entity\StationStreamerBroadcast[]
|
||||
* @return \App\Entity\StationStreamerBroadcast[]
|
||||
*/
|
||||
public function getActiveBroadcasts(Entity\Station $station): array
|
||||
public function getActiveBroadcasts(Station $station): array
|
||||
{
|
||||
return $this->repository->findBy([
|
||||
'station' => $station,
|
||||
|
@ -63,7 +65,7 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
]);
|
||||
}
|
||||
|
||||
public function findByPath(Entity\Station $station, string $path): ?Entity\StationStreamerBroadcast
|
||||
public function findByPath(Station $station, string $path): ?StationStreamerBroadcast
|
||||
{
|
||||
return $this->repository->findOneBy([
|
||||
'station' => $station,
|
||||
|
@ -72,12 +74,12 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
}
|
||||
|
||||
public function getOrCreateFromPath(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
string $recordingPath,
|
||||
): ?Entity\StationStreamerBroadcast {
|
||||
): ?StationStreamerBroadcast {
|
||||
$streamerUsername = pathinfo($recordingPath, PATHINFO_DIRNAME);
|
||||
|
||||
$streamer = $this->em->getRepository(Entity\StationStreamer::class)
|
||||
$streamer = $this->em->getRepository(StationStreamer::class)
|
||||
->findOneBy([
|
||||
'station' => $station,
|
||||
'streamer_username' => $streamerUsername,
|
||||
|
@ -89,7 +91,7 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
}
|
||||
|
||||
$startTimeRaw = str_replace(
|
||||
Entity\StationStreamerBroadcast::PATH_PREFIX . '_',
|
||||
StationStreamerBroadcast::PATH_PREFIX . '_',
|
||||
'',
|
||||
pathinfo($recordingPath, PATHINFO_FILENAME)
|
||||
);
|
||||
|
@ -106,7 +108,7 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
$record = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssb
|
||||
FROM App\Entity\StationStreamerBroadcast ssb
|
||||
FROM App\\App\Entity\StationStreamerBroadcast ssb
|
||||
WHERE ssb.streamer = :streamer
|
||||
AND ssb.timestampStart >= :start AND ssb.timestampStart <= :end
|
||||
AND ssb.recordingPath IS NULL
|
||||
|
@ -118,7 +120,7 @@ final class StationStreamerBroadcastRepository extends Repository
|
|||
->getOneOrNullResult();
|
||||
|
||||
if (null === $record) {
|
||||
$record = new Entity\StationStreamerBroadcast($streamer);
|
||||
$record = new StationStreamerBroadcast($streamer);
|
||||
}
|
||||
|
||||
$record->setTimestampStart($startTime->getTimestamp());
|
||||
|
|
|
@ -5,13 +5,15 @@ declare(strict_types=1);
|
|||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use App\Media\AlbumArt;
|
||||
use App\Radio\AutoDJ\Scheduler;
|
||||
use App\Entity\Station;
|
||||
use App\Entity\StationStreamer;
|
||||
use App\Entity\StationStreamerBroadcast;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationStreamer>
|
||||
* @extends AbstractStationBasedRepository<\App\Entity\StationStreamer>
|
||||
*/
|
||||
final class StationStreamerRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
|
@ -26,12 +28,12 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
/**
|
||||
* Attempt to authenticate a streamer.
|
||||
*
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*/
|
||||
public function authenticate(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
string $username = '',
|
||||
string $password = ''
|
||||
): bool {
|
||||
|
@ -41,7 +43,7 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
$streamer = $this->getStreamer($station, $username);
|
||||
if (!($streamer instanceof Entity\StationStreamer)) {
|
||||
if (!($streamer instanceof StationStreamer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -49,17 +51,17 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Station $station
|
||||
* @param \App\Entity\Station $station
|
||||
* @param string $username
|
||||
*
|
||||
*/
|
||||
public function onConnect(Entity\Station $station, string $username = ''): string|bool
|
||||
public function onConnect(Station $station, string $username = ''): string|bool
|
||||
{
|
||||
// End all current streamer sessions.
|
||||
$this->broadcastRepo->endAllActiveBroadcasts($station);
|
||||
|
||||
$streamer = $this->getStreamer($station, $username);
|
||||
if (!($streamer instanceof Entity\StationStreamer)) {
|
||||
if (!($streamer instanceof StationStreamer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -67,14 +69,14 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
$station->setCurrentStreamer($streamer);
|
||||
$this->em->persist($station);
|
||||
|
||||
$record = new Entity\StationStreamerBroadcast($streamer);
|
||||
$record = new StationStreamerBroadcast($streamer);
|
||||
$this->em->persist($record);
|
||||
$this->em->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onDisconnect(Entity\Station $station): bool
|
||||
public function onDisconnect(Station $station): bool
|
||||
{
|
||||
foreach ($this->broadcastRepo->getActiveBroadcasts($station) as $broadcast) {
|
||||
$broadcast->setTimestampEnd(time());
|
||||
|
@ -90,10 +92,10 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function getStreamer(
|
||||
Entity\Station $station,
|
||||
Station $station,
|
||||
string $username = '',
|
||||
bool $activeOnly = true
|
||||
): ?Entity\StationStreamer {
|
||||
): ?StationStreamer {
|
||||
$criteria = [
|
||||
'station' => $station,
|
||||
'streamer_username' => $username,
|
||||
|
@ -103,17 +105,17 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
$criteria['is_active'] = 1;
|
||||
}
|
||||
|
||||
/** @var Entity\StationStreamer|null $streamer */
|
||||
/** @var \App\Entity\StationStreamer|null $streamer */
|
||||
$streamer = $this->repository->findOneBy($criteria);
|
||||
|
||||
return $streamer;
|
||||
}
|
||||
|
||||
public function writeArtwork(
|
||||
Entity\StationStreamer $streamer,
|
||||
StationStreamer $streamer,
|
||||
string $rawArtworkString
|
||||
): void {
|
||||
$artworkPath = Entity\StationStreamer::getArtworkPath($streamer->getIdRequired());
|
||||
$artworkPath = StationStreamer::getArtworkPath($streamer->getIdRequired());
|
||||
$artworkString = AlbumArt::resize($rawArtworkString);
|
||||
|
||||
$fsConfig = StationFilesystems::buildConfigFilesystem($streamer->getStation());
|
||||
|
@ -124,9 +126,9 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function removeArtwork(
|
||||
Entity\StationStreamer $streamer
|
||||
StationStreamer $streamer
|
||||
): void {
|
||||
$artworkPath = Entity\StationStreamer::getArtworkPath($streamer->getIdRequired());
|
||||
$artworkPath = StationStreamer::getArtworkPath($streamer->getIdRequired());
|
||||
|
||||
$fsConfig = StationFilesystems::buildConfigFilesystem($streamer->getStation());
|
||||
$fsConfig->delete($artworkPath);
|
||||
|
@ -136,7 +138,7 @@ final class StationStreamerRepository extends AbstractStationBasedRepository
|
|||
}
|
||||
|
||||
public function delete(
|
||||
Entity\StationStreamer $streamer
|
||||
StationStreamer $streamer
|
||||
): void {
|
||||
$this->removeArtwork($streamer);
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Entity\Repository;
|
||||
|
||||
use App\Entity;
|
||||
use App\Entity\StationWebhook;
|
||||
|
||||
/**
|
||||
* @extends AbstractStationBasedRepository<Entity\StationWebhook>
|
||||
* @extends AbstractStationBasedRepository<StationWebhook>
|
||||
*/
|
||||
final class StationWebhookRepository extends AbstractStationBasedRepository
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue