cobalt API 完整技术指南:/api/json 处理端点、流式下载与请求规范解析
cobalt 是一个无广告、无跟踪的媒体下载服务,其核心能力全部通过一套极简的 REST API 暴露。本文基于仓库中的 API 官方文档 及后端源码,完整讲解 cobalt 的三个端点(POST /api/json、GET /api/stream、GET /api/serverInfo)的请求体/响应体规范、参数默认值与校验规则、/api/stream 不透明参数的签名与时效机制,以及从请求进入到结果返回的完整处理链路。读完本文,你可以直接在自己的项目中集成 cobalt API,并理解每个参数在服务端真正如何生效。
一、API 总体结构:三个端点各司其职
从 src/core/api.js 的路由注册可以看出,cobalt 的 API 层只暴露三个面向外部的端点:
| 端点 | 方法 | 作用 |
|---|---|---|
/api/json |
POST |
主处理端点:接收媒体链接与下载选项,返回直链、流式链接或选择器 |
/api/stream |
GET |
Live render(流式/实时渲染)端点:携带签名参数,由服务端代理并加工媒体内容 |
/api/serverInfo |
GET |
返回服务器基本信息(版本、commit、分支、启动时间等) |
官方文档 docs/api.md 开头明确声明:官方实例 api.cobalt.tools 可免费用于自己的项目。同时文档中有一条硬性要求:
⚠️ 每个 POST /api/json 请求必须包含 Accept 和 Content-Type 请求头:
Accept: application/json
Content-Type: application/json
这条要求在源码中是真实生效的校验。src/core/api.js 定义了校验正则 acceptRegex = /^application\/json(; charset=utf-8)?$/,并在 路由处理函数 中分别测试 Accept 与 Content-Type 两个头,任一不匹配即返回错误(分别对应本地化错误码 ErrorInvalidAcceptHeader 与 ErrorInvalidContentType)。
二、POST /api/json:主处理端点
/api/json 是 cobalt 唯一的核心入口。请求体类型与响应体类型均为 application/json。
2.1 请求体参数完整说明
以下是 docs/api.md 中请求体变量表的完整内容,并在“源码印证”列标注了每个参数在服务端被消费的位置:
| 参数 | 类型 | 可选值 | 默认值 | 说明 |
|---|---|---|---|---|
url |
string |
作为 URI 编码的 URL | null |
每个请求必须包含 |
vCodec |
string |
h264 / av1 / vp9 |
h264 |
仅对 YouTube 下载生效;手机端推荐 h264 |
vQuality |
string |
144 / ... / 2160 / max |
720 |
手机端推荐 720 质量 |
aFormat |
string |
best / mp3 / ogg / wav / opus |
mp3 |
音频输出格式 |
filenamePattern |
string |
classic / pretty / basic / nerdy |
classic |
改变文件命名方式,预览可在 web 应用中查看 |
isAudioOnly |
boolean |
true / false |
false |
仅下载音频 |
isTTFullAudio |
boolean |
true / false |
false |
启用下载 TikTok 视频中使用的原始声音 |
isAudioMuted |
boolean |
true / false |
false |
在下载的视频中禁用音轨 |
dubLang |
boolean |
true / false |
false |
为 true 时,后端对 YouTube 视频音轨使用 Accept-Language 请求头(用于选择配音语言) |
disableMetadata |
boolean |
true / false |
false |
为 true 时禁用文件元数据 |
twitterGif |
boolean |
true / false |
false |
控制 Twitter 循环视频是否转换为 .gif |
tiktokH265 |
boolean |
true / false |
false |
控制是否优先选择 1080p H.265 视频 |
2.2 参数如何被服务端解析:白名单 + 默认值模板
文档中“默认值”一栏并非摆设。src/modules/processing/request.js 中的 normalizeRequest 函数展示了完整的解析逻辑:
- 固定模板兜底:每个请求先被填入一份模板,其中
vCodec: "h264"、vQuality: "720"、aFormat: "mp3"、filenamePattern: "classic"以及全部布尔项为false——与文档中的默认值列完全一致; - 键数量限制:请求体中的键数量不得超过模板键数 + 1(即
url加上 11 个可选参数),多出的未知字段会让请求直接被拒绝(返回ErrorCantProcess错误); - 枚举白名单:
vCodec、vQuality、aFormat、filenamePattern的取值必须在 白名单 内才会被采纳(例如vQuality允许max / 4320 / 2160 / 1440 / 1080 / 720 / 480 / 360 / 240 / 144),不在白名单内的值会被静默忽略并回落到默认值; - 布尔归一化:
isAudioOnly、isTTFullAudio、isAudioMuted、dubLang、disableMetadata、twitterGif、tiktokH265这 7 个布尔参数(见 booleanOnly 列表)会被强制转换为布尔值; - URL 预处理:
url会先经过decodeURIComponent再由normalizeURL处理,src/modules/processing/url.js 会执行别名域名归一(youtu.be→youtube.com/watch、pin.it→pinterest.com、clips.twitch.tv→twitch.tv/clip等)并剥离无用的 query/端口/锚点。
另外一个容易被忽略的硬限制:src/core/api.js 对 /api/json 挂载了 express.json({ limit: 1024 }),即 请求体最大 1024 字节,超限会收到 HTTP 400 与 invalid json body。这也解释了为什么该端点只设计为接收轻量级的“链接 + 选项”对象。
2.3 请求处理链路与 URL 校验
参数归一化之后,POST 处理函数 的执行顺序是:
- 校验
Accept/Content-Type头(不合法 → 400 +error); - 校验
url字段存在(缺失 → 400 +ErrorNoLink); normalizeRequest归一化(失败 → 400 +ErrorCantProcess);extract解析 URL 得到host与patternMatch(url.js 中的 extract:基于psl解析公共后缀、按 servicesConfig.json 中的patterns做 UrlPattern 匹配;host 不在配置中或服务已禁用则返回null→ 400 +ErrorUnsupported);- 调用 match 分发到具体服务实现(
youtube、tiktok、twitter、vimeo等 20 个服务模块),最终由 matchActionDecider 决定返回redirect(直链跳转)、stream(流式链接)还是picker(多文件选择器); - 任何环节抛异常统一兜底为 500 +
ErrorSomethingWentWrong。
以 YouTube 为例,match.js 展示了 vCodec、vQuality、isAudioOnly、isAudioMuted、dubLang 如何被打包传入 youtube 服务函数;若 URL 来自 music.youtube.com 或显式 isAudioOnly,服务端会强制 quality: "max"、format: "vp9" 的音频优先策略。
2.4 响应体字段
根据 docs/api.md 与 createResponse 实现,响应体字段及含义如下:
| 字段 | 类型 | 说明 |
|---|---|---|
status |
string |
error / redirect / stream / success / rate-limit / picker |
text |
string |
各种文本,主要用于错误信息 |
url |
string |
文件直链,或指向 cobalt live render(/api/stream)的链接 |
pickerType |
string |
various / images |
picker |
array |
picker 条目数组 |
audio |
string |
文件直链,或指向 cobalt live render 的链接 |
各 status 对应的实际行为(来自 createResponse 的 switch 分支):
error:HTTP 400,body 为{ status: "error", text: "..." },text是经过本地化的错误消息(错误文案集中定义在 src/localization/languages/en.json,如ErrorNoLink、ErrorUnsupported、ErrorBrokenLink、ErrorLengthLimit等,可直接对照排查失败原因);success/rate-limit:success携带text;rate-limit对应 HTTP 429,text中包含可重试的等待秒数;redirect:HTTP 200,body 为{ status: "redirect", url: "..." }——服务端确认了目标文件的直链(如 Facebook、Instagram、Pinterest、Twitch 等多数视频/图片直接走此路径,见 matchActionDecider.js);stream:HTTP 200,url是带签名参数的/api/stream链接,适用于需要服务端转码、静音、GIF 转换或 HLS 处理的场景(见下文第三节);picker:多媒体的帖子(Twitter 图文、Instagram、TikTok 等)返回条目数组供客户端让用户选择。
2.5 picker 条目字段
picker 中每个条目是一个 object:
| 字段 | 类型 | 说明 |
|---|---|---|
type |
string |
video / photo / gif,仅在 pickerType 为 various 时使用 |
url |
string |
文件直链,或指向 cobalt live render 的链接 |
thumb |
string |
条目缩略图,用于 picker 展示;video 与 gif 类型使用 |
一个特殊的实现细节:createResponse 中 picker 分支 显示,当服务是 tiktok 时 pickerType 固定为 images,且响应会额外携带 audio 字段——它本身就是一个已签名的 /api/stream 音频流链接(由 matchActionDecider 的 tiktok picker 分支 直接调用 createStream 生成),供客户端单独下载原声。
2.6 实际调用示例
结合上述规范,一个最简集成(curl)如下:
curl -X POST "https://<your-api-host>/api/json" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"url":"https://youtube.com/watch?v=dQw4w9WgXcQ","vQuality":"1080","vCodec":"av1"}'
成功时(需要服务端加工的媒体)返回形如:
{
"status": "stream",
"url": "https://<your-api-host>/api/stream?id=...&exp=...&sig=...&sec=...&iv=..."
}
随后用 GET 请求该 url 即可拿到文件本体。若返回 redirect,则 url 已是直链,客户端可直接跟随下载。
三、GET /api/stream:不透明参数背后的签名与时效机制
docs/api.md 对 /api/stream 的原文表述是:通常你会在成功调用 /api/json 后收到指向该端点的 URL;它接收的参数从 API 客户端视角是**不透明(opaque)且不可修改(unmodifiable)**的,并且可能随版本变化,客户端不需要关心其含义。
源码印证了这个承诺,同时揭示了它“不透明”的原因。src/modules/stream/manage.js 中的 createStream(L27-L68)为每次流式下载生成 5 个 query 参数:
| 参数 | 长度 | 生成方式 |
|---|---|---|
id |
21 | nanoid() 随机流标识 |
exp |
13 | Date.now() + streamLifespan * 1000 的毫秒时间戳 |
sig |
43 | 对 id,exp,iv,sec 计算的 HMAC(盐为启动时 64 字节随机数) |
sec |
43 | 16 字节随机数的 base64url(加密密钥) |
iv |
22 | 12 字节随机数的 base64url(AES IV) |
而服务端 路由侧 在放行前会做三层前置校验:参数齐全性(5 个参数缺一不可)、基础长度(id 必须 21 位、exp 必须 13 位)、签名长度(sig/sec 43 位、iv 22 位),随后 verifyStream 再执行:
- HMAC 复核:用同一盐值重算
generateHmac(id, exp, iv, sec),与sig不一致返回 401——这保证链接无法被篡改或伪造; - 缓存查找:流数据加密后存于内存缓存(
NodeCache),查不到返回 404; - 解密:用
iv+sec解出真实的下游 URL、请求头、文件名等元数据(客户端永远接触不到加密密钥,服务端也保存的是密文); - 时效校验:
exp早于当前时间则 404。
关于时效:src/modules/config.js 中 streamLifespan 固定为 90 秒,缓存的 stdTTL 也取该值并开启过期自动删除。因此 /api/stream 链接是短时效的一次性凭证——客户端拿到后应尽快使用,过期后需重新调用 /api/json。官方隐私说明(见 en.json 的 PrivacyPolicy 文案)也与此一致:需要渲染的内容数据仅加密保存在服务器 RAM 中 90 秒。
此外,/api/stream 支持一个速率限制探测参数:带 p 参数时会返回 200 与 { "status": "continue" }(api.js L161-L166),文档注释标注该行为在 8.0 之后将不再返回 JSON——集成时不建议依赖它。
四、GET /api/serverInfo:服务器信息
该端点返回当前服务器的基本状态,响应体类型为 application/json,字段如下(与 docs/api.md 的表格一致):
| 字段 | 类型 | 说明 |
|---|---|---|
version |
string |
cobalt 版本 |
commit |
string |
git commit |
branch |
string |
git 分支 |
name |
string |
服务器名称 |
url |
string |
服务器 URL |
cors |
number |
CORS 状态(0/1,对应 CORS_WILDCARD) |
startTime |
string |
服务器启动时间(毫秒时间戳字符串) |
从 serverInfo 对象构造 可见,各字段分别取自 package.json 的 version(当前仓库为 7.15)、启动时传入的 gitCommit/gitBranch、以及环境变量 API_NAME(config.js,默认 unknown)、API_URL 等。部署时可用它快速确认实例版本与 CORS 配置是否符合预期。
五、速率限制与运行时约束
文档没有专门展开限速章节,但 rate-limit 是响应 status 的合法值之一,集成时必须处理。源码给出的事实是:
/api/json与/api/stream各自挂载了基于 express-rate-limit 的限流器,键是请求 IP 的 HMAC(IPv6 先截断为/56前缀以防遍历规避,见 getIP);- 触发限流后
/api/json返回 HTTP 429 与{ "status": "rate-limit", "text": "...try again in N seconds!" };/api/stream则直接返回 429; - 窗口与阈值由环境变量控制,默认值为 RATELIMIT_WINDOW=60 秒 内 RATELIMIT_MAX=20 次。完整的 API 环境变量列表(含
API_PORT、API_URL、CORS_WILDCARD、DURATION_LIMIT等)参见 docs/run-an-instance.md; - 响应头暴露了
Ratelimit-Limit、Ratelimit-Policy、Ratelimit-Remaining、Ratelimit-Reset(CORS 配置中 exposedHeaders),客户端可用它们实现平滑退避。
其他值得注意的运行约束:
- 时长限制:
DURATION_LIMIT默认 10800 秒(3 小时),超长视频会被拒绝(对应ErrorLengthLimit文案); - 服务支持范围:当前启用的服务与 URL 匹配模式集中在 servicesConfig.json(YouTube、TikTok、Twitter/X、Instagram、Bilibili、Vimeo、Twitch 等 20 个服务),每个服务的
enabled、subdomains、tld、patterns都在这里定义——排查“链接无效”类错误时,这是第一参照物; - 错误分级:createResponse 的 critical 分支 表明部分内部错误(如依赖服务不可达)会返回 500 且带
critical: true标记,与可重试的 400 错误在语义上不同。
六、集成要点清单
- 头必须齐:
Accept与Content-Type都必须是application/json(允许; charset=utf-8后缀),否则 400; - body 要短:请求体上限 1024 字节,且不接受模板之外的多余键;
- 参数要合法:枚举参数取值须与白名单一致,否则静默回落默认值;
- 按 status 分支处理:
redirect跟随url下载;stream尽快(90 秒内)请求url;picker遍历条目让用户选择,TikTok 场景注意audio字段是独立的音频流链接; - 处理 429:解析
Ratelimit-*响应头做退避; - 不要解析 stream 参数:
/api/stream的 query 参数是不透明签名凭证,只能原样使用,不能修改、拼接或长期保存。
以上规范在当前仓库(cobalt 7.15,API 入口 src/core/api.js、处理层 src/modules/processing/、流层 src/modules/stream/manage.js)中均有对应实现可查证;若自建实例,请同时参考 docs/run-an-instance.md 完成部署与环境变量配置。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00