diff --git a/config/routes.yaml b/config/routes.yaml index 28766ec..29a5f58 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -6,6 +6,14 @@ controllersBase: defaults: schemes: [ 'https' ] +controllersLibrary: + resource: + path: ../src/Library/Framework/Controller/ + namespace: App\Library\Framework\Controller + type: attribute + defaults: + schemes: [ 'https' ] + controllersSearch: resource: path: ../src/Search/Framework/Controller/ diff --git a/src/Library/Action/Command/SearchCommand.php b/src/Library/Action/Command/SearchCommand.php new file mode 100644 index 0000000..00a6728 --- /dev/null +++ b/src/Library/Action/Command/SearchCommand.php @@ -0,0 +1,16 @@ + + */ +class SearchHandler implements HandlerInterface +{ + private array $searchTypes = [ + 'episode_by_title' => 'episodeByTitle', + ]; + + public function __construct( + private readonly MediaFiles $mediaFiles, + ) {} + + public function handle(CommandInterface $command): ResultInterface + { + $searchType = $this->getSearchType($command); + $function = $this->searchTypes[$searchType]; + return $this->$function($command); + } + + private function getSearchType(CommandInterface $command): ?string + { + if ((!is_null($command->title) || is_null($command->imdbId)) && + !is_null($command->season) && + !is_null($command->episode) + ) { + return 'episode_by_title'; + } + return null; + } + + private function episodeByTitle(CommandInterface $command): ?SearchResult + { + $result = $this->mediaFiles->episodeExists( + $command->title, + (int) $command->season, + (int) $command->episode, + ); + + $exists = $result instanceof \SplFileInfo; + + return new SearchResult( + input: $command, + message: 'Success', + code: 200, + data: [ + 'exists' => $exists, + 'file' => true === $exists ? ['filename' => $result->getFilename(), 'size' => $result->getSize()] : null, + ] + ); + } +} diff --git a/src/Library/Action/Input/SearchInput.php b/src/Library/Action/Input/SearchInput.php new file mode 100644 index 0000000..32cdf0b --- /dev/null +++ b/src/Library/Action/Input/SearchInput.php @@ -0,0 +1,38 @@ + + */ +class SearchInput implements InputInterface +{ + public function __construct( + #[SourceQuery('term', nullify: true)] + private ?string $term = null, + #[SourceQuery('title', nullify: true)] + private ?string $title = null, + #[SourceQuery('imdbId', nullify: true)] + private ?string $imdbId = null, + #[SourceQuery('season', nullify: true)] + private ?string $season = null, + #[SourceQuery('episode', nullify: true)] + private ?string $episode = null, + ) {} + + public function toCommand(): CommandInterface + { + return new SearchCommand( + term: $this->term, + title: $this->title, + imdbId: $this->imdbId, + season: $this->season, + episode: $this->episode, + ); + } +} diff --git a/src/Library/Action/Result/SearchResult.php b/src/Library/Action/Result/SearchResult.php new file mode 100644 index 0000000..2dce110 --- /dev/null +++ b/src/Library/Action/Result/SearchResult.php @@ -0,0 +1,15 @@ +handle($input->toCommand()); + + if ($request->headers->get('Turbo-Frame')) { + return $this->sendFragmentResponse($result, $request); + } + + return $this->json($handler->handle($input->toCommand())); + } + + private function sendFragmentResponse(SearchResult $result, Request $request): Response + { + $request->setRequestFormat(TurboBundle::STREAM_FORMAT); + return $this->renderBlock( + 'search/fragments.html.twig', + $request->query->get('block'), + [ + 'result' => $result, + 'target' => $request->query->get('target') + ] + ); + } +} diff --git a/src/Search/Action/Handler/GetMediaInfoHandler.php b/src/Search/Action/Handler/GetMediaInfoHandler.php index a514d5e..c4ce8c6 100644 --- a/src/Search/Action/Handler/GetMediaInfoHandler.php +++ b/src/Search/Action/Handler/GetMediaInfoHandler.php @@ -15,19 +15,12 @@ class GetMediaInfoHandler implements HandlerInterface { public function __construct( private readonly Tmdb $tmdb, - private readonly MediaFiles $mediaFiles ) {} public function handle(CommandInterface $command): ResultInterface { $media = $this->tmdb->mediaDetails($command->imdbId, $command->mediaType); - if ("tvshows" === $command->mediaType) { - foreach ($media->episodes[$command->season] as $key => $episode) { - $media->episodes[$command->season][$key]['file'] = $this->mediaFiles->episodeExists($media->title, $command->season, $episode['episode_number']); - } - } - return new GetMediaInfoResult($media, $command->season); } } diff --git a/src/Twig/Extensions/UtilExtension.php b/src/Twig/Extensions/UtilExtension.php index 436b67a..a591490 100644 --- a/src/Twig/Extensions/UtilExtension.php +++ b/src/Twig/Extensions/UtilExtension.php @@ -47,7 +47,7 @@ class UtilExtension } #[AsTwigFilter('episode_id_from_results')] - public function episodeId($result): ?string + public function episodeIdFromResults($result): ?string { if (!$result instanceof GetTvShowOptionsResult) { return null; @@ -56,4 +56,11 @@ class UtilExtension return "S". str_pad($result->season, 2, "0", STR_PAD_LEFT) . "E". str_pad($result->episode, 2, "0", STR_PAD_LEFT); } + + #[AsTwigFunction('episode_id')] + public function episodeId($season, $episode): ?string + { + return "S". str_pad($season, 2, "0", STR_PAD_LEFT) . + "E". str_pad($episode, 2, "0", STR_PAD_LEFT); + } } diff --git a/templates/components/TvEpisodeList.html.twig b/templates/components/TvEpisodeList.html.twig index e58fde7..7d1a800 100644 --- a/templates/components/TvEpisodeList.html.twig +++ b/templates/components/TvEpisodeList.html.twig @@ -40,30 +40,17 @@ {{ episode['air_date']|date(null, 'UTC') }} - {% if episode['file'] != false %} - - - - exists - - - {% endif %} - - {% if episode['file'] == false %} + missing - {% endif %} +
diff --git a/templates/search/fragments.html.twig b/templates/search/fragments.html.twig new file mode 100644 index 0000000..798a049 --- /dev/null +++ b/templates/search/fragments.html.twig @@ -0,0 +1,32 @@ +{% block media_exists_badge %} + + + +{% endblock %} \ No newline at end of file