feat: /api/upcoming-episodes
This commit is contained in:
35
migrations/Version20250823173128.php
Normal file
35
migrations/Version20250823173128.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?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 Version20250823173128 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE monitor ADD air_date DATETIME 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 air_date
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use App\Monitor\Framework\Entity\Monitor;
|
|||||||
use App\Monitor\Framework\Repository\MonitorRepository;
|
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||||
use App\Tmdb\Tmdb;
|
use App\Tmdb\Tmdb;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use App\Base\Util\PTN;
|
use App\Base\Util\PTN;
|
||||||
@@ -96,6 +97,7 @@ readonly class MonitorTvShowHandler implements HandlerInterface
|
|||||||
->setMonitorType('tvepisode')
|
->setMonitorType('tvepisode')
|
||||||
->setSeason($episode['season_number'])
|
->setSeason($episode['season_number'])
|
||||||
->setEpisode($episode['episode_number'])
|
->setEpisode($episode['episode_number'])
|
||||||
|
->setAirDate($episode['air_date'] !== null && $episode['air_date'] !== "" ? Carbon::parse($episode['air_date']) : null)
|
||||||
->setCreatedAt(new DateTimeImmutable())
|
->setCreatedAt(new DateTimeImmutable())
|
||||||
->setSearchCount(0)
|
->setSearchCount(0)
|
||||||
->setStatus('New');
|
->setStatus('New');
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Monitor\Framework\Controller;
|
namespace App\Monitor\Framework\Controller;
|
||||||
|
|
||||||
|
use Aimeos\Map;
|
||||||
use App\Base\Service\Broadcaster;
|
use App\Base\Service\Broadcaster;
|
||||||
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;
|
||||||
use App\Monitor\Action\Input\DeleteMonitorInput;
|
use App\Monitor\Action\Input\DeleteMonitorInput;
|
||||||
|
use App\Monitor\Framework\Repository\MonitorRepository;
|
||||||
use App\Monitor\Framework\Scheduler\MonitorDispatcher;
|
use App\Monitor\Framework\Scheduler\MonitorDispatcher;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@@ -65,4 +67,25 @@ class ApiController extends AbstractController
|
|||||||
'message' => 'Manually dispatched MonitorDispatcher'
|
'message' => 'Manually dispatched MonitorDispatcher'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/api/upcoming-episodes', name: 'api.upcoming-episodes', methods: ['GET'])]
|
||||||
|
public function upcomingEpisodes(MonitorRepository $repository): Response
|
||||||
|
{
|
||||||
|
$monitors = $repository->whereAirDateNotNull();
|
||||||
|
$monitors = Map::from($monitors)->map(function ($monitor) {
|
||||||
|
return [
|
||||||
|
'id' => $monitor->getId(),
|
||||||
|
'title' => $monitor->getTitle() . ' (S' . str_pad($monitor->getSeason(), 2, '0', STR_PAD_LEFT) . 'E' . str_pad($monitor->getEpisode(), 2, '0', STR_PAD_LEFT) . ')',
|
||||||
|
'start' => $monitor->getAirDate()->format('Y-m-d H:i:s'),
|
||||||
|
'allDay' => true
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'status' => 200,
|
||||||
|
'data' => [
|
||||||
|
'episodes' => $monitors->toArray(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ class Monitor
|
|||||||
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
private ?\DateTimeInterface $lastSearch = null;
|
private ?\DateTimeInterface $lastSearch = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
|
private ?\DateTime $airDate = null;
|
||||||
|
|
||||||
#[ORM\Column]
|
#[ORM\Column]
|
||||||
private ?\DateTimeImmutable $createdAt = null;
|
private ?\DateTimeImmutable $createdAt = null;
|
||||||
|
|
||||||
@@ -257,6 +260,17 @@ class Monitor
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAirDate(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->airDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAirDate(?\DateTimeImmutable $airDate): static
|
||||||
|
{
|
||||||
|
$this->airDate = $airDate;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function removeChild(self $child): static
|
public function removeChild(self $child): static
|
||||||
{
|
{
|
||||||
if ($this->children->removeElement($child)) {
|
if ($this->children->removeElement($child)) {
|
||||||
|
|||||||
@@ -33,4 +33,12 @@ class MonitorRepository extends ServiceEntityRepository
|
|||||||
|
|
||||||
return $this->paginator->paginate($query, $page, $perPage);
|
return $this->paginator->paginate($query, $page, $perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function whereAirDateNotNull()
|
||||||
|
{
|
||||||
|
$query = $this->createQueryBuilder('m')
|
||||||
|
->andWhere('m.airDate IS NOT NULL')
|
||||||
|
->getQuery();
|
||||||
|
return $query->getResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
var calendarEl = document.getElementById('calendar');
|
let data = await fetch('/api/upcoming-episodes');
|
||||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
data = (await data.json())['data'];
|
||||||
initialView: 'dayGridMonth'
|
|
||||||
|
const calendarEl = document.getElementById('calendar');
|
||||||
|
const calendar = new FullCalendar.Calendar(calendarEl, {
|
||||||
|
initialView: 'dayGridMonth',
|
||||||
|
events: data['episodes'],
|
||||||
});
|
});
|
||||||
calendar.render();
|
calendar.render();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user