← 返回接口文档

动画直播组件接入

一个可以嵌进你网页或 App 的比赛动画直播:舞台放 2.5D 平面动画或 3D 球场,四周是比分条和数据页签。两种画面共用同一套布局,换画面只改配置,嵌入代码不用动。数据是本平台的实时动画流,球点、场面和事件随比赛推送。

两种画面

画面说明适合
2.5d俯视透视的平面动画:球点、场面标签(危险进攻 / 进攻 / 控球)、轨迹线、进攻区域、事件卡片。几十 KB,任何手机都流畅。首页卡片、列表页、App 内嵌
3d真实球场和 22 名球员按实时球点跑位,球衣颜色取自两队真实球衣,带观众、声音和进球 / 牌 / 角球等事件镜头。首次加载约 11 MB(浏览器缓存后很快)。比赛详情页、专题页

布局与数据模块

布局说明
standard标准:舞台 + 比分条 + 数据页签
wide宽屏:舞台在左,数据面板在右侧常驻(窄于 560px 时自动改成上下排)
compact紧凑:只有舞台和比分条
mobile手机竖屏:390 宽,页签切换
模块说明
scorebar比分条:队徽、队名、比分、比赛时钟
sceneLabel场面标签:危险进攻 / 进攻 / 控球,带主客(仅 2.5D)
eventCard事件卡片:进球、角球、牌、换人;3D 里是画面中央的横幅
trail轨迹线:最近 5 个场面点(仅 2.5D)
zone进攻区域着色(仅 2.5D)
stats技术统计:控球率、进攻、危险进攻、射门、射正、角球、黄红牌
timeline事件时间线:进球、牌、换人、角球
scene场面聚合:近 5 分钟危险进攻、进攻、控球和压迫指数
momentum势能:每分钟攻势(打开组件后累计)
tlive文字直播:逐条中文播报
lineup阵容:首发 / 替补、号码
ftPanel半场 / 完场面板:中场和完场时盖在舞台上的统计

场面标签、轨迹线、进攻区域只在 2.5D 里有;3D 里是球场和球员,这三个模块自动关闭。3D 的球和事件是实时数据;球员跑位由服务端根据球点、场面和事件推演,所有观众看到同一场画面,但不是真实跑位数据。模块和模板受套餐限制,以下面这个接口返回的为准: /api/v1/widget/options

