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();