受限于typecho博客没有通知,自己写了一个博客有评论就通知的gotify插件,脚本使用之前的python改的。这是效果  ```php finishComment = __CLASS__ . '::requestService'; \Typecho\Plugin::factory('Widget_Comments_Edit')->finishComment = __CLASS__ . '::requestService'; // 注册异步调用服务 \Typecho\Plugin::factory('Widget_Service')->sendGotify = __CLASS__ . '::sendGotify'; } /** * 禁用插件方法 * * @access public * @return void * @throws PluginException */ public static function deactivate() { // 通常不需要显式移除 } /** * 获取插件配置面板 * * @param Form $form 配置面板 * @access public * @return void */ public static function config(Form $form) { // Gotify 服务器地址 $serverUrl = new Text('serverUrl', NULL, '', _t('Gotify 服务器地址'), _t('例如: http://your-gotify-server.com')); $form->addInput($serverUrl->addRule('required', _t('Gotify 服务器地址不能为空'))); // 应用 Token $appToken = new Text('appToken', NULL, '', _t('应用 Token'), _t('在 Gotify 中创建应用后获得的 Token')); $form->addInput($appToken->addRule('required', _t('应用 Token 不能为空'))); // 通知标题 $title = new Text('title', NULL, '博客有新评论', _t('通知标题'), _t('收到新评论时的推送标题')); $form->addInput($title); // 消息优先级 (Priority) - 使用 Text 输入框 $priority = new Text('priority', NULL, '1', _t('消息优先级'), _t('设置 Gotify 消息的优先级 (自己在Gorify的定义)')); $form->addInput($priority); // 移除了 "是否启用" 的配置选项,插件默认启用 } /** * 个人用户的配置面板 * * @param Form $form * @access public * @return void */ public static function personalConfig(Form $form) { // 个人配置通常为空 } /** * 评论通知回调 - 触发异步服务 * 这个方法在评论完成后被调用 * * @access public * @param $comment (Widget_Comments_Edit 或 Widget_Feedback 的实例) * @return void * @throws PluginException */ public static function requestService($comment) { // 检查评论对象是否有效 if (!isset($comment->coid) || !$comment->have()) { error_log("GotifyNotify: Invalid comment object received in requestService."); return; } $coid = $comment->coid; $options = Options::alloc()->plugin('GotifyNotify'); // 移除了对 $options->enable 的检查,插件默认启用 // 检查必要配置 if (empty($options->serverUrl) || empty($options->appToken)) { error_log("GotifyNotify: Missing server URL or app token, skipping notification for comment ID {$coid}."); return; } // 调用 Widget_Service 中注册的异步方法 // 将评论 ID 传递给异步服务 try { error_log("GotifyNotify: Calling async service for comment ID {$coid}."); Utils\Helper::requestService('sendGotify', $coid); } catch (\Exception $e) { error_log("GotifyNotify: Failed to call async service for comment ID {$coid}. Error: " . $e->getMessage()); } } /** * 异步发送 Gotify 通知 * 这个方法由 Widget_Service 调用 * * @param integer $coid 评论ID * @access public * @return void * @throws WidgetException * @throws DbException */ public static function sendGotify(int $coid) { error_log("GotifyNotify Service: Starting to process comment ID {$coid}."); // 获取插件配置 $options = Options::alloc()->plugin('GotifyNotify'); // 移除了对 $options->enable 的检查,插件默认启用 // 重新获取评论对象 try { $commentWidget = Utils\Helper::widgetById('comments', $coid); } catch (WidgetException $e) { error_log("GotifyNotify Service: Failed to get comment widget for ID {$coid}. Error: " . $e->getMessage()); return; } if (!$commentWidget->have()) { error_log("GotifyNotify Service: Comment widget is empty for ID {$coid}."); return; } // 检查必要配置 if (empty($options->serverUrl) || empty($options->appToken)) { error_log("GotifyNotify Service: Missing configuration for comment ID {$coid}."); return; } try { // 构造通知内容 $title = $options->title ?: '博客有新评论'; $message = self::buildMessage($commentWidget); // 传入 widget 对象 // 获取优先级设置 $priority = $options->priority ?? '1'; // 默认优先级为 1 error_log("GotifyNotify Service: Prepared message for comment ID {$coid}. Title: {$title}, Priority: {$priority}"); // 发送通知,传入优先级 self::sendGotifyMessage($options->serverUrl, $options->appToken, $title, $message, $priority); error_log("GotifyNotify Service: Successfully sent notification for comment ID {$coid}."); } catch (\Exception $e) { // 记录详细错误信息 error_log("GotifyNotify Service: Failed to send notification for comment ID {$coid}. Error: " . $e->getMessage()); error_log("GotifyNotify Service: Stack trace: " . $e->getTraceAsString()); } } /** * 构造通知消息内容 * * @param \Widget\Base\Comments $comment 评论对象 * @return string 消息内容 */ private static function buildMessage($comment) { $content = ''; if (is_object($comment) && $comment->have()) { // 从评论对象获取信息 $author = $comment->author ?? '匿名用户'; $mail = $comment->mail ?? ''; $url = $comment->url ?? ''; $text = $comment->text ?? ''; // $ip = $comment->ip ?? ''; // Widget\Base\Comments 通常不直接暴露 IP $content = "作者: {$author}\n"; if (!empty($mail)) { $content .= "邮箱: {$mail}\n"; } if (!empty($url)) { $content .= "网站: {$url}\n"; } // if (!empty($ip)) { // $content .= "IP: {$ip}\n"; // } $content .= "内容: {$text}\n"; $content .= "时间: " . date('Y-m-d H:i:s', $comment->created) . "\n"; // 使用评论创建时间 $content .= "文章: " . $comment->title . "\n"; // 文章标题 $content .= "链接: " . $comment->permalink . "\n"; // 评论链接 } else { // 兼容其他情况 $content = "收到新评论,请登录后台查看 (评论ID: " . ($comment->coid ?? 'unknown') . ")"; } return $content; } /** * 发送 Gotify 消息 * * @param string $serverUrl Gotify 服务器地址 * @param string $appToken 应用 Token * @param string $title 消息标题 * @param string $message 消息内容 * @param string $priority 消息优先级 * @throws \Exception */ private static function sendGotifyMessage($serverUrl, $appToken, $title, $message, $priority = '1') { // 清理 URL $serverUrl = rtrim($serverUrl, '/'); // 构造请求 URL (使用查询参数传递 token) $url = $serverUrl . '/message'; // 准备表单数据,包含 priority $data = [ 'title' => $title, 'message' => $message, 'priority' => $priority // 使用传入的优先级 ]; // 准备查询参数 $params = ['token' => $appToken]; $fullUrl = $url . '?' . http_build_query($params); error_log("GotifyNotify: Sending request to {$fullUrl}"); error_log("GotifyNotify: POST data: " . print_r($data, true)); // 使用 cURL 发送请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $fullUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 发送表单数据 curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 根据你的服务器 SSL 配置调整 curl_setopt($ch, CURLOPT_USERAGENT, 'Typecho GotifyNotify Plugin/1.3.0'); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); error_log("GotifyNotify: cURL Response Code: {$httpCode}"); error_log("GotifyNotify: cURL Response Body: {$response}"); error_log("GotifyNotify: cURL Error (if any): {$error}"); // 检查响应 if ($response === false) { throw new \Exception('cURL error: ' . $error); } if ($httpCode >= 200 && $httpCode < 300) { // 成功 error_log("GotifyNotify: Message sent successfully."); // 可以进一步检查返回的 JSON $result = json_decode($response, true); if (!$result) { error_log("GotifyNotify: Warning - Could not decode JSON response, but HTTP status was OK."); } return; // 成功返回 } else { // 失败 throw new \Exception('HTTP error: ' . $httpCode . ', response: ' . $response); } } } ``` Loading... 受限于typecho博客没有通知,自己写了一个博客有评论就通知的gotify插件,脚本使用之前的python改的。这是效果  ```php <?php namespace TypechoPlugin\GotifyNotify; use Typecho\Plugin\PluginInterface; use Typecho\Widget\Helper\Form; use Typecho\Widget\Helper\Form\Element\Text; // use Typecho\Widget\Helper\Form\Element\Radio; // 不再需要 Radio 元素 use Widget\Options; use Typecho\Plugin\Exception as PluginException; use Typecho\Widget\Exception as WidgetException; use Typecho\Db\Exception as DbException; use Utils; if (!defined('__TYPECHO_ROOT_DIR__')) { exit; } /** * 当用户评论时通过 Gotify 发送通知 * * @package GotifyNotify * @author 白荼 * @version 1.3.0 * @link https://gotify.net */ class Plugin implements PluginInterface { /** * 激活插件方法 * * @access public * @return void * @throws PluginException */ public static function activate() { // 监听评论完成事件 - 触发服务调用 \Typecho\Plugin::factory('Widget_Feedback')->finishComment = __CLASS__ . '::requestService'; \Typecho\Plugin::factory('Widget_Comments_Edit')->finishComment = __CLASS__ . '::requestService'; // 注册异步调用服务 \Typecho\Plugin::factory('Widget_Service')->sendGotify = __CLASS__ . '::sendGotify'; } /** * 禁用插件方法 * * @access public * @return void * @throws PluginException */ public static function deactivate() { // 通常不需要显式移除 } /** * 获取插件配置面板 * * @param Form $form 配置面板 * @access public * @return void */ public static function config(Form $form) { // Gotify 服务器地址 $serverUrl = new Text('serverUrl', NULL, '', _t('Gotify 服务器地址'), _t('例如: http://your-gotify-server.com')); $form->addInput($serverUrl->addRule('required', _t('Gotify 服务器地址不能为空'))); // 应用 Token $appToken = new Text('appToken', NULL, '', _t('应用 Token'), _t('在 Gotify 中创建应用后获得的 Token')); $form->addInput($appToken->addRule('required', _t('应用 Token 不能为空'))); // 通知标题 $title = new Text('title', NULL, '博客有新评论', _t('通知标题'), _t('收到新评论时的推送标题')); $form->addInput($title); // 消息优先级 (Priority) - 使用 Text 输入框 $priority = new Text('priority', NULL, '1', _t('消息优先级'), _t('设置 Gotify 消息的优先级 (自己在Gorify的定义)')); $form->addInput($priority); // 移除了 "是否启用" 的配置选项,插件默认启用 } /** * 个人用户的配置面板 * * @param Form $form * @access public * @return void */ public static function personalConfig(Form $form) { // 个人配置通常为空 } /** * 评论通知回调 - 触发异步服务 * 这个方法在评论完成后被调用 * * @access public * @param $comment (Widget_Comments_Edit 或 Widget_Feedback 的实例) * @return void * @throws PluginException */ public static function requestService($comment) { // 检查评论对象是否有效 if (!isset($comment->coid) || !$comment->have()) { error_log("GotifyNotify: Invalid comment object received in requestService."); return; } $coid = $comment->coid; $options = Options::alloc()->plugin('GotifyNotify'); // 移除了对 $options->enable 的检查,插件默认启用 // 检查必要配置 if (empty($options->serverUrl) || empty($options->appToken)) { error_log("GotifyNotify: Missing server URL or app token, skipping notification for comment ID {$coid}."); return; } // 调用 Widget_Service 中注册的异步方法 // 将评论 ID 传递给异步服务 try { error_log("GotifyNotify: Calling async service for comment ID {$coid}."); Utils\Helper::requestService('sendGotify', $coid); } catch (\Exception $e) { error_log("GotifyNotify: Failed to call async service for comment ID {$coid}. Error: " . $e->getMessage()); } } /** * 异步发送 Gotify 通知 * 这个方法由 Widget_Service 调用 * * @param integer $coid 评论ID * @access public * @return void * @throws WidgetException * @throws DbException */ public static function sendGotify(int $coid) { error_log("GotifyNotify Service: Starting to process comment ID {$coid}."); // 获取插件配置 $options = Options::alloc()->plugin('GotifyNotify'); // 移除了对 $options->enable 的检查,插件默认启用 // 重新获取评论对象 try { $commentWidget = Utils\Helper::widgetById('comments', $coid); } catch (WidgetException $e) { error_log("GotifyNotify Service: Failed to get comment widget for ID {$coid}. Error: " . $e->getMessage()); return; } if (!$commentWidget->have()) { error_log("GotifyNotify Service: Comment widget is empty for ID {$coid}."); return; } // 检查必要配置 if (empty($options->serverUrl) || empty($options->appToken)) { error_log("GotifyNotify Service: Missing configuration for comment ID {$coid}."); return; } try { // 构造通知内容 $title = $options->title ?: '博客有新评论'; $message = self::buildMessage($commentWidget); // 传入 widget 对象 // 获取优先级设置 $priority = $options->priority ?? '1'; // 默认优先级为 1 error_log("GotifyNotify Service: Prepared message for comment ID {$coid}. Title: {$title}, Priority: {$priority}"); // 发送通知,传入优先级 self::sendGotifyMessage($options->serverUrl, $options->appToken, $title, $message, $priority); error_log("GotifyNotify Service: Successfully sent notification for comment ID {$coid}."); } catch (\Exception $e) { // 记录详细错误信息 error_log("GotifyNotify Service: Failed to send notification for comment ID {$coid}. Error: " . $e->getMessage()); error_log("GotifyNotify Service: Stack trace: " . $e->getTraceAsString()); } } /** * 构造通知消息内容 * * @param \Widget\Base\Comments $comment 评论对象 * @return string 消息内容 */ private static function buildMessage($comment) { $content = ''; if (is_object($comment) && $comment->have()) { // 从评论对象获取信息 $author = $comment->author ?? '匿名用户'; $mail = $comment->mail ?? ''; $url = $comment->url ?? ''; $text = $comment->text ?? ''; // $ip = $comment->ip ?? ''; // Widget\Base\Comments 通常不直接暴露 IP $content = "作者: {$author}\n"; if (!empty($mail)) { $content .= "邮箱: {$mail}\n"; } if (!empty($url)) { $content .= "网站: {$url}\n"; } // if (!empty($ip)) { // $content .= "IP: {$ip}\n"; // } $content .= "内容: {$text}\n"; $content .= "时间: " . date('Y-m-d H:i:s', $comment->created) . "\n"; // 使用评论创建时间 $content .= "文章: " . $comment->title . "\n"; // 文章标题 $content .= "链接: " . $comment->permalink . "\n"; // 评论链接 } else { // 兼容其他情况 $content = "收到新评论,请登录后台查看 (评论ID: " . ($comment->coid ?? 'unknown') . ")"; } return $content; } /** * 发送 Gotify 消息 * * @param string $serverUrl Gotify 服务器地址 * @param string $appToken 应用 Token * @param string $title 消息标题 * @param string $message 消息内容 * @param string $priority 消息优先级 * @throws \Exception */ private static function sendGotifyMessage($serverUrl, $appToken, $title, $message, $priority = '1') { // 清理 URL $serverUrl = rtrim($serverUrl, '/'); // 构造请求 URL (使用查询参数传递 token) $url = $serverUrl . '/message'; // 准备表单数据,包含 priority $data = [ 'title' => $title, 'message' => $message, 'priority' => $priority // 使用传入的优先级 ]; // 准备查询参数 $params = ['token' => $appToken]; $fullUrl = $url . '?' . http_build_query($params); error_log("GotifyNotify: Sending request to {$fullUrl}"); error_log("GotifyNotify: POST data: " . print_r($data, true)); // 使用 cURL 发送请求 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $fullUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 发送表单数据 curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Accept: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 根据你的服务器 SSL 配置调整 curl_setopt($ch, CURLOPT_USERAGENT, 'Typecho GotifyNotify Plugin/1.3.0'); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); error_log("GotifyNotify: cURL Response Code: {$httpCode}"); error_log("GotifyNotify: cURL Response Body: {$response}"); error_log("GotifyNotify: cURL Error (if any): {$error}"); // 检查响应 if ($response === false) { throw new \Exception('cURL error: ' . $error); } if ($httpCode >= 200 && $httpCode < 300) { // 成功 error_log("GotifyNotify: Message sent successfully."); // 可以进一步检查返回的 JSON $result = json_decode($response, true); if (!$result) { error_log("GotifyNotify: Warning - Could not decode JSON response, but HTTP status was OK."); } return; // 成功返回 } else { // 失败 throw new \Exception('HTTP error: ' . $httpCode . ', response: ' . $response); } } } ``` 最后修改:2025 年 08 月 01 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