你完全不必打开控制面板,也能把视频放到 UFOLOAD 上。REST API 支持通过 HTTPS 上传,服务器也可以替你从链接抓取文件,同一个账号还可以通过 WebDAV 和 FTP 访问,方便已经支持这些协议的工具使用。本指南用可运行的命令逐一介绍这五种途径,说明服务器的响应内容,并演示如何等待编码完成。下文的端点均已对照公开的 OpenAPI 规范核实;完整参考见 API 文档。
创建 API 密钥
在控制面板的“开发者”部分创建密钥。每个请求都要在 Authorization 请求头中以 bearer token 的形式携带它。密钥只在创建时显示一次,所以请把它保存在环境变量或密钥管理工具中;如果泄露,请在控制面板中吊销。同一个密钥也可用作 WebDAV 和 FTP 的密码,登录名为你的账号邮箱。如果你还没有账号,请免费创建一个;适用于你套餐的文件大小限制以及存储和流量配额列在价格页面。
export UFOLOAD_API_KEY="ufo_..."用 curl 上传
最简单的上传方式是把文件作为原始请求体发送,并把文件名放在 X-File-Name 请求头中。如果文件名包含空格或非 ASCII 字符,请以百分号编码(UTF-8)发送。默认情况下文件会存入根文件夹;添加 ?folder_id= 或 X-Folder-Id 请求头可以指定其他文件夹。
curl -X POST "https://ufoload.com/api/v1/files?folder_id=root" \
-H "Authorization: Bearer $UFOLOAD_API_KEY" \
-H "X-File-Name: holiday-2026.mp4" \
-H "Content-Type: video/mp4" \
--data-binary @holiday-2026.mp4也可以使用 multipart 表单。文件放在 file 字段中,文件夹可以通过 folder_id 表单字段指定:
curl -X POST "https://ufoload.com/api/v1/files" \
-H "Authorization: Bearer $UFOLOAD_API_KEY" \
-F "file=@holiday-2026.mp4"上传成功时返回 201,JSON 响应体中包含文件对象。最常用的字段是 id、public_id(填入播放器地址的短代码)、status、duration_ms 和 max_quality。对于已有的内容,服务器不会额外占用空间:如果你再次上传相同的字节,它会返回 200,附带已有的文件和 "duplicate": true,文件按 SHA-256 哈希进行匹配。
| 状态码 | 含义 |
|---|---|
201 | 文件已接收并进入处理队列 |
200 | 你的片库中已有相同内容;duplicate 为 true |
401 | 缺少密钥或密钥无效 |
404 | 目标文件夹不存在 |
409 | 存储空间不足 |
413 | 文件超过了你套餐允许的大小 |
429 | 请求过多;请稍候重试 |
大文件上传不受普通 API 调用那种较短请求超时的限制。只要请求体持续到达,服务器就会一直接收,因此慢速网络不会中断数 GB 的上传;不过,数据块之间停顿过久仍可能被反向代理切断。
等待视频就绪
上传只是前一半。之后文件会进入队列,被编码为自适应 HLS 码率阶梯(参见码率阶梯是如何构建的)。它的 status 会依次经历 uploading、queued 和 processing,最终变为 ready 或 failed;失败的文件会带有 error 信息。请每隔几秒轮询一次文件,切勿在紧密循环中轮询:API 有速率限制,会返回 429。
curl "https://ufoload.com/api/v1/files/FILE_ID" \
-H "Authorization: Bearer $UFOLOAD_API_KEY"响应包含两部分:带元数据的 file,以及带签名地址的 links,后者包括主播放列表(playback)、封面(poster)、悬停预览雪碧图(sprite)、每个清晰度档位以及 expires_at。如果需要不同的有效期,POST /files/{id}/links 可签发有效期为 60 秒到 30 天的链接,并可选择绑定到 IP 地址或 Cookie。
Python
使用 requests 库时,传入打开的文件对象会从磁盘流式读取,因此即使是大视频,内存占用也保持平稳。下面的函数先上传,然后等待结果。
import os
import time
import urllib.parse
import requests
BASE = "https://ufoload.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['UFOLOAD_API_KEY']}"}
def upload(path, folder_id="root"):
name = urllib.parse.quote(os.path.basename(path))
with open(path, "rb") as f:
r = requests.post(
f"{BASE}/files",
params={"folder_id": folder_id},
data=f,
headers={**HEADERS, "X-File-Name": name, "Content-Type": "application/octet-stream"},
)
r.raise_for_status()
return r.json()["file"]
def wait_ready(file_id, timeout=3600):
deadline = time.time() + timeout
while time.time() < deadline:
r = requests.get(f"{BASE}/files/{file_id}", headers=HEADERS)
r.raise_for_status()
data = r.json()
status = data["file"]["status"]
if status == "ready":
return data
if status == "failed":
raise RuntimeError(data["file"].get("error") or "encoding failed")
time.sleep(5)
raise TimeoutError("video is still processing")
file = upload("holiday-2026.mp4")
data = wait_ready(file["id"])
print("embed:", f"https://iframe.andromedans.live/e/{file['public_id']}")
print("playlist:", data["links"]["playback"])Node.js
Node.js 18 及更高版本内置了 fetch,因此无需任何依赖。这个版本会把文件读入内存,对于片段和短视频没有问题;对于数 GB 的文件,建议使用 curl、WebDAV 或 FTP,它们会从磁盘流式读取。
import { readFile } from 'node:fs/promises'
import { basename } from 'node:path'
import { setTimeout as sleep } from 'node:timers/promises'
const BASE = 'https://ufoload.com/api/v1'
const headers = { Authorization: `Bearer ${process.env.UFOLOAD_API_KEY}` }
async function upload(path) {
const res = await fetch(`${BASE}/files?folder_id=root`, {
method: 'POST',
headers: { ...headers, 'X-File-Name': encodeURIComponent(basename(path)), 'Content-Type': 'application/octet-stream' },
body: await readFile(path),
})
if (!res.ok) throw new Error(`upload failed: ${res.status}`)
return (await res.json()).file
}
async function waitReady(id) {
for (;;) {
const res = await fetch(`${BASE}/files/${id}`, { headers })
if (!res.ok) throw new Error(`status check failed: ${res.status}`)
const data = await res.json()
if (data.file.status === 'ready') return data
if (data.file.status === 'failed') throw new Error(data.file.error || 'encoding failed')
await sleep(5000)
}
}
const file = await upload('holiday-2026.mp4')
const data = await waitReady(file.id)
console.log('embed:', `https://iframe.andromedans.live/e/${file.public_id}`)
console.log('playlist:', data.links.playback)按 URL 导入
如果视频已经在网上有直链,就让服务器去下载,而不是先拉到你的机器上再推送一遍。该调用会立即返回 202 和一个导入任务;服务器抓取文件后将其加入编码队列。指向内网、回环地址和服务地址段的链接会被拒绝,同时最多可以有十个进行中的导入,GET /files/import 可以查看进度。
curl -X POST "https://ufoload.com/api/v1/files/import" \
-H "Authorization: Bearer $UFOLOAD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/video.mp4", "name": "video.mp4"}'WebDAV 与 FTP
对于批量传输以及无法调用 API 的工具,同一个片库也可以通过 WebDAV 和 FTP 访问。登录名是你的账号邮箱,密码是 API 密钥。两者都从磁盘流式传输,是传输超大文件最稳妥的选择。
curl -u "you@example.com:$UFOLOAD_API_KEY" https://ufoload.com/dav/
curl -u "you@example.com:$UFOLOAD_API_KEY" -T holiday-2026.mp4 https://ufoload.com/dav/holiday-2026.mp4curl -u "you@example.com:$UFOLOAD_API_KEY" ftp://ftp.ufoload.com/
curl -u "you@example.com:$UFOLOAD_API_KEY" --ftp-ssl -T holiday-2026.mp4 ftp://ftp.ufoload.com/只要客户端支持,就请使用加密方式,因为 API 密钥就是密码。任何支持 WebDAV 或 FTPS 的客户端,从文件管理器到同步工具,都可以使用同样的连接信息。以这种方式复制的文件会出现在你的片库中,并像其他上传一样被编码。
选择哪种途径
| 途径 | 最适合 | 注意事项 |
|---|---|---|
| API 上传 | 代表用户上传的应用程序和后端 | 如果客户端先读取整个文件,会占用内存 |
| 按 URL 导入 | 已有公开直链的文件 | 仅限 http(s) 直链;最多十个进行中的导入 |
| WebDAV | 大文件,将片库挂载为驱动器 | 使用你的邮箱和 API 密钥作为凭据 |
| FTP / FTPS | 现有工具和脚本,批量传输 | 使用显式 TLS 选项 |
使用视频
状态变为 ready 后,播放器地址就是 https://iframe.andromedans.live/e/ 加上 public_id,这正是你要放进 iframe 的内容(较长的 id 也可以使用,会被重定向到短地址);嵌入指南展示了页面代码以及 hls.js 方案。你可以用域名和国家/地区规则限制播放位置;有广告可投放时,还可以开启广告,从观看中获得收益。不要把密钥放进浏览器代码,有人离开团队时及时轮换密钥,另外请记住,所有套餐都可以使用 API,所以你今天就可以开始开发。