wip-feat: dispatches monitor commands for episodes, seasons, & shows
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,3 +13,7 @@
|
||||
/public/assets/
|
||||
/assets/vendor/
|
||||
###< symfony/asset-mapper ###
|
||||
|
||||
###> phpstan/phpstan ###
|
||||
phpstan.neon
|
||||
###< phpstan/phpstan ###
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"symfony/console": "7.2.*",
|
||||
"symfony/doctrine-messenger": "7.2.*",
|
||||
"symfony/dotenv": "7.2.*",
|
||||
"symfony/finder": "7.2.*",
|
||||
"symfony/flex": "^2",
|
||||
"symfony/form": "7.2.*",
|
||||
"symfony/framework-bundle": "7.2.*",
|
||||
@@ -95,6 +96,7 @@
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"symfony/maker-bundle": "^1.62",
|
||||
"symfony/stopwatch": "7.2.*",
|
||||
"symfony/web-profiler-bundle": "7.2.*"
|
||||
|
||||
60
composer.lock
generated
60
composer.lock
generated
@@ -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": "97689e103d8e0ba79aba71891384895d",
|
||||
"content-hash": "1acedc6a795947368d0673ec79564bec",
|
||||
"packages": [
|
||||
{
|
||||
"name": "1tomany/rich-bundle",
|
||||
@@ -8488,6 +8488,64 @@
|
||||
},
|
||||
"time": "2024-12-30T11:07:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f2e03099cac24ff3b379864d171c5acbfc6b9a2",
|
||||
"reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
},
|
||||
"bin": [
|
||||
"phpstan",
|
||||
"phpstan.phar"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpstan.org/user-guide/getting-started",
|
||||
"forum": "https://github.com/phpstan/phpstan/discussions",
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"security": "https://github.com/phpstan/phpstan/security/policy",
|
||||
"source": "https://github.com/phpstan/phpstan-src"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ondrejmirtes",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/phpstan",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-02T15:32:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/maker-bundle",
|
||||
"version": "v1.63.0",
|
||||
|
||||
@@ -25,6 +25,7 @@ framework:
|
||||
# Route your messages to the transports
|
||||
# 'App\Message\YourMessage': async
|
||||
'App\Download\Action\Command\DownloadMediaCommand': async
|
||||
'App\Download\Action\Command\MonitorTvEpisodeCommand': async
|
||||
|
||||
# when@test:
|
||||
# framework:
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
media.default_movies_dir: movies
|
||||
media.default_tvshows_dir: tvshows
|
||||
media.movies_path: '/var/download/%env(default:media.default_movies_dir:MOVIES_PATH)%'
|
||||
media.tvshows_path: '/var/download/%env(default:media.default_tvshows_dir:TVSHOWS_PATH)%'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
|
||||
53
migrations/Version20250505211458.php
Normal file
53
migrations/Version20250505211458.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250505211458 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE monitor (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, title VARCHAR(255) DEFAULT NULL, imdb_id VARCHAR(255) NOT NULL, tmdb_id VARCHAR(255) NOT NULL, status VARCHAR(255) NOT NULL, search_count INT DEFAULT NULL, last_search DATETIME DEFAULT NULL, created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', downloaded_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', monitor_type VARCHAR(255) NOT NULL, season INT DEFAULT NULL, episode INT DEFAULT NULL, INDEX IDX_E1159985A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE monitor ADD CONSTRAINT FK_E1159985A76ED395 FOREIGN KEY (user_id) REFERENCES user (id)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE movie_monitor DROP FOREIGN KEY FK_C183DBABA76ED395
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE movie_monitor
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE movie_monitor (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, title VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, imdb_id VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, tmdb_id VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, status VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, search_count INT DEFAULT NULL, last_search DATETIME DEFAULT NULL, created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', downloaded_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', INDEX IDX_C183DBABA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = ''
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE movie_monitor ADD CONSTRAINT FK_C183DBABA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE monitor DROP FOREIGN KEY FK_E1159985A76ED395
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE monitor
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
8
phpstan.dist.neon
Normal file
8
phpstan.dist.neon
Normal file
@@ -0,0 +1,8 @@
|
||||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- bin/
|
||||
- config/
|
||||
- public/
|
||||
- src/
|
||||
- tests/
|
||||
@@ -3,11 +3,18 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Handler\AddMovieMonitorHandler;
|
||||
use App\Download\Action\Command\MonitorTvSeasonCommand;
|
||||
use App\Download\Action\Command\MonitorTvShowCommand;
|
||||
use App\Download\Action\Handler\MonitorMovieHandler;
|
||||
use App\Download\Action\Input\AddMovieMonitorInput;
|
||||
use App\Download\Action\Handler\MonitorTvSeasonHandler;
|
||||
use App\Download\Action\Handler\MonitorTvShowHandler;
|
||||
use App\Download\Action\Input\DownloadMediaInput;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Download\Framework\Repository\DownloadRepository;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Download\Service\MediaFiles;
|
||||
use DateTimeImmutable;
|
||||
use Nihilarr\PTN;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
@@ -18,13 +25,28 @@ class DownloadController extends AbstractController
|
||||
public function __construct(
|
||||
private DownloadRepository $downloadRepository,
|
||||
private MessageBusInterface $bus,
|
||||
private readonly MonitorRepository $monitorRepository,
|
||||
) {}
|
||||
|
||||
#[Route('/test', name: 'app_test')]
|
||||
public function test(
|
||||
MonitorMovieHandler $handler,
|
||||
MonitorTvShowHandler $handler,
|
||||
) {
|
||||
$command = new MonitorMovieCommand(41);
|
||||
$monitor = (new Monitor())
|
||||
->setUser($this->getUser())
|
||||
->setTmdbId('95396')
|
||||
->setImdbId('tt11280740')
|
||||
->setTitle('Severance')
|
||||
->setMonitorType('tvshow')
|
||||
->setSeason(1)
|
||||
->setEpisode(null)
|
||||
->setCreatedAt(new DateTimeImmutable())
|
||||
->setSearchCount(0)
|
||||
->setStatus('New');
|
||||
$this->monitorRepository->getEntityManager()->persist($monitor);
|
||||
$this->monitorRepository->getEntityManager()->flush();
|
||||
|
||||
$command = new MonitorTvShowCommand($monitor->getId());
|
||||
$handler->handle($command);
|
||||
return $this->json([
|
||||
'status' => 200,
|
||||
@@ -53,16 +75,4 @@ class DownloadController extends AbstractController
|
||||
|
||||
return $this->json(['status' => 200, 'message' => 'Added to Queue']);
|
||||
}
|
||||
|
||||
#[Route('/monitor/movies/{tmdbId}/{imdbId}/{title}', name: 'app_add_movie_monitor', methods: ['GET', 'POST'])]
|
||||
public function addMonitor(
|
||||
AddMovieMonitorInput $input,
|
||||
AddMovieMonitorHandler $handler,
|
||||
) {
|
||||
$handler->handle($input->toCommand());
|
||||
return $this->json([
|
||||
'status' => 200,
|
||||
'message' => $input
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ namespace App\Controller;
|
||||
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Handler\MonitorMovieHandler;
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Download\Framework\Repository\DownloadRepository;
|
||||
use App\Download\Framework\Repository\MovieMonitorRepository;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Tmdb\Tmdb;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
namespace App\Download\Action\Command;
|
||||
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
|
||||
class AddMovieMonitorCommand implements CommandInterface
|
||||
class AddMonitorCommand implements CommandInterface
|
||||
{
|
||||
public function __construct(
|
||||
public string $userEmail,
|
||||
public string $title,
|
||||
public string $imdbId,
|
||||
public string $tmdbId,
|
||||
public string $monitorType,
|
||||
public ?int $season,
|
||||
public ?int $episode,
|
||||
) {}
|
||||
}
|
||||
12
src/Download/Action/Command/MonitorTvEpisodeCommand.php
Normal file
12
src/Download/Action/Command/MonitorTvEpisodeCommand.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Command;
|
||||
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
|
||||
class MonitorTvEpisodeCommand implements CommandInterface
|
||||
{
|
||||
public function __construct(
|
||||
public int $movieMonitorId,
|
||||
) {}
|
||||
}
|
||||
12
src/Download/Action/Command/MonitorTvSeasonCommand.php
Normal file
12
src/Download/Action/Command/MonitorTvSeasonCommand.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Command;
|
||||
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
|
||||
class MonitorTvSeasonCommand implements CommandInterface
|
||||
{
|
||||
public function __construct(
|
||||
public int $monitorId,
|
||||
) {}
|
||||
}
|
||||
12
src/Download/Action/Command/MonitorTvShowCommand.php
Normal file
12
src/Download/Action/Command/MonitorTvShowCommand.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Command;
|
||||
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
|
||||
class MonitorTvShowCommand implements CommandInterface
|
||||
{
|
||||
public function __construct(
|
||||
public int $monitorId,
|
||||
) {}
|
||||
}
|
||||
49
src/Download/Action/Handler/AddMonitorHandler.php
Normal file
49
src/Download/Action/Handler/AddMonitorHandler.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Handler;
|
||||
|
||||
use App\Download\Action\Command\AddMonitorCommand;
|
||||
use App\Download\Action\Result\AddMonitorResult;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\User\Framework\Repository\UserRepository;
|
||||
use DateTimeImmutable;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
/** @implements HandlerInterface<AddMonitorCommand> */
|
||||
readonly class AddMonitorHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MonitorRepository $movieMonitorRepository,
|
||||
private UserRepository $userRepository,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$user = $this->userRepository->findOneBy(['email' => $command->userEmail]);
|
||||
$monitor = (new Monitor())
|
||||
->setUser($user)
|
||||
->setTmdbId($command->tmdbId)
|
||||
->setImdbId($command->imdbId)
|
||||
->setTitle($command->title)
|
||||
->setMonitorType($command->monitorType)
|
||||
->setSeason($command->season)
|
||||
->setEpisode($command->episode)
|
||||
->setCreatedAt(new DateTimeImmutable())
|
||||
->setSearchCount(0)
|
||||
->setStatus('New');
|
||||
|
||||
$this->movieMonitorRepository->getEntityManager()->persist($monitor);
|
||||
$this->movieMonitorRepository->getEntityManager()->flush();
|
||||
|
||||
return new AddMonitorResult(
|
||||
status: 'OK',
|
||||
result: [
|
||||
'monitor' => $monitor,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Handler;
|
||||
|
||||
use App\Download\Action\Command\AddMovieMonitorCommand;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Repository\MovieMonitorRepository;
|
||||
use App\User\Framework\Repository\UserRepository;
|
||||
use DateTimeImmutable;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
/** @implements HandlerInterface<AddMovieMonitorCommand> */
|
||||
readonly class AddMovieMonitorHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MovieMonitorRepository $movieMonitorRepository,
|
||||
private UserRepository $userRepository,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$user = $this->userRepository->findOneBy(['email' => $command->userEmail]);
|
||||
$monitor = new MovieMonitor();
|
||||
$monitor->setTmdbId($command->tmdbId);
|
||||
$monitor->setImdbId($command->imdbId);
|
||||
$monitor->setTitle($command->title);
|
||||
$monitor->setUser($user);
|
||||
$monitor->setCreatedAt(new DateTimeImmutable());
|
||||
$monitor->setSearchCount(0);
|
||||
$monitor->setStatus('New');
|
||||
|
||||
$this->movieMonitorRepository->getEntityManager()->persist($monitor);
|
||||
$this->movieMonitorRepository->getEntityManager()->flush();
|
||||
|
||||
return new MonitorMovieResult(
|
||||
status: 'OK',
|
||||
result: [
|
||||
'monitor' => $monitor,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace App\Download\Action\Handler;
|
||||
use App\Download\Action\Command\DownloadMediaCommand;
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Framework\Repository\MovieMonitorRepository;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Download\Service\MonitorOptionEvaluator;
|
||||
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
|
||||
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||
@@ -21,7 +21,7 @@ use Symfony\Component\Messenger\MessageBusInterface;
|
||||
readonly class MonitorMovieHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MovieMonitorRepository $movieMonitorRepository,
|
||||
private MonitorRepository $movieMonitorRepository,
|
||||
private GetMovieOptionsHandler $getMovieOptionsHandler,
|
||||
private MonitorOptionEvaluator $monitorOptionEvaluator,
|
||||
private EntityManagerInterface $entityManager,
|
||||
@@ -36,7 +36,6 @@ readonly class MonitorMovieHandler implements HandlerInterface
|
||||
$monitor->setStatus('In Progress');
|
||||
|
||||
$this->logger->info('> [MonitorMovieHandler] Searching for "' . $monitor->getTitle() . '" download options');
|
||||
|
||||
$results = $this->getMovieOptionsHandler->handle(
|
||||
new GetMovieOptionsCommand($monitor->getTmdbId(), $monitor->getImdbId())
|
||||
);
|
||||
|
||||
76
src/Download/Action/Handler/MonitorTvEpisodeHandler.php
Normal file
76
src/Download/Action/Handler/MonitorTvEpisodeHandler.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Handler;
|
||||
|
||||
use App\Download\Action\Command\DownloadMediaCommand;
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Download\Service\MonitorOptionEvaluator;
|
||||
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
|
||||
use App\Torrentio\Action\Command\GetTvShowOptionsCommand;
|
||||
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
/** @implements HandlerInterface<MonitorMovieCommand> */
|
||||
readonly class MonitorTvEpisodeHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MonitorRepository $movieMonitorRepository,
|
||||
private GetMovieOptionsHandler $getMovieOptionsHandler,
|
||||
private MonitorOptionEvaluator $monitorOptionEvaluator,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private MessageBusInterface $bus,
|
||||
private LoggerInterface $logger,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$this->logger->info('> [MonitorTvEpisodeHandler] Executing MonitorTvEpisodeHandler');
|
||||
$monitor = $this->movieMonitorRepository->find($command->movieMonitorId);
|
||||
$monitor->setStatus('In Progress');
|
||||
|
||||
$this->logger->info('> [MonitorTvEpisodeHandler] Searching for "' . $monitor->getTitle() . '" download options');
|
||||
$results = $this->getMovieOptionsHandler->handle(
|
||||
new GetTvShowOptionsCommand(
|
||||
$monitor->getTmdbId(),
|
||||
$monitor->getImdbId(),
|
||||
$monitor->getSeason(),
|
||||
$monitor->getEpisode())
|
||||
);
|
||||
|
||||
$this->logger->info('> [MonitorTvEpisodeHandler] Found ' . count($results->results) . ' download options');
|
||||
|
||||
$result = $this->monitorOptionEvaluator->evaluateOptions($monitor, $results->results);
|
||||
|
||||
if (null !== $result) {
|
||||
$this->logger->info('> [MonitorTvEpisodeHandler] 1 result found: dispatching DownloadMediaCommand for "' . $result->title . '"');
|
||||
$this->bus->dispatch(new DownloadMediaCommand(
|
||||
$result->url,
|
||||
$monitor->getTitle(),
|
||||
$result->filename,
|
||||
'movies',
|
||||
$monitor->getImdbId(),
|
||||
));
|
||||
$monitor->setStatus('Complete');
|
||||
$monitor->setDownloadedAt(new DateTimeImmutable());
|
||||
}
|
||||
|
||||
$monitor->setLastSearch(new DateTimeImmutable());
|
||||
$monitor->setSearchCount($monitor->getSearchCount() + 1);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new MonitorMovieResult(
|
||||
status: 'OK',
|
||||
result: [
|
||||
'monitor' => $monitor,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
95
src/Download/Action/Handler/MonitorTvSeasonHandler.php
Normal file
95
src/Download/Action/Handler/MonitorTvSeasonHandler.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Handler;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\Download\Action\Command\DownloadMediaCommand;
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Command\MonitorTvEpisodeCommand;
|
||||
use App\Download\Action\Command\MonitorTvSeasonCommand;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Download\Service\MediaFiles;
|
||||
use App\Download\Service\MonitorOptionEvaluator;
|
||||
use App\Tmdb\Tmdb;
|
||||
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
|
||||
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Nihilarr\PTN;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
/** @implements HandlerInterface<MonitorMovieCommand> */
|
||||
readonly class MonitorTvSeasonHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MonitorRepository $monitorRepository,
|
||||
private GetMovieOptionsHandler $getMovieOptionsHandler,
|
||||
private MonitorOptionEvaluator $monitorOptionEvaluator,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private MediaFiles $mediaFiles,
|
||||
private MessageBusInterface $bus,
|
||||
private LoggerInterface $logger,
|
||||
private Tmdb $tmdb,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$this->logger->info('> [MonitorTvSeasonHandler] Executing MonitorTvSeasonHandler');
|
||||
$monitor = $this->monitorRepository->find($command->monitorId);
|
||||
|
||||
// Check current episodes
|
||||
$downloadedEpisodes = $this->mediaFiles
|
||||
->getEpisodes($monitor->getTitle())
|
||||
->map(fn($episode) => (object) (new PTN())->parse($episode))
|
||||
->rekey(fn($episode) => $episode->episode);
|
||||
$this->logger->info('> [MonitorTvSeasonHandler] Found ' . count($downloadedEpisodes) . ' downloaded episodes for title: ' . $monitor->getTitle());
|
||||
|
||||
// Compare against list from TMDB
|
||||
$episodesInSeason = Map::from(
|
||||
$this->tmdb->tvDetails($monitor->getTmdbId())
|
||||
->episodes[$monitor->getSeason()]
|
||||
)->rekey(fn($episode) => $episode['episode_number']);
|
||||
$this->logger->info('> [MonitorTvSeasonHandler] Found ' . count($episodesInSeason) . ' episodes in season ' . $monitor->getSeason() . ' for title: ' . $monitor->getTitle());
|
||||
|
||||
// Dispatch Episode commands for each missing Episode
|
||||
foreach ($episodesInSeason as $episode) {
|
||||
if (!array_key_exists($episode['episode_number'], $downloadedEpisodes->toArray())) {
|
||||
$monitor = (new Monitor())
|
||||
->setUser($monitor->getUser())
|
||||
->setTmdbId($monitor->getTmdbId())
|
||||
->setImdbId($monitor->getImdbId())
|
||||
->setTitle($monitor->getTitle())
|
||||
->setMonitorType('tvseason')
|
||||
->setSeason($monitor->getSeason())
|
||||
->setEpisode($episode['episode_number'])
|
||||
->setCreatedAt(new DateTimeImmutable())
|
||||
->setSearchCount(0)
|
||||
->setStatus('New');
|
||||
|
||||
$this->monitorRepository->getEntityManager()->persist($monitor);
|
||||
$this->monitorRepository->getEntityManager()->flush();
|
||||
|
||||
$command = new MonitorTvEpisodeCommand($monitor->getId());
|
||||
$this->bus->dispatch($command);
|
||||
$this->logger->info('> [MonitorTvSeasonHandler] Dispatching MonitorTvEpisodeCommand for season ' . $monitor->getSeason() . ' episode ' . $monitor->getEpisode() . ' for title: ' . $monitor->getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
$monitor->setLastSearch(new DateTimeImmutable());
|
||||
$monitor->setSearchCount($monitor->getSearchCount() + 1);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new MonitorMovieResult(
|
||||
status: 'OK',
|
||||
result: [
|
||||
'monitor' => $monitor,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
98
src/Download/Action/Handler/MonitorTvShowHandler.php
Normal file
98
src/Download/Action/Handler/MonitorTvShowHandler.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Handler;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\Download\Action\Command\DownloadMediaCommand;
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Action\Command\MonitorTvEpisodeCommand;
|
||||
use App\Download\Action\Command\MonitorTvSeasonCommand;
|
||||
use App\Download\Action\Result\MonitorMovieResult;
|
||||
use App\Download\Action\Result\MonitorTvEpisodeResult;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\Download\Service\MediaFiles;
|
||||
use App\Download\Service\MonitorOptionEvaluator;
|
||||
use App\Tmdb\Tmdb;
|
||||
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
|
||||
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Nihilarr\PTN;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
/** @implements HandlerInterface<MonitorMovieCommand> */
|
||||
readonly class MonitorTvShowHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MonitorRepository $monitorRepository,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private MediaFiles $mediaFiles,
|
||||
private MessageBusInterface $bus,
|
||||
private LoggerInterface $logger,
|
||||
private Tmdb $tmdb,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$this->logger->info('> [MonitorTvShowHandler] Executing MonitorTvShowHandler');
|
||||
$monitor = $this->monitorRepository->find($command->monitorId);
|
||||
|
||||
// Check current episodes
|
||||
$downloadedEpisodes = $this->mediaFiles
|
||||
->getEpisodes($monitor->getTitle())
|
||||
->map(fn($episode) => (object) (new PTN())->parse($episode));
|
||||
$this->logger->info('> [MonitorTvShowHandler] Found ' . count($downloadedEpisodes) . ' downloaded episodes for title: ' . $monitor->getTitle());
|
||||
|
||||
// Compare against list from TMDB
|
||||
$episodesInShow = Map::from(
|
||||
$this->tmdb->tvDetails($monitor->getTmdbId())
|
||||
->episodes
|
||||
)->flat(1);
|
||||
$this->logger->info('> [MonitorTvShowHandler] Found ' . count($episodesInShow) . ' episodes in season ' . $monitor->getSeason() . ' for title: ' . $monitor->getTitle());
|
||||
|
||||
// Dispatch Episode commands for each missing Episode
|
||||
foreach ($episodesInShow as $episode) {
|
||||
$episodeAlreadyDownloaded = $downloadedEpisodes->find(
|
||||
fn($ep) => $ep->episode === $episode['episode_number'] && $ep->season === $episode['season_number']
|
||||
);
|
||||
$episodeAlreadyDownloaded = !is_null($episodeAlreadyDownloaded);
|
||||
|
||||
if (false === $episodeAlreadyDownloaded) {
|
||||
$monitor = (new Monitor())
|
||||
->setUser($monitor->getUser())
|
||||
->setTmdbId($monitor->getTmdbId())
|
||||
->setImdbId($monitor->getImdbId())
|
||||
->setTitle($monitor->getTitle())
|
||||
->setMonitorType('tvshow')
|
||||
->setSeason($episode['season_number'])
|
||||
->setEpisode($episode['episode_number'])
|
||||
->setCreatedAt(new DateTimeImmutable())
|
||||
->setSearchCount(0)
|
||||
->setStatus('New');
|
||||
|
||||
$this->monitorRepository->getEntityManager()->persist($monitor);
|
||||
$this->monitorRepository->getEntityManager()->flush();
|
||||
|
||||
$command = new MonitorTvEpisodeCommand($monitor->getId());
|
||||
$this->bus->dispatch($command);
|
||||
$this->logger->info('> [MonitorTvShowHandler] Dispatching MonitorTvEpisodeCommand for season ' . $monitor->getSeason() . ' episode ' . $monitor->getEpisode() . ' for title: ' . $monitor->getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
$monitor->setLastSearch(new DateTimeImmutable());
|
||||
$monitor->setSearchCount($monitor->getSearchCount() + 1);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new MonitorTvEpisodeResult(
|
||||
status: 'OK',
|
||||
result: [
|
||||
'monitor' => $monitor,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
49
src/Download/Action/Input/AddMonitorInput.php
Normal file
49
src/Download/Action/Input/AddMonitorInput.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Input;
|
||||
|
||||
use App\Download\Action\Command\AddMonitorCommand;
|
||||
use OneToMany\RichBundle\Attribute\SourceRequest;
|
||||
use OneToMany\RichBundle\Attribute\SourceRoute;
|
||||
use OneToMany\RichBundle\Attribute\SourceSecurity;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\InputInterface;
|
||||
|
||||
class AddMonitorInput implements InputInterface
|
||||
{
|
||||
public function __construct(
|
||||
#[SourceSecurity]
|
||||
public string $userEmail,
|
||||
|
||||
#[SourceRequest('tmdbId')]
|
||||
public string $tmdbId,
|
||||
|
||||
#[SourceRequest('imdbId')]
|
||||
public string $imdbId,
|
||||
|
||||
#[SourceRequest('title')]
|
||||
public string $title,
|
||||
|
||||
#[SourceRequest('monitorType')]
|
||||
public string $monitorType,
|
||||
|
||||
#[SourceRequest('season', nullify: true)]
|
||||
public ?int $season,
|
||||
|
||||
#[SourceRequest('episode', nullify: true)]
|
||||
public ?int $episode,
|
||||
) {}
|
||||
|
||||
public function toCommand(): CommandInterface
|
||||
{
|
||||
return new AddMonitorCommand(
|
||||
$this->userEmail,
|
||||
$this->title,
|
||||
$this->imdbId,
|
||||
$this->tmdbId,
|
||||
$this->monitorType,
|
||||
$this->season,
|
||||
$this->episode,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Input;
|
||||
|
||||
use App\Download\Action\Command\AddMovieMonitorCommand;
|
||||
use OneToMany\RichBundle\Attribute\SourceRoute;
|
||||
use OneToMany\RichBundle\Attribute\SourceSecurity;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
use OneToMany\RichBundle\Contract\InputInterface;
|
||||
|
||||
class AddMovieMonitorInput implements InputInterface
|
||||
{
|
||||
public function __construct(
|
||||
#[SourceSecurity]
|
||||
public string $userEmail,
|
||||
|
||||
#[SourceRoute('tmdbId')]
|
||||
public string $tmdbId,
|
||||
|
||||
#[SourceRoute('imdbId')]
|
||||
public string $imdbId,
|
||||
|
||||
#[SourceRoute('title')]
|
||||
public string $title,
|
||||
) {}
|
||||
|
||||
public function toCommand(): CommandInterface
|
||||
{
|
||||
return new AddMovieMonitorCommand($this->userEmail, $this->title, $this->imdbId, $this->tmdbId);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace App\Download\Action\Result;
|
||||
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
class AddMovieMonitorResult implements ResultInterface
|
||||
class AddMonitorResult implements ResultInterface
|
||||
{
|
||||
public function __construct(
|
||||
public string $status,
|
||||
13
src/Download/Action/Result/MonitorTvEpisodeResult.php
Normal file
13
src/Download/Action/Result/MonitorTvEpisodeResult.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Action\Result;
|
||||
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
class MonitorTvEpisodeResult implements ResultInterface
|
||||
{
|
||||
public function __construct(
|
||||
public string $status,
|
||||
public array $result,
|
||||
) {}
|
||||
}
|
||||
23
src/Download/Framework/Controller/ApiController.php
Normal file
23
src/Download/Framework/Controller/ApiController.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Framework\Controller;
|
||||
|
||||
use App\Download\Action\Handler\AddMonitorHandler;
|
||||
use App\Download\Action\Input\AddMonitorInput;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ApiController extends AbstractController
|
||||
{
|
||||
#[Route('/monitor', name: 'app_add_movie_monitor', methods: ['POST'])]
|
||||
public function addMonitor(
|
||||
AddMonitorInput $input,
|
||||
AddMonitorHandler $handler,
|
||||
) {
|
||||
$response = $handler->handle($input->toCommand());
|
||||
return $this->json([
|
||||
'status' => 200,
|
||||
'message' => $response
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Download\Framework\Entity;
|
||||
|
||||
use App\Download\Framework\Repository\MovieMonitorRepository;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use App\User\Framework\Entity\User;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MovieMonitorRepository::class)]
|
||||
class MovieMonitor
|
||||
#[ORM\Entity(repositoryClass: MonitorRepository::class)]
|
||||
class Monitor
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
@@ -28,6 +28,15 @@ class MovieMonitor
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $tmdbId = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $monitorType = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $season = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $episode = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $status = null;
|
||||
|
||||
@@ -155,4 +164,40 @@ class MovieMonitor
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMonitorType(): ?string
|
||||
{
|
||||
return $this->monitorType;
|
||||
}
|
||||
|
||||
public function setMonitorType(string $monitorType): static
|
||||
{
|
||||
$this->monitorType = $monitorType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSeason(): ?int
|
||||
{
|
||||
return $this->season;
|
||||
}
|
||||
|
||||
public function setSeason(?int $season): static
|
||||
{
|
||||
$this->season = $season;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEpisode(): ?int
|
||||
{
|
||||
return $this->episode;
|
||||
}
|
||||
|
||||
public function setEpisode(?int $episode): static
|
||||
{
|
||||
$this->episode = $episode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
namespace App\Download\Framework\Repository;
|
||||
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<MovieMonitor>
|
||||
* @extends ServiceEntityRepository<Monitor>
|
||||
*/
|
||||
class MovieMonitorRepository extends ServiceEntityRepository
|
||||
class MonitorRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, MovieMonitor::class);
|
||||
parent::__construct($registry, Monitor::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
39
src/Download/Framework/Scheduler/MonitorDispatcher.php
Normal file
39
src/Download/Framework/Scheduler/MonitorDispatcher.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Framework\Scheduler;
|
||||
|
||||
use App\Download\Action\Handler\MonitorMovieHandler;
|
||||
use App\Download\Action\Handler\MonitorTvSeasonHandler;
|
||||
use App\Download\Framework\Repository\MonitorRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Component\Scheduler\Attribute\AsCronTask;
|
||||
|
||||
#[AsCronTask('* * * * *', schedule: 'monitor')]
|
||||
class MonitorDispatcher
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly MonitorRepository $monitorRepository,
|
||||
private readonly MessageBusInterface $bus,
|
||||
) {}
|
||||
|
||||
public function __invoke() {
|
||||
$this->logger->info('[MonitorDispatcher] Executing MovieMonitorDispatcher');
|
||||
|
||||
$monitorHandlers = [
|
||||
'movie' => MonitorMovieHandler::class,
|
||||
'tvepisode' => MonitorTvSeasonHandler::class,
|
||||
'tvseason' => MonitorTvSeasonHandler::class,
|
||||
'tvshow' => MonitorTvSeasonHandler::class,
|
||||
];
|
||||
|
||||
$monitors = $this->monitorRepository->findBy(['status' => ['New', 'In Progress']]);
|
||||
|
||||
foreach ($monitors as $monitor) {
|
||||
$handler = $monitorHandlers[$monitor->getMonitorType()];
|
||||
$this->logger->info('[MonitorDispatcher] Dispatching ' . $handler . ' for ' . $monitor->getTitle());
|
||||
$this->bus->dispatch(new $handler($monitor->getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Framework\Scheduler;
|
||||
|
||||
use App\Download\Action\Command\MonitorMovieCommand;
|
||||
use App\Download\Framework\Repository\MovieMonitorRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Component\Scheduler\Attribute\AsCronTask;
|
||||
|
||||
#[AsCronTask('* * * * *', schedule: 'movie_monitor')]
|
||||
class MovieMonitorDispatcher
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly MovieMonitorRepository $movieMonitorRepository,
|
||||
private readonly MessageBusInterface $bus,
|
||||
) {}
|
||||
|
||||
public function __invoke() {
|
||||
$this->logger->info('[MovieMonitorDispatcher] Executing MovieMonitorDispatcher');
|
||||
$monitors = $this->movieMonitorRepository->findBy(['status' => ['New', 'In Progress']]);
|
||||
|
||||
foreach ($monitors as $monitor) {
|
||||
$this->logger->info('[MovieMonitorDispatcher] Dispatching MovieMonitorCommand for ' . $monitor->getTitle());
|
||||
$this->bus->dispatch(new MonitorMovieCommand($monitor->getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/Download/Service/MediaFiles.php
Normal file
76
src/Download/Service/MediaFiles.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Download\Service;
|
||||
|
||||
use Aimeos\Map;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class MediaFiles
|
||||
{
|
||||
private Finder $finder;
|
||||
|
||||
private string $moviesPath;
|
||||
|
||||
private string $tvShowsPath;
|
||||
|
||||
public function __construct(
|
||||
#[Autowire(param: 'media.movies_path')]
|
||||
string $moviesPath,
|
||||
|
||||
#[Autowire(param: 'media.tvshows_path')]
|
||||
string $tvShowsPath,
|
||||
) {
|
||||
$this->finder = new Finder();
|
||||
$this->moviesPath = $moviesPath;
|
||||
$this->tvShowsPath = $tvShowsPath;
|
||||
}
|
||||
|
||||
public function getMoviesPath(): string
|
||||
{
|
||||
return $this->moviesPath;
|
||||
}
|
||||
|
||||
public function getTvShowsPath(): string
|
||||
{
|
||||
return $this->tvShowsPath;
|
||||
}
|
||||
|
||||
public function getMovieDirs(): Map
|
||||
{
|
||||
$results = [];
|
||||
foreach ($this->finder->in($this->moviesPath)->directories() as $file) {
|
||||
$results[] = $file;
|
||||
}
|
||||
|
||||
return Map::from($results);
|
||||
}
|
||||
|
||||
public function getTvShowDirs(): Map
|
||||
{
|
||||
$results = [];
|
||||
foreach ($this->finder->in($this->tvShowsPath)->directories() as $file) {
|
||||
$results[] = $file;
|
||||
}
|
||||
|
||||
return Map::from($results);
|
||||
}
|
||||
|
||||
public function getEpisodes(string $path, bool $onlyFilenames = true): Map
|
||||
{
|
||||
if (!str_starts_with($path, $this->tvShowsPath)) {
|
||||
$path = $this->tvShowsPath . DIRECTORY_SEPARATOR . $path;
|
||||
}
|
||||
|
||||
$results = [];
|
||||
foreach ($this->finder->in($path)->files() as $file) {
|
||||
if ($onlyFilenames) {
|
||||
$results[] = $file->getRelativePathname();
|
||||
} else {
|
||||
$results[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
return Map::from($results);
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,18 @@
|
||||
namespace App\Download\Service;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\Torrentio\Result\TorrentioResult;
|
||||
|
||||
class MonitorOptionEvaluator
|
||||
{
|
||||
/**
|
||||
* @param MovieMonitor $monitor
|
||||
* @param Monitor $monitor
|
||||
* @param TorrentioResult[] $results
|
||||
* @return TorrentioResult|null
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function evaluateOptions(MovieMonitor $monitor, array $results): ?TorrentioResult
|
||||
public function evaluateOptions(Monitor $monitor, array $results): ?TorrentioResult
|
||||
{
|
||||
$sizeLow = 500;
|
||||
$sizeHigh = 4096;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Download\Framework\Scheduler\MovieMonitorDispatcher;
|
||||
use App\Download\Framework\Scheduler\MonitorDispatcher;
|
||||
use Symfony\Component\Scheduler\Attribute\AsSchedule;
|
||||
use Symfony\Component\Scheduler\Schedule as SymfonySchedule;
|
||||
use Symfony\Component\Scheduler\ScheduleProviderInterface;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace App\User\Framework\Entity;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\Download\Framework\Entity\MovieMonitor;
|
||||
use App\Download\Framework\Entity\Monitor;
|
||||
use App\User\Framework\Repository\UserRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -41,9 +41,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
private Collection $userPreferences;
|
||||
|
||||
/**
|
||||
* @var Collection<int, MovieMonitor>
|
||||
* @var Collection<int, Monitor>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: MovieMonitor::class, mappedBy: 'user', orphanRemoval: true)]
|
||||
#[ORM\OneToMany(targetEntity: Monitor::class, mappedBy: 'user', orphanRemoval: true)]
|
||||
private Collection $yes;
|
||||
|
||||
public function __construct()
|
||||
@@ -213,14 +213,14 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, MovieMonitor>
|
||||
* @return Collection<int, Monitor>
|
||||
*/
|
||||
public function getYes(): Collection
|
||||
{
|
||||
return $this->yes;
|
||||
}
|
||||
|
||||
public function addYe(MovieMonitor $ye): static
|
||||
public function addYe(Monitor $ye): static
|
||||
{
|
||||
if (!$this->yes->contains($ye)) {
|
||||
$this->yes->add($ye);
|
||||
@@ -230,7 +230,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeYe(MovieMonitor $ye): static
|
||||
public function removeYe(Monitor $ye): static
|
||||
{
|
||||
if ($this->yes->removeElement($ye)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
|
||||
12
symfony.lock
12
symfony.lock
@@ -41,6 +41,18 @@
|
||||
"config/packages/http_discovery.yaml"
|
||||
]
|
||||
},
|
||||
"phpstan/phpstan": {
|
||||
"version": "2.1",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767"
|
||||
},
|
||||
"files": [
|
||||
"phpstan.dist.neon"
|
||||
]
|
||||
},
|
||||
"symfony/asset-mapper": {
|
||||
"version": "7.2",
|
||||
"recipe": {
|
||||
|
||||
Reference in New Issue
Block a user