*/ readonly class MonitorTvEpisodeHandler implements HandlerInterface { public function __construct( private GetTvShowOptionsHandler $getTvShowOptionsHandler, private DownloadOptionEvaluator $downloadOptionEvaluator, private EntityManagerInterface $entityManager, private MessageBusInterface $bus, private LoggerInterface $logger, private MonitorRepository $monitorRepository, private TmdbClient $tmdb, private DownloadRepository $downloadRepository, ) {} public function handle(CommandInterface $command): ResultInterface { try { $monitor = $this->monitorRepository->find($command->movieMonitorId); $this->logger->info('> [MonitorTvEpisodeHandler] Executing MonitorTvEpisodeHandler for ' . $monitor->getTitle() . ' season ' . $monitor->getSeason() . ' episode ' . $monitor->getEpisode()); $this->refreshData($monitor); $this->bus->dispatch(new AddEventLogCommand( $monitor->getUser(), MonitorEvents::MONITOR_STARTED->type(), MonitorEvents::MONITOR_STARTED->message(), (array) $command )); $episodeData = $this->tmdb->tvEpisodeDetails($monitor->getTmdbId(), $monitor->getImdbId(), $monitor->getSeason(), $monitor->getEpisode()); if (null === $episodeData->airDate || "" === $episodeData->airDate) { $this->logger->info('> [MonitorTvEpisodeHandler] ...Episode does not have an air date, skipping for now'); return new MonitorTvEpisodeResult( status: 'OK', result: [ 'message' => 'No change', 'monitor' => $monitor, ] ); } if (null === $monitor->getAirDate()) { $monitor->setAirDate(Carbon::parse($episodeData->airDate)); } if (Carbon::createFromTimestamp($episodeData->airDate) > Carbon::today('UTC')) { $this->logger->info('> [MonitorTvEpisodeHandler] ...Episode has not aired yet, skipping for now'); return new MonitorTvEpisodeResult( status: 'OK', result: [ 'message' => 'No change', 'monitor' => $monitor, ] ); } $monitor->setStatus('In Progress'); $this->monitorRepository->getEntityManager()->flush(); $results = $this->getTvShowOptionsHandler->handle( new GetTvShowOptionsCommand( $monitor->getTmdbId(), $monitor->getImdbId(), $monitor->getSeason(), $monitor->getEpisode() ) ); $this->logger->info('> [MonitorTvEpisodeHandler] ...Found ' . count($results->results) . ' total download options, beginning evaluation'); $result = $this->downloadOptionEvaluator->evaluateOptions($results->results, UserPreferencesFactory::createFromUser($monitor->getUser())); if (null !== $result) { $this->logger->info('> [MonitorTvEpisodeHandler] ...Found 1 matching result found: dispatching DownloadMediaCommand for "' . $result->title . '"'); $download = $this->downloadRepository->insert( user: $monitor->getUser(), url: $result->url, title: $monitor->getTitle(), filename: $result->filename, imdbId: $monitor->getImdbId(), mediaType: 'tvshows', episodeId: EpisodeId::fromSeasonEpisodeNumbers($monitor->getSeason(), $monitor->getEpisode()), ); $this->bus->dispatch(new DownloadMediaCommand( $download->getUrl(), $download->getTitle(), $download->getFilename(), 'tvshows', $download->getImdbId(), $monitor->getUser()->getId(), $download->getId(), )); $monitor->setStatus('Complete'); $monitor->setDownloadedAt(new DateTimeImmutable()); } else { $this->logger->info('> [MonitorTvEpisodeHandler] ...Found 0 matching results found, monitor will run at next interval'); $monitor->setStatus('Active'); } } catch (\Throwable $exception) { $this->logger->error('> [MonitorTvEpisodeHandler] ...Exception thrown: ' . $exception->getMessage()); $this->logger->error($exception->getMessage()); $monitor->setStatus('Active'); $this->bus->dispatch(new AddEventLogCommand( $monitor->getUser(), MonitorEvents::MONITOR_ERROR->type(), MonitorEvents::MONITOR_ERROR->message() . ': ' . $exception->getMessage(), (array) $monitor )); } $monitor->setLastSearch(new DateTimeImmutable()); $monitor->setSearchCount($monitor->getSearchCount() + 1); $this->monitorRepository->getEntityManager()->flush(); $this->bus->dispatch(new AddEventLogCommand( $monitor->getUser(), MonitorEvents::MONITOR_FINISHED->type(), MonitorEvents::MONITOR_FINISHED->message(), (array) $monitor )); return new MonitorTvEpisodeResult( status: 'OK', result: [ 'monitor' => $monitor, ] ); } private function refreshData(Monitor $monitor) { if (null === $monitor->getPoster()) { $this->logger->info('> [MonitorTvEpisodeHandler] Refreshing poster for "' . $monitor->getTitle() . '"'); $poster = $monitor->getParent()->getPoster(); if (null !== $poster && "" !== $poster) { $monitor->setPoster($poster); } } } }