Files
nanami-web/API.md
2026-05-12 09:58:25 +08:00

588 lines
18 KiB
Markdown
Raw 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.

# Nanami Web · Public API
Bilingual (zh / en) public REST API for the Nanami Turtle WoW platform.
> 标注:🆕 新增 · ✏️ 有变动 · 🌐 支持多语言
- **Base URL生产环境** `https://nanami.rucky.cn`
- **Base URL直连 IP** `http://120.77.146.152:3000`
- **Content-Type** `application/json`
- **认证:** 公共读接口无需认证POST/PUT/DELETE 写接口需要管理员 session不属于公共 API 范围)
---
## 🎮 WoW 客户端版本(多版本支持)
平台为 Turtle WoW **1.18****1.17** 两套客户端独立维护启动器、插件版本与发布渠道。每个 `Release` / `SoftwareVersion` 都打了 `wowVersion` 标签,且 `isLatest``(addon|software, wowVersion)` 维度内唯一 —— 同一插件可以同时存在「1.18 最新版」和「1.17 最新版」两条 latest。
### 如何选择 wow 版本
不同接口的解析策略略有差异:
#### 列表 / 浏览类接口addons / releases / software / changelog
| 来源 | 示例 | 优先级 |
|------|------|--------|
| 查询参数 `wow` | `?wow=1.18``?wow=1.17` | 1最高 |
| 查询参数 `wowVersion` | `?wowVersion=1.17` | 2别名 |
| Cookie `wow` | 浏览器侧由前台切换设置 | 3 |
| 默认 | — | `1.18` |
这些接口让浏览器在导航过程中保留用户选择的 wow 频道cookie 持久化)。多数列表型接口还支持 `?wow=all` 表示不过滤、返回所有版本。
#### 下载 / 自更新类接口latest / check-update / download/launcher
| 来源 | 示例 | 优先级 |
|------|------|--------|
| 查询参数 `wow` | `?wow=1.18` | 1最高 |
| 查询参数 `wowVersion` | `?wowVersion=1.17` | 2别名 |
| 默认 | — | `1.18` |
⚠️ **下载类接口故意不读 Cookie**。这是一个强约定:**URL 自己完全决定下载到的二进制**。
为什么这样设计:
1. `https://nanami.rucky.cn/download/launcher` 这种第三方嵌入直链,必须永远稳定指向 1.18 版本,不能被访客之前在前台切换过的 cookie 污染。
2. 启动器自更新(`/api/software/check-update`)的频道由启动器自身声明(`?wow=1.17`),避免 1.18 客户端因为 cookie 串台拿到 1.17 的更新。
3. 不论中英文(`lang`)切换,下载到的二进制都是同一个,只跟 `?wow=` 相关。
合法值:`1.18``1.17`
### 响应字段
- 单条对象上含 `wowVersion`,标识该 release / version 所属的客户端版本
- 列表型响应顶层含 `wowVersion` 字段,回显本次过滤值(`"all"` 表示未过滤)
### 启动器自更新建议
启动器调用 `/api/software/check-update` 时务必带上 `wow=1.18``wow=1.17`,否则会按默认 `1.18` 返回 —— 1.17 客户端拿到 1.18 的更新就出问题了。
```bash
# 1.17 启动器自检更新(已安装 versionCode=1010
curl 'https://nanami.rucky.cn/api/software/check-update?slug=nanami-launcher&versionCode=1010&wow=1.17'
# 1.18 启动器
curl 'https://nanami.rucky.cn/api/software/check-update?slug=nanami-launcher&versionCode=1010&wow=1.18'
```
---
## 🌐 国际化i18n
所有公共读接口都支持中英双语,通过查询参数选择语言。
### 语言协商
| 来源 | 示例 | 优先级 |
|------|------|--------|
| 查询参数 `lang` | `?lang=en``?lang=zh` | 1最高 |
| 查询参数 `locale` | `?locale=en` | 2`lang` 别名) |
| `Accept-Language` 请求头 | `Accept-Language: en-US,en;q=0.9` | 3 |
| 默认 | — | `zh` |
合法值:`zh``en`。其他值会被忽略,回退到默认。
### 响应字段约定
每条可翻译的文本字段,会同时返回三个键:
| 键名 | 含义 |
|------|------|
| `name` / `summary` / `description` / `changelog` / `title` / `content` | 「规范字段」,按当前 lang 解析后的值 |
| `*Zh`(如 `nameZh` | 原始中文 |
| `*En`(如 `nameEn` | 原始英文 |
响应顶层附带 `lang` 字段,回显本次实际响应使用的语言,便于客户端确认协商结果。
### 回退规则
请求 `lang=en` 时若 `*En` 字段为空,则规范字段回退到中文(保证客户端永远拿到非空内容)。`*Zh` / `*En` 始终是数据库存储的原始值(其中之一可能为空)。
### 兼容性
- **未传 `lang` 的旧客户端不受影响**`name``summary``changelog` 等字段仍是中文,行为与改造前一致
- 新增的 `*Zh` / `*En` 字段是增量字段,旧客户端可以安全忽略
---
## 1. 检查更新 ✏️ 🌐 🎮
```
GET /api/software/check-update?slug={slug}&versionCode={n}&wow={wow}&lang={lang}
```
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| slug | string | ✅ | 软件标识,例如 `nanami-launcher``nanami-launcher-patch` |
| versionCode | number | ❌ | 当前客户端版本号(整数),缺省为 0 |
| wow | string | ❌ | `1.18` / `1.17`,缺省 `1.18` |
| lang | string | ❌ | `zh` / `en`,缺省 `zh` |
**响应示例wow=1.18, lang=en**
```json
{
"hasUpdate": true,
"forceUpdate": false,
"lang": "en",
"wowVersion": "1.18",
"latest": {
"version": "1.0.15",
"versionCode": 1015,
"changelog": "Added Memorial Box feature\n…",
"changelogZh": "添加骨灰盒功能\n…",
"changelogEn": "Added Memorial Box feature\n…",
"downloadUrl": "https://nanami.rucky.cn/api/software/download/abc123?source=launcher",
"fileSize": 0,
"minVersion": null,
"wowVersion": "1.18",
"createdAt": "2026-04-28T14:40:30.844Z"
}
}
```
`forceUpdate=true` 仅当存在更新且最新版被标记为强制更新。`isLatest``(software, wowVersion)` 维度的 —— 1.18 与 1.17 各自有独立的 latest互不影响。下载 URL 自动带 `source=launcher`,启动器更新下载会单独计数。
---
## 2. 下载文件 ✏️
```
GET /api/software/download/{versionId}?source={source}
```
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| versionId | string | ✅ | 路径参数,版本记录 ID |
| source | string | ❌ | 下载来源标记,`launcher` 表示客户端自更新 |
**响应:**
- 本地文件:`Content-Type: application/octet-stream`,二进制流
- 外链文件HTTP 302 跳转
`source=launcher` 时,下载量计入「启动器更新下载」单独计数器。该参数已由 `check-update` 自动附加,启动器无需关心。
---
## 3. 获取最新启动器(网页用) 🌐
```
GET /api/software/latest?info=1&track=1&lang={lang}
```
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| info | string | ❌ | 传 `1` 返回 JSON 元数据;不传则直接返回二进制文件 |
| track | string | ❌ | 仅 `info=1` 时生效,传 `1` 同时累加下载计数 |
| lang | string | ❌ | `zh` / `en`,仅 `info=1` 时影响 changelog 字段 |
**响应示例info=1, lang=en**
```json
{
"available": true,
"version": "1.0.15",
"versionCode": 1015,
"changelog": "Added Memorial Box feature\n…",
"changelogZh": "添加骨灰盒功能\n…",
"changelogEn": "Added Memorial Box feature\n…",
"fileSize": 0,
"createdAt": "2026-04-28T14:40:30.844Z",
"downloadUrl": "/api/software/download/abc123",
"downloadType": "url",
"lang": "en"
}
```
---
## 4. 启动器友好直链 🆕 🎮
```
GET /download/launcher?wow={wow}
```
外部网页可直接 `<a href>` 引用这个地址下载最新版启动器,等价于 `GET /api/software/latest`(无 `info=1`):本地文件直返,外链 302 跳转。
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| wow | string | ❌ | `1.18` / `1.17`,缺省 `1.18` |
⚠️ **第三方链接安全**:这条 URL 是公开嵌入用的,**只看显式 `?wow=` 参数****不读用户 cookie**。意思是:即使用户之前在前台切到 1.17,再点这条不带 `?wow=` 的链接仍然会下载到 1.18。这样可以让站外的「下载启动器」按钮稳定指向 1.18。
```html
<a href="https://nanami.rucky.cn/download/launcher">下载 Nanami 启动器(默认 WoW 1.18</a>
<a href="https://nanami.rucky.cn/download/launcher?wow=1.18">下载 Nanami 启动器WoW 1.18</a>
<a href="https://nanami.rucky.cn/download/launcher?wow=1.17">下载 Nanami 启动器WoW 1.17</a>
```
---
## 5. 上报心跳(在线状态) 🆕
```
POST /api/launcher/heartbeat
Content-Type: application/json
```
**请求体:**
```json
{
"deviceId": "unique-machine-id",
"os": "Windows",
"osVersion": "10.0.19045",
"appVersion": "1.3.0"
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| deviceId | string | ✅ | 设备唯一标识,建议机器码或 UUID 并持久化 |
| os | string | ❌ | 操作系统,例如 `Windows` |
| osVersion | string | ❌ | 系统版本号 |
| appVersion | string | ❌ | 启动器版本 |
**响应:** `{ "ok": true }`
实现建议:启动时发送一次心跳,之后每 60 秒一次;超过 3 分钟未心跳视为离线。
---
## 6. 历史更新日志 ✏️ 🌐 🎮
```
GET /api/software/changelog?slug={slug}&wow={wow}&lang={lang}
```
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| slug | string | ✅ | 软件标识 |
| wow | string | ❌ | `1.18` / `1.17`(缺省 `1.18`),传 `all` 不过滤 |
| lang | string | ❌ | `zh` / `en` |
**响应示例wow=1.18, lang=en**
```json
{
"name": "Nanami Launcher",
"nameZh": "Nanami 启动器",
"nameEn": "Nanami Launcher",
"slug": "nanami-launcher",
"lang": "en",
"wowVersion": "1.18",
"versions": [
{
"version": "1.0.15",
"versionCode": 1015,
"changelog": "Added Memorial Box feature\n…",
"changelogZh": "添加骨灰盒功能\n…",
"changelogEn": "Added Memorial Box feature\n…",
"fileSize": 0,
"isLatest": true,
"forceUpdate": false,
"wowVersion": "1.18",
"createdAt": "2026-04-28T14:40:30.844Z"
}
]
}
```
---
## 7. 软件列表 / 详情 🆕 🌐
### `GET /api/software?lang={lang}`
返回全部软件包及其当前最新版本。
**响应示例:**
```json
[
{
"id": "...",
"slug": "nanami-launcher",
"name": "Nanami Launcher",
"nameZh": "Nanami 启动器",
"nameEn": "Nanami Launcher",
"description": "Nanami addon launcher…",
"descriptionZh": "Nanami 插件启动器…",
"descriptionEn": "Nanami addon launcher…",
"createdAt": "...",
"updatedAt": "...",
"versions": [{ "version": "1.0.15", "isLatest": true, "...": "..." }],
"_count": { "versions": 48 },
"lang": "en"
}
]
```
### `GET /api/software/{idOrSlug}?lang={lang}`
返回单个软件包及其全部历史版本versions 按 versionCode 倒序)。
---
## 8. 插件列表 / 详情 🆕 🌐 🎮
### `GET /api/addons`
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| lang | string | ❌ | `zh` / `en` |
| wow | string | ❌ | `1.18` / `1.17` —— 仅返回此 WoW 版本下的 latest release`all` 表示不过滤 |
| published | string | ❌ | 默认 `true`;传 `false` 包括草稿 |
| category | string | ❌ | 按分类过滤 |
| search | string | ❌ | 名称 / 简介模糊匹配,中英都搜 |
**响应示例:**
```json
[
{
"id": "...",
"slug": "nanami-ui",
"name": "Nanami-UI",
"nameZh": "Nanami-UI",
"nameEn": "Nanami-UI",
"summary": "All-in-one UI replacement…",
"summaryZh": "一款为乌龟服精心打造的全功能界面…",
"summaryEn": "All-in-one UI replacement…",
"description": "# Nanami-UI\n…",
"descriptionZh": "# Nanami-UI\n…",
"descriptionEn": "# Nanami-UI\n…",
"iconUrl": "/uploads/...",
"category": "ui",
"published": true,
"totalDownloads": 1234,
"releases": [
{
"id": "...",
"version": "0.9.14",
"changelog": "See the launcher changelog for details.",
"changelogZh": "详见启动器更新日志",
"changelogEn": "See the launcher changelog for details.",
"downloadType": "local",
"filePath": "/uploads/...",
"isLatest": true
}
],
"screenshots": [],
"_count": { "releases": 5 },
"lang": "en"
}
]
```
### `GET /api/addons/{idOrSlug}?lang={lang}`
返回单个插件及其所有 releases按 createdAt 倒序)。
---
## 9. 插件版本Releases 🆕 🌐 🎮
### `GET /api/releases?addonId={id}&wow={wow}&lang={lang}`
列出 release。
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| addonId | string | ❌ | 限定某个插件;缺省返回全平台所有插件的 release |
| wow | string | ❌ | `1.18` / `1.17`,缺省 `1.18`;传 `all` 不过滤 |
| lang | string | ❌ | `zh` / `en` |
**响应示例:**
```json
[
{
"id": "...",
"version": "1.2.5",
"changelog": "2026.04.03 update:\n…",
"changelogZh": "2026.04.03更新:\n…",
"changelogEn": "2026.04.03 update:\n…",
"downloadType": "local",
"filePath": "/uploads/...",
"externalUrl": null,
"gameVersion": "1.18.1",
"downloadCount": 0,
"isLatest": true,
"createdAt": "...",
"addon": {
"id": "...",
"slug": "instancejournal",
"name": "InstanceJournal",
"nameZh": "InstanceJournal",
"nameEn": "InstanceJournal"
},
"lang": "en"
}
]
```
### `GET /api/download/{releaseId}`
直接下载 release 文件(本地文件返二进制,外链 302 跳转),同时累加 release 下载量。
---
## 10. 公告文章 🆕 🌐
### `GET /api/articles`
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| lang | string | ❌ | `zh` / `en` |
| published | string | ❌ | 默认 `true` |
| limit | number | ❌ | 限制条数 |
**响应:**
```json
[
{
"id": "...",
"slug": "shutdown-announcement",
"title": "Server shutdown",
"titleZh": "关服公告",
"titleEn": "Server shutdown",
"summary": "...",
"summaryZh": "...",
"summaryEn": "...",
"content": "Markdown content…",
"contentZh": "Markdown 内容…",
"contentEn": "Markdown content…",
"coverImage": "/uploads/…",
"published": true,
"createdAt": "...",
"updatedAt": "...",
"lang": "en"
}
]
```
### `GET /api/articles/{idOrSlug}?lang={lang}`
返回单篇文章。字段同上。
---
## 11. 站点资源 🌐
### `GET /api/banners?enabled=1`
首页 Hero Banner 图。无可翻译文本,`lang` 参数不影响响应。
```json
[{ "id": "...", "imageUrl": "/uploads/...", "sortOrder": 0, "enabled": true }]
```
### `GET /api/gallery?enabled=1&lang={lang}`
截图画廊。`title` 字段双语。
```json
[
{
"id": "...",
"imageUrl": "/uploads/...",
"title": "Nameplate showcase",
"titleZh": "姓名版展示",
"titleEn": "Nameplate showcase",
"sortOrder": 0,
"enabled": true
}
]
```
---
## 12. 服务器时间
```
GET /api/server-time
```
```json
{ "serverTime": "2026-04-29T08:00:00.000Z", "epochMs": 1798156800000 }
```
供客户端校时与首页倒计时使用。
---
## 错误处理
所有失败响应都返回统一结构:
```json
{ "error": "Slug already exists" }
```
| HTTP | 含义 |
|------|------|
| 400 | 参数缺失或格式错误 |
| 401 | 未授权(写接口) |
| 404 | 资源不存在 |
| 409 | 冲突(如 slug 重复) |
| 500 | 服务端错误 |
---
## 接口一览
| 方法 | 路径 | 状态 | 多语言 | WoW 过滤 | 用途 |
|------|------|------|--------|----------|------|
| GET | `/api/software/check-update` | ✏️ | ✅ | ✅ | 启动器自更新检查 |
| GET | `/api/software/download/{id}` | ✏️ | ❌ | ❌ | 下载启动器文件(按 versionId 精确) |
| GET | `/api/software/latest` | ✏️ | ✅ | ✅ | 最新启动器信息 / 下载(网页用) |
| GET | `/download/launcher` | 🆕 | ❌ | ✅ | 友好直链:按 wow 始终下载最新 |
| POST | `/api/launcher/heartbeat` | — | ❌ | ❌ | 上报启动器在线状态 |
| GET | `/api/software/changelog` | ✏️ | ✅ | ✅ | 启动器历史 changelog |
| GET | `/api/software` | 🆕 | ✅ | ✅ | 软件列表 |
| GET | `/api/software/{idOrSlug}` | 🆕 | ✅ | ✅ | 单个软件 + 全部版本 |
| GET | `/api/addons` | 🆕 | ✅ | ✅ | 插件列表 |
| GET | `/api/addons/{idOrSlug}` | 🆕 | ✅ | ✅ | 单个插件 + 所有 release |
| GET | `/api/releases` | 🆕 | ✅ | ✅ | 插件版本列表 |
| GET | `/api/download/{id}` | — | ❌ | ❌ | 下载插件 release 文件(按 releaseId |
| GET | `/api/articles` | 🆕 | ✅ | ❌ | 公告列表 |
| GET | `/api/articles/{idOrSlug}` | 🆕 | ✅ | ❌ | 单篇公告 |
| GET | `/api/banners` | 🆕 | ❌ | ❌ | Hero Banner 图 |
| GET | `/api/gallery` | 🆕 | ✅ | ❌ | 截图画廊 |
| GET | `/api/server-time` | — | — | ❌ | 服务器时间 |
---
## 调用示例
```bash
# 1.18 启动器最新版(英文 changelog
curl 'https://nanami.rucky.cn/api/software/latest?info=1&lang=en&wow=1.18'
# 1.17 启动器最新版
curl 'https://nanami.rucky.cn/api/software/latest?info=1&wow=1.17'
# 1.18 启动器全部历史 changelog中文
curl 'https://nanami.rucky.cn/api/software/changelog?slug=nanami-launcher&wow=1.18&lang=zh'
# 1.17 启动器自更新检查(已安装 versionCode=1010
curl 'https://nanami.rucky.cn/api/software/check-update?slug=nanami-launcher&versionCode=1010&wow=1.17'
# 1.17 客户端的 UI 类插件(英文)
curl 'https://nanami.rucky.cn/api/addons?lang=en&category=ui&wow=1.17'
# 不限 WoW 版本,列出所有 release
curl 'https://nanami.rucky.cn/api/releases?wow=all'
# 1.18 启动器友好直链
curl -L -o nanami-launcher-1.18.exe 'https://nanami.rucky.cn/download/launcher?wow=1.18'
# 1.17 启动器友好直链
curl -L -o nanami-launcher-1.17.exe 'https://nanami.rucky.cn/download/launcher?wow=1.17'
# 通过 Accept-Language 协商语言
curl -H 'Accept-Language: en-US,en;q=0.9' 'https://nanami.rucky.cn/api/articles'
```