wip-feat: working tv season/episode monitor

This commit is contained in:
2025-05-07 22:13:38 -05:00
parent 527adb73c1
commit 25ff3e726d
9 changed files with 71 additions and 37 deletions

View File

@@ -29,14 +29,14 @@ services:
volumes:
- ./:/var/www
- ./var/download:/var/download
command: php ./bin/console messenger:consume async -v --time-limit=3600 --limit=10
command: php ./bin/console messenger:consume async -vv --time-limit=3600
scheduler:
build: .
volumes:
- ./:/var/www
- ./var/download:/var/download
command: php ./bin/console messenger:consume scheduler_movie_monitor -v --time-limit=3600
command: php ./bin/console messenger:consume scheduler_monitor -vv --time-limit=3600
mercure:
image: dunglas/mercure

View File

@@ -26,6 +26,9 @@ framework:
# 'App\Message\YourMessage': async
'App\Download\Action\Command\DownloadMediaCommand': async
'App\Download\Action\Command\MonitorTvEpisodeCommand': async
'App\Download\Action\Command\MonitorTvSeasonCommand': async
'App\Download\Action\Command\MonitorTvShowCommand': async
'App\Download\Action\Command\MonitorMovieCommand': async
# when@test:
# framework:

View File

@@ -34,10 +34,10 @@ class DownloadController extends AbstractController
) {
$monitor = (new Monitor())
->setUser($this->getUser())
->setTmdbId('95396')
->setImdbId('tt11280740')
->setTitle('Severance')
->setMonitorType('tvshow')
->setTmdbId('112442')
->setImdbId('tt9288860')
->setTitle('Trash Truck')
->setMonitorType('tvseason')
->setSeason(1)
->setEpisode(null)
->setCreatedAt(new DateTimeImmutable())
@@ -46,8 +46,8 @@ class DownloadController extends AbstractController
$this->monitorRepository->getEntityManager()->persist($monitor);
$this->monitorRepository->getEntityManager()->flush();
$command = new MonitorTvShowCommand($monitor->getId());
$handler->handle($command);
$command = new MonitorTvSeasonCommand($monitor->getId());
// $handler->handle($command);
return $this->json([
'status' => 200,
'message' => $command

View File

@@ -54,6 +54,8 @@ readonly class MonitorMovieHandler implements HandlerInterface
));
$monitor->setStatus('Complete');
$monitor->setDownloadedAt(new DateTimeIMmutable());
} else {
$monitor->setStatus('Active');
}
$monitor->setLastSearch(new DateTimeImmutable());

View File

