yellow = $yellow;
$this->yellow->system->setDefault("mastodonapiInstanceUrl", "https://example.social");
$this->yellow->system->setDefault("mastodonapiAccountId", "");
$this->yellow->system->setDefault("mastodonapiAccessToken", "");
$this->yellow->system->setDefault("mastodonapiHashtag", "");
$this->yellow->system->setDefault("mastodonapiAuthor", "YellowUser");
$this->yellow->system->setDefault("mastodonapiTag", "Fediverse");
$this->yellow->system->setDefault("mastodonapiFolder", "content/2-blog/");
$this->yellow->system->setDefault("mastodonapiLimit", "20");
$this->yellow->system->setDefault("mastodonapiStatus", "public");
$this->yellow->system->setDefault("mastodonapiMaxAge", "0");
$this->yellow->system->setDefault("mastodonapiUpdateInterval", "30");
}
// Reagiert auf System-Events und manuelle Aufrufe
public function onUpdate($action) {
if ($action == "mastodon" || $action == "daily" || $action == "install") {
$this->updateMastodonPosts();
}
}
// Ermöglicht 'php yellow.php mastodonapi' im Terminal
public function onCommand($command, $text) {
if ($command == "mastodonapi") {
echo "Mastodon Import gestartet...\n";
$count = $this->updateMastodonPosts();
if ($count === false) {
echo "Fehler: API nicht erreichbar oder falsche ID.\n";
return 500;
}
echo "Erfolg: $count neue Posts verarbeitet.\n";
return 0;
}
return 0;
}
// Hilfsfunktion für den Pfad zur Status-Datei
private function getStatusFile() {
return $this->yellow->system->get("coreWorkerDirectory")."mastodonapi.status";
}
// Die einzige Version dieser Funktion behalten:
public function updateMastodonPosts() {
$postsCreated = $this->processMastodonFeed();
if ($postsCreated !== false) {
file_put_contents($this->getStatusFile(), time());
}
return $postsCreated;
}
public function onTick() {
$interval = intval($this->yellow->system->get("mastodonapiUpdateInterval")) 60;
$statusFile = $this->getStatusFile();
$lastUpdate = file_exists($statusFile) ? intval(file_get_contents($statusFile)) : 0;
if (time() - $lastUpdate >= $interval) {
$this->updateMastodonPosts();
}
}
private function processMastodonFeed() {
$instanceUrl = $this->yellow->system->get("mastodonapiInstanceUrl");
$accountId = $this->yellow->system->get("mastodonapiAccountId");
$accessToken = $this->yellow->system->get("mastodonapiAccessToken");
$hashtag = ltrim($this->yellow->system->get("mastodonapiHashtag"), '#');
$defaultAuthor = $this->yellow->system->get("mastodonapiAuthor");
$defaultTag = $this->yellow->system->get("mastodonapiTag");
$targetFolder = $this->yellow->system->get("mastodonapiFolder");
$status = $this->yellow->system->get("mastodonapiStatus");
$maxAgeHours = intval($this->yellow->system->get("mastodonapiMaxAge"));
$limit = intval($this->yellow->system->get("mastodonapiLimit"));
if (empty($instanceUrl) || empty($accountId)) return false;
$apiUrl = rtrim($instanceUrl, "/") . "/api/v1/accounts/" . $accountId . "/statuses?limit=" . $limit;
$headers = ["User-Agent: YellowMastodonAPI"];
if (!empty($accessToken)) $headers[] = "Authorization: Bearer " . $accessToken;
$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2
]);
$json = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($json === false || $httpCode < 200 || $httpCode >= 300) return false;
$posts = json_decode($json, true);
if (!is_array($posts)) return false;
$postsCreated = 0;
foreach ($posts as $post) {
if (!empty($post['reblog']) || (!empty($post['reblogged']) && $post['reblogged'] === true)) continue;
if (!is_null($post['in_reply_to_id'])) continue;
$contentHtml = $post['content'] ?? '';
$createdAt = $post['created_at'] ?? '';
if ($maxAgeHours > 0) {
if (strtotime($createdAt) < (time() - ($maxAgeHours * 3600))) continue;
}
$tags = array_column($post['tags'] ?? [], 'name');
if (!empty($hashtag) && !in_array(strtolower($hashtag), array_map('strtolower', $tags))) continue;
$title = $this->generateTitle($contentHtml);
$titleSlug = $this->generateTitleSlug($title);
$fileName = date('Y-m-d', strtotime($createdAt)) . '-' . $titleSlug . '.md';
$fullPath = $this->yellow->system->get("coreServerDocument") . $targetFolder . $fileName;
if (file_exists($fullPath)) continue;
if (!is_dir(dirname($fullPath))) mkdir(dirname($fullPath), 0755, true);
$imageFilenames = [];
$imageAltTexts = [];
foreach ($post['media_attachments'] ?? [] as $media) {
if (($media['type'] ?? '') === 'image') {
$filename = $this->downloadAndSaveImage($media, $this->yellow->system->get("coreServerDocument") . 'media/images/');
if ($filename) {
$imageFilenames[] = $filename;
$imageAltTexts[] = $media['description'] ?? '';
}
}
}
$markdownContent = $this->generateMarkdown(
$title, $titleSlug, $createdAt, $contentHtml,
$post['account']['display_name'] ?: $defaultAuthor,
$post['account']['url'] ?: "#",
$defaultAuthor, $defaultTag, $imageFilenames, $imageAltTexts, $status
);
file_put_contents($fullPath, $markdownContent);
$postsCreated++;
}
return $postsCreated;
}
private function downloadAndSaveImage($media, $dirPath) {
$imageUrl = $media['remote_url'] ?? $media['url'] ?? $media['preview_url'] ?? null;
if (empty($imageUrl)) return false;
if (!is_dir($dirPath)) mkdir($dirPath, 0755, true);
$fileName = basename(parse_url($imageUrl, PHP_URL_PATH));
$fullPath = $dirPath . $fileName;
if (file_exists($fullPath)) return $fileName;
$ch = curl_init($imageUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_USERAGENT => "YellowMastodonAPI",
CURLOPT_SSL_VERIFYPEER => true,
]);
$imgData = curl_exec($ch);
curl_close($ch);
if (!$imgData) return false;
file_put_contents($fullPath, $imgData);
return $fileName;
}
private function generateTitle($content) {
$text = trim(strip_tags($content));
$text = preg_replace('/https?:\/\/[^\s]+|#\w+/u', '', $text);
$words = explode(' ', $text);
return trim(mb_substr(implode(' ', array_slice($words, 0, 7)), 0, 100, 'UTF-8')) ?: "Mastodon Post";
}
private function generateTitleSlug($title) {
$slug = mb_strtolower($title, 'UTF-8');
$slug = str_replace(['ä','ö','ü','ß',' '], ['ae','oe','ue','ss','-'], $slug);
return trim(preg_replace('/[^a-z0-9-]+/', '', $slug), '-');
}
private function generateMarkdown($title, $slug, $dateTime, $html, $origAuthor, $origUrl, $yellowAuthor, $yellowTag, $images, $alts, $status) {
$date = new DateTime($dateTime);
$pub = $date->format('Y-m-d H:i:s');
$content = trim(html_entity_decode(strip_tags(str_replace(["
", "