diff --git a/src/Monitor/Action/Handler/MonitorTvShowHandler.php b/src/Monitor/Action/Handler/MonitorTvShowHandler.php index 17e14f1..732a25a 100644 --- a/src/Monitor/Action/Handler/MonitorTvShowHandler.php +++ b/src/Monitor/Action/Handler/MonitorTvShowHandler.php @@ -30,7 +30,8 @@ readonly class MonitorTvShowHandler implements HandlerInterface private MediaFiles $mediaFiles, private LoggerInterface $logger, private TmdbClient $tmdb, - ) {} + ) { + } public function handle(CommandInterface $command): ResultInterface { @@ -40,79 +41,77 @@ readonly class MonitorTvShowHandler implements HandlerInterface // Check current episodes $downloadedEpisodes = $this->mediaFiles ->getEpisodes($monitor->getTitle()) - ->map(fn($episode) => (object) (new PTN())->parse($episode)) - ->filter(fn ($episode) => - property_exists($episode, 'episode') + ->map(fn($episode) => (object)(new PTN())->parse($episode)) + ->filter(fn($episode) => property_exists($episode, 'episode') && property_exists($episode, 'season') && null !== $episode->episode && null !== $episode->season - ) - ; + ); $this->logger->info('> [MonitorTvShowHandler] Found ' . count($downloadedEpisodes) . ' downloaded episodes for title: ' . $monitor->getTitle()); // Compare against list from TMDB $episodesInShow = Map::from( $this->tmdb->tvshowDetails($monitor->getImdbId())->episodes - )->flat(1); + )->flat(1) + ->filter(fn(TmdbEpisodeDto $episode) => $episode->seasonNumber >= $monitor->getSeason()) + ->values(); $this->logger->info('> [MonitorTvShowHandler] Found ' . count($episodesInShow) . ' episodes for title: ' . $monitor->getTitle()); $episodeMonitors = []; - if ($downloadedEpisodes->count() !== $episodesInShow->count()) { - // Dispatch Episode commands for each missing Episode - foreach ($episodesInShow as $episode) { - /** @var TmdbEpisodeDto $episode */ - // Only monitor future episodes - $this->logger->info('> [MonitorTvShowHandler] Evaluating "' . $monitor->getTitle() . '", season "' . $episode->seasonNumber . '" episode "' . $episode->episodeNumber . '"'); - $episodeInFuture = $this->episodeReleasedAfterMonitorCreated($monitor->getCreatedAt(), $episode); - $this->logger->info('> [MonitorTvShowHandler] ...Released after monitor started? ' . (true === $episodeInFuture ? 'YES' : 'NO')); - if (false === $episodeInFuture) { - $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); - continue; - } - - // Check if the episode is already downloaded - $episodeExists = $this->episodeExists($episode, $downloadedEpisodes); - $this->logger->info('> [MonitorTvShowHandler] ...Episode exists? ' . (true === $episodeExists ? 'YES' : 'NO')); - if (true === $episodeExists) { - $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); - continue; - } - - // Check for existing monitors - $monitorExists = $this->monitorExists($monitor, $episode); - $this->logger->info('> [MonitorTvShowHandler] ...Monitor exists? ' . (true === $monitorExists ? 'YES' : 'NO')); - if (true === $monitorExists) { - $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); - continue; - } - - // Create the monitor - $episodeMonitor = (new Monitor()) - ->setParent($monitor) - ->setUser($monitor->getUser()) - ->setTmdbId($monitor->getTmdbId()) - ->setImdbId($monitor->getImdbId()) - ->setTitle($monitor->getTitle()) - ->setMonitorType('tvepisode') - ->setSeason($episode->seasonNumber) - ->setEpisode($episode->episodeNumber) - ->setAirDate($episode->airDate !== null && $episode->airDate !== "" ? Carbon::parse($episode->airDate) : null) - ->setCreatedAt(new DateTimeImmutable()) - ->setSearchCount(0) - ->setStatus('New'); - - $this->monitorRepository->getEntityManager()->persist($episodeMonitor); - $this->monitorRepository->getEntityManager()->flush(); - - $episodeMonitors[] = $episodeMonitor; - - // Immediately run the monitor - $command = new MonitorTvEpisodeCommand($episodeMonitor->getId()); - $this->monitorTvEpisodeHandler->handle($command); - $this->logger->info('> [MonitorTvShowHandler] ...Dispatching MonitorTvEpisodeCommand'); + // Dispatch Episode commands for each missing Episode + foreach ($episodesInShow as $episode) { + /** @var TmdbEpisodeDto $episode */ + // Only monitor future episodes + $this->logger->info('> [MonitorTvShowHandler] Evaluating "' . $monitor->getTitle() . '", season "' . $episode->seasonNumber . '" episode "' . $episode->episodeNumber . '"'); + $episodeInFuture = $this->episodeReleasedAfterMonitorCreated($monitor->getCreatedAt(), $episode); + $this->logger->info('> [MonitorTvShowHandler] ...Released after monitor started? ' . (true === $episodeInFuture ? 'YES' : 'NO')); + if (false === $episodeInFuture) { + $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); + continue; } + + // Check if the episode is already downloaded + $episodeExists = $this->episodeExists($episode, $downloadedEpisodes); + $this->logger->info('> [MonitorTvShowHandler] ...Episode exists? ' . (true === $episodeExists ? 'YES' : 'NO')); + if (true === $episodeExists) { + $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); + continue; + } + + // Check for existing monitors + $monitorExists = $this->monitorExists($monitor, $episode); + $this->logger->info('> [MonitorTvShowHandler] ...Monitor exists? ' . (true === $monitorExists ? 'YES' : 'NO')); + if (true === $monitorExists) { + $this->logger->info('> [MonitorTvShowHandler] ...Skipping'); + continue; + } + + // Create the monitor + $episodeMonitor = (new Monitor()) + ->setParent($monitor) + ->setUser($monitor->getUser()) + ->setTmdbId($monitor->getTmdbId()) + ->setImdbId($monitor->getImdbId()) + ->setTitle($monitor->getTitle()) + ->setMonitorType('tvepisode') + ->setSeason($episode->seasonNumber) + ->setEpisode($episode->episodeNumber) + ->setAirDate($episode->airDate !== null && $episode->airDate !== "" ? Carbon::parse($episode->airDate) : null) + ->setCreatedAt(new DateTimeImmutable()) + ->setSearchCount(0) + ->setStatus('New'); + + $this->monitorRepository->getEntityManager()->persist($episodeMonitor); + $this->monitorRepository->getEntityManager()->flush(); + + $episodeMonitors[] = $episodeMonitor; + + // Immediately run the monitor + $command = new MonitorTvEpisodeCommand($episodeMonitor->getId()); + $this->monitorTvEpisodeHandler->handle($command); + $this->logger->info('> [MonitorTvShowHandler] ...Dispatching MonitorTvEpisodeCommand'); } // Set the status to Active, so it will be re-executed. @@ -130,8 +129,10 @@ readonly class MonitorTvShowHandler implements HandlerInterface ); } - private function episodeReleasedAfterMonitorCreated(string|DateTimeImmutable $monitorStartDate, TmdbEpisodeDto $episodeInShow): bool - { + private function episodeReleasedAfterMonitorCreated( + string|DateTimeImmutable $monitorStartDate, + TmdbEpisodeDto $episodeInShow + ): bool { $monitorStartDate = Carbon::parse($monitorStartDate)->setTime(0, 0); $episodeAirDate = Carbon::parse($episodeInShow->airDate); return $episodeAirDate >= $monitorStartDate; @@ -140,8 +141,8 @@ readonly class MonitorTvShowHandler implements HandlerInterface private function episodeExists(TmdbEpisodeDto $episodeInShow, Map $downloadedEpisodes): bool { return $downloadedEpisodes->filter( - fn (object $episode) => $episode->episode === $episodeInShow->episodeNumber - && $episode->season === $episodeInShow->seasonNumber + fn(object $episode) => $episode->episode === $episodeInShow->episodeNumber + && $episode->season === $episodeInShow->seasonNumber )->count() > 0; }