首页 / 运维与参考

OpenAPI 接入:开放应用、签名与接口清单

创建开放应用与接口开关、请求头与签名算法、Python 示例、视频/演员/标签/专辑/发行商/Telegram Bot/采集接口的地址与用法。

OpenAPI 让第三方系统(采集工具、重写脚本、Telegram 机器人、内容同步程序)通过签名认证读取或写入站内数据。接口由**前台服务(默认 6166 / 你的前台域名)**提供,路径前缀为 /openApi/v1。

与后台接口的区别

后台管理接口(6188,全程 AES 加密)只给后台页面使用,不要拿它做对接。OpenAPI 使用 X-OpenAPI-* 请求头 + query 签名,不依赖前台登录态,也不需要前台加密协议。

订阅功能

「开放接口扩展」属于订阅能力,未获得授权时部分接口或配置可能不可用,详见订阅与高级功能一览。

接入准备:后台配置

后台左侧菜单「开放接口」下有两个页面:

页面 路由 作用
接口配置 /openApi/interfaceConfig 统一控制公共采集、视频、演员、专辑、发行商、标签等开放 API 是否启用,以及每类接口开放哪些操作
应用管理 /openApi/apps 创建开放应用,获得 App ID 与 Secret,配置接口范围、签名算法、IP 白名单、限流等

接口配置
接口配置

应用管理
应用管理

接口配置:每个模块(视频、演员、标签、专辑、发行商)有「增 / 删 / 改 / 查」四个操作开关;另有「公共采集接口」开关。接口未启用时调用会返回 403。

应用管理(开放应用)字段:

字段 说明
账号名称 / 账号状态 启用或禁用;禁用后该应用所有请求认证失败
App ID 请求头 X-OpenAPI-App-ID 使用
Secret / Secret 指纹 Secret 明文只在创建或「重置应用密钥」时一次性显示,请立即保存;列表只显示指纹
接口范围 视频/演员/专辑/标签/厂商的 读取、新增、编辑(/关联)、删除,以及 Bot 机器人读取、Bot 机器人标记
签名算法 可勾选 md5、sha256、HMAC-MD5、HMAC-SHA256;请求的 sign_method 必须是已启用的之一
IP 白名单 开启后只有名单内出口 IP 可调用
限流 每分钟请求上限,超出返回 429
时间戳偏差 允许的客户端时间偏差秒数;未配置时默认 300 秒
输出详细错误 开启后认证失败会返回更具体原因(如「签名无效」),调试时开启,上线后建议关闭

一次成功调用要同时满足:应用已启用、对应接口模块与操作已在「接口配置」开启、应用「接口范围」包含该操作、IP/限流/时间戳通过、签名正确。

建议用最小权限

为每个对接方单独创建应用,只勾选它需要的范围;不要把 Secret 写进前端代码或公开仓库;泄露后立即「重置应用密钥」。

认证与签名

请求头与 query 参数

位置 名称 必填 说明
请求头 X-OpenAPI-App-ID 是 开放应用 ID(不参与签名)
请求头 X-OpenAPI-Signature 是 签名结果,hex,校验时不区分大小写(不参与签名)
query sign_method 是 md5 / sha256 / hmac-md5 / hmac-sha256
query timestamp 是 秒级时间戳,与服务器时间偏差不能超过应用配置的容忍秒数
query body_hash POST 必填 原始 JSON body 的 sha256 小写 hex;GET 不需要

签名算法

  1. 取 URL 中全部 query 参数(排除名为 sign 的参数),按参数名排序并 URL 编码,得到 canonicalQuery(即标准的 URL 编码,参数名排序后用 &、= 拼接)。业务参数(GET)和 sign_method、timestamp、body_hash 都在其中;POST 的业务参数在 JSON body 里,通过 body_hash 间接参与签名;
  2. secretHash = sha256(明文 secret) 的小写 hex;
  3. 按 sign_method 计算:
