API 与使用方式

这份文档说明如何把 schema 用到当前项目里。

1. HTTP API

当前入口:

  • POST /api/json
  • GET /v/:id
  • GET /

2. POST /api/json

用途:

  • 提交一份 schema JSON
  • 对顶层结构做校验
  • 如果字幕使用 words: { src },会先抓取并归一化
  • 最后把归一化后的 JSON 存到 R2

请求头

Content-Type: application/json

请求体

请求体就是完整的 schema JSON。

最小示例:

{
  "meta": {
    "version": "2.0.0",
    "width": 1920,
    "height": 1080,
    "fps": 30
  },
  "tracks": [
    {
      "clips": [
        {
          "type": "text",
          "start": 0,
          "duration": 3,
          "text": "Hello",
          "transform": {
            "x": "50%",
            "y": "50%"
          }
        }
      ]
    }
  ]
}

成功响应

{
  "success": true,
  "taskId": "uuid",
  "url": "/v/uuid",
  "configUrl": "uuid.json",
  "schema": "AI Video JSON Schema v2"
}

常见失败情况

常见失败原因:

  • JSON 非法
  • 缺少 meta
  • 缺少 tracks
  • width / height / fps 不是正整数
  • 外部字幕 JSON 拉取失败
  • 远程字幕返回结构不正确

3. GET /v/:id

用途:

  • 加载已存储的 schema
  • 注入到播放器页面
  • 在页面里启动 Revideo Player

远程资源代理

为了避免浏览器直接加载第三方 video / image / audio / 外部字幕 JSON 时触发 CORS,播放器会在注入 schema 前,把跨域绝对 URL 改写成同源代理地址:

/api/asset?url=<remote-url>

这意味着:

  • 远程图片会走代理
  • 远程视频会走代理
  • 远程音频会走代理
  • 外部字幕 words.src 在需要时也会被代理

同源或相对路径资源不会重复代理。

运行时说明

播放器初始化前会执行:

normalizeExternalSubtitleSources(schema)

这样可以保证:

  • 服务端入库时的 schema 可被归一化
  • 客户端直接注入的 schema 也可被归一化

4. 本地直接播放

如果你不走 HTTP API,而是想把 schema 直接传给播放器,建议先归一化外部字幕:

import {normalizeExternalSubtitleSources} from "./src/revideo/schema";

const normalized = await normalizeExternalSubtitleSources(schema);

然后再把 normalized 交给播放器或项目创建流程。

5. 推荐使用流程

推荐顺序:

  1. 先组织好 meta / assets / tracks
  2. 可复用媒体尽量放进 assets
  3. 在 clip 里通过 $ref 引用素材
  4. 字幕优先用 { src } 或字幕素材池
  5. 提交到 POST /api/json
  6. 用返回的 /v/:id 页面播放

6. 编写建议

建议 1

可复用资源优先用 $ref,不要在多个 clip 里重复写 URL。

建议 2

如果字幕来自外部服务,推荐返回:

{
  "words": [
    {
      "word": "hello",
      "punctuated_word": "Hello",
      "start": 0,
      "end": 0.4
    }
  ]
}

建议 3

不要依赖未文档化字段,尤其是那些类型里写了、但实现并没有读取的模板参数。

7. 排查清单

如果输出结果不符合预期,优先检查:

  • 是否还在发送旧版顶层 video
  • 是否把 layout.children 当成真正的嵌套时间线
  • 是否假设模板参数已经实现但其实没有
  • 是否在无效位置依赖 objectFit
  • 外部字幕数据是否已经归一化

8. 请求示例

curl -X POST http://localhost:8787/api/json \
  -H "Content-Type: application/json" \
  -d @test/json-v2/30-mixed-scene.json

补充:

  • 新的 v2 测试 JSON 在 test/json-v2/
  • 按元素拆分的场景可从 test/json-v2/README.md 开始看
  • 文档里的示例也集中在 示例