diff --git a/mastodonapi.php b/mastodonapi.php index 4583c88..035a338 100644 --- a/mastodonapi.php +++ b/mastodonapi.php @@ -1,11 +1,9 @@ yellow = $yellow; $this->yellow->system->setDefault("mastodonapiInstanceUrl", "https://example.social"); @@ -21,211 +19,190 @@ class YellowMastodonapi { $this->yellow->system->setDefault("mastodonapiUpdateInterval", "30"); } - // Reagiert auf System-Events und manuelle Aufrufe + // Handle update public function onUpdate($action) { - if ($action == "mastodon" || $action == "daily" || $action == "install") { + if ( $action=="mastodon" || $action=="daily" || $action=="install" ) { $this->updateMastodonPosts(); } } - // Ermöglicht 'php yellow.php mastodonapi' im Terminal + // Handle command public function onCommand($command, $text) { - if ($command == "mastodonapi") { + if ( $command=="mastodonapi" ) { echo "Mastodon Import gestartet...\n"; $count = $this->updateMastodonPosts(); - - if ($count === false) { + if ( $count===false ) { echo "Fehler: API nicht erreichbar oder falsche ID.\n"; return 500; } - - echo "Erfolg: $count neue Posts verarbeitet.\n"; + echo "Erfolg: " . $count . " neue Posts verarbeitet.\n"; return true; } return 0; } - // Hilfsfunktion für den Pfad zur Status-Datei - private function getStatusFile() { - return $this->yellow->system->get("coreWorkerDirectory")."mastodonapi.status"; + // Handle periodic update + 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(); + } } - // Die einzige Version dieser Funktion behalten: + // Update Mastodon posts public function updateMastodonPosts() { $postsCreated = $this->processMastodonFeed(); - - if ($postsCreated !== false) { + 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(); - } - } - + // Process Mastodon feed and create pages 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"), '#'); + $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; - + $defaultTag = $this->yellow->system->get("mastodonapiTag"); + $targetFolder = $this->yellow->system->get("mastodonapiFolder"); + $statusSetting = $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; - + $headers = array("User-Agent: YellowMastodonapi/" . self::VERSION); + if ( !empty($accessToken) ) $headers[] = "Authorization: Bearer " . $accessToken; $ch = curl_init($apiUrl); - curl_setopt_array($ch, [ + curl_setopt_array($ch, array( 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; - + if ( $json===false || $httpCode < 200 || $httpCode >= 300 ) return false; $posts = json_decode($json, true); - if (!is_array($posts)) return false; - + 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; + 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; - + $tags = array_column($post["tags"] ?? array(), "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'; + $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) { + if ( file_exists($fullPath) ) continue; + if ( !is_dir(dirname($fullPath)) ) mkdir(dirname($fullPath), 0755, true); + $imageFilenames = array(); + $imageAltTexts = array(); + foreach ( $post["media_attachments"] ?? array() as $media ) { + if ( ( $media["type"] ?? "" )==="image" ) { + $filename = $this->downloadAndSaveImage($media, $this->yellow->system->get("coreServerDocument") . "media/images/"); + if ( $filename ) { $imageFilenames[] = $filename; - $imageAltTexts[] = $media['description'] ?? ''; + $imageAltTexts[] = $media["description"] ?? ""; } } } - $markdownContent = $this->generateMarkdown( $title, $titleSlug, $createdAt, $contentHtml, - $post['account']['display_name'] ?: $defaultAuthor, - $post['account']['url'] ?: "#", - $defaultAuthor, $defaultTag, $imageFilenames, $imageAltTexts, $status + $post["account"]["display_name"] ?: $defaultAuthor, + $post["account"]["url"] ?: "#", + $defaultAuthor, $defaultTag, $imageFilenames, $imageAltTexts, $statusSetting ); - file_put_contents($fullPath, $markdownContent); $postsCreated++; } return $postsCreated; } + // Download and save image 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); - + $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; - + if ( file_exists($fullPath) ) return $fileName; $ch = curl_init($imageUrl); - curl_setopt_array($ch, [ + curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 30, - CURLOPT_USERAGENT => "YellowMastodonAPI", + CURLOPT_USERAGENT => "YellowMastodonapi/" . self::VERSION, CURLOPT_SSL_VERIFYPEER => true, - ]); + )); $imgData = curl_exec($ch); curl_close($ch); - - if (!$imgData) return false; + if ( !$imgData ) return false; file_put_contents($fullPath, $imgData); return $fileName; } + // Generate title from content 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"; + $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"; } + // Generate slug from title 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), '-'); + $slug = mb_strtolower($title, "UTF-8"); + $slug = str_replace(array("ä","ö","ü","ß"," "), array("ae","oe","ue","ss","-"), $slug); + return trim(preg_replace("/[^a-z0-9-]+/", "", $slug), "-"); } + // Generate markdown content 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(["
", "

"], ["\n", "

\n"], $html)), ENT_QUOTES | ENT_HTML5, 'UTF-8')); + $pub = $date->format("Y-m-d H:i:s"); + $content = trim(html_entity_decode(strip_tags(str_replace(array("
", "

"), array("\n", "

\n"), $html)), ENT_QUOTES | ENT_HTML5, "UTF-8")); $content = str_replace("\n", "\n> ", $content); - - $imageMarkdown = ''; - $featuredImage = $featuredImageAlt = ''; - foreach ($images as $i => $filename) { - $alt = isset($alts[$i]) ? htmlspecialchars($alts[$i], ENT_QUOTES) : ''; + $imageMarkdown = ""; + $featuredImage = $featuredImageAlt = ""; + foreach ( $images as $i => $filename ) { + $alt = isset($alts[$i]) ? htmlspecialchars($alts[$i], ENT_QUOTES) : ""; $imageMarkdown .= "\n\"$alt\"/\n"; - if ($i === 0) { + if ( $i===0 ) { $featuredImage = "Image: $filename\n"; $featuredImageAlt = "ImageAlt: $alt\n"; } } + $authorSafe = str_replace("@", "@", $origAuthor); + return "---\n" . + "Title: $title\n" . + "TitleSlug: $slug\n" . + "Published: $pub\n" . + "Author: $yellowAuthor\n" . + "Layout: blog\n" . + "Tag: $yellowTag\n" . + "Status: $status\n" . + $featuredImage . $featuredImageAlt . + "---\n\n" . + $imageMarkdown . "\n" . + "> " . $content . "\n>\n" . + "> — $authorSafe"; + } - $authorSafe = str_replace('@', '@', $origAuthor); - - return << $content -> -> — $authorSafe -MD; + // Return status file path + private function getStatusFile() { + return $this->yellow->system->get("coreWorkerDirectory") . "mastodonapi.status"; } } \ No newline at end of file