feat(*.php, *.psql): deduplicate API code + performance improvements
This commit is contained in:
parent
cf3dac8a46
commit
4bad005e58
31 changed files with 502 additions and 666 deletions
171
api/mastodon.php
171
api/mastodon.php
|
@ -7,12 +7,9 @@ use GuzzleHttp\Client;
|
|||
|
||||
class MastodonPostHandler extends ApiHandler
|
||||
{
|
||||
protected string $postgrestUrl;
|
||||
protected string $postgrestApiKey;
|
||||
|
||||
private string $mastodonAccessToken;
|
||||
private string $rssFeedUrl;
|
||||
private string $baseUrl;
|
||||
private string $rssFeedUrl = "https://www.coryd.dev/feeds/syndication.xml";
|
||||
private string $baseUrl = "https://www.coryd.dev";
|
||||
|
||||
private const MASTODON_API_STATUS = "https://follow.coryd.dev/api/v1/statuses";
|
||||
|
||||
|
@ -22,21 +19,11 @@ class MastodonPostHandler extends ApiHandler
|
|||
{
|
||||
parent::__construct();
|
||||
$this->ensureCliAccess();
|
||||
$this->loadEnvironment();
|
||||
$this->validateAuthorization();
|
||||
$this->httpClient = $httpClient ?: new Client();
|
||||
}
|
||||
|
||||
private function loadEnvironment(): void
|
||||
{
|
||||
$this->postgrestUrl =
|
||||
getenv("POSTGREST_URL") ?: $_ENV["POSTGREST_URL"] ?? "";
|
||||
$this->postgrestApiKey =
|
||||
getenv("POSTGREST_API_KEY") ?: $_ENV["POSTGREST_API_KEY"] ?? "";
|
||||
$this->mastodonAccessToken =
|
||||
getenv("MASTODON_ACCESS_TOKEN") ?: $_ENV["MASTODON_ACCESS_TOKEN"] ?? "";
|
||||
$this->rssFeedUrl = "https://www.coryd.dev/feeds/syndication.xml";
|
||||
$this->baseUrl = "https://www.coryd.dev";
|
||||
$this->mastodonAccessToken = getenv("MASTODON_ACCESS_TOKEN") ?: $_ENV["MASTODON_ACCESS_TOKEN"] ?? "";
|
||||
$this->httpClient = $httpClient ?: new Client();
|
||||
|
||||
$this->validateAuthorization();
|
||||
}
|
||||
|
||||
private function validateAuthorization(): void
|
||||
|
@ -46,7 +33,7 @@ class MastodonPostHandler extends ApiHandler
|
|||
|
||||
if ($authHeader !== $expectedToken) {
|
||||
http_response_code(401);
|
||||
echo json_encode(["error" => "Unauthorized."]);
|
||||
echo json_encode(["error" => "Unauthorized"]);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
@ -61,16 +48,16 @@ class MastodonPostHandler extends ApiHandler
|
|||
$latestItems = $this->fetchRSSFeed($this->rssFeedUrl);
|
||||
|
||||
foreach (array_reverse($latestItems) as $item) {
|
||||
$existingPost = $this->fetchFromPostgREST("mastodon_posts", "link=eq." . urlencode($item["link"]));
|
||||
|
||||
if (!empty($existingPost)) continue;
|
||||
$existing = $this->fetchFromApi("mastodon_posts", "link=eq." . urlencode($item["link"]));
|
||||
if (!empty($existing)) continue;
|
||||
|
||||
$content = $this->truncateContent(
|
||||
$item["title"],
|
||||
str_replace(array("\n", "\r"), '', strip_tags($item["description"])),
|
||||
strip_tags($item["description"]),
|
||||
$item["link"],
|
||||
500
|
||||
);
|
||||
|
||||
$timestamp = date("Y-m-d H:i:s");
|
||||
|
||||
if (!$this->storeInDatabase($item["link"], $timestamp)) {
|
||||
|
@ -78,15 +65,11 @@ class MastodonPostHandler extends ApiHandler
|
|||
continue;
|
||||
}
|
||||
|
||||
$mastodonPostUrl = $this->postToMastodon($content, $item["image"] ?? null);
|
||||
|
||||
if ($mastodonPostUrl) {
|
||||
if (strpos($item["link"], $this->baseUrl . "/posts") !== false) {
|
||||
$slug = str_replace($this->baseUrl, "", $item["link"]);
|
||||
echo "Posted and stored URL: {$item["link"]}\n";
|
||||
}
|
||||
$postedUrl = $this->postToMastodon($content, $item["image"] ?? null);
|
||||
if ($postedUrl) {
|
||||
echo "Posted: {$postedUrl}\n";
|
||||
} else {
|
||||
echo "Failed to post to Mastodon. Skipping database update.\n";
|
||||
echo "Failed to post to Mastodon for: {$item["link"]}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,16 +79,16 @@ class MastodonPostHandler extends ApiHandler
|
|||
private function fetchRSSFeed(string $rssFeedUrl): array
|
||||
{
|
||||
$rssText = file_get_contents($rssFeedUrl);
|
||||
|
||||
if (!$rssText) throw new Exception("Failed to fetch RSS feed.");
|
||||
if (!$rssText) throw new \Exception("Failed to fetch RSS feed.");
|
||||
|
||||
$rss = new \SimpleXMLElement($rssText);
|
||||
$items = [];
|
||||
|
||||
foreach ($rss->channel->item as $item) {
|
||||
$imageUrl = null;
|
||||
|
||||
if ($item->enclosure && isset($item->enclosure['url'])) $imageUrl = (string) $item->enclosure['url'];
|
||||
if ($item->enclosure && isset($item->enclosure['url'])) {
|
||||
$imageUrl = (string) $item->enclosure['url'];
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
"title" => (string) $item->title,
|
||||
|
@ -120,15 +103,13 @@ class MastodonPostHandler extends ApiHandler
|
|||
|
||||
private function uploadImageToMastodon(string $imageUrl): ?string
|
||||
{
|
||||
$headers = [
|
||||
"Authorization" => "Bearer {$this->mastodonAccessToken}"
|
||||
];
|
||||
|
||||
$tempFile = tempnam(sys_get_temp_dir(), "mastodon_img");
|
||||
file_put_contents($tempFile, file_get_contents($imageUrl));
|
||||
|
||||
$response = $this->httpClient->request("POST", "https://follow.coryd.dev/api/v2/media", [
|
||||
"headers" => $headers,
|
||||
"headers" => [
|
||||
"Authorization" => "Bearer {$this->mastodonAccessToken}"
|
||||
],
|
||||
"multipart" => [
|
||||
[
|
||||
"name" => "file",
|
||||
|
@ -140,13 +121,12 @@ class MastodonPostHandler extends ApiHandler
|
|||
|
||||
unlink($tempFile);
|
||||
|
||||
$statusCode = $response->getStatusCode();
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new \Exception("Image upload failed with status {$response->getStatusCode()}");
|
||||
}
|
||||
|
||||
if ($statusCode !== 200) throw new Exception("Image upload failed with status $statusCode.");
|
||||
|
||||
$responseBody = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return $responseBody["id"] ?? null;
|
||||
$json = json_decode($response->getBody(), true);
|
||||
return $json["id"] ?? null;
|
||||
}
|
||||
|
||||
private function postToMastodon(string $content, ?string $imageUrl = null): ?string
|
||||
|
@ -156,43 +136,42 @@ class MastodonPostHandler extends ApiHandler
|
|||
"Content-Type" => "application/json",
|
||||
];
|
||||
|
||||
$mediaIds = [];
|
||||
$postData = ["status" => $content];
|
||||
|
||||
if ($imageUrl) {
|
||||
try {
|
||||
$mediaId = $this->uploadImageToMastodon($imageUrl);
|
||||
if ($mediaId) $mediaIds[] = $mediaId;
|
||||
} catch (Exception $e) {
|
||||
echo "Image upload failed: " . $e->getMessage() . "\n";
|
||||
if ($mediaId) $postData["media_ids"] = [$mediaId];
|
||||
} catch (\Exception $e) {
|
||||
echo "Image upload failed: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
||||
$postData = ["status" => $content];
|
||||
$response = $this->httpClient->request("POST", self::MASTODON_API_STATUS, [
|
||||
"headers" => $headers,
|
||||
"json" => $postData
|
||||
]);
|
||||
|
||||
if (!empty($mediaIds)) $postData["media_ids"] = $mediaIds;
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
throw new \Exception("Mastodon post failed: {$response->getBody()}");
|
||||
}
|
||||
|
||||
$response = $this->httpRequest(
|
||||
self::MASTODON_API_STATUS,
|
||||
"POST",
|
||||
$headers,
|
||||
$postData
|
||||
);
|
||||
|
||||
return $response["url"] ?? null;
|
||||
$body = json_decode($response->getBody()->getContents(), true);
|
||||
return $body["url"] ?? null;
|
||||
}
|
||||
|
||||
private function storeInDatabase(string $link, string $timestamp): bool
|
||||
{
|
||||
$data = [
|
||||
"link" => $link,
|
||||
"created_at" => $timestamp,
|
||||
];
|
||||
|
||||
try {
|
||||
$this->fetchFromPostgREST("mastodon_posts", "", "POST", $data);
|
||||
$this->makeRequest("POST", "mastodon_posts", [
|
||||
"json" => [
|
||||
"link" => $link,
|
||||
"created_at" => $timestamp
|
||||
]
|
||||
]);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
echo "Error storing post in database: " . $e->getMessage() . "\n";
|
||||
} catch (\Exception $e) {
|
||||
echo "Error storing post in DB: " . $e->getMessage() . "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -200,70 +179,32 @@ class MastodonPostHandler extends ApiHandler
|
|||
private function isDatabaseAvailable(): bool
|
||||
{
|
||||
try {
|
||||
$response = $this->fetchFromPostgREST("mastodon_posts", "limit=1");
|
||||
$response = $this->fetchFromApi("mastodon_posts", "limit=1");
|
||||
return is_array($response);
|
||||
} catch (Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
echo "Database check failed: " . $e->getMessage() . "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function truncateContent(
|
||||
string $title,
|
||||
string $description,
|
||||
string $link,
|
||||
int $maxLength
|
||||
): string {
|
||||
private function truncateContent(string $title, string $description, string $link, int $maxLength): string
|
||||
{
|
||||
$baseLength = strlen("$title\n\n$link");
|
||||
$availableSpace = $maxLength - $baseLength - 4;
|
||||
$available = $maxLength - $baseLength - 4;
|
||||
|
||||
if (strlen($description) > $availableSpace) {
|
||||
$description = substr($description, 0, $availableSpace);
|
||||
if (strlen($description) > $available) {
|
||||
$description = substr($description, 0, $available);
|
||||
$description = preg_replace('/\s+\S*$/', "", $description) . "...";
|
||||
}
|
||||
|
||||
return "$title\n\n$description\n\n$link";
|
||||
}
|
||||
|
||||
private function httpRequest(
|
||||
string $url,
|
||||
string $method = "GET",
|
||||
array $headers = [],
|
||||
?array $data = null
|
||||
): array {
|
||||
$options = ["headers" => $headers];
|
||||
|
||||
if ($data) $options["json"] = $data;
|
||||
|
||||
$response = $this->httpClient->request($method, $url, $options);
|
||||
$statusCode = $response->getStatusCode();
|
||||
|
||||
if ($statusCode >= 400) throw new Exception("HTTP error $statusCode: " . $response->getBody());
|
||||
|
||||
$responseBody = $response->getBody()->getContents();
|
||||
|
||||
if (empty($responseBody)) return [];
|
||||
|
||||
$decodedResponse = json_decode($responseBody, true);
|
||||
|
||||
if (!is_array($decodedResponse)) return [];
|
||||
|
||||
return $decodedResponse;
|
||||
}
|
||||
|
||||
private function getPostgRESTHeaders(): array
|
||||
{
|
||||
return [
|
||||
"Authorization" => "Bearer {$this->postgrestApiKey}",
|
||||
"Content-Type" => "application/json",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$handler = new MastodonPostHandler();
|
||||
$handler->handlePost();
|
||||
} catch (Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode(["error" => $e->getMessage()]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue