Files
DanDingNoneBot/danding_bot/plugins/danding_qqpush/README.md

9.4 KiB
Raw Blame History

Danding_QqPush 插件

用于通过外部 HTTP API 向 QQ 群定向推送通知的 NoneBot 插件。

功能特性

  • ✅ 通过 HTTP API 推送消息到指定 QQ 群
  • ✅ 自动将文本渲染为图片,避免长文本刷屏
  • ✅ 统一通知卡片版式,群聊/私聊使用不同场景徽章
  • ✅ 可选 @指定 QQ 用户;省略 qq 时直接发送群消息
  • ✅ 使用 # 符号表示换行
  • ✅ 基于 Token 的简单鉴权机制
  • ✅ 支持中文文本渲染
  • ✅ 自带超级用户预览命令「测试通知图片」,可在群聊/私聊中直接核对卡片版式

目录结构

danding_qqpush/
├── __init__.py         # 插件初始化模块
├── config.py           # 配置模块
├── api.py              # FastAPI 路由模块
├── text_parser.py      # 文本处理模块
├── image_render.py     # 通知卡片生成模块
├── article_render.py   # 公告 HTML 截图模块
├── preview_image_render.py # 预览命令共用的渲染器实例
├── sender.py           # 消息发送模块
├── test_command.py     # 超级用户「测试通知图片」预览命令
└── utils.py            # 工具函数模块

通知卡片样式

群聊与私聊的普通图片通知(即未传 html 的文本通知)共用同一套「冷灰外衬 + 白色圆角卡片」版式,只通过右上角的场景徽章区分来源:

  • 顶部为蓝色品牌头部:左侧固定文案「蛋定助手」,右侧为白底胶囊场景徽章
  • 正文使用比纯黑更柔和的墨色,行距不低于 1.6 倍
  • 底部为分割线与脚注「本消息由蛋定助手自动生成」
  • 正文按宽度自动折行,并做中文避头尾处理
  • Emoji 按整体方块宽度测量,避免溢出卡片;Emoji 数据源不可用时自动降级为普通文本绘制,通知仍会正常发出

场景徽章

场景 (scene) 徽章文案 徽章颜色 使用位置
common 通用通知 灰色 渲染默认值
group 群聊通知 品牌蓝 POST /danding/qqpush/{token} 的普通文本通知
private 私聊通知 橙色 POST /danding/private/{token} 的图片通知
  • scene 是渲染层内部参数,不新增配置项、也不新增 API 请求字段:请求体格式保持不变,场景由插件按接口自动选择(群聊接口传 group,私聊接口传 private)
  • 未知的 scene 取值会回退为 common
  • 传入 html 的公告推送使用 Chromium 截图(article_render.py),不使用本卡片版式
renderer.render(text)                        # 通用通知
renderer.render(text, scene="group")         # 群聊通知
renderer.render(text, scene="private")       # 私聊通知
renderer.render_to_base64(text, title="🏇 赛马开赛", scene="group")  # 自定义标题行
renderer.render(text, title=None)            # 不绘制标题行

title 默认沿用旧版固定文案「蛋定助手通知您:」以保持向后兼容;显式传 None 或空字符串才隐藏标题行(卡片头部已展示「蛋定助手」品牌,需要更紧凑的版式时可以隐藏)。

测试通知图片命令

不想注册 HTTP 接口、也不想占用群聊刷屏时,可以直接用机器人自带的预览命令核对卡片版式。

项目 说明
主命令 测试通知图片
别名 通知图片测试、测试通知卡片
权限 仅 NoneBot 超级用户(SUPERUSER,即 .env 的 SUPERUSERS)
触发方式 群聊直接发送,或与机器人私聊发送;均不需要 @机器人
  • 群聊中触发时渲染 scene="group"(群聊通知徽章),私聊中触发时渲染 scene="private"(私聊通知徽章)
  • 预览内容是固定示例,覆盖标题行、中文、多行、Emoji 与中文标点;标题行特意写成 # 会被解析为换行:,同时演示 # 作为换行符的用法
  • 命令复用通知卡片渲染器与插件配置(字体、宽度、行距等),不新增配置项,也不改变任何 HTTP 接口
  • 渲染是同步阻塞操作,命令会把它放到 asyncio.to_thread 执行,避免阻塞事件循环
  • 渲染失败时机器人会记录 [Danding_QqPush] 通知图片测试失败 日志,并回复「通知图片生成失败,请查看机器人日志后重试。」

用法示例

(群聊 / 私聊中直接发送)
测试通知图片

安装与配置

1. 确保依赖已安装

pip install pillow

2. 配置 Token

在 .env 文件或 NoneBot 配置文件中添加:

DANDING_QQPUSH_TOKEN = "your-custom-token-here"

如果不配置,默认使用 danding-8HkL9xQ2。

3. 启动 NoneBot

