Compare commits
5 Commits
v0.36.7
...
dev-child-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec0d2a198c | ||
|
|
1f1c6f775f | ||
|
|
cd14a197aa | ||
|
|
a9031df3c3 | ||
|
|
55ab9d840e |
@@ -67,6 +67,9 @@ export default class MonitorListRow extends HTMLTableRowElement {
|
||||
<th class="px-4 py-2">
|
||||
<div class="dark:text-orange-500 text-right whitespace-nowrap ">Downloaded At</div>
|
||||
</th>
|
||||
<th class="px-4 py-2">
|
||||
<div class="dark:text-orange-500 text-right whitespace-nowrap ">Air Date</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -107,6 +110,9 @@ export default class MonitorListRow extends HTMLTableRowElement {
|
||||
<td class="px-4 py-2">
|
||||
<div class="text-left dark:text-white whitespace-nowrap font-normal">${this.getAttribute('downloaded-at') ?? "-"}</div>
|
||||
</td>
|
||||
<td class="px-4 py-2">
|
||||
<div class="text-left dark:text-white whitespace-nowrap font-normal">${this.getAttribute('air-date') ?? "-"}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -23,7 +23,12 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
if (null !== content && undefined !== content && "" !== content) {
|
||||
document.dispatchEvent(new CustomEvent('showPreviewContentModal', {detail: {heading: heading, content: content}}))
|
||||
if (['', null, undefined].includes(monitor.getAttribute('parent-id'))) {
|
||||
window.location.href = `/monitors/${monitor.getAttribute('monitor-id')}`;
|
||||
} else {
|
||||
document.dispatchEvent(new CustomEvent('showPreviewContentModal', {detail: {heading: heading, content: content}}))
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
34
migrations/Version20251106045808.php
Normal file
34
migrations/Version20251106045808.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20251106045808 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE monitor ADD poster VARCHAR(1024) DEFAULT NULL
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE monitor DROP poster
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ class Paginator
|
||||
public function paginate($query, int $page = 1, int $limit = 5): Paginator
|
||||
{
|
||||
$paginator = new OrmPaginator($query);
|
||||
|
||||
$paginator
|
||||
->getQuery()
|
||||
->setFirstResult($limit * ($page - 1))
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Monitor\Action\Result\AddMonitorResult;
|
||||
use App\Monitor\Framework\Entity\Monitor;
|
||||
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||
use App\Monitor\MonitorEvents;
|
||||
use App\Tmdb\TmdbClient;
|
||||
use App\User\Framework\Repository\UserRepository;
|
||||
use DateTimeImmutable;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
@@ -22,13 +23,17 @@ readonly class AddMonitorHandler implements HandlerInterface
|
||||
private MessageBusInterface $bus,
|
||||
private MonitorRepository $movieMonitorRepository,
|
||||
private UserRepository $userRepository,
|
||||
private TmdbClient $tmdb,
|
||||
) {}
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
$user = $this->userRepository->find($command->userId);
|
||||
$poster = $this->getPoster($command->imdbId);
|
||||
|
||||
$monitor = (new Monitor())
|
||||
->setUser($user)
|
||||
->setPoster($poster)
|
||||
->setTmdbId($command->tmdbId)
|
||||
->setImdbId($command->imdbId)
|
||||
->setTitle($command->title)
|
||||
@@ -56,4 +61,10 @@ readonly class AddMonitorHandler implements HandlerInterface
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function getPoster(string $imdbId): ?string
|
||||
{
|
||||
$data = $this->tmdb->tvShowDetails($imdbId);
|
||||
return $data->poster;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Download\Framework\Repository\DownloadRepository;
|
||||
use App\EventLog\Action\Command\AddEventLogCommand;
|
||||
use App\Monitor\Action\Command\MonitorMovieCommand;
|
||||
use App\Monitor\Action\Result\MonitorTvEpisodeResult;
|
||||
use App\Monitor\Framework\Entity\Monitor;
|
||||
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||
use App\Monitor\MonitorEvents;
|
||||
use App\Tmdb\TmdbClient;
|
||||
@@ -43,6 +44,7 @@ readonly class MonitorTvEpisodeHandler implements HandlerInterface
|
||||
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(),
|
||||
@@ -151,4 +153,15 @@ readonly class MonitorTvEpisodeHandler implements HandlerInterface
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ readonly class MonitorTvShowHandler implements HandlerInterface
|
||||
{
|
||||
$this->logger->info('> [MonitorTvShowHandler] Executing MonitorTvShowHandler');
|
||||
$monitor = $this->monitorRepository->find($command->monitorId);
|
||||
$this->refreshData($monitor);
|
||||
|
||||
// Check current episodes
|
||||
$downloadedEpisodes = $this->mediaFiles
|
||||
@@ -157,4 +158,15 @@ readonly class MonitorTvShowHandler implements HandlerInterface
|
||||
'status' => ['New', 'Active', 'In Progress']
|
||||
]) !== null;
|
||||
}
|
||||
|
||||
private function refreshData(Monitor $monitor)
|
||||
{
|
||||
if (null === $monitor->getPoster()) {
|
||||
$this->logger->info('> [MonitorTvShowHandler] Refreshing poster for "' . $monitor->getTitle() . '"');
|
||||
$poster = $this->tmdb->tvshowDetails($monitor->getImdbId())->poster;
|
||||
if (null !== $poster && "" !== $poster) {
|
||||
$monitor->setPoster($poster);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Monitor\Framework\Controller;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\Monitor\Framework\Entity\Monitor;
|
||||
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||
use App\User\Framework\Entity\User;
|
||||
use Spatie\IcalendarGenerator\Components\Calendar;
|
||||
@@ -27,9 +28,10 @@ class CalendarController extends AbstractController
|
||||
->refreshInterval(10);
|
||||
|
||||
$monitors = $monitorRepository->whereAirDateNotNull();
|
||||
$calendar->event(Map::from($monitors)->map(function ($monitor) {
|
||||
$calendar->event(Map::from($monitors)->map(function (Monitor $monitor) {
|
||||
return new Event($monitor->getTitle())
|
||||
->startsAt($monitor->getAirDate())
|
||||
->attachment($monitor->getPoster())
|
||||
->fullDay();
|
||||
})->toArray());
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Monitor\Action\Handler\AddMonitorHandler;
|
||||
use App\Monitor\Action\Handler\DeleteMonitorHandler;
|
||||
use App\Monitor\Action\Input\AddMonitorInput;
|
||||
use App\Monitor\Action\Input\DeleteMonitorInput;
|
||||
use App\Monitor\Framework\Entity\Monitor;
|
||||
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
@@ -34,4 +35,12 @@ class WebController extends AbstractController
|
||||
{
|
||||
return $this->render('monitor/upcoming-episodes.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/monitors/{id}', name: 'app.monitor.view', methods: ['GET'])]
|
||||
public function viewMonitor(Monitor $monitor)
|
||||
{
|
||||
return $this->render('monitor/view.html.twig', [
|
||||
'monitor' => $monitor,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ class Monitor
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $searchCount = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?string $poster = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private bool $onlyFuture = true;
|
||||
|
||||
@@ -230,6 +233,17 @@ class Monitor
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPoster(): ?string
|
||||
{
|
||||
return $this->poster;
|
||||
}
|
||||
|
||||
public function setPoster(?string $poster): ?self
|
||||
{
|
||||
$this->poster = $poster;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParent(): ?self
|
||||
{
|
||||
return $this->parent;
|
||||
|
||||
@@ -17,11 +17,14 @@ final class MonitorList extends AbstractController
|
||||
|
||||
use PaginateTrait;
|
||||
|
||||
#[LiveProp(writable: true)]
|
||||
public ?int $parentMonitorId = null;
|
||||
|
||||
#[LiveProp(writable: true)]
|
||||
public string $term = "";
|
||||
|
||||
#[LiveProp(writable: true)]
|
||||
public string $type;
|
||||
public string $type = "";
|
||||
|
||||
#[LiveProp(writable: true)]
|
||||
public bool $isWidget = true;
|
||||
@@ -33,7 +36,9 @@ final class MonitorList extends AbstractController
|
||||
#[LiveAction]
|
||||
public function getMonitors()
|
||||
{
|
||||
if ($this->type === "active") {
|
||||
if (null !== $this->parentMonitorId) {
|
||||
return $this->getChildMonitorsByParentId($this->parentMonitorId);
|
||||
} elseif ($this->type === "active") {
|
||||
return $this->getActiveUserMonitors();
|
||||
} elseif ($this->type === "complete") {
|
||||
return $this->getCompleteUserMonitors();
|
||||
@@ -48,6 +53,7 @@ final class MonitorList extends AbstractController
|
||||
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')
|
||||
@@ -67,4 +73,16 @@ final class MonitorList extends AbstractController
|
||||
->getQuery()
|
||||
);
|
||||
}
|
||||
|
||||
#[LiveAction]
|
||||
public function getChildMonitorsByParentId(int $parentId)
|
||||
{
|
||||
return $this->asPaginator(
|
||||
$this->monitorRepository->createQueryBuilder('m')
|
||||
->andWhere("m.parent = :parentId")
|
||||
->setParameter('parentId', $parentId)
|
||||
->orderBy('m.id', 'DESC')
|
||||
->getQuery()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,17 @@
|
||||
class="px-6 py-3 text-start">
|
||||
ID
|
||||
</th>
|
||||
{% if null != parentMonitorId %}
|
||||
<th scope="col"
|
||||
class="hidden md:table-cell px-6 py-3 text-start">
|
||||
Search Count
|
||||
</th>
|
||||
{% else %}
|
||||
<th scope="col"
|
||||
class="hidden md:table-cell px-6 py-3 text-start">
|
||||
Episodes
|
||||
</th>
|
||||
{% endif %}
|
||||
<th scope="col"
|
||||
class="hidden md:table-cell px-6 py-3 text-start">
|
||||
Created at
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<tr{{ attributes }} is="monitor-list-row" id="monitor_{{ monitor.id }}" class="dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-900"
|
||||
monitor-id="{{ monitor.id }}"
|
||||
parent-id="{{ monitor.parent.id ?? null }}"
|
||||
imdb-id="{{ monitor.imdbId }}"
|
||||
media-title="{{ monitor.title }}"
|
||||
season="{{ monitor.season }}"
|
||||
@@ -11,6 +12,7 @@
|
||||
created-at="{{ monitor.createdAt|date('m/d/Y g:i a') }}"
|
||||
last-search="{{ monitor.lastSearch|date('m/d/Y g:i a') }}"
|
||||
downloaded-at="{{null != monitor.downloadedAt ? monitor.downloadedAt|date('m/d/Y g:i a') : '-' }}"
|
||||
air-date="{{ null != monitor.airDate ? monitor.airDate|date('m/d/Y g:i a') : '-' }}"
|
||||
>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-stone-800 truncate">
|
||||
<a href="{{ path('app_search_result', {imdbId: monitor.imdbId, mediaType: monitor.monitorType|as_download_type}) }}"
|
||||
@@ -26,9 +28,15 @@
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm">
|
||||
{{ monitor|monitor_media_id }}
|
||||
</td>
|
||||
{% if null != monitor.parent %}
|
||||
<td class="hidden md:table-cell px-6 py-4 whitespace-nowrap text-sm">
|
||||
{{ monitor.searchCount }}
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="hidden md:table-cell px-6 py-4 whitespace-nowrap text-sm">
|
||||
{{ monitor.children|length }}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="hidden md:table-cell px-6 py-4 whitespace-nowrap text-sm">
|
||||
{{ monitor.createdAt|date('m/d/Y h:i a') }}
|
||||
</td>
|
||||
|
||||
12
templates/monitor/view.html.twig
Normal file
12
templates/monitor/view.html.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}{{ monitor.title }} — Monitors — Torsearch{% endblock %}
|
||||
{% block h2 %}Monitors{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="px-4 py-2">
|
||||
<twig:Card title="Viewing your monitors for {{ monitor.title }}">
|
||||
<twig:MonitorList :parentMonitorId="monitor.id" :isWidget="false" :perPage="10"></twig:MonitorList>
|
||||
</twig:Card>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user