Metadata-Version: 2.1
Name: nonebot-plugin-douyin-notify
Version: 0.1.0
Summary: Douyin video and live notifications for NoneBot2 and OneBot V11
Keywords: nonebot2,nonebot,douyin,onebot,qq
Author: mengbingnaixi
License: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Project-URL: Homepage, https://github.com/mengbingnaixi/nonebot-plugin-douyin-notify
Project-URL: Repository, https://github.com/mengbingnaixi/nonebot-plugin-douyin-notify
Project-URL: Documentation, https://github.com/mengbingnaixi/nonebot-plugin-douyin-notify#readme
Project-URL: Issues, https://github.com/mengbingnaixi/nonebot-plugin-douyin-notify/issues
Requires-Python: <4.0,>=3.10
Requires-Dist: nonebot2[fastapi]>=2.5.0
Requires-Dist: nonebot-adapter-onebot>=2.4.6
Requires-Dist: nonebot-plugin-apscheduler>=0.5.0
Requires-Dist: nonebot-plugin-localstore>=0.7.4
Requires-Dist: aiosqlite>=0.20.0
Requires-Dist: jinja2>=3.1.4
Requires-Dist: playwright>=1.45.0
Requires-Dist: python-multipart>=0.0.9
Description-Content-Type: text/markdown

# nonebot-plugin-douyin-notify

基于 NoneBot2、OneBot V11 和 Playwright 的抖音视频/直播订阅推送插件。插件使用固定的无头 Chromium 打开公开抖音页面，复用抖音网页自身产生的请求获取账号、作品和直播状态，并将新内容渲染为图片卡片推送到 QQ 群。

> 抖音网页接口不是公开稳定 API，页面结构、访问频率限制和安全验证策略可能随时变化。请仅处理公开信息，合理设置轮询间隔，并遵守平台条款、版权规则和个人信息保护要求。

## 功能

- 订阅公开抖音用户的新视频、开播状态或两者
- 为每条群订阅分别配置 `@全体成员`、视频/直播自定义封面和渲染方案
- 同一作者只采集一次，再向多个订阅群分发
- 首次检查只建立基线，不补发历史作品或当前直播
- 按作品、直播场次、机器人和群持久化去重
- 固定使用无头 Chromium，不支持切换为可见浏览器
- 受管理令牌保护的 Web 控制台
- 在 Web 中扫码登录并操作抖音官方二次验证页面
- 视频/直播 PNG 卡片渲染，失败时自动回退为文本消息
- 按群或按订阅用户、按视频/直播选择模板、字体、主色和辅色
- 主题色支持在单色与双色渐变之间切换
- 上传自定义 UTF-8 HTML 模板、字体和 PNG/JPEG/WebP 封面并实时预览

## 安装

```bash
nb plugin install nonebot-plugin-douyin-notify
playwright install chromium
```

也可以使用 pip：

```bash
pip install nonebot-plugin-douyin-notify
playwright install chromium
```

NoneBot 必须使用 FastAPI 驱动并加载 OneBot V11 适配器：

```dotenv
DRIVER=~fastapi+~httpx+~websockets
```

```toml
[tool.nonebot]
plugins = ["nonebot_plugin_douyin_notify"]

[tool.nonebot.adapters]
nonebot-adapter-onebot = [
  { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" },
]
```

## 配置

插件零配置可加载，但 Web 管理默认关闭。启用 Web 时应配置高强度随机令牌，并通过防火墙、反向代理或内网限制访问范围。

```dotenv
# 相对路径以 NoneBot 工作目录为基准；Windows 也推荐使用正斜杠
DOUYIN_NOTIFY_DATA="E:/BotData/douyin-notify"
DOUYIN_NOTIFY_POLL_INTERVAL=120
DOUYIN_NOTIFY_REQUEST_CONCURRENCY=1
DOUYIN_NOTIFY_PAGE_TIMEOUT=45000
DOUYIN_NOTIFY_PAGE_SETTLE_MS=2500
DOUYIN_NOTIFY_OPERATION_TIMEOUT=90
DOUYIN_NOTIFY_LOGIN_TIMEOUT=900
DOUYIN_NOTIFY_COOKIE=
DOUYIN_NOTIFY_BROWSER_CHANNEL=
DOUYIN_NOTIFY_BROWSER_EXECUTABLE_PATH=
DOUYIN_NOTIFY_NOTIFY_LIVE_END=false
DOUYIN_NOTIFY_AUTO_FOLLOW=false

DOUYIN_NOTIFY_WEB_ENABLED=true
DOUYIN_NOTIFY_WEB_PATH=/douyin-notify
DOUYIN_NOTIFY_WEB_TOKEN=请替换为高强度随机令牌
DOUYIN_NOTIFY_WEB_PUBLIC_URL=https://bot.example.com/douyin-notify
DOUYIN_NOTIFY_RENDER_WIDTH=620
DOUYIN_NOTIFY_RENDER_TIMEOUT=20000
```