nb run

插件会自动加载,并在日志中显示注册的 API 路径。

API 使用说明

接口信息

  • 方法: POST
  • 路径: /danding/qqpush/{token}
  • Content-Type: application/json

请求参数

参数名 类型 必填 说明
token path 是 配置的 Token
group_id int 是 接收消息的 QQ 群号
qq int 否 可选的被 @ QQ 号;省略时不 @ 任何人
text string 是 通知文本(# 表示换行)

请求示例

curl -X POST "http://localhost:8080/danding/qqpush/danding-8HkL9xQ2" \
  -H "Content-Type: application/json" \
  -d '{
    "group_id": 123456789,
    "text": "系统告警#数据库连接失败#请立即处理"
  }'

Python 请求示例

import requests

url = "http://localhost:8080/danding/qqpush/danding-8HkL9xQ2"
data = {
    "group_id": 123456789,
    "text": "系统告警#数据库连接失败#请立即处理"
}

response = requests.post(url, json=data)
print(response.json())

响应示例

成功响应 (200):

{
  "success": true,
  "message": "推送成功",
  "data": {
    "group_id": 123456789,
    "qq": null,
    "message_id": 12345
  }
}

错误响应 (400):

{
  "detail": "group_id 不能为空"
}

错误响应 (403):

{
  "detail": "Token 验证失败"
}

错误响应 (500):

{
  "detail": "Bot 未连接,请检查机器人状态"
}

配置选项

可以在配置文件中自定义以下选项:

class Config(BaseModel):
    Token: str = "danding-8HkL9xQ2"
    """API 访问 Token"""
    
    ImageWidth: int = 800
    """图片宽度(像素)"""
    
    ImageFontSize: int = 24
    """字体大小(像素)"""
    
    ImagePadding: int = 30
    """图片内边距(像素)"""
    
    ImageLineSpacing: float = 1.4
    """行距倍数"""
    
    ImageBgColor: tuple = (252, 252, 252)
    """图片背景颜色 (R, G, B)"""
    
    ImageTextColor: tuple = (0, 0, 0)
    """文本颜色 (R, G, B)"""
    
    MaxTextLength: int = 2000
    """最大文本长度(字符数)"""
    
    FontPaths: list = [...]
    """字体文件路径列表"""

与通知卡片相关的渲染约定(沿用上述配置,无需新增配置项):

  • ImageBgColor 用作卡片填充色;卡片外衬固定为冷灰色,保证浅色卡片轮廓可见
  • ImageTextColor 传入纯黑 (0, 0, 0) 时会自动替换为柔和的 (31, 35, 41),其他颜色原样使用
  • ImageLineSpacing 低于 1.6 时正文按 1.6 倍行距渲染
  • ImageWidth/ImagePadding/FontPaths 的语义不变,卡片与正文均按它们计算版式

文本格式说明

  • 使用 # 符号表示换行
  • 示例:第一行#第二行#第三行 会被渲染为三行文本
  • 超过最大长度的文本会被自动截断

注意事项

  1. 安全性: Token 泄露只影响推送能力,无账号风险,但建议定期更换
  2. Bot 状态: 确保 Bot 已连接,否则会返回 500 错误
  3. 群权限: 确保 Bot 在目标群中有发送消息的权限
  4. 字体支持: 插件会自动尝试加载系统中的中文字体

故障排查

问题:启动时显示 "未找到可用的 Bot 实例"

说明: 这是正常现象。插件加载时 Bot 可能还未连接,API 调用时会动态获取 Bot 实例。

问题:返回 "Bot 未连接"

解决方案:

  • 检查 NoneBot 是否正常启动
  • 检查 OneBot V11 连接状态
  • 确认 Bot 已成功连接到 QQ 服务器

问题:图片显示乱码

解决方案:

  • 检查系统是否安装了中文字体
  • 在 FontPaths 配置中添加正确的字体路径

问题:消息发送失败

解决方案:

  • 检查 Bot 是否在目标群中
  • 检查 Bot 是否有发送消息的权限
  • 查看日志中的详细错误信息

问题:发送「测试通知图片」没有反应

解决方案:

  • 确认发送者的 QQ 号在 .env 的 SUPERUSERS 中(该命令仅超级用户可用,其他用户发送不会触发、也不会有提示)
  • 确认消息就是命令本身(测试通知图片 / 通知图片测试 / 测试通知卡片),命令后跟其他内容不会触发
  • 若机器人回复「通知图片生成失败,请查看机器人日志后重试。」,按日志中 [Danding_QqPush] 通知图片测试失败 的报错排查字体路径与配置

测试

使用提供的测试脚本进行测试:

python test_qqpush.py

修改脚本中的 group_id 和 qq 为实际值。

插件自带的自动化测试(不需要真实 QQ 连接):

python -m pytest tests/test_danding_qqpush_test_command.py -q