diff --git a/assets/controllers/download_button_controller.js b/assets/controllers/download_button_controller.js new file mode 100644 index 0000000..9cffbab --- /dev/null +++ b/assets/controllers/download_button_controller.js @@ -0,0 +1,37 @@ +import { Controller } from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static values = { + url: String, + title: String, + filename: String, + mediaType: String, + imdbId: String, + } + + download() { + fetch('/download', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ + url: this.urlValue, + title: this.titleValue, + filename: this.filenameValue, + mediaType: this.mediaTypeValue, + imdbId: this.imdbIdValue + }) + }) + .then(res => res.json()) + .then(json => { + console.log(json) + }) + } +} diff --git a/assets/controllers/movie_results_controller.js b/assets/controllers/movie_results_controller.js index 49a7668..a59af7b 100644 --- a/assets/controllers/movie_results_controller.js +++ b/assets/controllers/movie_results_controller.js @@ -7,6 +7,7 @@ import { Controller } from '@hotwired/stimulus'; /* stimulusFetch: 'lazy' */ export default class extends Controller { static values = { + tmdbId: String, imdbId: String }; @@ -20,7 +21,7 @@ export default class extends Controller { async setOptions() { if (this.options.length === 0) { - await fetch(`/torrentio/movies/${this.imdbIdValue}`) + await fetch(`/torrentio/movies/${this.tmdbIdValue}/${this.imdbIdValue}`) .then(res => res.text()) .then(response => { this.element.innerHTML = response; diff --git a/composer.json b/composer.json index 248b6e7..987ac94 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "php-tmdb/api": "^4.1", "symfony/asset": "7.2.*", "symfony/console": "7.2.*", + "symfony/doctrine-messenger": "7.2.*", "symfony/dotenv": "7.2.*", "symfony/flex": "^2", "symfony/form": "7.2.*", diff --git a/composer.lock b/composer.lock index 2e6f4d1..1fc4b62 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eeaaf3d88479bdcd00dcb637222408f4", + "content-hash": "0448ecb537f5d169d81a56ba2b3c2cc6", "packages": [ { "name": "1tomany/data-uri", @@ -3469,6 +3469,78 @@ ], "time": "2025-03-25T15:54:33+00:00" }, + { + "name": "symfony/doctrine-messenger", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-messenger.git", + "reference": "c353e6ee6b41748d8ea6faa2d0b84ac501e3ec0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/c353e6ee6b41748d8ea6faa2d0b84ac501e3ec0c", + "reference": "c353e6ee6b41748d8ea6faa2d0b84ac501e3ec0c", + "shasum": "" + }, + "require": { + "doctrine/dbal": "^3.6|^4", + "php": ">=8.2", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "symfony-messenger-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Doctrine Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-messenger/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-25T15:54:33+00:00" + }, { "name": "symfony/dotenv", "version": "v7.2.0", diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml index 3ef0967..ca007a4 100644 --- a/config/packages/messenger.yaml +++ b/config/packages/messenger.yaml @@ -5,14 +5,7 @@ framework: transports: # https://symfony.com/doc/current/messenger.html#transport-configuration - async: - dsn: '%env(MESSENGER_TRANSPORT_DSN)%' - options: - use_notify: true - check_delayed_interval: 60000 - retry_strategy: - max_retries: 1 - multiplier: 1 + async: '%env(MESSENGER_TRANSPORT_DSN)%' failed: 'doctrine://default?queue_name=failed' default_bus: messenger.bus.default diff --git a/src/Controller/DownloadController.php b/src/Controller/DownloadController.php index 86398b8..d955046 100644 --- a/src/Controller/DownloadController.php +++ b/src/Controller/DownloadController.php @@ -18,7 +18,11 @@ class DownloadController extends AbstractController public function download( DownloadMediaInput $input, ): Response { - $this->bus->dispatch($input->toCommand()); + try { + $this->bus->dispatch($input->toCommand()); + } catch (\Throwable $exception) { + return $this->json(['error' => $exception->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR); + } return $this->json(['status' => 200, 'message' => 'Added to Queue']); } diff --git a/src/Controller/TorrentioController.php b/src/Controller/TorrentioController.php index 52c4d9b..e34e269 100644 --- a/src/Controller/TorrentioController.php +++ b/src/Controller/TorrentioController.php @@ -17,7 +17,7 @@ final class TorrentioController extends AbstractController private readonly GetTvShowOptionsHandler $getTvShowOptionsHandler, ) {} - #[Route('/torrentio/movies/{imdbId}', name: 'app_torrentio_movies')] + #[Route('/torrentio/movies/{tmdbId}/{imdbId}', name: 'app_torrentio_movies')] public function movieOptions(GetMovieOptionsInput $input): Response { $results = $this->getMovieOptionsHandler->handle($input->toCommand()); diff --git a/src/Torrentio/Action/Command/GetMovieOptionsCommand.php b/src/Torrentio/Action/Command/GetMovieOptionsCommand.php index 8dfeb75..cccac16 100644 --- a/src/Torrentio/Action/Command/GetMovieOptionsCommand.php +++ b/src/Torrentio/Action/Command/GetMovieOptionsCommand.php @@ -7,6 +7,7 @@ use OneToMany\RichBundle\Contract\CommandInterface; class GetMovieOptionsCommand implements CommandInterface { public function __construct( + public string $tmdbId, public string $imdbId, ) {} } diff --git a/src/Torrentio/Action/Handler/GetMovieOptionsHandler.php b/src/Torrentio/Action/Handler/GetMovieOptionsHandler.php index aebbd4f..f9e6ea8 100644 --- a/src/Torrentio/Action/Handler/GetMovieOptionsHandler.php +++ b/src/Torrentio/Action/Handler/GetMovieOptionsHandler.php @@ -2,6 +2,7 @@ namespace App\Torrentio\Action\Handler; +use App\Tmdb\Tmdb; use App\Torrentio\Action\Result\GetMovieOptionsResult; use App\Torrentio\Client\Torrentio; use OneToMany\RichBundle\Contract\CommandInterface; @@ -11,13 +12,15 @@ use OneToMany\RichBundle\Contract\ResultInterface; class GetMovieOptionsHandler implements HandlerInterface { public function __construct( + private readonly Tmdb $tmdb, private readonly Torrentio $torrentio, ) {} public function handle(CommandInterface $command): ResultInterface { return new GetMovieOptionsResult( - results: $this->torrentio->search($command->imdbId, 'movies') + media: $this->tmdb->mediaDetails($command->tmdbId, 'movies'), + results: $this->torrentio->search($command->imdbId, 'movies'), ); } } diff --git a/src/Torrentio/Action/Input/GetMovieOptionsInput.php b/src/Torrentio/Action/Input/GetMovieOptionsInput.php index b5a9653..8aac9bf 100644 --- a/src/Torrentio/Action/Input/GetMovieOptionsInput.php +++ b/src/Torrentio/Action/Input/GetMovieOptionsInput.php @@ -10,12 +10,15 @@ use OneToMany\RichBundle\Contract\InputInterface; class GetMovieOptionsInput implements InputInterface { public function __construct( + #[SourceRoute('tmdbId')] + public string $tmdbId, + #[SourceRoute('imdbId')] public string $imdbId, ) {} public function toCommand(): CommandInterface { - return new GetMovieOptionsCommand($this->imdbId); + return new GetMovieOptionsCommand($this->tmdbId, $this->imdbId); } } diff --git a/src/Torrentio/Action/Result/GetMovieOptionsResult.php b/src/Torrentio/Action/Result/GetMovieOptionsResult.php index 4e77a33..6d63c9a 100644 --- a/src/Torrentio/Action/Result/GetMovieOptionsResult.php +++ b/src/Torrentio/Action/Result/GetMovieOptionsResult.php @@ -2,11 +2,13 @@ namespace App\Torrentio\Action\Result; +use App\Tmdb\TmdbResult; use OneToMany\RichBundle\Contract\ResultInterface; class GetMovieOptionsResult implements ResultInterface { public function __construct( + public TmdbResult $media, public array $results ) {} } diff --git a/src/Torrentio/Result/ResultFactory.php b/src/Torrentio/Result/ResultFactory.php index c9afd00..fc9950d 100644 --- a/src/Torrentio/Result/ResultFactory.php +++ b/src/Torrentio/Result/ResultFactory.php @@ -15,7 +15,8 @@ class ResultFactory $ptn = (object) (new PTN())->parse($title); return new TorrentioResult( self::trimTitle($title), - $url, + urldecode($url), + self::setFilename($url), self::setSize($title), self::setSeeders($title), self::setProvider($title), @@ -33,6 +34,12 @@ class ResultFactory ); } + public static function setFilename(string $url) + { + $file = explode("/", urldecode($url)); + return end($file); + } + public static function setSize(string $title): string { $sizeMatch = []; diff --git a/src/Torrentio/Result/TorrentioResult.php b/src/Torrentio/Result/TorrentioResult.php index fbdef74..f731591 100644 --- a/src/Torrentio/Result/TorrentioResult.php +++ b/src/Torrentio/Result/TorrentioResult.php @@ -7,6 +7,7 @@ class TorrentioResult public function __construct( public ?string $title = "-", public ?string $url = "-", + public ?string $filename = "-", public ?string $size = "-", public ?string $seeders = "-", public ?string $provider = "-", diff --git a/templates/search/result.html.twig b/templates/search/result.html.twig index 06b977d..d95acaa 100644 --- a/templates/search/result.html.twig +++ b/templates/search/result.html.twig @@ -27,7 +27,7 @@ {{ include('search/partial/filter.html.twig') }} {% if "movies" == results.media.mediaType %} -