From 242dd6fe99daef46be921abf0bc1ddabbd06290e Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Sat, 28 Jun 2025 15:15:49 -0500 Subject: [PATCH] wip: adds cache rich functionality --- assets/controllers/clear_cache_controller.js | 30 +++++++++ assets/styles/app.css | 7 +++ config/routes.yaml | 9 +++ src/Controller/TorrentioController.php | 2 +- .../Action/Command/DeleteCacheCommand.php | 18 ++++++ .../Action/Handler/DeleteCacheHandler.php | 61 +++++++++++++++++++ .../Action/Input/DeleteCacheInput.php | 49 +++++++++++++++ .../Action/Result/DeleteCacheResult.php | 15 +++++ .../Framework/Controller/ApiController.php | 21 +++++++ templates/components/Modal.html.twig | 6 +- templates/user/preferences.html.twig | 14 +++-- 11 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 assets/controllers/clear_cache_controller.js create mode 100644 src/Torrentio/Action/Command/DeleteCacheCommand.php create mode 100644 src/Torrentio/Action/Handler/DeleteCacheHandler.php create mode 100644 src/Torrentio/Action/Input/DeleteCacheInput.php create mode 100644 src/Torrentio/Action/Result/DeleteCacheResult.php create mode 100644 src/Torrentio/Framework/Controller/ApiController.php diff --git a/assets/controllers/clear_cache_controller.js b/assets/controllers/clear_cache_controller.js new file mode 100644 index 0000000..a6f8921 --- /dev/null +++ b/assets/controllers/clear_cache_controller.js @@ -0,0 +1,30 @@ +import { Controller } from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://symfony.com/bundles/StimulusBundle/current/index.html#lazy-stimulus-controllers +*/ + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + initialize() {} + + connect() {} + + disconnect() {} + + async clearAll() { + let response = await fetch('/api/torrentio/cache', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ + type: 'torrentio', + mediaType: 'tvshows', + }) + }); + response = await response.json() + } +} diff --git a/assets/styles/app.css b/assets/styles/app.css index 22d38c3..8e4e2fa 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -25,6 +25,13 @@ .alert-warning { @apply bg-yellow-500/70 hover:bg-yellow-600 border-yellow-400 text-black } + + .primary-btn { + @apply px-1 py-1 rounded-md bg-orange-500 self-end text-white w-16 ml-2 hover:bg-orange-600 + } + .secondary-btn { + @apply px-1 py-1 rounded-md self-end w-16 hover:bg-stone-100 + } } /* Prevent scrolling while dialog is open */ diff --git a/config/routes.yaml b/config/routes.yaml index 5b63236..6abaf8b 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -29,3 +29,12 @@ 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/Controller/TorrentioController.php b/src/Controller/TorrentioController.php index 2319497..296ef7b 100644 --- a/src/Controller/TorrentioController.php +++ b/src/Controller/TorrentioController.php @@ -69,7 +69,7 @@ final class TorrentioController extends AbstractController try { return $pageCache->get($cacheId, function (ItemInterface $item) use ($input) { $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0)); - $item->tag(['page', 'page.torrentio', 'page.torrentio.tvshows', "page.torrentio.tvshows.$input->tmdbId.$input->imdbId", "page.torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season", "page.torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season.$input->episode", 'torrentio', 'torrentio.tvshows', "torrentio.tvshows.$input->tmdbId.$input->imdbId", "torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season", "torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season.$input->episode"]); + $item->tag(['page', 'page.torrentio', 'page.torrentio.tvshows', "page.torrentio.tvshows.$input->tmdbId.$input->imdbId", "page.torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season", "page.torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season.$input->episode", 'torrentio', 'torrentio.tvshows', "torrentio.tvshows.$input->tmdbId.$input->imdbId", "torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season", "torrentio.tvshows.$input->tmdbId.$input->imdbId.$input->season.$input->episode", $input->imdbId, $input->tmdbId]); $results = $this->getTvShowOptionsHandler->handle($input->toCommand()); return $this->render('torrentio/tvshows.html.twig', [ 'results' => $results, diff --git a/src/Torrentio/Action/Command/DeleteCacheCommand.php b/src/Torrentio/Action/Command/DeleteCacheCommand.php new file mode 100644 index 0000000..60f4bad --- /dev/null +++ b/src/Torrentio/Action/Command/DeleteCacheCommand.php @@ -0,0 +1,18 @@ + */ +class DeleteCacheHandler implements HandlerInterface +{ + public function __construct( + private readonly TagAwareCacheInterface $torrentioCache + ) {} + + public function handle(CommandInterface $command): ResultInterface + { + $input = Map::from((array) $command) + ->filter(fn ($value, $key) => null !== $value && "" !== $value) + ; + + $cacheKey = null; + if ($input->has('type')) { + $cacheKey = $input->get('type'); + + if ($input->has('mediaType')) { + $cacheKey .= ".".$input->get('mediaType'); + + if ($input->has('tmdbId')) { + $cacheKey .= ".".$input->get('tmdbId'); + + if ($input->has('imdbId')) { + $cacheKey .= ".".$input->get('imdbId'); + + if ($input->has('season')) { + $cacheKey .= ".".$input->get('season'); + + if ($input->has('episode')) { + $cacheKey .= ".".$input->get('episode'); + } + } + } + } + } + } + + if ($cacheKey !== null) { + $this->torrentioCache->invalidateTags([$cacheKey]); + } + + if ($input->has('tags')) { + $this->torrentioCache->invalidateTags($input->get('tags')); + } + + return new DeleteCacheResult($input, $cacheKey, $command->tags); + } +} diff --git a/src/Torrentio/Action/Input/DeleteCacheInput.php b/src/Torrentio/Action/Input/DeleteCacheInput.php new file mode 100644 index 0000000..4fb29a1 --- /dev/null +++ b/src/Torrentio/Action/Input/DeleteCacheInput.php @@ -0,0 +1,49 @@ + + */ +class DeleteCacheInput implements InputInterface +{ + public function __construct( + #[SourceRequest('type', nullify: true)] + public ?string $type, + + #[SourceRequest('mediaType', nullify: true)] + public ?string $mediaType, + + #[SourceRequest('tmdbId', nullify: true)] + public ?string $tmdbId, + + #[SourceRequest('imdbId', nullify: true)] + public ?string $imdbId, + + #[SourceRequest('season', nullify: true)] + public ?int $season, + + #[SourceRequest('episode', nullify: true)] + public ?int $episode, + + #[SourceRequest('tags', nullify: true)] + public ?array $tags, + ) {} + + public function toCommand(): CommandInterface + { + return new DeleteCacheCommand( + type: $this->type, + mediaType: $this->mediaType, + tmdbId: $this->tmdbId, + imdbId: $this->imdbId, + season: $this->season, + episode: $this->episode + ); + } +} diff --git a/src/Torrentio/Action/Result/DeleteCacheResult.php b/src/Torrentio/Action/Result/DeleteCacheResult.php new file mode 100644 index 0000000..9106fd9 --- /dev/null +++ b/src/Torrentio/Action/Result/DeleteCacheResult.php @@ -0,0 +1,15 @@ +handle($deleteCacheInput->toCommand()); + return $this->json($result, Response::HTTP_OK); + } +} diff --git a/templates/components/Modal.html.twig b/templates/components/Modal.html.twig index 91e6ea9..bf0903a 100644 --- a/templates/components/Modal.html.twig +++ b/templates/components/Modal.html.twig @@ -9,12 +9,12 @@ {% if show_cancel is defined or show_submit is defined %}
{% if show_cancel is defined %} - {% endif %} {% if show_submit is defined %} - {% endif %} @@ -22,5 +22,5 @@ {% endif %} - +
\ No newline at end of file diff --git a/templates/user/preferences.html.twig b/templates/user/preferences.html.twig index ff7de51..661b894 100644 --- a/templates/user/preferences.html.twig +++ b/templates/user/preferences.html.twig @@ -3,11 +3,15 @@ {% block h2 %}Preferences{% endblock %} {% block action_buttons %} - +
+ + This will clear the TMDB, Torrentio, and application cache. Clearing the cache is safe, but may lead to + slower page loads and rate limits by Torrentio. Would you like to proceed? + +
{% endblock %} {% block body %}