feat: additional info displayed on child monitor page
This commit is contained in:
@@ -168,6 +168,37 @@ class MediaFiles
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $tvshowTitle
|
||||||
|
* @return array<SplFileInfo>|false
|
||||||
|
*/
|
||||||
|
public function tvshowExists(string $tvshowTitle): Map|false
|
||||||
|
{
|
||||||
|
$existingEpisodes = $this->getEpisodes($tvshowTitle, false);
|
||||||
|
|
||||||
|
if ($existingEpisodes->isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$episodes = new Map;
|
||||||
|
/** @var SplFileInfo $episode */
|
||||||
|
foreach ($existingEpisodes as $episode) {
|
||||||
|
$ptn = (object) (new PTN())->parse($episode->getFilename());
|
||||||
|
|
||||||
|
if (!property_exists($ptn, 'season') || !property_exists($ptn, 'episode')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$episodes->push($episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($episodes->count() > 0) {
|
||||||
|
return $episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function movieExists(string $title)
|
public function movieExists(string $title)
|
||||||
{
|
{
|
||||||
$filepath = $this->moviesPath . DIRECTORY_SEPARATOR . $title;
|
$filepath = $this->moviesPath . DIRECTORY_SEPARATOR . $title;
|
||||||
|
|||||||
20
src/Library/Action/Command/GetMediaFromLibraryCommand.php
Normal file
20
src/Library/Action/Command/GetMediaFromLibraryCommand.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Library\Action\Command;
|
||||||
|
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements CommandInterface<GetMediaFromLibraryCommand>
|
||||||
|
*/
|
||||||
|
class GetMediaFromLibraryCommand implements CommandInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?int $userId = null,
|
||||||
|
public ?string $mediaType = null,
|
||||||
|
public ?string $imdbId = null,
|
||||||
|
public ?string $title = null,
|
||||||
|
public ?string $season = null,
|
||||||
|
public ?string $episode = null,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
169
src/Library/Action/Handler/GetMediaInfoFromLibraryHandler.php
Normal file
169
src/Library/Action/Handler/GetMediaInfoFromLibraryHandler.php
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Library\Action\Handler;
|
||||||
|
|
||||||
|
use Aimeos\Map;
|
||||||
|
use App\Base\Enum\MediaType;
|
||||||
|
use App\Base\Service\MediaFiles;
|
||||||
|
use App\Base\Util\PTN;
|
||||||
|
use App\Library\Action\Command\GetMediaFromLibraryCommand;
|
||||||
|
use App\Library\Action\Result\GetMediaFromLibraryResult;
|
||||||
|
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||||
|
use App\Tmdb\TmdbClient;
|
||||||
|
use App\Tmdb\TmdbResult;
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface as C;
|
||||||
|
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||||
|
use OneToMany\RichBundle\Contract\ResultInterface as R;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements HandlerInterface<GetMediaFromLibraryCommand,GetMediaFromLibraryResult>
|
||||||
|
*/
|
||||||
|
class GetMediaInfoFromLibraryHandler implements HandlerInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly TmdbClient $tmdb,
|
||||||
|
private readonly MediaFiles $mediaFiles,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
|
private readonly MonitorRepository $monitorRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function handle(C $command): R
|
||||||
|
{
|
||||||
|
$result = new GetMediaFromLibraryResult();
|
||||||
|
$tmdbResult = $this->fetchTmdbData($command->imdbId, $command->mediaType);
|
||||||
|
|
||||||
|
if (null === $tmdbResult) {
|
||||||
|
$this->logger->warning('[GetMediaInfoFromLibraryHandler] TMDb result was not found, this may lead to issues in the rest of the library search', (array) $command);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setResultExists($tmdbResult->mediaType, $tmdbResult->title, $result);
|
||||||
|
if ($result->notExists()) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parseFromTmdbResult($tmdbResult, $result);
|
||||||
|
|
||||||
|
if ($command->mediaType === MediaType::TvShow->value) {
|
||||||
|
$this->setEpisodes($tmdbResult, $result);
|
||||||
|
$this->setSeasons($tmdbResult, $result);
|
||||||
|
$this->setMonitors($command->userId, $command->imdbId, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fetchTmdbData(string $imdbId, string $mediaType): ?TmdbResult
|
||||||
|
{
|
||||||
|
return match($mediaType) {
|
||||||
|
MediaType::Movie->value => $this->tmdb->movieDetails($imdbId),
|
||||||
|
MediaType::TvShow->value => $this->tmdb->tvShowDetails($imdbId),
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setResultExists(string $mediaType, string $title, GetMediaFromLibraryResult $result): void
|
||||||
|
{
|
||||||
|
$fsResult = match($mediaType) {
|
||||||
|
MediaType::Movie->value => $this->mediaFiles->movieExists($title),
|
||||||
|
MediaType::TvShow->value => $this->mediaFiles->tvShowExists($title),
|
||||||
|
default => false,
|
||||||
|
};
|
||||||
|
if (false === $fsResult) {
|
||||||
|
$result->setExists(false);
|
||||||
|
} else {
|
||||||
|
$result->setExists(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseFromTmdbResult(TmdbResult $tmdbResult, GetMediaFromLibraryResult $result): void
|
||||||
|
{
|
||||||
|
$result->setTitle($tmdbResult->title);
|
||||||
|
$result->setMediaType($tmdbResult->mediaType);
|
||||||
|
$result->setImdbId($tmdbResult->imdbId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEpisodes(TmdbResult $tmdbResult, GetMediaFromLibraryResult $result): void
|
||||||
|
{
|
||||||
|
$existingEpisodeFiles = $this->mediaFiles->tvshowExists($tmdbResult->title);
|
||||||
|
|
||||||
|
$existingEpisodeMap = [];
|
||||||
|
foreach ($existingEpisodeFiles as $file) {
|
||||||
|
/** @var \SplFileInfo $file */
|
||||||
|
$ptn = (object) new PTN()->parse($file->getBasename());
|
||||||
|
|
||||||
|
if (!array_key_exists($ptn->season, $existingEpisodeMap)) {
|
||||||
|
$existingEpisodeMap[$ptn->season] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($ptn->episode, $existingEpisodeMap[$ptn->season])) {
|
||||||
|
$existingEpisodeMap[$ptn->season][] = $ptn->episode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingEpisodes = [];
|
||||||
|
$missingEpisodes = [];
|
||||||
|
foreach ($tmdbResult->episodes as $season => $episodes) {
|
||||||
|
foreach ($episodes as $episode) {
|
||||||
|
if (array_key_exists($season, $existingEpisodeMap)) {
|
||||||
|
if (in_array($episode->episodeNumber, $existingEpisodeMap[$season])) {
|
||||||
|
$existingEpisodes[] = $episode;
|
||||||
|
} else {
|
||||||
|
$missingEpisodes[] = $episode;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$missingEpisodes[] = $episode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result->setEpisodes($existingEpisodes);
|
||||||
|
$result->setMissingEpisodes($missingEpisodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSeasons(TmdbResult $tmdbResult, GetMediaFromLibraryResult $result): void
|
||||||
|
{
|
||||||
|
$existingEpisodeFiles = $this->mediaFiles->tvshowExists($tmdbResult->title);
|
||||||
|
|
||||||
|
$existingEpisodeMap = [];
|
||||||
|
foreach ($existingEpisodeFiles as $file) {
|
||||||
|
/** @var \SplFileInfo $file */
|
||||||
|
$ptn = (object) new PTN()->parse($file->getBasename());
|
||||||
|
$existingEpisodeMap[$ptn->season][] = $ptn->episode;
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingFullSeasons = [];
|
||||||
|
$existingPartialSeasons = [];
|
||||||
|
$missingSeasons = [];
|
||||||
|
foreach ($existingEpisodeMap as $season => $episodes) {
|
||||||
|
if (count($tmdbResult->episodes[$season]) === count($episodes)) {
|
||||||
|
$existingFullSeasons[] = $season;
|
||||||
|
} elseif (count($episodes) > 0) {
|
||||||
|
$existingPartialSeasons[] = $season;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$seasons = array_keys($tmdbResult->episodes);
|
||||||
|
foreach ($seasons as $season) {
|
||||||
|
if (!in_array($season, $existingFullSeasons) && !in_array($season, $existingPartialSeasons)) {
|
||||||
|
$missingSeasons[] = $season;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result->setSeasons($existingFullSeasons);
|
||||||
|
$result->setPartialSeasons($existingPartialSeasons);
|
||||||
|
$result->setMissingSeasons($missingSeasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMonitors(int $userId, string $imdbId, GetMediaFromLibraryResult $result)
|
||||||
|
{
|
||||||
|
$result->setMonitorCount(
|
||||||
|
$this->monitorRepository->countUserChildrenByParentId($userId, $imdbId)
|
||||||
|
);
|
||||||
|
$result->setActiveMonitorCount(
|
||||||
|
$this->monitorRepository->countUserActiveChildrenByParentId($userId, $imdbId)
|
||||||
|
);
|
||||||
|
$result->setCompleteMonitorCount(
|
||||||
|
$this->monitorRepository->countUserCompleteChildrenByParentId($userId, $imdbId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/Library/Action/Input/GetMediaInfoFromLibraryInput.php
Normal file
39
src/Library/Action/Input/GetMediaInfoFromLibraryInput.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Library\Action\Input;
|
||||||
|
|
||||||
|
use App\Library\Action\Command\GetMediaFromLibraryCommand;
|
||||||
|
use OneToMany\RichBundle\Attribute\SourceRequest;
|
||||||
|
use OneToMany\RichBundle\Contract\CommandInterface as C;
|
||||||
|
use OneToMany\RichBundle\Contract\InputInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements InputInterface<GetMediaInfoFromLibraryInput, GetMediaFromLibraryCommand>
|
||||||
|
*/
|
||||||
|
class GetMediaInfoFromLibraryInput implements InputInterface
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
#[SourceRequest('imdbId', nullify: true)]
|
||||||
|
public ?string $imdbId = null,
|
||||||
|
#[SourceRequest('title', nullify: true)]
|
||||||
|
public ?string $title = null,
|
||||||
|
#[SourceRequest('season', nullify: true)]
|
||||||
|
public ?string $season = null,
|
||||||
|
#[SourceRequest('episode', nullify: true)]
|
||||||
|
public ?string $episode = null,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function toCommand(): C
|
||||||
|
{
|
||||||
|
if (null === $this->imdbId && null === $this->title) {
|
||||||
|
throw new \InvalidArgumentException('Either imdbId or title must be set', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GetMediaFromLibraryCommand(
|
||||||
|
imdbId: $this->imdbId,
|
||||||
|
title: $this->title,
|
||||||
|
season: $this->season,
|
||||||
|
episode: $this->episode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
171
src/Library/Action/Result/GetMediaFromLibraryResult.php
Normal file
171
src/Library/Action/Result/GetMediaFromLibraryResult.php
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Library\Action\Result;
|
||||||
|
|
||||||
|
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||||
|
|
||||||
|
class GetMediaFromLibraryResult implements ResultInterface
|
||||||
|
{
|
||||||
|
private bool $exists;
|
||||||
|
private ?string $title = null;
|
||||||
|
private ?string $imdbId = null;
|
||||||
|
private ?string $mediaType = null;
|
||||||
|
private ?array $episodes = null;
|
||||||
|
private ?array $missingEpisodes = null;
|
||||||
|
private ?array $seasons = null;
|
||||||
|
private ?array $partialSeasons = null;
|
||||||
|
private ?array $missingSeasons = null;
|
||||||
|
private ?int $monitorCount = null; // Monitor Repo
|
||||||
|
private ?int $activeMonitorCount = null; // Monitor Repo
|
||||||
|
private ?int $completeMonitorCount = null; // Monitor Repo
|
||||||
|
|
||||||
|
public function exists(): bool
|
||||||
|
{
|
||||||
|
return $this->exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notExists(): bool
|
||||||
|
{
|
||||||
|
return !$this->exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExists(bool $exists): void
|
||||||
|
{
|
||||||
|
$this->exists = $exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): ?string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle(?string $title): void
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImdbId(): ?string
|
||||||
|
{
|
||||||
|
return $this->imdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setImdbId(?string $imdbId): void
|
||||||
|
{
|
||||||
|
$this->imdbId = $imdbId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMediaType(): ?string
|
||||||
|
{
|
||||||
|
return $this->mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMediaType(?string $mediaType): void
|
||||||
|
{
|
||||||
|
$this->mediaType = $mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEpisodes(): ?array
|
||||||
|
{
|
||||||
|
return $this->episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEpisodes(?array $episodes): void
|
||||||
|
{
|
||||||
|
$this->episodes = $episodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEpisodeCount(): ?int
|
||||||
|
{
|
||||||
|
return count($this->episodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMissingEpisodes(): ?array
|
||||||
|
{
|
||||||
|
return $this->missingEpisodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMissingEpisodes(?array $missingEpisodes): void
|
||||||
|
{
|
||||||
|
$this->missingEpisodes = $missingEpisodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMissingEpisodeCount(): ?int
|
||||||
|
{
|
||||||
|
return count($this->missingEpisodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSeasons(): ?array
|
||||||
|
{
|
||||||
|
return $this->seasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSeasons(?array $seasons): void
|
||||||
|
{
|
||||||
|
$this->seasons = $seasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSeasonCount(): ?int
|
||||||
|
{
|
||||||
|
return count($this->seasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPartialSeasons(): ?array
|
||||||
|
{
|
||||||
|
return $this->partialSeasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPartialSeasons(?array $partialSeasons): void
|
||||||
|
{
|
||||||
|
$this->partialSeasons = $partialSeasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPartialSeasonCount(): ?int
|
||||||
|
{
|
||||||
|
return count($this->partialSeasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMissingSeasons(): ?array
|
||||||
|
{
|
||||||
|
return $this->missingSeasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMissingSeasons(?array $missingSeasons): void
|
||||||
|
{
|
||||||
|
$this->missingSeasons = $missingSeasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMissingSeasonCount(): ?int
|
||||||
|
{
|
||||||
|
return count($this->missingSeasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMonitorCount(): ?int
|
||||||
|
{
|
||||||
|
return $this->monitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMonitorCount(?int $monitorCount): void
|
||||||
|
{
|
||||||
|
$this->monitorCount = $monitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActiveMonitorCount(): ?int
|
||||||
|
{
|
||||||
|
return $this->activeMonitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setActiveMonitorCount(?int $activeMonitorCount): void
|
||||||
|
{
|
||||||
|
$this->activeMonitorCount = $activeMonitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompleteMonitorCount(): ?int
|
||||||
|
{
|
||||||
|
return $this->completeMonitorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCompleteMonitorCount(?int $completeMonitorCount): void
|
||||||
|
{
|
||||||
|
$this->completeMonitorCount = $completeMonitorCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
namespace App\Monitor\Framework\Controller;
|
namespace App\Monitor\Framework\Controller;
|
||||||
|
|
||||||
use App\Download\Action\Input\DeleteDownloadInput;
|
use App\Download\Action\Input\DeleteDownloadInput;
|
||||||
|
use App\Library\Action\Command\GetMediaFromLibraryCommand;
|
||||||
|
use App\Library\Action\Handler\GetMediaInfoFromLibraryHandler;
|
||||||
use App\Monitor\Action\Handler\AddMonitorHandler;
|
use App\Monitor\Action\Handler\AddMonitorHandler;
|
||||||
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
||||||
use App\Monitor\Action\Input\AddMonitorInput;
|
use App\Monitor\Action\Input\AddMonitorInput;
|
||||||
@@ -40,7 +42,7 @@ class WebController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/monitors/{id}', name: 'app.monitor.view', methods: ['GET'])]
|
#[Route('/monitors/{id}', name: 'app.monitor.view', methods: ['GET'])]
|
||||||
public function viewMonitor(Monitor $monitor, GetMediaInfoHandler $getMediaInfoHandler)
|
public function viewMonitor(Monitor $monitor, GetMediaInfoHandler $getMediaInfoHandler, GetMediaInfoFromLibraryHandler $handler)
|
||||||
{
|
{
|
||||||
$media = $getMediaInfoHandler->handle(
|
$media = $getMediaInfoHandler->handle(
|
||||||
new GetMediaInfoCommand(
|
new GetMediaInfoCommand(
|
||||||
@@ -48,9 +50,19 @@ class WebController extends AbstractController
|
|||||||
mediaType: 'tvshows',
|
mediaType: 'tvshows',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$libraryResult = $handler->handle(
|
||||||
|
new GetMediaFromLibraryCommand(
|
||||||
|
$this->getUser()->getId(),
|
||||||
|
$media->media->mediaType,
|
||||||
|
$media->media->imdbId,
|
||||||
|
$media->media->title,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return $this->render('monitor/view.html.twig', [
|
return $this->render('monitor/view.html.twig', [
|
||||||
'monitor' => $monitor,
|
'monitor' => $monitor,
|
||||||
'results' => $media,
|
'results' => $media,
|
||||||
|
'library' => $libraryResult
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,4 +41,83 @@ class MonitorRepository extends ServiceEntityRepository
|
|||||||
->getQuery();
|
->getQuery();
|
||||||
return $query->getResult();
|
return $query->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getActiveUserMonitors()
|
||||||
|
{
|
||||||
|
return $this->asPaginator($this->monitorRepository->createQueryBuilder('m')
|
||||||
|
->andWhere('m.status IN (:statuses)')
|
||||||
|
->andWhere('(m.title LIKE :term OR m.imdbId LIKE :term OR m.monitorType LIKE :term OR m.status LIKE :term)')
|
||||||
|
->andWhere('m.parent IS NULL')
|
||||||
|
->setParameter('statuses', ['New', 'In Progress', 'Active'])
|
||||||
|
->setParameter('term', '%'.$this->term.'%')
|
||||||
|
->orderBy('m.id', 'DESC')
|
||||||
|
->getQuery()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getChildMonitorsByParentId(int $parentId)
|
||||||
|
{
|
||||||
|
return $this->asPaginator(
|
||||||
|
$this->monitorRepository->createQueryBuilder('m')
|
||||||
|
->andWhere("m.parent = :parentId")
|
||||||
|
->setParameter('parentId', $parentId)
|
||||||
|
->orderBy('m.id', 'DESC')
|
||||||
|
->getQuery()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompleteUserMonitors()
|
||||||
|
{
|
||||||
|
return $this->asPaginator($this->monitorRepository->createQueryBuilder('m')
|
||||||
|
->andWhere('m.status = :status')
|
||||||
|
->andWhere('(m.title LIKE :term OR m.imdbId LIKE :term OR m.monitorType LIKE :term OR m.status LIKE :term)')
|
||||||
|
->setParameter('status', 'Complete')
|
||||||
|
->setParameter('term', '%'.$this->term.'%')
|
||||||
|
->orderBy('m.id', 'DESC')
|
||||||
|
->getQuery()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countUserChildrenByParentId(int $userId, string $imdbId): ?int
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('m')
|
||||||
|
->select('COUNT(m.id)')
|
||||||
|
->andWhere('m.user = :user')
|
||||||
|
->andWhere('m.imdbId = :imdbId')
|
||||||
|
->setParameter('user', $userId)
|
||||||
|
->setParameter('imdbId', $imdbId)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countUserActiveChildrenByParentId(int $userId, string $imdbId): ?int
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('m')
|
||||||
|
->select('COUNT(m.id)')
|
||||||
|
->andWhere('m.user = :user')
|
||||||
|
->andWhere('m.imdbId = :imdbId')
|
||||||
|
->andWhere('m.status IN (:statuses)')
|
||||||
|
->setParameter('user', $userId)
|
||||||
|
->setParameter('statuses', ['Active', 'New', 'In Progress'])
|
||||||
|
->setParameter('imdbId', $imdbId)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countUserCompleteChildrenByParentId(int $userId, string $imdbId): ?int
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('m')
|
||||||
|
->select('COUNT(m.id)')
|
||||||
|
->andWhere('m.user = :user')
|
||||||
|
->andWhere('m.imdbId = :imdbId')
|
||||||
|
->andWhere('m.status IN (:statuses)')
|
||||||
|
->setParameter('user', $userId)
|
||||||
|
->setParameter('statuses', ['Complete'])
|
||||||
|
->setParameter('imdbId', $imdbId)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,25 +26,34 @@
|
|||||||
{{ results.media.description }}
|
{{ results.media.description }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="text-gray-50">
|
<div class="text-gray-50 mb-2">
|
||||||
{% if results.media.stars != null %}
|
<div id="people" class="mb-1">
|
||||||
<strong>Starring</strong>: {{ results.media.stars|join(', ') }} <br />
|
{% if results.media.stars != null %}
|
||||||
{% endif %}
|
<strong>Starring</strong>: {{ results.media.stars|join(', ') }} <br />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if results.media.directors != null %}
|
{% if results.media.directors != null %}
|
||||||
<strong>Directors</strong>: {{ results.media.directors|join(', ') }} <br />
|
<strong>Directors</strong>: {{ results.media.directors|join(', ') }} <br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if results.media.producers != null %}
|
{% if results.media.producers != null %}
|
||||||
<strong>Producers</strong>: {{ results.media.producers|join(', ') }} <br />
|
<strong>Producers</strong>: {{ results.media.producers|join(', ') }} <br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if results.media.creators != null %}
|
{% if results.media.creators != null %}
|
||||||
<strong>Creators</strong>: {{ results.media.creators|join(', ') }} <br />
|
<strong>Creators</strong>: {{ results.media.creators|join(', ') }} <br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="dates" class="mb-1">
|
||||||
|
{% if results.media.premiereDate %}
|
||||||
|
<strong>Premiered</strong>: {{ results.media.premiereDate|date('n/j/Y', 'UTC') }} <br />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if results.media.genres != null %}
|
{% if results.media.genres != null %}
|
||||||
<div id="genres" class="text-gray-50 my-4">
|
<div id="genres" class="text-gray-50 my-4">
|
||||||
|
{# <strong>Genres</strong>: <br />#}
|
||||||
{% for genre in results.media.genres %}
|
{% for genre in results.media.genres %}
|
||||||
<small class="px-2 py-1 border border-orange-500 rounded-full">{{ genre }}</small>
|
<small class="px-2 py-1 border border-orange-500 rounded-full">{{ genre }}</small>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -53,14 +62,55 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if results.media.mediaType == "tvshows" %}
|
{% if results.media.mediaType == "tvshows" %}
|
||||||
<div class="flex flex-row justify-start items-end grow text-xs">
|
<div class="flex flex-col gap-4">
|
||||||
<span class="py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-orange-500 rounded-lg text-white">
|
<div class="flex flex-col grow text-white">
|
||||||
<span>{{ results.media.numberSeasons }}</span> season(s)
|
<strong class="mb-1">In Your Library</strong>
|
||||||
</span>
|
<div class="flex flex-col md:flex-row border-t-orange-500 text-xs gap-2">
|
||||||
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-sky-700 rounded-lg text-white" title='"{{ results.media.title }}" first aired on {{ results.media.premiereDate|date(null, 'UTC') }}.'>
|
<div class="flex flex-col">
|
||||||
{{ results.media.premiereDate|date(null, 'UTC') }}
|
<span class="text-sm mb-1">Seasons</span>
|
||||||
</span>
|
<div class="flex flex-col md:flex-row border p-2 border-orange-500 rounded-lg text-xs items-center">
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-orange-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.seasonCount }}</span> full
|
||||||
|
</span>
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-orange-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.partialSeasonCount }}</span> partial
|
||||||
|
</span>
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-orange-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.missingSeasonCount }}</span> missing
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm mb-1">Episodes</span>
|
||||||
|
<div class="flex flex-col md:flex-row border p-2 border-orange-500 rounded-lg text-xs items-center">
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-cyan-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.episodeCount }}</span> existing
|
||||||
|
</span>
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-cyan-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.missingEpisodeCount }}</span> missing
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-sm mb-1">Monitors</span>
|
||||||
|
<div class="flex flex-col md:flex-row border p-2 border-orange-500 rounded-lg text-xs items-center">
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-pink-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.monitorCount }}</span> total
|
||||||
|
</span>
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-pink-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.activeMonitorCount }}</span> active
|
||||||
|
</span>
|
||||||
|
<span class="py-1 px-1.5 mr-1 grow-0 font-bold bg-pink-500 rounded-lg text-white">
|
||||||
|
<span>{{ library.completeMonitorCount }}</span> complete
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if "movies" == results.media.mediaType %}
|
{% if "movies" == results.media.mediaType %}
|
||||||
|
|||||||
Reference in New Issue
Block a user