@@ -10,6 +10,7 @@ use App\Download\Service\MonitorOptionEvaluator;
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
use App\Torrentio\Action\Command\GetTvShowOptionsCommand;
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use OneToMany\RichBundle\Contract\CommandInterface;
@@ -22,27 +23,29 @@ use Symfony\Component\Messenger\MessageBusInterface;
readonly class MonitorTvEpisodeHandler implements HandlerInterface
{
public function __construct(
private MonitorRepository $movieMonitorRepository,
private GetMovieOptionsHandler $getMovieOptionsHandler,
private GetTvShowOptionsHandler $getTvShowOptionsHandler,
private MonitorOptionEvaluator $monitorOptionEvaluator,
private EntityManagerInterface $entityManager,
private MessageBusInterface $bus,
private LoggerInterface $logger,
private MonitorRepository $monitorRepository,
) {}
public function handle(CommandInterface $command): ResultInterface
{
$this->logger->info('> [MonitorTvEpisodeHandler] Executing MonitorTvEpisodeHandler');
$monitor = $this->movieMonitorRepository->find($command->movieMonitorId);
$monitor = $this->monitorRepository->find($command->movieMonitorId);
$monitor->setStatus('In Progress');
$this->monitorRepository->getEntityManager()->flush();
$this->logger->info('> [MonitorTvEpisodeHandler] Searching for "' . $monitor->getTitle() . '" download options');
$results = $this->getMovieOptionsHandler->handle(
$this->logger->info('> [MonitorTvEpisodeHandler] Searching for "' . $monitor->getTitle() . '" season ' . $monitor->getSeason() . ' episode ' . $monitor->getEpisode() . ' download options');
$results = $this->getTvShowOptionsHandler->handle(
new GetTvShowOptionsCommand(
$monitor->getTmdbId(),
$monitor->getImdbId(),
$monitor->getSeason(),
$monitor->getEpisode())
$monitor->getEpisode()
)
);
$this->logger->info('> [MonitorTvEpisodeHandler] Found ' . count($results->results) . ' download options');
@@ -50,16 +53,19 @@ readonly class MonitorTvEpisodeHandler implements HandlerInterface
$result = $this->monitorOptionEvaluator->evaluateOptions($monitor, $results->results);
if (null !== $result) {
$this->logger->info('> [MonitorTvEpisodeHandler] 1 result found: dispatching DownloadMediaCommand for "' . $result->title . '"');
$this->logger->info('> [MonitorTvEpisodeHandler] 1 matching result found: dispatching DownloadMediaCommand for "' . $result->title . '"');
$this->bus->dispatch(new DownloadMediaCommand(
$result->url,
$monitor->getTitle(),
$result->filename,
'movies',
'tvshows',
$monitor->getImdbId(),
));
$monitor->setStatus('Complete');
$monitor->setDownloadedAt(new DateTimeImmutable());
} else {
$this->logger->info('> [MonitorTvEpisodeHandler] 0 matching results found, monitor will run at next interval');
$monitor->setStatus('Active');
}
$monitor->setLastSearch(new DateTimeImmutable());

View File

@@ -29,13 +29,12 @@ 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,
private MonitorTvEpisodeHandler $monitorTvEpisodeHandler,
) {}
public function handle(CommandInterface $command): ResultInterface
@@ -59,30 +58,43 @@ readonly class MonitorTvSeasonHandler implements HandlerInterface
// Dispatch Episode commands for each missing Episode
foreach ($episodesInSeason as $episode) {
if (!array_key_exists($episode['episode_number'], $downloadedEpisodes->toArray())) {
$monitor = (new Monitor())
$monitorCheck = $this->monitorRepository->findOneBy([
'imdbId' => $monitor->getImdbId(),
'title' => $monitor->getTitle(),
'monitorType' => 'tvepisode',
'season' => $monitor->getSeason(),
'episode' => $episode['episode_number'],
]);
$this->logger->info('> [MonitorTvSeasonHandler] Monitor exists for season ' . $monitor->getSeason() . ' episode ' . $episode['episode_number'] . ' for title: ' . $monitor->getTitle() . ' ? ' . (null !== $monitorCheck ? 'YES' : 'NO'));
if (!array_key_exists($episode['episode_number'], $downloadedEpisodes->toArray())
&& null === $monitorCheck
) {
$episodeMonitor = (new Monitor())
->setUser($monitor->getUser())
->setTmdbId($monitor->getTmdbId())
->setImdbId($monitor->getImdbId())
->setTitle($monitor->getTitle())
->setMonitorType('tvseason')
->setMonitorType('tvepisode')
->setSeason($monitor->getSeason())
->setEpisode($episode['episode_number'])
->setCreatedAt(new DateTimeImmutable())
->setSearchCount(0)
->setStatus('New');
$this->monitorRepository->getEntityManager()->persist($monitor);
$this->monitorRepository->getEntityManager()->persist($episodeMonitor);
$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());
$command = new MonitorTvEpisodeCommand($episodeMonitor->getId());
$this->monitorTvEpisodeHandler->handle($command);
$this->logger->info('> [MonitorTvSeasonHandler] Dispatching MonitorTvEpisodeCommand for season ' . $episodeMonitor->getSeason() . ' episode ' . $episodeMonitor->getEpisode() . ' for title: ' . $monitor->getTitle());
}
}
$monitor->setLastSearch(new DateTimeImmutable());
$monitor->setSearchCount($monitor->getSearchCount() + 1);
$monitor->setStatus('Complete');
$this->entityManager->flush();
return new MonitorMovieResult(

View File

@@ -86,6 +86,7 @@ readonly class MonitorTvShowHandler implements HandlerInterface
$monitor->setLastSearch(new DateTimeImmutable());
$monitor->setSearchCount($monitor->getSearchCount() + 1);
$monitor->setStatus('Complete');
$this->entityManager->flush();
return new MonitorTvEpisodeResult(

View File

@@ -2,8 +2,10 @@
namespace App\Download\Framework\Scheduler;
use App\Download\Action\Handler\MonitorMovieHandler;
use App\Download\Action\Handler\MonitorTvSeasonHandler;
use App\Download\Action\Command\MonitorMovieCommand;
use App\Download\Action\Command\MonitorTvEpisodeCommand;
use App\Download\Action\Command\MonitorTvSeasonCommand;
use App\Download\Action\Command\MonitorTvShowCommand;
use App\Download\Framework\Repository\MonitorRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\MessageBusInterface;
@@ -19,21 +21,24 @@ class MonitorDispatcher
) {}
public function __invoke() {
$this->logger->info('[MonitorDispatcher] Executing MovieMonitorDispatcher');
$this->logger->info('[MonitorDispatcher] Executing MonitorDispatcher');
$monitorHandlers = [
'movie' => MonitorMovieHandler::class,
'tvepisode' => MonitorTvSeasonHandler::class,
'tvseason' => MonitorTvSeasonHandler::class,
'tvshow' => MonitorTvSeasonHandler::class,
'movie' => MonitorMovieCommand::class,
'tvepisode' => MonitorTvEpisodeCommand::class,
'tvseason' => MonitorTvSeasonCommand::class,
'tvshow' => MonitorTvShowCommand::class,
];
$monitors = $this->monitorRepository->findBy(['status' => ['New', 'In Progress']]);
$monitors = $this->monitorRepository->findBy(['status' => ['New', 'Active']]);
foreach ($monitors as $monitor) {
$handler = $monitorHandlers[$monitor->getMonitorType()];
$this->logger->info('[MonitorDispatcher] Dispatching ' . $handler . ' for ' . $monitor->getTitle());
$this->bus->dispatch(new $handler($monitor->getId()));
$monitor->setStatus('In Progress');
$this->monitorRepository->getEntityManager()->flush();
$command = $monitorHandlers[$monitor->getMonitorType()];
$this->logger->info('[MonitorDispatcher] Dispatching ' . $command . ' for ' . $monitor->getTitle());
$this->bus->dispatch(new $command($monitor->getId()));
}
}
}

View File

@@ -16,7 +16,7 @@ class MonitorOptionEvaluator
*/
public function evaluateOptions(Monitor $monitor, array $results): ?TorrentioResult
{
$sizeLow = 500;
$sizeLow = 000;
$sizeHigh = 4096;
$bestMatches = [];
@@ -48,6 +48,11 @@ class MonitorOptionEvaluator
) {
$matches[] = $result;
}
if (($userPreferences['codec'] === null )
&& ($userPreferences['resolution'] === null )) {
$matches[] = $result;
}
}
$sizeMatches = [];