From b98d1600cc3eb155a6aaad581648bb4c0ff639bf Mon Sep 17 00:00:00 2001 From: Buster Neece Date: Mon, 30 Jan 2023 10:04:56 -0600 Subject: [PATCH] Allow searching media inside playlists ("chaining" media search queries). --- .../Api/Stations/Files/ListAction.php | 84 ++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/Controller/Api/Stations/Files/ListAction.php b/src/Controller/Api/Stations/Files/ListAction.php index 0c529a2d4..3c75f8d22 100644 --- a/src/Controller/Api/Stations/Files/ListAction.php +++ b/src/Controller/Api/Stations/Files/ListAction.php @@ -130,29 +130,34 @@ final class ListAction $mediaQueryBuilder->andWhere( 'sm.id NOT IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2)' ); - } elseif (str_starts_with($searchPhrase, 'playlist:')) { - [, $playlistName] = explode(':', $searchPhrase, 2); + } else { + if (str_contains($searchPhrase, 'playlist:')) { + preg_match('/playlist:(\w*)/', $searchPhrase, $matches, PREG_UNMATCHED_AS_NULL); - $playlist = $this->em->getRepository(Entity\StationPlaylist::class) - ->findOneBy( - [ - 'station' => $station, - 'name' => $playlistName, - ] - ); + if ($matches[1]) { + $playlist = $this->em->getRepository(Entity\StationPlaylist::class) + ->findOneBy( + [ + 'station' => $station, + 'name' => $matches[1], + ] + ); - if (!$playlist instanceof Entity\StationPlaylist) { - return $response->withStatus(400) - ->withJson(new Entity\Api\Error(400, 'Playlist not found.')); + if ($playlist instanceof Entity\StationPlaylist) { + $mediaQueryBuilder->andWhere( + 'sm.id IN (SELECT spm2.media_id FROM App\Entity\StationPlaylistMedia spm2 ' + . 'WHERE spm2.playlist = :playlist)' + )->setParameter('playlist', $playlist); + } + + $searchPhrase = trim(str_replace($matches[0] ?? '', '', $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 . '%'); + if (!in_array($searchPhrase, ['*', '%'], true)) { + $mediaQueryBuilder->andWhere('(sm.title LIKE :query OR sm.artist LIKE :query)') + ->setParameter('query', '%' . $searchPhrase . '%'); + } } $mediaQuery = $mediaQueryBuilder->getQuery(); @@ -246,7 +251,7 @@ final class ListAction $unprocessableMedia[$unprocessableRow['path']] = $unprocessableRow['error']; } - if (!empty($searchPhrase)) { + if ($isSearch) { if ('special:unprocessable' === $searchPhrase) { $files = array_keys($unprocessableMedia); } else { @@ -284,7 +289,7 @@ final class ListAction $row->size = ($row->is_dir) ? 0 : $fs->fileSize($row->path); - $shortname = (!empty($searchPhrase)) + $shortname = ($isSearch) ? $row->path : basename($row->path); @@ -325,21 +330,27 @@ final class ListAction } // Apply sorting - [$sort, $sortOrder] = $this->getSortFromRequest($request); + if ('special:duplicates' === $searchPhrase) { + usort( + $result, + static fn(Entity\Api\FileList $a, Entity\Api\FileList $b) => $a->media->id <=> $b->media->id + ); + } else { + [$sort, $sortOrder] = $this->getSortFromRequest($request); - $propertyAccessor = self::getPropertyAccessor(); + $propertyAccessor = self::getPropertyAccessor(); - usort( - $result, - static fn(Entity\Api\FileList $a, Entity\Api\FileList $b) => self::sortRows( - $a, - $b, - $propertyAccessor, - $searchPhrase, - $sort, - $sortOrder - ) - ); + usort( + $result, + static fn(Entity\Api\FileList $a, Entity\Api\FileList $b) => self::sortRows( + $a, + $b, + $propertyAccessor, + $sort, + $sortOrder + ) + ); + } $paginator = Paginator::fromArray($result, $request); @@ -357,14 +368,9 @@ final class ListAction Entity\Api\FileList $a, Entity\Api\FileList $b, PropertyAccessorInterface $propertyAccessor, - ?string $searchPhrase = null, ?string $sort = null, string $sortOrder = Criteria::ASC ): int { - if ('special:duplicates' === $searchPhrase) { - return $a->media->id <=> $b->media->id; - } - $isDirComp = $b->is_dir <=> $a->is_dir; if (0 !== $isDirComp) { return $isDirComp;