| 配置 | 默认值 | 说明 |
| --- | --- | --- |
| `DOUYIN_NOTIFY_DATA` | LocalStore 数据目录 | 数据库、浏览器会话、模板、字体和封面的资源根目录；不存在时自动创建 |
| `DOUYIN_NOTIFY_POLL_INTERVAL` | `120` | 作者检查间隔，最低 30 秒；可在 Web 中调整 |
| `DOUYIN_NOTIFY_REQUEST_CONCURRENCY` | `1` | 同时检查的作者数，范围 1 至 8 |
| `DOUYIN_NOTIFY_PAGE_TIMEOUT` | `45000` | 页面和接口等待超时，单位毫秒 |
| `DOUYIN_NOTIFY_PAGE_SETTLE_MS` | `2500` | 页面加载后的额外等待时间 |
| `DOUYIN_NOTIFY_OPERATION_TIMEOUT` | `90` | 单次账号读取总超时，单位秒 |
| `DOUYIN_NOTIFY_LOGIN_TIMEOUT` | `900` | Web 登录会话有效期，单位秒 |
| `DOUYIN_NOTIFY_COOKIE` | 空 | 可选的私有抖音网页版 Cookie |
| `DOUYIN_NOTIFY_BROWSER_CHANNEL` | 空 | Chromium 通道，例如 `msedge` |
| `DOUYIN_NOTIFY_BROWSER_EXECUTABLE_PATH` | 空 | 自定义 Chromium 可执行文件 |
| `DOUYIN_NOTIFY_NOTIFY_LIVE_END` | `false` | 是否推送下播卡片 |
| `DOUYIN_NOTIFY_AUTO_FOLLOW` | `false` | 新建订阅时是否使用插件已登录的抖音账号关注作者；可在 Web 中调整 |
| `DOUYIN_NOTIFY_WEB_ENABLED` | `false` | 是否启用 Web 控制台 |
| `DOUYIN_NOTIFY_WEB_PATH` | `/douyin-notify` | Web 路径 |
| `DOUYIN_NOTIFY_WEB_TOKEN` | 空 | Web 管理令牌；启用 Web 时应显式配置 |
| `DOUYIN_NOTIFY_WEB_PUBLIC_URL` | 空 | 反向代理后的公开地址，预留给部署集成 |
| `DOUYIN_NOTIFY_RENDER_WIDTH` | `620` | 渲染浏览器的 CSS 视口宽度；PNG 使用 2 倍设备像素比输出 |
| `DOUYIN_NOTIFY_RENDER_TIMEOUT` | `20000` | 单次卡片渲染超时，单位毫秒 |

`DOUYIN_NOTIFY_DATA` 的作用与其他插件常见的 `*_PATH` 资源路径配置相同。可以填写带引号的绝对路径，例如 Windows 下的 `DOUYIN_NOTIFY_DATA="E:/BotData/douyin-notify"`，也可以填写 `DOUYIN_NOTIFY_DATA="./data/nonebot_plugin_douyin_notify"`。相对路径以 NoneBot 当前工作目录为基准。

配置的根目录及其父目录即使尚不存在，插件也会在加载时自动创建，并同时准备以下内容：

```text
douyin-notify/
├── subscription.sqlite3
├── browser-profile/
├── covers/
├── fonts/
└── templates/
```

其中 `subscription.sqlite3` 会在数据库初始化时生成。插件只使用自己的 `browser-profile/`，不会读取系统 Chrome、Edge 或其他浏览器的 Cookie、密码和配置。运行 NoneBot 的系统用户必须对所配置路径具有写入权限；如果路径指向已有文件或无权写入的位置，系统仍会报告配置错误。

## Web 控制台

启用后访问：

```text
http://<NoneBot 地址>:<端口>/douyin-notify/
```

控制台包含机器人连接和轮询设置、QQ群扫描、订阅增删、订阅用户设置、立即检查、抖音登录、二次验证操作、渲染方案、资源上传和实时预览。

订阅列表中每位作者都有独立设置按钮。`@全体成员` 按“机器人、QQ群、作者”保存；封面、模板、字体、主色、辅色和渐变开关按视频与直播分别保存。未设置的项目继承群级渲染方案，自定义封面为空时使用抖音接口返回的封面，不再打开直播间截图。机器人需要具备相应群权限才能成功发送 `@全体成员`。

