TWL 开放 API 参考
世界盒子(WorldBox)模组、地图、游戏版本、前置框架的只读索引与上传接口。 索引结构与 TWL 源完全一致,第三方启动器只要把 base URL 换过来就能接入。
概览
| 主入口 | https://apigtl.tidewhisperai.xyz |
|---|---|
| 备用入口 | https://api.twl.tidewhisperai.xyz(Cloudflare Worker 前置,行为一致) |
| 数据规模 | 208 模组 · 272 地图 · 5 个 PC 游戏版本 · 8 个安卓版本 · 9 个前置框架 |
| 协议 | HTTPS,全部返回 JSON(下载接口返回文件流或 302) |
| CORS | 完全开放,Access-Control-Allow-Origin 回显请求来源,浏览器可直接调用 |
| 更新频率 | 索引每小时自动与上游全量同步一次,上传后立即生效 |
| Swagger | /docs · OpenAPI JSON /docs/json |
快速开始
# 拿全部模组 curl https://apigtl.tidewhisperai.xyz/api/v1/mods # 下某个模组(会 302 跳到 CDN,加 -L 跟随) curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download
鉴权
上传与同步触发需要在请求头带 Key,两种写法等价:
x-api-key: twl_xxxxxxxxxxxxxxxxxxxx Authorization: Bearer twl_xxxxxxxxxxxxxxxxxxxx
两种数据格式
所有索引接口支持 ?format= 参数:
| 取值 | 说明 | 适用 |
|---|---|---|
compat默认 |
字段与 TWL 源 mods.json 完全一致,裸数组(versions 接口除外,它是带 versions 字段的对象)。旧启动器换地址即可用。 |
直接接入 |
rest |
语义化字段名 + { data, meta } 外壳,更适合新写的客户端。 |
新建项目 |
compat 与 rest 的字段对应:
| compat | rest | 含义 |
|---|---|---|
mod | name | 模组 / 地图名称 |
introduce | description | 介绍 |
tag | tags | 分类标签数组 |
preview | cover | 封面图地址 |
versions[].gameversion | versions[].gameVersion | 适配的游戏版本 |
versions[].modVersion | versions[].version | 模组自身版本 |
versions[].downloadLink | versions[].downloadUrl | 下载地址 |
下载行为
下载接口返回 HTTP 302,Location 指向 CDN 直链,客户端跟随即可拿到文件(curl 要加 -L)。
HTTP/1.1 302 Found location: https://www.modelscope.cn/models/bm2410/TIDE/resolve/master/mods/698fe727c7de4d7eafd7e954385b5c29.zip content-disposition: attachment; filename*=UTF-8''698fe727c7de4d7eafd7e954385b5c29.zip
| 特性 | 说明 |
|---|---|
| Range 断点续传 | 支持。跟随 302 后由 CDN 返回 206 Partial Content,多线程分片可用 |
| CORS | 302 响应与 CDN 最终响应都带 Access-Control-Allow-Origin,浏览器 fetch 也能用 |
| 文件名 | 游戏本体是 WorldBox-x.y.z.zip,模组是 <uuid>.zip(建议客户端按索引里的名称自行重命名) |
Location 里是自建的公开镜像地址,不涉及任何保密内容。
模组索引
返回全部模组条目。每条含多个版本(不同游戏版本各一份文件)。
查询参数
| 参数 | 类型 | 说明 |
|---|---|---|
format | 可选 | compat(默认)或 rest |
响应(compat,节选)
[
{
"mod": "更多权力PowerBox",
"introduce": "①扩展功能:查看文明单位…",
"author": "Keymasterer, IFailedLife, don_nikon",
"preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/698fe727c7de4d7eafd7e954385b5c29",
"tag": ["辅助模组"],
"updatedAt": 1765267152,
"versions": [
{
"uuid": "698fe727c7de4d7eafd7e954385b5c29",
"gameversion": "0.50.5",
"modVersion": "1.4.0",
"variant": null,
"size": 419953,
"fileName": "698fe727c7de4d7eafd7e954385b5c29.zip",
"downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download?gameversion=0.50.5"
}
]
}
]
versions 的顺序:数组是上传先后顺序,不是版本高低。
想要最适配某个游戏版本的,请在客户端自己按 gameversion 筛选匹配,不要直接取 versions[0]。
响应头
| 头 | 说明 |
|---|---|
X-TWL-Catalog | 固定为 mods |
X-TWL-Total | 条目总数 |
Cache-Control | public, max-age=300(5 分钟) |
地图索引
结构与模组完全一致,只是内容换成了社区地图。
[
{
"mod": "莫泰拉幻想世界Morterra",
"introduce": "",
"author": "Mr.Calamitous",
"preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/7e5db993f02942609434ed3bfb10c826",
"tag": ["架空幻想", "类世界地图", "多岛屿", "多版本"],
"versions": [
{
"uuid": "7e5db993f02942609434ed3bfb10c826",
"gameversion": "0.22.x",
"size": "14x7",
"fileName": "7e5db993f02942609434ed3bfb10c826.zip",
"downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/maps/7e5db993f02942609434ed3bfb10c826/download?gameversion=0.22.x"
}
]
}
]
size 是地图尺寸("14x7"),不是字节数。
真实文件大小以下载时 Content-Length 为准。
游戏版本索引(PC)
PC 端 WorldBox 游戏本体清单,解压即用的 zip 包。
响应(compat)
{
"schema": 1,
"source": "TWL",
"versions": [
{
"version": "0.51.2",
"channel": "stable",
"totalSize": 449049815,
"notes": "WorldBox 0.51.2 完整游戏本体(解压即用)",
"files": [
{
"path": "WorldBox-0.51.2.zip",
"size": 449049815,
"url": "https://apigtl.tidewhisperai.xyz/api/v1/versions/0.51.2/download"
}
]
}
]
}
注意这个接口返回的是对象而不是裸数组(其余索引是数组)。channel 取值 stable / archived。
游戏版本索引(安卓)
安卓端游戏本体清单。原样返回,不做 compat/rest 转换 —— 字段是安卓特有的,转换会丢信息。
{
"schema": 1,
"source": "TWL",
"platform": "android",
"versions": [
{
"version": "0.51.2",
"variant": "pure",
"label": "纯游戏原版",
"channel": "stable",
"totalSize": 321686443,
"minSdk": 23,
"abi": ["arm64-v8a"],
"notes": "最新稳定版…",
"files": [
{
"path": "android/game/twl-wb-0.51.2-pure.apk",
"size": 321686443,
"sha256": "e51972fac3aef32ce4b797983a70c1bc5b6a4ea3d51a6700ef7ca7e8dee41a88",
"url": "https://www.modelscope.cn/models/bm2410/TIDE/resolve/master/android/game/twl-wb-0.51.2-pure.apk"
}
]
}
]
}
files[].url 是 CDN 直链,不经过 API 转发,可以直接下载。
variant 区分同版本的不同构建(pure 纯原版 / menu 内置菜单版)。
前置框架索引
模组能跑起来需要的前置:BepInEx(注入器)、NeoModLoader(模组加载器)。结构与模组索引一致,是裸数组。
[
{
"mod": "BepInEx 模组加载器",
"introduce": "WorldBox 模组加载器(Doorstop 注入)…",
"author": "BepInEx",
"preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/bepinex-5.4.22",
"tag": ["前置", "加载器"],
"versions": [
{
"uuid": "bepinex-5.4.22",
"gameversion": "all",
"modVersion": "5.4.22.0",
"size": 622553,
"fileName": "BepInEx_x64_5.4.22.0.zip",
"downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/mods/bepinex-5.4.22/download?gameversion=all"
}
]
}
]
downloadLink 指向 /api/v1/mods/<uuid>/download,
这个端点在模组里找不到时会自动回退查前置框架索引,直接用即可。
单条详情
按 uuid 取单条。返回结构是只含这一条的数组(compat)或 { data: [ … ] }(rest),方便复用列表解析逻辑。
# 取模组详情
curl https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29
# 不存在时
HTTP/1.1 404 Not Found
{ "error": "not_found" }
下载模组 / 地图
查询参数
| 参数 | 类型 | 说明 |
|---|---|---|
gameversion | 可选 | 同一个 uuid 对应多个游戏版本时用来精确指定;不给则取第一个匹配项 |
# -L 跟随 302,-O -J 用服务端给的文件名保存 curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download # 指定游戏版本 curl -L -O -J "https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download?gameversion=0.50.5" # 断点续传 / 分片 curl -L -H "Range: bytes=0-1048575" -o part1 \ https://apigtl.tidewhisperai.xyz/api/v1/maps/7e5db993f02942609434ed3bfb10c826/download
下载游戏本体
version 是版本号本身(如 0.51.2),不是 uuid。
curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/versions/0.51.2/download
下载前置框架
name 支持模糊匹配,大小写不敏感。
| 写法 | 匹配到 |
|---|---|
bepinex | 名称含 bepinex 的条目 |
NeoModLoader | 名称含 neomloader 的条目(取第一个版本的加载器) |
BepInEx_x64_5.4.22.0.zip | 按文件名精确匹配 |
curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/framework/bepinex
/api/v1/mods/<uuid>/download,
uuid 从 /api/v1/dependencies 里取。
封面图
返回图片本体(image/jpeg / image/webp / image/png / image/gif),带 30 天强缓存。
<img src="https://apigtl.tidewhisperai.xyz/api/v1/preview/698fe727c7de4d7eafd7e954385b5c29">
按 uuid 命名,内容不会变,可放心长期缓存。Cache-Control: public, max-age=2592000, immutable。
上传资源
需要 API Key。multipart/form-data,异步处理:立刻返回 202 + taskId,文件在后台写入仓库并推送,用任务接口查进度。
表单字段
| 字段 | 必填 | 说明 |
|---|---|---|
file | 必填 | 要上传的文件,只接受 .zip |
name | 必填 | 资源名(模组名 / 地图名 / 游戏版本号) |
gameversion | mod/map 必填 | 适配的游戏版本,如 0.51.x、0.50.5 |
modVersion | 可选 | 模组自身版本号,如 1.4.0 |
author | 可选 | 作者,默认 - |
introduce | 可选 | 介绍文本,支持换行 |
tag | 可选 | 标签,多个用逗号 / 空格分隔:辅助模组,优化 |
preview | 可选 | 封面图 URL |
channel | version 专用 | stable(默认)/ archived |
notes | version 专用 | 版本说明 |
示例
curl -X POST "https://apigtl.tidewhisperai.xyz/api/v1/upload?type=mod" \ -H "x-api-key: twl_xxxxxxxxxxxx" \ -F "file=@我的模组.zip" \ -F "name=我的模组" \ -F "gameversion=0.51.x" \ -F "modVersion=1.0.0" \ -F "author=你的名字" \ -F "introduce=一句话介绍" \ -F "tag=辅助模组,优化"
响应 202
{
"taskId": "4b32aae5-45e3-458b-9de4-162fc2239e81",
"status": "running",
"message": "文件已接收,正在写入源站",
"fileName": "我的模组__0.51.x__31f51332.zip",
"size": 502,
"quota": {
"bytesLeft": 5368708618,
"countLeft": 199,
"dailyBytes": 5368709120,
"dailyCount": 200
},
"poll": "https://apigtl.tidewhisperai.xyz/api/v1/tasks/4b32aae5-45e3-458b-9de4-162fc2239e81"
}
上传错误
| 状态码 | error | 原因 |
|---|---|---|
| 400 | bad_type | type 不是 mod / map / version |
| 400 | no_file | 没带 file 字段 |
| 400 | bad_name | 缺 name |
| 400 | bad_gameversion | mod/map 没给 gameversion |
| 400 | bad_extension | 不是 .zip |
| 401 | unauthorized | Key 缺失或无效 |
| 413 | too_large | 超过单文件上限(2 GB) |
| 429 | quota_exceeded | 今日次数或容量用完 |
| 503 | upload_disabled | 服务端关闭了上传 |
任务进度
轮询上传进度。status 为 done 或 failed 时停止轮询。
{
"id": "4b32aae5-45e3-458b-9de4-162fc2239e81",
"type": "mod",
"name": "我的模组",
"size": 502,
"status": "done",
"phase": "完成",
"progress": 100,
"result": {
"type": "mod",
"name": "我的模组",
"gameVersion": "0.51.x",
"fileName": "我的模组__0.51.x__31f51332.zip",
"size": 502,
"downloadUrl": "https://apigtl.tidewhisperai.xyz/api/v1/mods/31f51332/download",
"index": "mods"
},
"error": null,
"createdAt": "2026-11-01T18:34:50.368Z",
"updatedAt": "2026-11-01T18:34:54.344Z"
}
phase 会经历:接收文件 → 写入源站 → 推送文件 → 更新索引 → 推送索引 → 清理本地副本 → 完成。
最近的任务列表,?limit=50(1–200)。不含 Key 明文。
额度查询
需要 API Key。返回当前 Key 的剩余额度。无效或不带 Key 都返回 401。
{
"bytesLeft": 5368709120,
"countLeft": 200,
"dailyBytes": 5368709120,
"dailyCount": 200,
"note": "主账号自用",
"limits": {
"maxFileSize": 2147483648,
"dailyBytes": 5368709120,
"dailyCount": 200,
"allowedExt": [".zip"]
}
}
健康检查
适合做存活探针,也可用来显示「当前资源量」。
{
"status": "ok",
"version": "1.0.0",
"uptimeSeconds": 1000,
"uploadEnabled": true,
"counts": { "mods": 208, "maps": 272, "versions": 5 }
}
服务自述:全部端点、鉴权方式、限额、CORS 策略。写客户端时可以先打这个接口做能力探测。
同步状态
上游同步状态。服务每小时自动与上游全量同步一次(补资源 + 补封面 + 体检游戏本体实体)。
{
"enabled": true,
"intervalMinutes": 60,
"running": false,
"lastRunAt": "2026-11-01T18:53:23.511Z",
"lastResult": {
"ok": true,
"full": true,
"kinds": { "mods": { "added": 0 }, "maps": { "added": 0 }, "dependencies": { "added": 0 } },
"elapsedMs": 10600
},
"consecutiveFailures": 0
}
需要 API Key。立刻触发一轮同步,默认全量。参数:?dryRun=1 只比对不下载、?full=0 只补资源、?maxFiles=N 限制本轮文件数(默认不限)。
错误码
错误响应统一是 { "error": "...", "message": "..." } 结构。
| 状态码 | error | 说明 |
|---|---|---|
| 400 | bad_* / no_file | 请求参数不合法 |
| 401 | unauthorized | Key 缺失、格式错或无效 |
| 404 | not_found | uuid / 版本号 / 任务 / 封面不存在 |
| 404 | no_download | 条目存在但没有可下载文件 |
| 413 | too_large | 文件超过 2 GB |
| 429 | quota_exceeded | 额度用完 |
| 502 | upstream_failed | 回源失败(CDN 暂时不可达) |
| 503 | catalog_unavailable | 索引文件读不到(仓库未就绪) |
字段说明
资源条目(模组 / 地图 / 前置框架通用)
| 字段 | 类型 | 说明 |
|---|---|---|
mod | string | 名称(同一条目的唯一键) |
introduce | string | 介绍,可能是空串,可能含换行 |
author | string | 作者,未知时为 - |
preview | string | null | 封面图地址(本站转发端点) |
tag | string[] | 分类标签 |
updatedAt | number | Unix 时间戳(秒) |
versions | object[] | 版本列表,见下 |
版本条目(versions[])
| 字段 | 类型 | 说明 |
|---|---|---|
uuid | string | 该版本的唯一标识,下载接口用它 |
gameversion | string | 适配的游戏版本。可能是精确版(0.50.5)也可能是通配(0.51.x)或 all |
modVersion | string | null | 模组自身版本号 |
variant | string | null | 同版本的不同构建(如安卓的 pure / menu) |
size | number | string | null | 模组 / 框架是字节数;地图是尺寸字符串(如 "14x7");也可能是 null |
fileName | string | 仓库里的文件名,模组/地图为 <uuid>.zip |
downloadLink | string | 下载地址(指向本 API 的 download 端点) |
游戏版本条目
| 字段 | 类型 | 说明 |
|---|---|---|
version | string | 游戏版本号,如 0.51.2 |
channel | string | stable / archived |
totalSize | number | 压缩包总字节数 |
notes | string | 版本说明 |
files[] | object[] | path 文件名、size 字节数、url 下载地址 |
接入示例
JavaScript(浏览器 / Node 18+)
const BASE = 'https://apigtl.tidewhisperai.xyz'; // 1. 拉模组列表,挑出适配 0.51.x 的版本 const mods = await (await fetch(`${BASE}/api/v1/mods`)).json(); const pick = mods .map(m => ({ name: m.mod, cover: m.preview, hit: (m.versions || []).find(v => v.gameversion === '0.51.x'), })) .filter(x => x.hit); console.log(`共 ${pick.length} 个模组支持 0.51.x`); // 2. 下载(fetch 会自动跟随 302) const res = await fetch(pick[0].hit.downloadLink); const buf = Buffer.from(await res.arrayBuffer()); require('fs').writeFileSync('mod.zip', buf);
Python
import requests BASE = "https://apigtl.tidewhisperai.xyz" # 拉地图列表 maps = requests.get(f"{BASE}/api/v1/maps", timeout=30).json() # 下载第一个地图(requests 默认跟随 302) url = maps[0]["versions"][0]["downloadLink"] r = requests.get(url, timeout=120) with open("map.zip", "wb") as f: f.write(r.content) print(f"下载 {len(r.content)} 字节") # 上传(需要 Key) files = {"file": ("mod.zip", open("mod.zip", "rb"), "application/zip")} data = {"name": "我的模组", "gameversion": "0.51.x", "author": "我"} r = requests.post( f"{BASE}/api/v1/upload?type=mod", headers={"x-api-key": "twl_xxxx"}, files=files, data=data, timeout=120, ) task_id = r.json()["taskId"] # 轮询进度 while True: t = requests.get(f"{BASE}/api/v1/tasks/{task_id}", timeout=30).json() print(t["status"], t["phase"]) if t["status"] in ("done", "failed"): break time.sleep(3)
游戏版本匹配建议
gameversion 有三种形态,匹配时按这个顺序判断:
- 精确匹配优先:
0.50.5对0.50.5 - 通配其次:
0.51.x匹配任何0.51.* all兜底:前置框架多为all,任何版本都能用
versions[0]。数组是上传顺序,旧版本可能排在前面。