ensureCliAccess(); $this->artistImportToken = getenv("ARTIST_IMPORT_TOKEN"); $this->navidromeApiUrl = getenv("NAVIDROME_API_URL"); $this->navidromeAuthToken = getenv("NAVIDROME_API_TOKEN"); } public function handleRequest(): void { $input = json_decode(file_get_contents("php://input"), true); if (!$input) $this->sendJsonResponse("error", "Invalid or missing JSON body", 400); $providedToken = $input["token"] ?? null; $artistId = $input["artistId"] ?? null; if ($providedToken !== $this->artistImportToken) { $this->sendJsonResponse("error", "Unauthorized access", 401); } if (!$artistId) { $this->sendJsonResponse("error", "Artist ID is required", 400); } try { $artistData = $this->fetchNavidromeArtist($artistId); $artistExists = $this->processArtist($artistData); if ($artistExists) $this->processAlbums($artistId, $artistData->name); $this->sendJsonResponse("message", "Artist and albums synced successfully", 200); } catch (\Exception $e) { $this->sendJsonResponse("error", "Error: " . $e->getMessage(), 500); } } private function sendJsonResponse(string $key, string $message, int $statusCode): void { http_response_code($statusCode); header("Content-Type: application/json"); echo json_encode([$key => $message]); exit(); } private function fetchNavidromeArtist(string $artistId): object { $client = new Client(); $response = $client->get("{$this->navidromeApiUrl}/api/artist/{$artistId}", [ "headers" => [ "x-nd-authorization" => "Bearer {$this->navidromeAuthToken}", "Accept" => "application/json" ] ]); return json_decode($response->getBody()); } private function fetchNavidromeAlbums(string $artistId): array { $client = new Client(); $response = $client->get("{$this->navidromeApiUrl}/api/album", [ "query" => [ "_end" => 0, "_order" => "ASC", "_sort" => "max_year", "_start" => 0, "artist_id" => $artistId ], "headers" => [ "x-nd-authorization" => "Bearer {$this->navidromeAuthToken}", "Accept" => "application/json" ] ]); return json_decode($response->getBody(), true); } private function processArtist(object $artistData): bool { $artistName = $artistData->name ?? ""; if (!$artistName) throw new \Exception("Artist name is missing."); $existingArtist = $this->getArtistByName($artistName); if ($existingArtist) return true; $artistKey = sanitizeMediaString($artistName); $slug = "/music/artists/{$artistKey}"; $description = strip_tags($artistData->biography ?? ""); $genre = $this->resolveGenreId($artistData->genres[0]->name ?? ""); $starred = $artistData->starred ?? false; $artistPayload = [ "name_string" => $artistName, "slug" => $slug, "description" => $description, "tentative" => true, "art" => $this->placeholderImageId, "mbid" => "", "favorite" => $starred, "genres" => $genre, ]; $this->makeRequest("POST", "artists", ["json" => $artistPayload]); return true; } private function processAlbums(string $artistId, string $artistName): void { $artist = $this->getArtistByName($artistName); if (!$artist) throw new \Exception("Artist not found after insert."); $existingAlbums = $this->getExistingAlbums($artist["id"]); $existingAlbumKeys = array_column($existingAlbums, "key"); $navidromeAlbums = $this->fetchNavidromeAlbums($artistId); foreach ($navidromeAlbums as $album) { $albumName = $album["name"] ?? ""; $releaseYearRaw = $album["date"] ?? null; $releaseYear = null; if ($releaseYearRaw && preg_match('/^\d{4}/', $releaseYearRaw, $matches)) { $releaseYear = (int)$matches[0]; } $artistKey = sanitizeMediaString($artistName); $albumKey = "{$artistKey}-" . sanitizeMediaString($albumName); if (in_array($albumKey, $existingAlbumKeys)) { error_log("Skipping existing album: {$albumName}"); continue; } try { $albumPayload = [ "name" => $albumName, "key" => $albumKey, "release_year" => $releaseYear, "artist" => $artist["id"], "artist_name" => $artistName, "art" => $this->placeholderImageId, "tentative" => true, ]; $this->makeRequest("POST", "albums", ["json" => $albumPayload]); } catch (\Exception $e) { error_log("Error adding album '{$albumName}': " . $e->getMessage()); } } } private function getArtistByName(string $nameString): ?array { $response = $this->fetchFromApi("artists", "name_string=eq." . urlencode($nameString)); return $response[0] ?? null; } private function getExistingAlbums(string $artistId): array { return $this->fetchFromApi("albums", "artist=eq." . urlencode($artistId)); } private function resolveGenreId(string $genreName): ?string { $genres = $this->fetchFromApi("genres", "name=eq." . urlencode(strtolower($genreName))); return $genres[0]["id"] ?? null; } } $handler = new ArtistImportHandler(); $handler->handleRequest();