ensureCliAccess(); $this->tmdbApiKey = $_ENV["TMDB_API_KEY"] ?? getenv("TMDB_API_KEY"); $this->tmdbImportToken = $_ENV["WATCHING_IMPORT_TOKEN"] ?? getenv("WATCHING_IMPORT_TOKEN"); } public function handleRequest(): void { $input = json_decode(file_get_contents("php://input"), true); if (!$input) $this->sendErrorResponse("Invalid or missing JSON body", 400); $providedToken = $input["token"] ?? null; $tmdbId = $input["tmdb_id"] ?? null; $mediaType = $input["media_type"] ?? null; if ($providedToken !== $this->tmdbImportToken) { $this->sendErrorResponse("Unauthorized access", 401); } if (!$tmdbId || !$mediaType) { $this->sendErrorResponse("tmdb_id and media_type are required", 400); } try { $mediaData = $this->fetchTMDBData($tmdbId, $mediaType); $this->processMedia($mediaData, $mediaType); $this->sendResponse(["message" => "Media imported successfully"], 200); } catch (\Exception $e) { $this->sendErrorResponse("Error: " . $e->getMessage(), 500); } } private function fetchTMDBData(string $tmdbId, string $mediaType): array { $client = new Client(); $url = "https://api.themoviedb.org/3/{$mediaType}/{$tmdbId}"; $response = $client->get($url, [ "query" => ["api_key" => $this->tmdbApiKey], "headers" => ["Accept" => "application/json"], ]); $data = json_decode($response->getBody(), true); if (empty($data)) throw new \Exception("No data found for TMDB ID: {$tmdbId}"); return $data; } private function processMedia(array $mediaData, string $mediaType): void { $tagline = $mediaData["tagline"] ?? null; $overview = $mediaData["overview"] ?? null; $description = ""; if (!empty($tagline)) $description .= "> " . trim($tagline) . "\n\n"; if (!empty($overview)) $description .= trim($overview); $id = $mediaData["id"]; $title = $mediaType === "movie" ? $mediaData["title"] : $mediaData["name"]; $year = $mediaData["release_date"] ?? $mediaData["first_air_date"] ?? null; $year = $year ? substr($year, 0, 4) : null; $tags = array_map( fn($genre) => strtolower(trim($genre["name"])), $mediaData["genres"] ?? [] ); $slug = $mediaType === "movie" ? "/watching/movies/{$id}" : "/watching/shows/{$id}"; $payload = [ "title" => $title, "year" => $year, "description" => $description, "tmdb_id" => $id, "slug" => $slug, ]; $table = $mediaType === "movie" ? "movies" : "shows"; try { $response = $this->makeRequest("POST", $table, ["json" => $payload]); } catch (\Exception $e) { $response = $this->fetchFromApi($table, "tmdb_id=eq.{$id}")[0] ?? []; } if (!empty($response["id"])) { $mediaId = $response["id"]; $existingTagMap = $this->getTagIds($tags); $updatedTagMap = $this->insertMissingTags($tags, $existingTagMap); $this->associateTagsWithMedia($mediaType, $mediaId, array_values($updatedTagMap)); } } private function getTagIds(array $tags): array { $map = []; foreach ($tags as $tag) { $response = $this->fetchFromApi("tags", "name=ilike." . urlencode($tag)); if (!empty($response[0]["id"])) { $map[strtolower($tag)] = $response[0]["id"]; } } return $map; } private function insertMissingTags(array $tags, array $existingMap): array { $newTags = array_diff($tags, array_keys($existingMap)); foreach ($newTags as $tag) { try { $created = $this->makeRequest("POST", "tags", ["json" => ["name" => $tag]]); if (!empty($created["id"])) $existingMap[$tag] = $created["id"]; } catch (\Exception $e) { $fallback = $this->fetchFromApi("tags", "name=eq." . urlencode($tag)); if (!empty($fallback[0]["id"])) $existingMap[$tag] = $fallback[0]["id"]; } } return $existingMap; } private function associateTagsWithMedia(string $mediaType, int $mediaId, array $tagIds): void { $junction = $mediaType === "movie" ? "movies_tags" : "shows_tags"; $mediaColumn = $mediaType === "movie" ? "movies_id" : "shows_id"; foreach ($tagIds as $tagId) { $this->makeRequest("POST", $junction, ["json" => [ $mediaColumn => $mediaId, "tags_id" => $tagId ]]); } } } $handler = new WatchingImportHandler(); $handler->handleRequest();