12 KiB
12 KiB
Nanami API 文档
所有公开接口均无需认证,供客户端软件直接调用。
基础 URL: https://nui.rucky.cn
一、插件市场 API
供启动器拉取插件列表、详情、版本和下载。
1.1 获取插件列表
请求
GET /api/addons
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| category | string | 否 | 按分类筛选(如 ui, quest, combat, general) |
| search | string | 否 | 按名称或简介模糊搜索 |
| published | string | 否 | 默认 true 只返回已发布插件,传 false 返回全部 |
响应示例
[
{
"id": "cxxx001",
"name": "Nanami",
"slug": "nanami",
"summary": "一站式乌龟服插件管理器",
"description": "详细描述...",
"iconUrl": "/uploads/nanami-icon.png",
"category": "general",
"published": true,
"totalDownloads": 1234,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-03-18T10:00:00.000Z",
"releases": [
{
"id": "rel001",
"version": "1.0.0",
"isLatest": true
}
],
"_count": {
"releases": 3
}
}
]
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 插件唯一 ID |
| name | string | 插件名称 |
| slug | string | 插件标识(URL 友好) |
| summary | string | 简短描述 |
| description | string | 详细描述(支持长文本) |
| iconUrl | string|null | 图标地址 |
| category | string | 分类标签 |
| published | boolean | 是否已发布 |
| totalDownloads | int | 累计下载次数 |
| releases | array | 最新版本信息(仅包含 isLatest=true 的版本) |
| _count.releases | int | 版本总数 |
1.2 获取插件详情
通过 ID 或 slug 获取单个插件的完整信息,包含所有版本和截图。
请求
GET /api/addons/{id_or_slug}
参数
| 参数 | 说明 |
|---|---|
| id_or_slug | 插件 ID 或 slug,如 nanami |
响应示例
{
"id": "cxxx001",
"name": "Nanami",
"slug": "nanami",
"summary": "一站式乌龟服插件管理器",
"description": "详细的 Markdown 描述...",
"iconUrl": "/uploads/nanami-icon.png",
"category": "general",
"published": true,
"totalDownloads": 1234,
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-03-18T10:00:00.000Z",
"releases": [
{
"id": "rel003",
"addonId": "cxxx001",
"version": "1.2.0",
"changelog": "- 新增XX功能\n- 修复YY问题",
"downloadType": "local",
"filePath": "uploads/nanami-1.2.0.zip",
"externalUrl": null,
"gameVersion": "1.12.1",
"downloadCount": 500,
"isLatest": true,
"createdAt": "2026-03-18T10:00:00.000Z"
},
{
"id": "rel002",
"addonId": "cxxx001",
"version": "1.1.0",
"changelog": "- 修复界面问题",
"downloadType": "local",
"filePath": "uploads/nanami-1.1.0.zip",
"externalUrl": null,
"gameVersion": "1.12.1",
"downloadCount": 300,
"isLatest": false,
"createdAt": "2026-02-15T10:00:00.000Z"
}
],
"screenshots": [
{
"id": "ss001",
"addonId": "cxxx001",
"imageUrl": "/uploads/screenshot1.png",
"sortOrder": 0
}
]
}
错误响应
| HTTP 状态码 | 说明 |
|---|---|
| 404 | 插件不存在 |
1.3 获取版本列表
获取所有版本,可按插件 ID 筛选。
请求
GET /api/releases?addonId={addonId}
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| addonId | string | 否 | 按插件 ID 筛选 |
响应示例
[
{
"id": "rel003",
"addonId": "cxxx001",
"version": "1.2.0",
"changelog": "- 新增XX功能",
"downloadType": "local",
"filePath": "uploads/nanami-1.2.0.zip",
"externalUrl": null,
"gameVersion": "1.12.1",
"downloadCount": 500,
"isLatest": true,
"createdAt": "2026-03-18T10:00:00.000Z",
"addon": {
"id": "cxxx001",
"name": "Nanami",
"slug": "nanami"
}
}
]
版本字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 版本唯一 ID |
| addonId | string | 所属插件 ID |
| version | string | 版本号(如 "1.2.0") |
| changelog | string | 更新日志 |
| downloadType | string | local 本地文件 / url 外部链接 |
| gameVersion | string | 适配的游戏版本(如 "1.12.1") |
| downloadCount | int | 下载次数 |
| isLatest | boolean | 是否为最新版本 |
| addon | object | 所属插件基本信息 |
1.4 下载插件
通过版本 ID 下载对应的插件压缩包。
请求
GET /api/download/{releaseId}
行为
- 本地文件:返回文件二进制流,
Content-Disposition设为attachment - 外部链接:302 重定向到外部下载地址
- 每次调用自动递增版本下载计数和插件总下载计数
响应头(本地文件时)
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="nanami-1.2.0.zip"
Content-Length: 1048576
错误响应
| HTTP 状态码 | 说明 |
|---|---|
| 404 | 版本不存在或文件丢失 |
二、软件更新 API
供启动器检查自身版本更新和热更新。
软件标识(slug)
| slug | 用途 | 文件类型 |
|---|---|---|
nanami-launcher |
启动器全量安装包 | Nanami-Launcher-x.x.x.exe |
nanami-launcher-patch |
热更新补丁包 | app.asar |
2.1 检查更新
客户端启动时调用此接口,传入当前版本号以检测是否有新版本可用。
请求
GET /api/software/check-update?slug={slug}&versionCode={versionCode}
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| slug | string | 是 | 软件标识 |
| versionCode | int | 否 | 当前客户端的版本代码(整数),不传默认为 0 |
响应示例
有更新:
{
"hasUpdate": true,
"forceUpdate": false,
"latest": {
"version": "1.2.0",
"versionCode": 120,
"changelog": "- 新增XX功能\n- 修复YY问题",
"downloadUrl": "https://nui.rucky.cn/api/software/download/cxxx123",
"fileSize": 5242880,
"minVersion": "1.0.0",
"createdAt": "2026-03-18T10:00:00.000Z"
}
}
无更新:
{
"hasUpdate": false,
"forceUpdate": false,
"latest": {
"version": "1.0.0",
"versionCode": 100,
"changelog": "...",
"downloadUrl": "https://nui.rucky.cn/api/software/download/cxxx123",
"fileSize": 5242880,
"minVersion": null,
"createdAt": "2026-03-01T10:00:00.000Z"
}
}
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| hasUpdate | boolean | 是否有新版本 |
| forceUpdate | boolean | 是否强制更新(true 时客户端应阻止用户继续使用旧版) |
| latest.version | string | 最新版本号(如 "1.2.0") |
| latest.versionCode | int | 最新版本代码(整数,用于比较大小) |
| latest.changelog | string | 更新日志 |
| latest.downloadUrl | string | 下载地址(直接用于下载) |
| latest.fileSize | int | 文件大小(字节) |
| latest.minVersion | string|null | 最低兼容版本号 |
| latest.createdAt | string | 发布时间 (ISO 8601) |
错误响应
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 slug 参数 |
| 404 | 软件不存在或暂无版本 |
2.2 下载软件包
通过版本 ID 下载对应的软件安装包。一般从"检查更新"接口返回的 downloadUrl 直接获取。
请求
GET /api/software/download/{versionId}
行为
- 本地文件:返回文件二进制流,
Content-Disposition设为attachment - 外部链接:302 重定向到外部下载地址
- 每次调用自动递增下载计数
响应头(本地文件时)
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="nanami-launcher-v1.2.0.exe"
Content-Length: 5242880
错误响应
| HTTP 状态码 | 说明 |
|---|---|
| 404 | 版本不存在或文件丢失 |
2.3 首页启动器最新版本下载
直接下载 nanami-launcher 的最新版本,用于首页下载按钮。
请求
GET /api/software/latest
下载最新全量包(自动递增下载计数)。
GET /api/software/latest?info=1
仅返回版本信息 JSON,不下载。
2.4 客户端更新检查流程
Nanami 启动器在启动后应按以下顺序检查更新:
客户端启动(当前 versionCode = 76)
│
├── 步骤 1: 检查全量更新
│ GET /api/software/check-update?slug=nanami-launcher&versionCode=76
│ │
│ ├── forceUpdate=true → 弹出强制更新对话框,下载完整安装包
│ │ 不再检查热更新
│ │
│ └── hasUpdate=true, forceUpdate=false → 显示"新版本"徽章(用户自行决定)
│ │
│ └── 继续步骤 2
│
├── 步骤 2: 检查热更新
│ GET /api/software/check-update?slug=nanami-launcher-patch&versionCode=76
│ │
│ ├── hasUpdate=true → 静默下载 app.asar,替换本地文件
│ │ 显示"就绪"徽章,提示重启生效
│ │
│ └── hasUpdate=false → 当前已是最新,无需操作
│
└── 正常运行
版本号对应关系示例
| 发布类型 | 版本号 | versionCode | slug |
|---|---|---|---|
| 全量安装包 | 0.7.6 | 76 | nanami-launcher |
| 热更新补丁 | 0.7.7 | 77 | nanami-launcher-patch |
| 全量大版本 | 0.8.0 | 80 | nanami-launcher |
后台操作
- 发布全量版本:在「Nanami 启动器(全量包)」中上传
.exe文件 - 发布热更新:在「Nanami 热更新包」中上传
app.asar文件 - 两者的
versionCode应保持递增关系,以便客户端正确比较
三、客户端集成示例(Electron)
3.1 启动器自身更新
const BASE_URL = "https://nui.rucky.cn/api/software/check-update";
const CURRENT_VERSION_CODE = 76;
async function checkUpdates() {
// 步骤 1: 检查全量更新
const fullResp = await fetch(
`${BASE_URL}?slug=nanami-launcher&versionCode=${CURRENT_VERSION_CODE}`
);
const fullData = await fullResp.json();
if (fullData.hasUpdate && fullData.forceUpdate) {
showForceUpdateDialog(fullData.latest);
return;
}
if (fullData.hasUpdate) {
showUpdateBadge(fullData.latest);
}
// 步骤 2: 检查热更新
const patchResp = await fetch(
`${BASE_URL}?slug=nanami-launcher-patch&versionCode=${CURRENT_VERSION_CODE}`
);
const patchData = await patchResp.json();
if (patchData.hasUpdate) {
const asarResp = await fetch(patchData.latest.downloadUrl);
const buffer = await asarResp.arrayBuffer();
// 写入本地 app.asar 路径...
showRestartBadge();
}
}
3.2 插件市场拉取
const API_BASE = "https://nui.rucky.cn";
// 获取全部已发布插件
async function fetchAddons(category?: string, search?: string) {
const params = new URLSearchParams();
if (category) params.set("category", category);
if (search) params.set("search", search);
const resp = await fetch(`${API_BASE}/api/addons?${params}`);
return resp.json();
}
// 获取单个插件详情(含所有版本和截图)
async function fetchAddonDetail(slug: string) {
const resp = await fetch(`${API_BASE}/api/addons/${slug}`);
return resp.json();
}
// 下载插件最新版本
async function downloadAddon(addon: any) {
const latestRelease = addon.releases?.find((r: any) => r.isLatest);
if (!latestRelease) return;
const downloadUrl = `${API_BASE}/api/download/${latestRelease.id}`;
const resp = await fetch(downloadUrl);
const buffer = await resp.arrayBuffer();
// 保存到 WoW 插件目录 Interface/AddOns/...
}
// 检查插件是否有更新(对比本地已安装版本)
async function checkAddonUpdates(installedAddons: { slug: string; version: string }[]) {
const addons = await fetchAddons();
const updates = [];
for (const installed of installedAddons) {
const remote = addons.find((a: any) => a.slug === installed.slug);
if (!remote) continue;
const latestRelease = remote.releases?.[0];
if (latestRelease && latestRelease.version !== installed.version) {
updates.push({
addon: remote,
currentVersion: installed.version,
newVersion: latestRelease.version,
});
}
}
return updates;
}