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, 'headers' => ['Prefer' => 'return=representation'], ]); } catch (\Exception $e) { $response = $this->fetchFromApi($table, "tmdb_id=eq.{$id}")[0] ?? []; } $record = $response[0] ?? []; if (! empty($record['id'])) { $mediaId = $record['id']; $tagIds = $this->getTagIds($tags); if (! empty($tagIds)) { $this->associateTagsWithMedia($mediaType, $mediaId, array_values($tagIds)); } } } 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 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();