接入步骤

  1. 开通:联系商务开通动画直播组件,登记允许嵌入的域名(如 *.example.com)、可用画面和同时观看上限。开通后你的 API Key 就能调 /api/v1/widget/*。
  2. 配置:在 组件控制台 里选画面、模板、样式、数据模块和布局,右边是真实比赛的实时预览;保存并发布后得到配置 id(wgt_ 开头)。
  3. 换令牌:你的服务端用 API Key 调 POST /api/v1/widget/token,传配置 id 和嵌入页面的 origin,拿到默认 2 小时有效的令牌。API Key 只放服务端,不要写进网页或 App 包。
  4. 嵌入:页面里放 iframe,地址是 /widget/anim?cfg=<配置 id>&match=<比赛 id 或 auto>&token=<令牌>。match 是本平台的比赛 id;auto 自动选一场正在进行的热门比赛。
  5. 推送方式:组件默认用 SSE 接收实时数据;地址加 &transport=ws 改用 WebSocket(连不上时自动退回 SSE)。两种方式内容相同,3D 画面的球员跑位帧也一起推送,每秒约 10 帧。

没有服务端?看下面的 App Key 嵌入。在 Flutter、iOS、Android App 里嵌入,见 SDK 与客户端库 →

代码

① 服务端换令牌

Terminal
curl -X POST https://api.sports.csap.ai/api/v1/widget/token \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"config":"wgt_1a2b3c4d","origin":"https://www.example.com","ttl":7200}'
# → {"code":0,"data":{"token":"…","expires_at":1794240000,"embed_url":"/widget/anim?cfg=wgt_1a2b3c4d&token=…"}}

② 页面嵌入(令牌由你的服务端下发)

HTML
<iframe id="live-anim" style="width:100%;height:640px;border:0" allow="autoplay; fullscreen"
  src="https://api.sports.csap.ai/widget/anim?cfg=wgt_1a2b3c4d&match=auto&token=<令牌>"></iframe>
<script>
  // 组件告诉页面它需要多高
  addEventListener('message', (e) => {
    const f = document.getElementById('live-anim');
    if (e.source === f.contentWindow && e.data && e.data.type === 'anim-widget-size') f.style.height = e.data.height + 'px';
  });
</script>

没有服务端?用 App Key 直接嵌入 新

在控制台「动画直播组件 → App Key」新建一个 pk_ 开头的 App Key,填上你网站的域名。它只能加载组件、不能调数据接口,可以写在页面源码里;页面带上比赛 ID 就能播,不需要换令牌的服务端。 去控制台新建 App Key →

① iframe:贴一段 HTML

HTML
<!-- App Key 可以放在页面源码里;只在白名单域名下能播 -->
<iframe src="https://api.sports.csap.ai/widget/embed?app_key=pk_3f9a…&match=4651805&view=3d"
        style="width:100%;aspect-ratio:16/9;border:0" allow="autoplay; fullscreen"></iframe>

② 脚本:自动调高度,并把进球 / 完场转成页面事件

HTML
<!-- 脚本在它所在的位置建 iframe -->
<script src="https://api.sports.csap.ai/widget/embed.js" data-app-key="pk_3f9a…"
        data-match="4651805" data-view="2.5d" async></script>
<script>
  document.addEventListener('animwidget:goal', (e) => console.log('进球', e.detail.score));
  document.addEventListener('animwidget:end', (e) => console.log('完场', e.detail.score));
  document.addEventListener('animwidget:error', (e) => console.warn(e.detail.reason)); // 没能播放的原因
</script>

参数

参数说明
app_key必填。控制台里的 App Key(pk_ 开头)。脚本嵌入写成 data-app-key。
match本平台的比赛 ID;不传或传 auto 时由平台自动选一场正在进行的热门比赛(这种加载不能再另指一场)。脚本嵌入写成 data-match。
view可选,2.5d 或 3d;不传用配置里的画面。只能选套餐已开通的画面。
lang可选,zh 或 en;不传用配置里的语言。
exp / sig只在签名模式下需要:过期时间(Unix 秒)和签名,见下文。
data-height只用于脚本嵌入:固定高度(像素);不传时按组件内容自动调高度。

脚本嵌入的页面事件(在 document 上监听,数据在 e.detail 里)

animwidget:ready组件连上比赛:match_id、home、away
animwidget:goal进球:side(1 主队 / 2 客队)、score、minute
animwidget:end完场:score
animwidget:error没能播放:reason 是下面「被拒原因」里的代号

App Key 的安全

域名白名单必填,且必须在平台给你开通的组件域名之内,只写主机名(字母、数字、连字符和点,可用 *.example.com)。服务端核对嵌入页面的 Origin / Referer;组件页带 Content-Security-Policy: frame-ancestors,别的网站框不住,也换不到令牌。不要给 iframe 设置 referrerpolicy="no-referrer",否则无法确认来源、会被拒。
短期令牌每次加载换一个绑定你域名、2 小时有效的令牌,到期自动续;App Key 本身不能调任何数据接口。令牌只能由组件页自己使用:从别的网站的页面拿它去连数据会被拒。
限速与上限按 Key、按访客 IP 限速;可设每日观看上限和并发上限,超出时组件位置显示「暂不可用」。一次观看 = 一位访客打开一次页面(同一页面断线重连不重复计);同一个令牌被别的地址拿去播,按另一次观看计。
停用 / 轮换停用后新的加载立即被拒,正在播放的页面几秒内停止;轮换后旧 Key 立即失效。组织被暂停或组件被关闭时同样几秒内停止。被平台停用的 Key 只能查看:不能自行启用、修改、轮换或删除,也不能另建 Key 接同一个网站,要恢复请联系商务。
签名模式(可选)开启后页面必须带服务端签名:你的服务端用 App Secret 计算 HMAC-SHA256(secret, "比赛ID:过期时间") 的十六进制值,页面加上 exp 和 sig 两个参数。改了比赛或过期时间,签名就不对;过期时间最长 7 天。App Secret 只在创建、轮换或重新生成时显示一次,只放服务端。

③ 签名模式:服务端算签名(Node.js 示例)

Node.js
const crypto = require('crypto');
const secret = process.env.WIDGET_APP_SECRET;        // App Secret 只放服务端
const match = '4651805';
const exp = Math.floor(Date.now() / 1000) + 3600;    // 过期时间(Unix 秒),最长 7 天
const sig = crypto.createHmac('sha256', secret).update(match + ':' + exp).digest('hex');
// 把 exp 和 sig 写进页面:
// https://api.sports.csap.ai/widget/embed?app_key=pk_3f9a…&match=${match}&exp=${exp}&sig=${sig}

被拒原因(「暂不可用」页左下角的代号、响应头 X-Widget-Refused、animwidget:error 的 reason)

unknownApp Key 不存在(写错、已轮换或已删除)
domain嵌入页面的域名不在白名单里,或无法确认来源;直接在地址栏打开嵌入地址也算
disabledApp Key 已停用,组件未开通,或组织已被暂停
quota今日观看次数达到上限
concurrent同时观看人数达到上限
rate访问太频繁(按 Key、按 IP;同一地址对所有 Key 的加载也有上限)
signature签名模式下签名缺失、不对或已过期
scope比赛 ID 不对,或不在这个 Key 允许的比赛范围内
config绑定的配置还没发布,或套餐未开通该画面

页面消息

组件通过 postMessage 告诉嵌入它的页面(令牌嵌入和 App Key 嵌入都会发;用脚本嵌入时脚本已经替你处理,并转成 animwidget:* 页面事件):

消息说明
anim-widget-size字段 height:组件内容的高度(px)。布局或页签变化时都会发,把 iframe 的高度设成它就不会出现滚动条。
anim-widget-event字段 event 和 data。event 是 ready(连上一场比赛:match_id、home、away)、goal(进球:side 为 1 主队或 2 客队、score、minute)或 end(完场:score)。
anim-widget-error字段 reason 和 height:组件没能播放或被停止,reason 是上面「被拒原因」里的代号。令牌嵌入也会发:播放中组件被关闭、组织被暂停或 App Key 被停用 / 轮换时,组件在舞台位置显示提示,并发一条 reason 为 disabled 的消息。

安全与限制

  • 令牌绑定配置和 origin;组件页只允许被这个 origin 嵌入(响应头 Content-Security-Policy: frame-ancestors),换个域名用不了。
  • 令牌默认 2 小时、最长 24 小时;过期后组件提示刷新,页面重新向你的服务端要令牌即可。
  • 同时观看人数超过开通的上限时,新打开的组件返回 429。
  • 组件被关闭或组织被暂停时,两种嵌入方式都会停:新的加载被拒,正在播放的页面几秒内停止并显示提示。
  • 没有动画数据的比赛(未开赛、已结束或这场没有动画)组件不会空等:比分条显示真实比分,舞台写明「比赛未开始 / 比赛已结束 / 暂无动画数据」。
  • 配置只在发布后生效;改画面、模板或布局后重新发布,已嵌入的页面刷新即可看到。

相关接口

POST /api/v1/widget/token换嵌入令牌(只在服务端调用)
GET /api/v1/widget/options本账户可用的画面、模板、布局和模块
GET /api/v1/widget/configs本账户保存的配置
GET /api/v1/widget/stats当前在线和今日观看
GET /api/v1/widget/app-keysApp Key 列表、今日观看和被拒次数;新建和修改用同一路径的 POST