161 lines
6.8 KiB
PHP
161 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Monitor\Action\Handler;
|
|
|
|
use Aimeos\Map;
|
|
use App\Base\Service\MediaFiles;
|
|
use App\Monitor\Action\Command\MonitorMovieCommand;
|
|
use App\Monitor\Action\Command\MonitorTvEpisodeCommand;
|
|
use App\Monitor\Action\Result\MonitorTvShowResult;
|
|
use App\Monitor\Framework\Entity\Monitor;
|
|
use App\Monitor\Framework\Repository\MonitorRepository;
|
|
use App\Tmdb\Dto\TmdbEpisodeDto;
|
|
use App\Tmdb\TmdbClient;
|
|
use Carbon\Carbon;
|
|
use DateTimeImmutable;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use App\Base\Util\PTN;
|
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
|
use OneToMany\RichBundle\Contract\HandlerInterface;
|
|
use OneToMany\RichBundle\Contract\ResultInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
/** @implements HandlerInterface<MonitorMovieCommand> */
|
|
readonly class MonitorTvShowHandler implements HandlerInterface
|
|
{
|
|
public function __construct(
|
|
private MonitorRepository $monitorRepository,
|
|
private EntityManagerInterface $entityManager,
|
|
private MonitorTvEpisodeHandler $monitorTvEpisodeHandler,
|
|
private MediaFiles $mediaFiles,
|
|
private LoggerInterface $logger,
|
|
private TmdbClient $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))
|
|
->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)
|
|
->filter(fn(TmdbEpisodeDto $episode) => $episode->seasonNumber >= $monitor->getSeason())
|
|
->values();
|
|
|
|
$this->logger->info('> [MonitorTvShowHandler] Found ' . count($episodesInShow) . ' episodes for title: ' . $monitor->getTitle());
|
|
|
|
$episodeMonitors = [];
|
|
// 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.
|
|
$monitor->setStatus('Active');
|
|
$monitor->setLastSearch(new DateTimeImmutable());
|
|
$monitor->setSearchCount($monitor->getSearchCount() + 1);
|
|
$this->entityManager->flush();
|
|
|
|
return new MonitorTvShowResult(
|
|
status: 'OK',
|
|
result: [
|
|
'monitor' => $monitor,
|
|
'new_monitors' => $episodeMonitors,
|
|
]
|
|
);
|
|
}
|
|
|
|
private function episodeReleasedAfterMonitorCreated(
|
|
string|DateTimeImmutable $monitorStartDate,
|
|
TmdbEpisodeDto $episodeInShow
|
|
): bool {
|
|
$monitorStartDate = Carbon::parse($monitorStartDate)->setTime(0, 0);
|
|
$episodeAirDate = Carbon::parse($episodeInShow->airDate);
|
|
return $episodeAirDate >= $monitorStartDate;
|
|
}
|
|
|
|
private function episodeExists(TmdbEpisodeDto $episodeInShow, Map $downloadedEpisodes): bool
|
|
{
|
|
return $downloadedEpisodes->filter(
|
|
fn(object $episode) => $episode->episode === $episodeInShow->episodeNumber
|
|
&& $episode->season === $episodeInShow->seasonNumber
|
|
)->count() > 0;
|
|
}
|
|
|
|
private function monitorExists(Monitor $monitor, TmdbEpisodeDto $episode): bool
|
|
{
|
|
return $this->monitorRepository->findOneBy([
|
|
'imdbId' => $monitor->getImdbId(),
|
|
'title' => $monitor->getTitle(),
|
|
'monitorType' => 'tvepisode',
|
|
'season' => $episode->seasonNumber,
|
|
'episode' => $episode->episodeNumber,
|
|
'status' => ['New', 'Active', 'In Progress']
|
|
]) !== null;
|
|
}
|
|
}
|