sign_method 签名
md5 hex(md5(canonicalQuery + secretHash))
sha256 hex(sha256(canonicalQuery + secretHash))
hmac-md5 hex(hmac-md5(key=secretHash, msg=canonicalQuery))
hmac-sha256 hex(hmac-sha256(key=secretHash, msg=canonicalQuery))

Python 示例

下面的示例已与服务端的签名函数对拍验证(同样的 query、secret 得到相同的签名值):

python
import hashlib, hmac, json, time, urllib.parse, urllib.request

BASE_URL = "https://www.example.com"   # 你的前台域名
APP_ID = "fc_app_xxx"                  # 开放应用的 App ID
SECRET = "sk_live_xxx"                 # 明文 secret
SIGN_METHOD = "hmac-sha256"            # 必须是该应用已启用的算法

def sign(query: dict, ts=None):
    q = dict(query)
    q["sign_method"] = SIGN_METHOD
    q["timestamp"] = str(ts or int(time.time()))
    canonical = urllib.parse.urlencode(sorted(q.items()))   # canonicalQuery
    secret_hash = hashlib.sha256(SECRET.encode()).hexdigest()
    sig = hmac.new(secret_hash.encode(), canonical.encode(), hashlib.sha256).hexdigest()
    return canonical, sig

def get(path, params):
    canonical, sig = sign(params)
    req = urllib.request.Request(f"{BASE_URL}{path}?{canonical}",
        headers={"X-OpenAPI-App-ID": APP_ID, "X-OpenAPI-Signature": sig})
    return json.load(urllib.request.urlopen(req))

def post(path, body: dict):
    raw = json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode()
    canonical, sig = sign({"body_hash": hashlib.sha256(raw).hexdigest()})
    req = urllib.request.Request(f"{BASE_URL}{path}?{canonical}", data=raw, method="POST",
        headers={"X-OpenAPI-App-ID": APP_ID, "X-OpenAPI-Signature": sig,
                 "Content-Type": "application/json"})
    return json.load(urllib.request.urlopen(req))

print(get("/openApi/v1/videos", {"page": 1, "page_size": 20}))

对拍用例:page=1&page_size=20&sign_method=hmac-sha256&timestamp=1779184800,secret 为 sk_live_xxx 时签名为 908d48418022603f3c300f76a3eec2015f260e5f50bfb3c90ee7a76583f6c323。POST 的 body_hash 必须按实际发送的原始字节计算,所以示例里先序列化为 raw,再用同一份 raw 发送。

响应与状态码

成功:{"code":1,"message":"获取成功","data":{...}};失败:{"code":0,"message":"..."}。

HTTP 状态码 场景
400 参数或 JSON body 无效
401 认证失败:签名算法未开启、签名无效、body_hash 无效、时间戳无效
403 接口未启用、缺少接口范围、IP 白名单拒绝、游标任务不可用
404 资源不存在、游标没有下一条
409 资源重复或游标已推进
429 应用每分钟限流达到上限
500 系统处理失败

接口清单

所有路径都挂在前台域名下,例如 https://www.example.com/openApi/v1/videos。

视频

接口 方法 接口范围
/openApi/v1/videos GET 视频读取
/openApi/v1/videos/detail GET 视频读取
/openApi/v1/videos/cursor-detail GET 视频读取
/openApi/v1/videos/create POST 视频新增
/openApi/v1/videos/update POST 视频编辑
/openApi/v1/videos/delete GET 视频删除

视频列表参数:page(默认 1)、page_size(默认 20,最大 100)、ids(逗号分隔本地 ID)、keyword、category_id、sort_by(id/created_at/updated_at/views_count/like_count/source_updated_at 等)、sort_order(asc/desc)、lang(默认 zh_cn)。列表不返回播放地址和分集详情。

视频详情:id 只能传一个本地视频 ID。

游标详情(适合批量改写/同步任务):传 cursor_key(仅字母、数字、下划线,长度 1–16;不存在会自动创建任务),返回 id 大于游标位置的第一条前台可见视频,只读取不推进游标;之后调用「修改视频」时带上同一个 cursor_key,修改成功才推进游标。不允许同时传 id/ids。

