Add Meilisearch to media list function.
This commit is contained in:
parent
dc9b189a3f
commit
0a08a6fd4e
|
@ -12,6 +12,7 @@ use App\Http\RouterInterface;
|
||||||
use App\Http\ServerRequest;
|
use App\Http\ServerRequest;
|
||||||
use App\Media\MimeType;
|
use App\Media\MimeType;
|
||||||
use App\Paginator;
|
use App\Paginator;
|
||||||
|
use App\Service\Meilisearch;
|
||||||
use App\Utilities;
|
use App\Utilities;
|
||||||
use Doctrine\Common\Collections\Criteria;
|
use Doctrine\Common\Collections\Criteria;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
@ -27,7 +28,8 @@ final class ListAction
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly EntityManagerInterface $em,
|
private readonly EntityManagerInterface $em,
|
||||||
private readonly CacheInterface $cache
|
private readonly CacheInterface $cache,
|
||||||
|
private readonly Meilisearch $meilisearch
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +106,7 @@ final class ListAction
|
||||||
)->setParameter('storageLocation', $storageLocation)
|
)->setParameter('storageLocation', $storageLocation)
|
||||||
->setParameter('path', $pathLike);
|
->setParameter('path', $pathLike);
|
||||||
|
|
||||||
if (!empty($searchPhrase)) {
|
if ($isSearch) {
|
||||||
if ('special:unprocessable' === $searchPhrase) {
|
if ('special:unprocessable' === $searchPhrase) {
|
||||||
$mediaInDirRaw = [];
|
$mediaInDirRaw = [];
|
||||||
|
|
||||||
|
@ -130,29 +132,30 @@ final class ListAction
|
||||||
$mediaQueryBuilder->andWhere(
|
$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\Entity\StationPlaylistMedia spm2)'
|
||||||
);
|
);
|
||||||
} elseif (str_starts_with($searchPhrase, 'playlist:')) {
|
} else {
|
||||||
[, $playlistName] = explode(':', $searchPhrase, 2);
|
[$searchPhrase, $playlist] = $this->parseSearchQuery($station, $searchPhrase);
|
||||||
|
|
||||||
$playlist = $this->em->getRepository(Entity\StationPlaylist::class)
|
if ($this->meilisearch->isSupported()) {
|
||||||
->findOneBy(
|
$ids = $this->meilisearch
|
||||||
[
|
->getIndex($storageLocation)
|
||||||
'station' => $station,
|
->searchMedia($searchPhrase, $playlist);
|
||||||
'name' => $playlistName,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$playlist instanceof Entity\StationPlaylist) {
|
$mediaQueryBuilder->andWhere(
|
||||||
return $response->withStatus(400)
|
'sm.id IN (:ids)'
|
||||||
->withJson(new Entity\Api\Error(400, 'Playlist not found.'));
|
)->setParameter('ids', $ids);
|
||||||
|
} else {
|
||||||
|
if (null !== $playlist) {
|
||||||
|
$mediaQueryBuilder->andWhere(
|
||||||
|
'sm.id IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2 '
|
||||||
|
. 'WHERE spm2.playlist = :playlist)'
|
||||||
|
)->setParameter('playlist', $playlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($searchPhrase)) {
|
||||||
|
$mediaQueryBuilder->andWhere('(sm.title LIKE :query OR sm.artist LIKE :query)')
|
||||||
|
->setParameter('query', '%' . $searchPhrase . '%');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$mediaQueryBuilder->andWhere(
|
|
||||||
'sm.id IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2 '
|
|
||||||
. 'WHERE spm2.playlist = :playlist)'
|
|
||||||
)->setParameter('playlist', $playlist);
|
|
||||||
} elseif (!in_array($searchPhrase, ['*', '%'], true)) {
|
|
||||||
$mediaQueryBuilder->andWhere('(sm.title LIKE :query OR sm.artist LIKE :query)')
|
|
||||||
->setParameter('query', '%' . $searchPhrase . '%');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$mediaQuery = $mediaQueryBuilder->getQuery();
|
$mediaQuery = $mediaQueryBuilder->getQuery();
|
||||||
|
@ -246,7 +249,7 @@ final class ListAction
|
||||||
$unprocessableMedia[$unprocessableRow['path']] = $unprocessableRow['error'];
|
$unprocessableMedia[$unprocessableRow['path']] = $unprocessableRow['error'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($searchPhrase)) {
|
if ($isSearch) {
|
||||||
if ('special:unprocessable' === $searchPhrase) {
|
if ('special:unprocessable' === $searchPhrase) {
|
||||||
$files = array_keys($unprocessableMedia);
|
$files = array_keys($unprocessableMedia);
|
||||||
} else {
|
} else {
|
||||||
|
@ -284,7 +287,7 @@ final class ListAction
|
||||||
|
|
||||||
$row->size = ($row->is_dir) ? 0 : $fs->fileSize($row->path);
|
$row->size = ($row->is_dir) ? 0 : $fs->fileSize($row->path);
|
||||||
|
|
||||||
$shortname = (!empty($searchPhrase))
|
$shortname = ($isSearch)
|
||||||
? $row->path
|
? $row->path
|
||||||
: basename($row->path);
|
: basename($row->path);
|
||||||
|
|
||||||
|
@ -353,6 +356,35 @@ final class ListAction
|
||||||
return $paginator->write($response);
|
return $paginator->write($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function parseSearchQuery(
|
||||||
|
Entity\Station $station,
|
||||||
|
string $query
|
||||||
|
): array {
|
||||||
|
$playlist = null;
|
||||||
|
|
||||||
|
if (str_contains($query, 'playlist:')) {
|
||||||
|
preg_match('/playlist:(\w*)/', $query, $matches, PREG_UNMATCHED_AS_NULL);
|
||||||
|
|
||||||
|
if ($matches[1]) {
|
||||||
|
$playlist = $this->em->getRepository(Entity\StationPlaylist::class)
|
||||||
|
->findOneBy(
|
||||||
|
[
|
||||||
|
'station' => $station,
|
||||||
|
'name' => $matches[1],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = trim(str_replace($matches[0] ?? '', '', $query));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($query, ['*', '%'], true)) {
|
||||||
|
$query = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$query, $playlist];
|
||||||
|
}
|
||||||
|
|
||||||
private static function sortRows(
|
private static function sortRows(
|
||||||
Entity\Api\FileList $a,
|
Entity\Api\FileList $a,
|
||||||
Entity\Api\FileList $b,
|
Entity\Api\FileList $b,
|
||||||
|
|
|
@ -25,7 +25,7 @@ final class Meilisearch
|
||||||
|
|
||||||
public function isSupported(): bool
|
public function isSupported(): bool
|
||||||
{
|
{
|
||||||
return $this->environment->isDocker();
|
return $this->environment->isDocker() && !$this->environment->isTesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClient(): Client
|
public function getClient(): Client
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Service\Meilisearch;
|
||||||
use App\Doctrine\ReloadableEntityManagerInterface;
|
use App\Doctrine\ReloadableEntityManagerInterface;
|
||||||
use App\Entity\Repository\CustomFieldRepository;
|
use App\Entity\Repository\CustomFieldRepository;
|
||||||
use App\Entity\Station;
|
use App\Entity\Station;
|
||||||
|
use App\Entity\StationPlaylist;
|
||||||
use App\Entity\StorageLocation;
|
use App\Entity\StorageLocation;
|
||||||
use App\Environment;
|
use App\Environment;
|
||||||
use App\Service\Meilisearch;
|
use App\Service\Meilisearch;
|
||||||
|
@ -14,6 +15,7 @@ use Doctrine\ORM\AbstractQuery;
|
||||||
use Meilisearch\Contracts\DocumentsQuery;
|
use Meilisearch\Contracts\DocumentsQuery;
|
||||||
use Meilisearch\Endpoints\Indexes;
|
use Meilisearch\Endpoints\Indexes;
|
||||||
use Meilisearch\Exceptions\ApiException;
|
use Meilisearch\Exceptions\ApiException;
|
||||||
|
use Meilisearch\Search\SearchResult;
|
||||||
|
|
||||||
final class Index
|
final class Index
|
||||||
{
|
{
|
||||||
|
@ -446,6 +448,33 @@ final class Index
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function searchMedia(
|
||||||
|
string $query,
|
||||||
|
?StationPlaylist $playlist = null
|
||||||
|
): array {
|
||||||
|
$searchParams = [
|
||||||
|
'hitsPerPage' => PHP_INT_MAX,
|
||||||
|
'page' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (null !== $playlist) {
|
||||||
|
$station = $playlist->getStation();
|
||||||
|
$searchParams['filter'] = [
|
||||||
|
[
|
||||||
|
'station_' . $station->getIdRequired() . '_playlists = ' . $playlist->getIdRequired(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var SearchResult $searchResult */
|
||||||
|
$searchResult = $this->indexClient->search(
|
||||||
|
$query,
|
||||||
|
$searchParams
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_column($searchResult->getHits(), 'id');
|
||||||
|
}
|
||||||
|
|
||||||
/** @return int[] */
|
/** @return int[] */
|
||||||
private function getStationIds(): array
|
private function getStationIds(): array
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue