From d6cbb53da64efeaec6ef0c46e164ebd858769335 Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Fri, 4 Jul 2025 14:57:39 -0500 Subject: [PATCH] feat: adds torrentio api endpoint --- config/routes.yaml | 8 ++ src/Torrentio/Client/Torrentio.php | 31 +++-- .../Framework/Controller/ApiController.php | 116 ++++++++++++++++++ .../Framework/Controller/WebController.php} | 10 +- 4 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 src/Torrentio/Framework/Controller/ApiController.php rename src/{Controller/TorrentioController.php => Torrentio/Framework/Controller/WebController.php} (92%) diff --git a/config/routes.yaml b/config/routes.yaml index 5b63236..8fc8973 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -29,3 +29,11 @@ controllersMonitor: type: attribute defaults: schemes: ['https'] + +controllersTorrentio: + resource: + path: ../src/Torrentio/Framework/Controller + namespace: App\Torrentio\Framework\Controller + type: attribute + defaults: + schemes: ['https'] diff --git a/src/Torrentio/Client/Torrentio.php b/src/Torrentio/Client/Torrentio.php index d9fef60..3ab0d3d 100644 --- a/src/Torrentio/Client/Torrentio.php +++ b/src/Torrentio/Client/Torrentio.php @@ -32,7 +32,7 @@ class Torrentio ]); } - public function search(string $imdbCode, string $type, array $filter = []): array + public function search(string $imdbCode, string $type, bool $parseResults = true): array { $cacheKey = "torrentio.{$imdbCode}"; @@ -56,10 +56,14 @@ class Torrentio return []; }); - return $this->parse($results, $filter); + if (true === $parseResults) { + return $this->parse($results); + } + + return $results; } - public function fetchEpisodeResults(string $imdbId, int $season, int $episode): array + public function fetchEpisodeResults(string $imdbId, int $season, int $episode, bool $parseResults = true): array { $cacheKey = "torrentio.$imdbId.$season.$episode"; $results = $this->cache->get($cacheKey, function (ItemInterface $item) use ($imdbId, $season, $episode) { @@ -86,18 +90,15 @@ class Torrentio throw new TorrentioRateLimitException(); } - return $this->parse($results, []); - } - - public function parse(array $data, array $filter): array - { - $ruleEngine = new RuleEngine(); - foreach ($filter as $rule => $value) { - if ('resolution' === $rule) { - $ruleEngine->addRule(new Resolution($value)); - } + if (true === $parseResults) { + return $this->parse($results); } + return $results; + } + + public function parse(array $data): array + { $results = []; foreach ($data['streams'] as $stream) { if (!str_starts_with($stream['url'], "https")) { @@ -119,9 +120,7 @@ class Torrentio $bingeGroup ); - if ($ruleEngine->validateAll($result)) { - $results[] = $result; - } + $results[] = $result; } return $results; diff --git a/src/Torrentio/Framework/Controller/ApiController.php b/src/Torrentio/Framework/Controller/ApiController.php new file mode 100644 index 0000000..9b76927 --- /dev/null +++ b/src/Torrentio/Framework/Controller/ApiController.php @@ -0,0 +1,116 @@ +json( + $this->torrentio->fetchEpisodeResults($imdbId, $season, $episode, false) + ); + } + return $this->json( + $this->torrentio->search($imdbId, 'movies', false), + ); + } + + #[Route('/torrentio/movies/{tmdbId}/{imdbId}', name: 'app_torrentio_movies')] + public function movieOptions(GetMovieOptionsInput $input, CacheInterface $cache): Response + { + $cacheId = sprintf( + "page.torrentio.movies.%s.%s", + $input->tmdbId, + $input->imdbId + ); + + return $cache->get($cacheId, function (ItemInterface $item) use ($input) { + $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); + $results = $this->getMovieOptionsHandler->handle($input->toCommand()); + return $this->render('torrentio/movies.html.twig', [ + 'results' => $results, + ]); + }); + } + + #[Route('/torrentio/tvshows/{tmdbId}/{imdbId}/{season?}/{episode?}', name: 'app_torrentio_tvshows')] + public function tvShowOptions(GetTvShowOptionsInput $input, CacheInterface $cache): Response + { + $cacheId = sprintf( + "page.torrentio.tvshows.%s.%s.%s.%s", + $input->tmdbId, + $input->imdbId, + $input->season, + $input->episode, + ); + + try { +// return $cache->get($cacheId, function (ItemInterface $item) use ($input) { +// $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); + $results = $this->getTvShowOptionsHandler->handle($input->toCommand()); + return $this->render('torrentio/tvshows.html.twig', [ + 'results' => $results, + ]); +// }); + } catch (TorrentioRateLimitException $exception) { + $this->broadcaster->alert('Warning', 'Torrentio has rate limited your requests. Please wait a few minutes before trying again.', 'warning'); + return $this->render('bare.html.twig', + [], + new Response('Too many requests', + Response::HTTP_TOO_MANY_REQUESTS, + ['Retry-After' => 4000] + ) + ); + } + } + + #[Route('/torrentio/tvshows/clear/{tmdbId}/{imdbId}/{season?}/{episode?}', name: 'app_clear_torrentio_tvshows')] + public function clearTvShowOptions(GetTvShowOptionsInput $input, CacheInterface $cache, Request $request): Response + { + $cacheId = sprintf( + "page.torrentio.tvshows.%s.%s.%s.%s", + $input->tmdbId, + $input->imdbId, + $input->season, + $input->episode, + ); + $cache->delete($cacheId); + + $this->broadcaster->alert( + title: 'Success', + message: 'Torrentio cache Cleared.' + ); + + return $cache->get($cacheId, function (ItemInterface $item) use ($input) { + $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); + $results = $this->getTvShowOptionsHandler->handle($input->toCommand()); + return $this->render('torrentio/tvshows.html.twig', [ + 'results' => $results, + ]); + }); + } +} diff --git a/src/Controller/TorrentioController.php b/src/Torrentio/Framework/Controller/WebController.php similarity index 92% rename from src/Controller/TorrentioController.php rename to src/Torrentio/Framework/Controller/WebController.php index c5ea21b..a7b912d 100644 --- a/src/Controller/TorrentioController.php +++ b/src/Torrentio/Framework/Controller/WebController.php @@ -1,6 +1,6 @@ get($cacheId, function (ItemInterface $item) use ($input) { - $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); +// return $cache->get($cacheId, function (ItemInterface $item) use ($input) { +// $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); $results = $this->getTvShowOptionsHandler->handle($input->toCommand()); return $this->render('torrentio/tvshows.html.twig', [ 'results' => $results, ]); - }); +// }); } catch (TorrentioRateLimitException $exception) { $this->broadcaster->alert('Warning', 'Torrentio has rate limited your requests. Please wait a few minutes before trying again.', 'warning'); return $this->render('bare.html.twig',