新增视频(POST,query 需 sign_method、timestamp、body_hash)必填字段:source_id(已存在的采集源)、source_category_id(属于该 source_id)、source_video_id、titles({"语言标识":"标题"},至少一个非空标题)。source_id + source_video_id 已存在(含已删除)返回 409。可选:封面/预览地址、area/lang/year、统计数、access_mode、price(单位:分)、episodes、tags、actors(按名称查找或创建)等。示例 body:

json
{"source_id":1,"source_category_id":8,"source_video_id":9001,"titles":{"zh_cn":"示例视频"}}

修改视频:id 为本地 ID,只更新传入的 titles/descriptions 等字段,不修改演员、分类、标签、专辑、厂商和分集;可选 cursor_key 推进游标。删除视频是标记删除,只传一个 id,之后普通读取接口不再返回。

演员、标签、专辑、发行商

四类资源的接口形态一致(以演员为例,actors 换成 tags / albums / issuers 即可):

接口 方法 说明
/openApi/v1/actors GET 分页列表,lang 控制名称/别名/简介语言
/openApi/v1/actors/detail GET 详情,id 单个
/openApi/v1/actors/cursor-detail GET 游标详情,同视频规则
/openApi/v1/actors/create POST 新增(names 至少一个语言的名称)
/openApi/v1/actors/update POST 修改,可带 cursor_key
/openApi/v1/actors/link-video POST 关联视频:actor_id + video_id,已关联时 changed=false,重复调用也返回成功
/openApi/v1/actors/unlink-video POST 取消关联,未关联时 changed=false
/openApi/v1/actors/delete GET 删除,只传一个 id,会移除相关视频关联

标签的 count 不允许由客户端直接写入。接口范围名称:演员/专辑/标签的「读取、新增、编辑/关联、删除」,发行商对应「厂商读取/新增/编辑/关联/删除」。

Telegram 机器人

接口 方法 接口范围 说明
/openApi/v1/telegram-bot GET Bot 机器人读取 查询待推送视频;identifier(1–16 字符)必填,会排除该 identifier 已标记推送的视频;支持分页、分类、搜索、入库/源更新时间区间、排序
/openApi/v1/telegram-bot/source-categories GET Bot 机器人读取 源分类列表,供筛选
/openApi/v1/telegram-bot/mark POST Bot 机器人标记 body:identifier 与 video_ids(正整数列表,最多 100 条);幂等

identifier 只影响当前机器人或频道,不同频道用不同 identifier 即可各自独立记录推送进度。

公共采集接口(苹果 CMS 兼容)

GET|POST /openApi/v1/collect,不需要签名,只受「接口配置 → 公共采集接口」开关控制(关闭时返回 HTTP 403,{"code":0,"msg":"接口未启用"})。仅输出 JSON(不支持 XML),输出的是原始采集数据中的图片和播放地址,不按会员/付费权限过滤,也不写入访问统计。

参数 说明
ac 为空或 list 返回列表(含 class 分类);detail 返回详情列表
t 本地分类 ID
ids 本地视频 ID,逗号分隔
pg 页码,从 1 开始
limit / pagesize 每页数量,最大 100;同时传时优先 limit
wd 按默认语言标题搜索

对外使用的是本地分类:源分类需要先在采集管理里绑定到本地分类,未绑定的源分类下的视频不会出现在 list/detail 中。

联调检查清单

  1. 「接口配置」中对应模块与操作已开启;
  2. 开放应用已启用,「接口范围」勾选了对应项,签名算法与请求的 sign_method 一致;
  3. 调用方服务器时间准确(偏差在容忍秒数内,默认 300);
  4. 出口 IP 在白名单内(若开启);
  5. 开启「输出详细错误」联调,返回 401 时看具体原因,完成后关闭;
  6. POST 的 body_hash 用实际发送的原始字节计算。
发财CMS 使用教程