- musicbot/reload.py:轮询监控 musicbot/ 下的 .py 与 intents.toml/.env, 变更后重启 bot 子进程;跳过 logs/、__pycache__/、.venv/ - 进程级重启而非模块重载:长连接 + 模块级状态 + handler 闭包, 就地重载易留幽灵 handler,重启子进程状态干净 - 子进程用 _MUSICBOT_RELOAD_CHILD 标记,不会套娃自我复制 - Windows 用 taskkill /T 收整棵进程树,实测连续重载无进程泄漏 - 开启方式:`uv run musicbot --reload`(start.bat 已带)或 RELOAD=on - 监督者不配日志,避免与子进程抢写同一日志文件
54 lines
4.2 KiB
Markdown
54 lines
4.2 KiB
Markdown
# musicbot
|
||
|
||
QQ 群点歌 bot,基于 [qqbotsdk](https://gitea.4i.hk/hhhge/qqbotsdk),两步点歌:
|
||
|
||
1. **选歌菜单**——`点歌 <歌名 [歌手]>` 只负责选歌:Markdown 歌单(编号 + 歌名/歌手,默认 QQ 音乐源,搜不到自动聚合兜底),下方每行 5 个编号回调按钮 + `[上一页][下一页]`(每页 `MENU_PAGE_SIZE` 首,默认 10,上限 20)
|
||
2. **歌曲卡片**——点编号弹出卡片:专辑封面图 + 歌名/歌手/来源 + `[▶ 播放][⬇ 下载]` 回调按钮,再点才执行
|
||
|
||
- **专辑封面**:卡片用 Markdown 图片语法 `` 显示封面(QQ 后台会代理并缓存图片到客户端,不落库);封面来自 MusicServer 的 `img` 字段,tx/wy 有值,kw/kg 无(这些源卡片就不带图)
|
||
- 回调按钮(type=1)点一下直接生效,无需再按发送;播放发语音、下载发文件或直链(见 `SEND_MODE`),失败回退直链文本;无 Markdown 权限自动回退文本
|
||
- **下载发送方式**(`SEND_MODE`,默认 `link`):群文件上传仅限群主/管理员(40093005),故默认直接发直链;`file` 则先尝试上传群文件、失败(含无权限)回退直链。播放始终发语音
|
||
- **直链候选源回退**:tx 等源直链常受 CDN 风控抓不动(bot 抓不动时 QQ 服务器侧上传同样报 40093007),上传前先探测直链可抓性,不可抓则按 kw/wy/mg 逐个搜索换源
|
||
- **自动撤回**(`WITHDRAW`,默认开):翻页撤旧菜单、选歌后撤菜单、下载/播放点击后撤卡片(无论发送成败都撤,卡片是一次性 UI);关闭后所有消息都保留
|
||
- **日志**:控制台 + `LOG_DIR/musicbot.log`(按天轮转、保留 7 天),级别由 `LOG_LEVEL` 控制;目录不可写时自动退化为仅控制台
|
||
- **热重载(开发用)**:监控 `musicbot/` 下的 `.py` 与 `intents.toml`/`.env`,变更后重启 bot 子进程(重连一次 websocket)。默认关,`uv run musicbot --reload`(`start.bat` 已带)或 `RELOAD=on` 开启
|
||
- 按钮回调需 `intents.toml` 开启 `INTERACTION`(本仓库已开启)
|
||
|
||
## 配置
|
||
|
||
复制 `.env.example` 为 `.env`,填入开放平台 `APPID`/`APPSECRET`。`intents.toml` 控制事件订阅。MusicServer(lx-music 聚合音源)需在本机或 `MUSIC_SERVER_URL` 指向处运行。
|
||
|
||
点歌相关开关:
|
||
|
||
| 变量 | 默认 | 说明 |
|
||
|---|---|---|
|
||
| `MENU_PAGE_SIZE` | `10` | 选歌菜单每页候选数,1~20(内嵌键盘 5 行所限) |
|
||
| `WITHDRAW` | `on` | 自动撤回旧菜单/卡片;`off` 则全部保留 |
|
||
| `SEND_MODE` | `link` | 下载按钮:`link` 直接发直链 / `file` 先传群文件(需群主/管理员) |
|
||
| `LOG_LEVEL` | `INFO` | 日志级别 TRACE/DEBUG/INFO/SUCCESS/WARNING/ERROR/CRITICAL |
|
||
| `LOG_DIR` | `logs` | 日志目录(自动按天轮转、保留 7 天) |
|
||
| `RELOAD` | `off` | 热重载;`on` 等价于命令行 `--reload`(`start.bat` 已带) |
|
||
|
||
### 不 @ 机器人也能点歌
|
||
|
||
1. **群侧开关**:群主/管理员在 QQ 里打开机器人资料页,把消息接收切换为「接收群内全部消息」——三种取值为 `all`(全量)/ `only_mention`(仅@)/ `mention_and_context`(@+上下文),切换时平台会推 `GROUP_MSG_RECEIVE`/`GROUP_MSG_REJECT` 事件。未开启时网关不推送非 @ 消息,bot 行为与现在完全一致。当前群设置可用 `GET /v2/groups/{group_openid}/bot_state` 查(字段 `recv_msg_setting`)。
|
||
2. `intents.toml` 订阅 `GROUP_AND_C2C_EVENT`(本仓库已开启)——@消息(`GROUP_AT_MESSAGE_CREATE`)与全量消息(`GROUP_MESSAGE_CREATE`)同属这一个分组,无需额外配置。
|
||
|
||
两个事件共用同一个 dataclass 与 handler,被动回复都用该消息的 `msg_id`(群聊 5 分钟内有效、每条最多回复 5 次)。全量事件**不支持 `event_id`**——官方 event_id 支持列表只有 `INTERACTION_CREATE`、`GROUP_ADD_ROBOT`、`GROUP_MSG_RECEIVE`。
|
||
|
||
## 运行
|
||
|
||
```bash
|
||
uv sync
|
||
uv run musicbot # 正常启动
|
||
uv run musicbot --reload # 开发:改源码/配置自动重启
|
||
```
|
||
|
||
Windows 上双击 `start.bat` 即以热重载模式启动。
|
||
|
||
## 开发
|
||
```bash
|
||
uv run pytest
|
||
uv run ruff check musicbot tests conftest.py && uv run pyright
|
||
```
|