发布资源
POST /api/releases/publish —— 字幕组用 API Key 发布种子的写入端点;支持 JSON(磁力)和 multipart/form-data(种子文件)两种格式。
/api/releases/publish 是字幕组写入资源的唯一端点。需要在请求头里携带字幕组 API Key 鉴权;支持 application/json(直接传磁力链接)和 multipart/form-data(上传种子文件)两种格式。
这是写入接口,调用频率与配额由字幕组维度独立计数;与公开 RSS 的 IP 速率窗口不共享。Key 一旦泄露请立即在后台重置。
URL
POST https://anibt.net/api/releases/publish
Authorization: Bearer <YOUR_API_KEY>200 OK 与公开可见性
正式发布返回 200 OK 和 releaseId,表示站内主记录已写入,后续索引、公开快照与缓存任务已经可靠交接。它不表示 RSS、搜索、公开页面和 CDN 在这个响应返回时已经包含该资源,也不表示 Nyaa 等外站代发已经完成。
公开读链路会异步推进:对应的 Typesense 写入完成后生成受影响的不可变 R2 快照,Web 核对快照发布头、失效并严格预热 Redis,随后才发出 page-ready 事件让 Edge 清理 CDN。任一步显式失败都会保留可重试任务,并阻止该次 page-ready 提前完成。
当前成功响应不确认该 release 已在所有公开读模型可见。自动化发布端应把 200 OK 当作已接受,再用返回的 releaseId 检查详情页和目标 RSS / magnets 响应正文;只看到 HTTP 200、较新的 generatedAt、ETag 或 cf-cache-status: HIT,都不能单独证明目标资源已出现。缓存链路细节见 HTTP 缓存与 304。
两种请求格式
上传种子文件,后端自动从种子里提取磁力链接、infoHash、文件大小等元数据。
curl -X POST 'https://anibt.net/api/releases/publish' \
-H 'Authorization: Bearer <YOUR_API_KEY>' \
-F 'animeIdType=anilist' \
-F 'animeId=170942' \
-F 'title=[字幕组] 葬送的芙莉莲 - 01 [1080p].mkv' \
-F 'episodeKey=01' \
-F 'resolution=1080p' \
-F 'language=CHS' -F 'language=JP' \
-F 'subtitle=EXTERNAL' \
-F 'format=MKV' \
-F 'torrent=@/path/to/release.torrent'language 重复表示多个值(CHS + JP)。
直接给磁力链接(仍然需要先有种子,因为后端只接受能解析的合法 magnet)。
curl -X POST 'https://anibt.net/api/releases/publish' \
-H 'Authorization: Bearer <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
--data @- <<'JSON'
{
"animeIdType": "mal",
"animeId": "52991",
"title": "[字幕组] 葬送的芙莉莲 - 01 [1080p].mkv",
"magnetBase64": "magnet:?xt=urn:btih:...",
"episodeKey": "01",
"resolution": "1080p",
"language": ["CHS", "JP"],
"subtitle": "EXTERNAL",
"format": "MKV",
"fileSize": 734003200,
"notes": "**字体内嵌**,缺帧问题已修复。"
}
JSONmagnetBase64 既接受原始 magnet 链接,也接受 Base64 编码后的磁力。
参数
属性
类型
torrent 种子文件必填(multipart)。magnetBase64 可选——不提供时后端会从种子文件解析出磁力链接。
参数值速查
请求格式差异
| 场景 | 应该怎么传 |
|---|---|
上传 .torrent | 使用 multipart/form-data,字段名为 torrent,例如 -F 'torrent=@release.torrent'。 |
| 只传磁力链接 | 使用 JSON,传 magnetBase64。这个字段既接受原始 magnet:?xt=...,也接受 Base64 编码后的 magnet。 |
| 多语言 | JSON 用数组:"language":["CHS","JP"];multipart 可以重复字段:-F 'language=CHS' -F 'language=JP',也可以传 JSON 数组字符串。 |
| tracker 列表 | JSON 用数组;multipart 用换行分隔。站点会与默认 tracker 合并去重。 |
| 布尔值 | JSON 用 true/false;multipart 可用 true/false、1/0、yes/no、on/off。 |
| 番剧 ID | 推荐只传一种番剧标识。新接入用 animeIdType + animeId;历史 Bangumi 写法 bgmId 继续兼容。 |
番剧与集数
| 字段 | 可填值 | 说明 |
|---|---|---|
animeIdType + animeId | bgm / anilist / mal / anidb + 对应站点 ID | 推荐写法。例:animeIdType=anilist、animeId=170942。 |
anime | {"source":"anidb","id":"17617"} | 结构化写法,适合 JSON 客户端;source 同样只能是 bgm / anilist / mal / anidb。 |
bgmId | Bangumi subject id,例如 400602 | 兼容旧字段。可先调用 /api/bgm/search 搜索番剧。 |
episode | 非负整数,例如 1、12 | 用于排序。自定义 episodeKey(如 SP、BATCH)时请传 episode=0。 |
episodeKey | 01、1-12、13.5、SP、OVA、MOVIE、BATCH | 用于显示和去重。纯数字会规范化为数字字符串,例如 01 最终按 1 去重。 |
version | v1、v2、v2_fix | 不传时默认 v1。修正版建议用 v2。 |
番剧识别推荐只传一种 ID。外部站点 ID 统一用 animeIdType + animeId 或 anime,对应关系以 bangumi-data 为准;历史脚本里只传 bgmId 仍然可用。若外部 ID 对应多个 BGM 条目、多个外部 ID 解析结果互相冲突,或暂时找不到对应番剧,API Key 发布会进入待匹配状态,之后由字幕组或管理员补匹配。
分辨率、语言、字幕、格式
| 字段 | 可填值 | 含义 |
|---|---|---|
resolution | 4K / 2160p / 1080p / 720p / 480p / 360p | 必须完全按这些代码填写。常见 4K 可填 2160p 或 4K。 |
language | CHS | 简体中文。 |
language | CHT | 繁体中文。 |
language | JP | 日语。 |
language | EN | 英语;例如“英文字幕”就填 EN。 |
language | KO | 韩语。 |
language | ES | 西班牙语。 |
language | PT | 葡萄牙语。 |
language | FR | 法语。 |
language | DE | 德语。 |
language | IT | 意大利语。 |
language | RU | 俄语。 |
language | AR | 阿拉伯语。 |
language | HI | 印地语。 |
language | ID | 印尼语。 |
language | MS | 马来语。 |
language | TH | 泰语。 |
language | VI | 越南语。 |
language | TL | 菲律宾语 / 他加禄语。 |
language | TR | 土耳其语。 |
language | PL | 波兰语。 |
language | UK | 乌克兰语。 |
subtitle | EXTERNAL | 外挂字幕,字幕文件独立于视频文件。 |
subtitle | INTERNAL | 内封软字幕,字幕封装在 MKV/MP4 内,可开关。 |
subtitle | EMBEDDED | 内嵌/硬字幕,字幕已压进画面,无法关闭。 |
subtitle | NONE | 无字幕;设置后语言会按空列表处理。 |
format | MKV / MP4 / AVI / WEBM | 视频容器格式,不是编码格式。 |
如果不显式传这些字段,服务端会先从 title 推断,再从种子内部主文件名推断。仍然无法识别时,默认值为 resolution=1080p、format=MKV、subtitle=INTERNAL、language=["CHS"]、version=v1;如果最终 format=MP4,默认字幕类型会更倾向 EMBEDDED。
现实世界语言数量取决于统计口径;Ethnologue 2025 统计约 7,159 种现存语言,ISO 639 也维护标准语言代码。AniBT 不追全量语言清单,而是先支持字幕发布中常见的大语种;新增语言代码优先沿用 ISO 639-1,两岸中文继续保留站内兼容代码 CHS / CHT。
Nyaa 代发
Nyaa 代发仅对白名单字幕组开放。发布超分资源者无法申请白名单;申请规则见 Nyaa 代发说明。
Nyaa 代发必须使用 multipart/form-data 上传 .torrent 文件,并且种子的 announce 或 announce-list 必须包含:
http://nyaa.tracker.wf:7777/announceAPI Key 在 /groups/<slug>/api-keys 创建;站内参数说明页在 /groups/<slug>/publish?tab=api。
curl -X POST 'https://anibt.net/api/releases/publish' \
-H 'Authorization: Bearer <YOUR_API_KEY>' \
-F 'torrent=@release.torrent' \
-F 'title=[字幕组] 作品名 - 01 [1080p][CHS]' \
-F 'animeIdType=mal' \
-F 'animeId=58514' \
-F 'nyaa=true' \
-F 'nyaaCategory=1_3' \
-F 'nyaaComplete=false' \
-F 'nyaaRemake=false' \
-F 'nyaaDescription=可选:覆盖提交到 Nyaa 的 Markdown 说明'也可以使用结构化字段 sitePublish.nyaa.enabled / sitePublish.nyaa.category / sitePublish.nyaa.description。生产代发仍应使用 multipart,因为本站需要校验实际 torrent bytes 中的 Nyaa tracker。
Nyaa 代发字段和分类
| 表单字段 | JSON 结构化字段 | 必填 | 说明 |
|---|---|---|---|
nyaa | sitePublish.nyaa.enabled | 否 | 设为 true 表示请求 Nyaa 代发。只传 nyaaCategory 等 Nyaa 字段时,服务端也会视为启用。 |
nyaaCategory | sitePublish.nyaa.category | 启用代发时必填 | Nyaa 分类代码,必须从下表选择。普通中文动画字幕常用 1_3。 |
nyaaComplete | sitePublish.nyaa.complete | 否 | 对应 Nyaa 的 Complete 标记;合集、全卷、全季等完整资源可设为 true。默认 false。 |
nyaaRemake | sitePublish.nyaa.remake | 否 | 对应 Nyaa 的 Remake 标记;重传、修复版、重制版按需要设为 true。默认 false。 |
nyaaDescription | sitePublish.nyaa.description | 否 | 提交到 Nyaa 的 Markdown 说明,最多 20000 字符。不传时继承本站 notes。 |
nyaaInformation | sitePublish.nyaa.information | 否 | Nyaa information 字段,最多 500 字符,通常填写官网、字幕组页面、项目页或相关说明链接。 |
Nyaa 分类代码必须原样填写:
| 代码 | Nyaa 分类 | 什么时候用 |
|---|---|---|
1_1 | Anime - AMV | 动画音乐视频、剪辑、MAD/AMV。 |
1_2 | Anime - English-translated | 英文翻译动画字幕。 |
1_3 | Anime - Non-English-translated | 非英文翻译动画字幕。中文简体、繁体、双语中文字幕通常选这个。 |
1_4 | Anime - Raw | 动画 RAW,无翻译字幕。 |
2_1 | Audio - Lossless | 无损音频,例如 FLAC、WAV。 |
2_2 | Audio - Lossy | 有损音频,例如 MP3、AAC、Opus。 |
3_1 | Literature - English-translated | 英文翻译漫画、轻小说、书籍。 |
3_2 | Literature - Non-English-translated | 非英文翻译漫画、轻小说、书籍。中文漫画/小说通常选这个。 |
3_3 | Literature - Raw | 未翻译漫画、轻小说、书籍原文。 |
4_1 | Live Action - English-translated | 英文翻译真人影视。 |
4_2 | Live Action - Idol/Promotional Video | 偶像、宣传视频、PV 类真人资源。 |
4_3 | Live Action - Non-English-translated | 非英文翻译真人影视。 |
4_4 | Live Action - Raw | 真人影视 RAW。 |
5_1 | Pictures - Graphics | CG、画集、插画、扫描图等图像资源。 |
5_2 | Pictures - Photos | 照片写真类资源。 |
6_1 | Software - Applications | 应用软件。 |
6_2 | Software - Games | 游戏。 |
预览模式
发布前想先看看渲染效果(标题解析、Markdown 备注、磁力是否正确),把 preview=true 即可:
curl -X POST 'https://anibt.net/api/releases/publish' \
-H 'Authorization: Bearer <YOUR_API_KEY>' \
-F 'animeIdType=bgm' \
-F 'animeId=400602' \
-F 'title=[字幕组] 葬送的芙莉莲 - 01 [1080p].mkv' \
-F 'preview=true' \
-F 'torrent=@/path/to/release.torrent'返回的预览 URL 10 分钟后过期,不会进入 RSS / 搜索 / 前端列表。适合自动化流水线在正式发布前做最后一次人工确认。
本地 smoke test
下面的脚本只使用 JSON + magnet,并且固定传 preview: true;适合在 CI 或本地验证 Key、番剧 ID 和基础字段是否能通过。
const apiKey = process.env.ANIBT_API_KEY;
if (!apiKey) throw new Error("Set ANIBT_API_KEY first");
const body = {
preview: true,
animeIdType: "mal",
animeId: "52991",
title: "[Group] Preview Smoke - 01 [1080p][CHS].mkv",
magnetBase64: "magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567",
episodeKey: "01",
resolution: "1080p",
language: ["CHS"],
subtitle: "EXTERNAL",
format: "MKV",
fileSize: 734003200,
};
const res = await fetch("https://anibt.net/api/releases/publish", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify(body),
});
const data = await res.json();
console.log(res.status, data.ok, data.previewUrl);
if (!res.ok || !data.previewUrl) process.exit(1);鉴权与 Key 管理
在字幕组后台生成 API Key
每个字幕组可独立生成多个 Key,建议为 CI / 个人脚本各申请一把。
在请求头携带
Authorization: Bearer <YOUR_API_KEY>Key 泄露立即重置
旧 Key 立即失效;新 Key 只在生成时显示一次,请妥善保存。
Key 不要写进客户端代码、不要 commit 到仓库、不要贴 issue。CI 必须用 secret 注入。
统一错误响应
无论使用 JSON 磁力发布还是 multipart 种子上传,认证、请求解析、上传、站内写入或任务交接失败时,接口都会返回同一种 JSON envelope:
{
"ok": false,
"error": {
"code": "PUBLIC_SNAPSHOT_ENQUEUE_PAUSED",
"message": "System deployment in progress. Please retry shortly.",
"reason": "DEPLOYMENT_IN_PROGRESS",
"retryable": true,
"retryAfterMs": 15000,
"requestId": "req-example-123",
"i18n": {
"key": "error_deployment_in_progress"
}
}
}| 字段 | 含义 |
|---|---|
code | 稳定的机器错误码,用于程序分支,例如 CONFLICT、RATE_LIMIT_EXCEEDED。 |
message | 可直接显示的安全错误说明;服务端内部错误不会把凭据或上游异常细节返回给客户端。 |
reason | 比 code 更具体的业务原因,例如 RELEASE_VERSION_EXISTS、DEPLOYMENT_IN_PROGRESS。仅在适用时返回。 |
retryable | 是否适合在条件不变时重试。仅在服务端能够明确判断时返回。 |
retryAfterMs | 建议等待的毫秒数。存在时,响应头也会带按秒向上取整的 Retry-After。 |
requestId | 本次请求的关联 ID;响应头 X-Request-ID 返回相同值,反馈问题时请一并提供。 |
i18n | 本地化元数据,包含 key,必要时还会包含 params;客户端可优先按它显示本地化提示。 |
计划部署期间暂停发布交接时,接口返回 503 Service Unavailable,code=PUBLIC_SNAPSHOT_ENQUEUE_PAUSED、reason=DEPLOYMENT_IN_PROGRESS、retryable=true,并同时返回 Retry-After 与 retryAfterMs。这不是普通的 500;调用方应等待指定时间后重试。
同一发布版本已经存在时,接口返回 409 Conflict,code=CONFLICT、reason=RELEASE_VERSION_EXISTS、i18n.key=error_release_version_exists。不要原样无限重试;确认确实是新修订后再使用新的 version。
写入限流时,接口返回 429 Too Many Requests,code=RATE_LIMIT_EXCEEDED、reason=RATE_LIMITED、retryable=true,并通过 Retry-After / retryAfterMs 告知退避时间。
常见错误
| HTTP | 原因 | 处理 |
|---|---|---|
| 400 | title / 番剧标识缺失,或 torrent 解析失败 | 检查必填项;确认上传的是合法 .torrent 文件 |
| 401 | Authorization 头缺失或格式错误 | Bearer 前缀必填,注意空格 |
| 403 | API Key 无效 / 已撤销 / 不属于该字幕组 | 重新生成 Key |
| 409 | reason=RELEASE_VERSION_EXISTS,同一发布版本已存在 | 不要原样重试;确认是新修订后使用新的 version |
| 413 | 种子文件 / 表单超过大小限制 | 压缩种子(裁剪 tracker 列表) |
| 429 | reason=RATE_LIMITED,写入配额耗尽 | 按 Retry-After / retryAfterMs 退避 |
| 503 | reason=DEPLOYMENT_IN_PROGRESS,系统正在部署 | 按 Retry-After / retryAfterMs 等待后重试 |
下一步:发完直接订阅 /rss/anime.xml 验证;找 Bangumi ID 用 Bangumi 搜索,AniList / MyAnimeList / AniDB 可直接填对应站点 ID;想看自己字幕组的统计走 /api/subtitle-groups/me。