Files
nanami-web/docs/API.md
2026-03-18 17:13:27 +08:00

12 KiB
Raw Permalink Blame History

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 或 slugnanami

响应示例

{
  "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;
}