Files
sansenhoshiandClaude b61d09f09f Add HeXi bot codebase: custom plugins, web frontends, tests
- hexi core: message handling, rate limiting, cooldown, plugin manager
- Custom plugins: BF stats, daily check-in, quotes, persona cards, etc.
- Community plugins vendored under hexi/plugins with local fixes
- Web admin frontends (learning-chat, persona-admin), unified hexi/web
- Tests for rate_limit/cooldown/memes/persona; poetry.lock

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-01 13:13:40 +08:00

146 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# nonebot_plugin_helldivers_tools
绝地潜兵小助手。命令:
- `简报`:获取星系战争概况(现在走 **[helldivers-2/api](https://github.com/helldivers-2/api)** 社区接口,用 Playwright 渲染自建 HTML 卡片,**不再打开外部网页截图**)。
- `随机战备`:随机一套战备(自建 HTML 卡片,与 `简报` 一样用 `nonebot_plugin_htmlrender` 出图)。
## 为什么改成 API?
旧方案用 Playwright 打开 `hd2galaxy.com` 截全页图,要等 `networkidle`(本地化 30s 左右),还要在页面 DOM 里做星球名替换,慢且脆弱。
新方案:
1. 调 `helldivers-2/api` 的 `/api/v1/war`、`/assignments`、`/campaigns`、`/planets`(带缓存,避免触发限流);
2. 用**自己的 HTML 模板**(内联 CSS + base64 logo + 系统字体)渲染一张战况卡片;
3. 交给 **[nonebot_plugin_htmlrender](https://github.com/nonebotjs/nonebot-plugin-htmlrender)** 的 `get_new_page()` 出图。因为模板是本地内容、无外部资源,`set_content` 后秒级完成,不再卡 30s。
> 说明:由 `nonebot_plugin_htmlrender` 管理 Playwright 内核(机器人日志里 `HTMLRender Started.` 即已加载)。`简报` 与 `随机战备` 都依赖 `require("nonebot_plugin_htmlrender")`,与 `nonebot_plugin_picstatus` 的做法一致。
## 新增/改动文件
| 文件 | 作用 |
| --- | --- |
| `config.py` | NoneBot 插件配置 |
| `hd2_api.py` | 异步 API 客户端(httpx + 进程内缓存 + 并发聚合) |
| `war_renderer.py` | 战况 HTML 模板 + 用 `nonebot_plugin_htmlrender` 渲染为 PNG |
| `equipment_renderer.py` | `随机战备` HTML 模板 + 用 `nonebot_plugin_htmlrender` 渲染为 PNG |
| `__init__.py` | `简报` 与 `随机战备` 命令改为走 API / 本地 + 渲染(移除了 `screen_shot` 依赖) |
## 配置
NoneBot 配置(`.env` / `.env.dev`)读取以下环境变量,均为可选,用默认值即可开箱即用:
| 环境变量 | 默认值 | 说明 |
| --- | --- | --- |
| `hd2_api_base_url` | `https://api.helldivers2.dev` | 自托管 helldivers-2/api 的根地址;不填用公共社区 API |
| `hd2_api_language` | `zh-Hans` | 请求本地化语言(自托管默认支持 zh-Hans / zh-Hant) |
| `hd2_cache_ttl` | `60` | 缓存秒数,避免频繁打接口触发限流(5次/10秒) |
| `hd2_super_client` | `hexi-bot.local` | 请求头,社区 API 必备 |
| `hd2_super_contact` | `https://github.com/sansenhoshi/nonebot_plugin_helldivers_tools` | 请求头,社区 API 必备 |
> **⚠️ 两个 `X-Super-*` 头必须都存在**:`RateLimitMiddleware` 在 `ValidateClients=true` 时(公共实例默认开启)要求请求**同时**带 `X-Super-Client` 和 `X-Super-Contact`,缺一即返回 `400 Bad Request / "The X-Super-Client and X-Super-Contact headers are required"`。客户端已保证始终发这两个头,`hd2_super_contact` 留空也会用 `hd2_super_client` 兜底。
示例:
```ini
hd2_api_base_url=http://127.0.0.1:8080
hd2_api_language=zh-Hans
hd2_cache_ttl=60
```
## 自托管 helldivers-2/api
项目是 .NET 10 + Docker。用 Docker Compose 最省事。
### 1) 克隆(务必带子模块)
```bash
git clone --recurse-submodules https://github.com/helldivers-2/api.git
cd api
```
> `src/Helldivers-2-Models/json` 是子模块,里面是星球名/本地化数据,**不带上它接口会没数据**。
### 2) 放一个 `docker-compose.yml`(在 `api` 根目录)
> 本仓库已写好一份:`HeXi/deploy/helldivers-api/docker-compose.yml`,复制到 `api` 仓库根目录即可。要点:`ASPNETCORE_URLS=http://+:8080`(否则默认监听 5000)、`Helldivers__API__Authentication__Enabled=false`(必须)、`ValidateClients=false`、含健康检查/重启/日志轮转。
```yaml
services:
helldivers-api:
build:
context: .
dockerfile: src/Helldivers-2-API/Dockerfile
image: helldivers2-api
container_name: helldivers2-api
ports:
- "8080:8080"
environment:
# 自托管务必关鉴权:默认 Authentication.Enabled=true 但没 SigningKey,直接启动会抛 ArgumentNullException(issue #90)
- Helldivers__API__Authentication__Enabled=false
# 抬高本地限流,多核打也不怕
- Helldivers__API__RateLimit=300
- Helldivers__API__RateLimitWindow=10
# 与 ArrowHead 官方接口同步频率(秒)
- Helldivers__Synchronization__IntervalSeconds=60
restart: unless-stopped
```
### 3) 构建并启动
```bash
docker compose up -d --build
```
### 4) 验证
```bash
# 应该返回 JSON(当前战争信息)
curl http://127.0.0.1:8080/api/v1/war
curl http://127.0.0.1:8080/api/v1/assignments
```
### 5) 让机器人指向它
在机器人 `.env` / `.env.dev` 里(本项目在 `HeXi/.env`)写:
```ini
hd2_api_base_url=http://127.0.0.1:8080
hd2_api_language=zh-Hans
```
然后重启机器人,发 `简报` 即可。默认配置的 `Languages` 已含 `zh-Hans`,星球名/大指令就是中文。
### 常见问题
- **`docker compose up` 报 `ArgumentNullException (Parameter 's')`**:忘关鉴权了,确认有 `Helldivers__API__Authentication__Enabled=false`。
- **`/api/v1/war` 一直是 200 但 `planet.name` 为空**:子模块没拉全,重新 `git submodule update --init --recursive` 后重建。
- **返回 400 / "X-Super-Client and X-Super-Contact headers are required"**:这是实例开了 `ValidateClients`;我方客户端已永远带这两个头,正常不会触发。
- **容器能起但数组为空**:容器要联网访问 ArrowHead 官方接口才能同步,检查机器能否访问外网。
- **想用 Fly.io**:仓库自带 `fly.toml`,直接 `fly deploy`。
### 备选部署(不用 Docker)
数据(星球名/本地化)由 `Helldivers-2-SourceGen` 在**编译期**写进二进制,运行时**不读任何 json 文件**,所以直接跑发布产物完全可行。
**Windows 本机跑(只需 .NET 10 SDK 构建一次):**
```powershell
git clone --recurse-submodules https://github.com/helldivers-2/api.git && cd api
dotnet publish src/Helldivers-2-API/Helldivers-2-API.csproj `
-c Release -r win-x64 --self-contained true -p:PublishAot=false -o .\publish
$env:ASPNETCORE_URLS="http://127.0.0.1:8080"
$env:Helldivers__API__Authentication__Enabled="false"
$env:Helldivers__API__RateLimit="300"
.\publish\Helldivers-2-API.exe
```
> `-p:PublishAot=false`:项目默认 AOT,Windows 上要 VC++ 工具链,关掉避免踩坑。
**VPS + systemd**:把发布产物换成 `linux-x64` 上传,用 systemd 挂服务(`Environment=Helldivers__API__Authentication__Enabled=false`)。
**Fly.io / 其它 PaaS**:仓库自带 `fly.toml`,`fly deploy` 即可;Render/Railway/Azure 同理。
## 接口字段依赖
- `war.statistics`:`playerCount`、`missionSuccessRate`、`terminidKills`、`automatonKills`、`illuminateKills`、`deaths`
- `assignments[0]`:`title`、`description`、`briefing`、`reward/rewards`、`expiration`
- `campaigns[]` → `planet`:`name`、`currentOwner`、`health`、`maxHealth`、`statistics.playerCount`
- `planets[]` → `currentOwner`(星系控制统计用)
## 翻译兜底
接口带 `Accept-Language: zh-Hans` 时,`LocalizedMessage` 字段会返回中文。若某字段仍为英文,渲染层会用 `data/plantes_mix.json` 做兜底翻译。