197 lines
5.8 KiB
PHP
197 lines
5.8 KiB
PHP
<?php
|
|
|
|
require_once __DIR__.'/../bootstrap.php';
|
|
|
|
use App\Classes\ApiHandler;
|
|
use GuzzleHttp\Client;
|
|
|
|
class SeasonImportHandler extends ApiHandler
|
|
{
|
|
private string $tmdbApiKey;
|
|
|
|
private string $seasonsImportToken;
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->ensureCliAccess();
|
|
$this->tmdbApiKey = getenv('TMDB_API_KEY') ?: $_ENV['TMDB_API_KEY'];
|
|
$this->seasonsImportToken = getenv('SEASONS_IMPORT_TOKEN') ?: $_ENV['SEASONS_IMPORT_TOKEN'];
|
|
$this->authenticateRequest();
|
|
}
|
|
|
|
private function authenticateRequest(): void
|
|
{
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
$this->sendErrorResponse('Method Not Allowed', 405);
|
|
}
|
|
|
|
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
|
|
|
if (! preg_match('/Bearer\s+(.+)/', $authHeader, $matches)) {
|
|
$this->sendErrorResponse('Unauthorized', 401);
|
|
}
|
|
|
|
$providedToken = trim($matches[1]);
|
|
|
|
if ($providedToken !== $this->seasonsImportToken) {
|
|
$this->sendErrorResponse('Forbidden', 403);
|
|
}
|
|
}
|
|
|
|
public function importSeasons(): void
|
|
{
|
|
$ongoingShows = $this->fetchFromApi('optimized_shows', 'ongoing=eq.true');
|
|
|
|
if (empty($ongoingShows)) {
|
|
$this->sendResponse(['message' => 'No ongoing shows to update'], 200);
|
|
}
|
|
|
|
foreach ($ongoingShows as $show) {
|
|
$this->processShowSeasons($show);
|
|
}
|
|
|
|
$this->sendResponse(['message' => 'Season import completed'], 200);
|
|
}
|
|
|
|
private function processShowSeasons(array $show): void
|
|
{
|
|
$tmdbId = $show['tmdb_id'] ?? null;
|
|
$showId = $show['id'] ?? null;
|
|
|
|
if (! $tmdbId || ! $showId) {
|
|
return;
|
|
}
|
|
|
|
$tmdbShowData = $this->fetchShowDetails($tmdbId);
|
|
$seasons = $tmdbShowData['seasons'] ?? [];
|
|
$status = $tmdbShowData['status'] ?? 'Unknown';
|
|
|
|
if (empty($seasons) && ! $this->shouldKeepOngoing($status)) {
|
|
$this->disableOngoingStatus($showId);
|
|
|
|
return;
|
|
}
|
|
|
|
foreach ($seasons as $season) {
|
|
$this->processSeasonEpisodes($showId, $tmdbId, $season);
|
|
}
|
|
}
|
|
|
|
private function shouldKeepOngoing(string $status): bool
|
|
{
|
|
return in_array($status, ['Returning Series', 'In Production']);
|
|
}
|
|
|
|
private function fetchShowDetails(string $tmdbId): array
|
|
{
|
|
$client = new Client();
|
|
$url = "https://api.themoviedb.org/3/tv/{$tmdbId}?api_key={$this->tmdbApiKey}&append_to_response=seasons";
|
|
|
|
try {
|
|
$response = $client->get($url, ['headers' => ['Accept' => 'application/json']]);
|
|
|
|
return json_decode($response->getBody(), true) ?? [];
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private function fetchWatchedEpisodes(int $showId): array
|
|
{
|
|
$episodes = $this->fetchFromApi('optimized_last_watched_episodes', "show_id=eq.{$showId}&order=last_watched_at.desc&limit=1");
|
|
|
|
if (empty($episodes)) {
|
|
return [];
|
|
}
|
|
|
|
return [
|
|
'season_number' => (int) $episodes[0]['season_number'],
|
|
'episode_number' => (int) $episodes[0]['episode_number'],
|
|
];
|
|
}
|
|
|
|
private function processSeasonEpisodes(int $showId, string $tmdbId, array $season): void
|
|
{
|
|
$seasonNumber = $season['season_number'] ?? null;
|
|
|
|
if ($seasonNumber === null || $seasonNumber == 0) {
|
|
return;
|
|
}
|
|
|
|
$episodes = $this->fetchSeasonEpisodes($tmdbId, $seasonNumber);
|
|
|
|
if (empty($episodes)) {
|
|
return;
|
|
}
|
|
|
|
$watched = $this->fetchWatchedEpisodes($showId);
|
|
$lastWatchedSeason = $watched['season_number'] ?? null;
|
|
$lastWatchedEpisode = $watched['episode_number'] ?? null;
|
|
|
|
$scheduled = $this->fetchFromApi(
|
|
'optimized_scheduled_episodes',
|
|
"show_id=eq.{$showId}&season_number=eq.{$seasonNumber}"
|
|
);
|
|
|
|
$scheduledEpisodeNumbers = array_column($scheduled, 'episode_number');
|
|
|
|
foreach ($episodes as $episode) {
|
|
$episodeNumber = $episode['episode_number'] ?? null;
|
|
|
|
if ($episodeNumber === null) {
|
|
continue;
|
|
}
|
|
if (in_array($episodeNumber, $scheduledEpisodeNumbers)) {
|
|
continue;
|
|
}
|
|
if ($lastWatchedSeason !== null && $seasonNumber < $lastWatchedSeason) {
|
|
return;
|
|
}
|
|
if ($seasonNumber == $lastWatchedSeason && $episodeNumber <= $lastWatchedEpisode) {
|
|
continue;
|
|
}
|
|
|
|
$this->addEpisodeToSchedule($showId, $seasonNumber, $episode);
|
|
}
|
|
}
|
|
|
|
private function fetchSeasonEpisodes(string $tmdbId, int $seasonNumber): array
|
|
{
|
|
$client = new Client();
|
|
$url = "https://api.themoviedb.org/3/tv/{$tmdbId}/season/{$seasonNumber}?api_key={$this->tmdbApiKey}";
|
|
|
|
try {
|
|
$response = $client->get($url, ['headers' => ['Accept' => 'application/json']]);
|
|
|
|
return json_decode($response->getBody(), true)['episodes'] ?? [];
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private function addEpisodeToSchedule(int $showId, int $seasonNumber, array $episode): void
|
|
{
|
|
$airDate = $episode['air_date'] ?? null;
|
|
|
|
if (! $airDate) {
|
|
return;
|
|
}
|
|
|
|
$today = date('Y-m-d');
|
|
$status = ($airDate < $today) ? 'aired' : 'upcoming';
|
|
$payload = [
|
|
'show_id' => $showId,
|
|
'season_number' => $seasonNumber,
|
|
'episode_number' => $episode['episode_number'],
|
|
'air_date' => $airDate,
|
|
'status' => $status,
|
|
];
|
|
|
|
$this->makeRequest('POST', 'scheduled_episodes', ['json' => $payload]);
|
|
}
|
|
}
|
|
|
|
$handler = new SeasonImportHandler();
|
|
$handler->importSeasons();
|