AzuraCast/src/Controller/Api/Stations/OnDemand/ListAction.php

155 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controller\Api\Stations\OnDemand;
use App\Doctrine\ReadOnlyBatchIteratorAggregate;
use App\Entity;
use App\Http\Response;
use App\Http\RouterInterface;
use App\Http\ServerRequest;
use App\Paginator;
use App\Utilities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Contracts\Cache\CacheInterface;
final class ListAction
{
public function __construct(
private readonly EntityManagerInterface $em,
private readonly Entity\Repository\CustomFieldRepository $customFieldRepo,
private readonly Entity\ApiGenerator\SongApiGenerator $songApiGenerator,
private readonly CacheInterface $cache,
) {
}
public function __invoke(
ServerRequest $request,
Response $response,
string $station_id
): ResponseInterface {
$station = $request->getStation();
// 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.')));
}
$cacheKey = 'ondemand_' . $station->getId();
$trackList = $this->cache->get(
$cacheKey,
function (CacheItem $item) use ($station, $request) {
$item->expiresAfter(300);
return $this->buildTrackList($station, $request->getRouter());
}
);
$trackList = new ArrayCollection($trackList);
$queryParams = $request->getQueryParams();
$searchPhrase = trim($queryParams['searchPhrase'] ?? '');
if (!empty($searchPhrase)) {
$searchFields = [
'media_title',
'media_artist',
'media_album',
'playlist',
];
foreach (array_keys($this->customFieldRepo->getFieldIds()) as $customField) {
$searchFields[] = 'media_custom_fields_' . $customField;
}
$trackList = $trackList->filter(
function ($row) use ($searchFields, $searchPhrase) {
foreach ($searchFields as $searchField) {
if (false !== stripos($row[$searchField] ?? '', $searchPhrase)) {
return true;
}
}
return false;
}
);
}
if (!empty($queryParams['sort'])) {
$sortField = (string)$queryParams['sort'];
$sortDirection = (string)($queryParams['sortOrder'] ?? Criteria::ASC);
$criteria = new Criteria();
$criteria->orderBy([$sortField => $sortDirection]);
$trackList = $trackList->matching($criteria);
}
return Paginator::fromCollection($trackList, $request)
->write($response);
}
/**
* @return mixed[]
*/
private function buildTrackList(Entity\Station $station, RouterInterface $router): array
{
$list = [];
$playlists = $this->em->createQuery(
<<<'DQL'
SELECT sp FROM App\Entity\StationPlaylist sp
WHERE sp.station = :station
AND sp.id IS NOT NULL
AND sp.is_enabled = 1
AND sp.include_in_on_demand = 1
DQL
)->setParameter('station', $station)
->getArrayResult();
foreach ($playlists as $playlist) {
$query = $this->em->createQuery(
<<<'DQL'
SELECT sm FROM App\Entity\StationMedia sm
WHERE sm.id IN (
SELECT spm.media_id
FROM App\Entity\StationPlaylistMedia spm
WHERE spm.playlist_id = :playlist_id
)
ORDER BY sm.artist ASC, sm.title ASC
DQL
)->setParameter('playlist_id', $playlist['id']);
foreach (ReadOnlyBatchIteratorAggregate::fromQuery($query, 50) as $media) {
/** @var Entity\StationMedia $media */
$row = new Entity\Api\StationOnDemand();
$row->track_id = $media->getUniqueId();
$row->media = ($this->songApiGenerator)(
song: $media,
station: $station
);
$row->playlist = $playlist['name'];
$row->download_url = $router->named(
'api:stations:ondemand:download',
[
'station_id' => $station->getId(),
'media_id' => $media->getUniqueId(),
]
);
$row->resolveUrls($router->getBaseUrl());
$list[] = Utilities\Arrays::flattenArray($row, '_');
}
}
return $list;
}
}