“订阅时自动关注”默认关闭。启用后，从受管理令牌保护的 Web 控制台新建订阅会尝试关注作者；通过 QQ 命令新建订阅时，只有 NoneBot 超级用户可以触发关注，普通群主或群管理员仍可保存订阅，但不会修改登录抖音账号的关注列表。更新已有订阅不会重复关注。

自动关注只操作抖音官方作者主页上的“关注”按钮，并在页面显示“已关注”后才报告成功。未登录、按钮未确认或触发安全验证时，订阅仍会保存，并返回自动关注失败提示；安全验证必须在 Web 登录区按抖音官方流程人工完成。

管理令牌验证成功后写入 `HttpOnly`、`SameSite=Strict` Cookie。令牌不要提交到仓库、截图、Issue、商店提交表单或聊天记录。生产环境建议通过 HTTPS 反向代理访问。

## 登录与二次验证

插件始终运行无头浏览器。Web 登录区显示插件专用 Chromium 的实时截图，并把人工点击、拖动和键盘输入转发到该抖音官方页面。因此扫码、短信输入、普通点击确认和需要人工拖动的页面可以在 Web 中完成。

插件不会识别验证码、自动求解滑块、模拟人脸、绕过设备验证或调用非官方验证服务。手机 App 出现确认或人脸验证时，仍需在手机端按抖音官方流程完成。登录成功后会话保存在插件数据目录，轮询和后续重启会继续复用。

## QQ 命令

默认命令前缀取决于 NoneBot 配置，以下以 `/` 为例。

| 命令 | 说明 | 权限 |
| --- | --- | --- |
| `/douyin subscribe <链接> [video\|live\|all]` | 添加或更新订阅 | 群主、管理员、超管 |
| `/douyin unsubscribe <用户ID\|序号>` | 取消订阅 | 群主、管理员、超管 |
| `/douyin list` | 查看本群订阅 | 所有人 |
| `/douyin check <用户ID\|序号>` | 立即检查指定作者 | 群主、管理员、超管 |
| `/douyin clear` | 清空本群订阅 | 群主、管理员、超管 |
| `/douyin help` | 查看帮助 | 所有人 |

登录命令已移除，登录只在受保护的 Web 控制台中进行。命令支持中文别名：`订阅`、`取消`、`列表`、`检查`、`清空`、`帮助`。

## 自定义渲染

内置 `video.html` 和 `live.html` 模板使用 Jinja2 沙箱渲染。上传模板必须为 UTF-8 HTML，并包含唯一的卡片根节点：

```html
<article id="douyin-card">
  <h1>{{ event.title }}</h1>
  <p>{{ event.author_name }}</p>
</article>
```

| 字段 | 内容 |
| --- | --- |
| `event.kind.value` | `video` 或 `live` |
| `event.author_name` | 作者昵称 |
| `event.author_avatar` | 作者头像 URL |
| `event.title` | 视频描述或直播标题 |
| `event.cover_url` | 封面 URL |
| `event.published_text` | 北京时间格式化发布时间 |
| `event.url` | 官方内容链接 |
| `accent_color` | Web 中选择的主色 |
| `gradient_color` | Web 中选择的辅色 |
| `theme_background` | 渐变开启时为双色渐变，关闭时为主色纯色 |

模板外部请求只允许抖音图片域名和 QQ 群头像域名，渲染上下文关闭 JavaScript。字体支持 `.ttf`、`.otf`、`.woff` 和 `.woff2`；自定义封面支持 `.png`、`.jpg`、`.jpeg` 和 `.webp`，并校验文件头。单个上传文件最大 10 MiB。

渲染器使用 `device_scale_factor=2` 生成高像素密度 PNG。内置模板的 CSS 卡片尺寸为 `576 × 431`，最终图片为 `1152 × 862 px`；自定义模板也会按其 `#douyin-card` 尺寸以 2 倍像素输出。

## 数据与隐私

- 数据库：`subscription.sqlite3`
- 抖音浏览器状态：`browser-profile/`
- 自定义模板：`templates/`
- 自定义字体：`fonts/`
- 自定义封面：`covers/`
- 日志不会输出 Cookie、动态签名、管理令牌或完整接口请求 URL
- 删除群订阅后，无其他群引用的作者状态会自动清理

## 开发

```bash
pdm install
pdm run playwright install chromium
pdm run format
pdm run test
pdm run python -m build
```
## 鸣谢

- [NoneBot2](https://nonebot.dev/) — Python 异步聊天机器人框架

---

## License

MIT License
