自建弹幕系统:从22个平台聚合弹幕
为什么自己搞
影视站接的是第三方视频源,没有自带弹幕。市面上也有弹幕 API 服务,但国内访问不稳定,而且一旦服务关了就全没了。
所以自己搭了一个纯 Node.js 的弹幕聚合服务,从一个接口进,从 22 个国内视频平台(爱奇艺、腾讯、B站、优酷、搜狐、西瓜等)分别抓取弹幕,聚合成统一格式返回。
架构:一个入口,多个出口
影视站请求 → danmu_api(:9321) → 路由分发 → 各平台 sources/xxx.js
→ 聚合 → 统一格式 → 返回
每个平台一个 sources/ 下的文件,实现两个核心方法:
- search(anime) — 搜番,返回候选列表
- comment(episodeId) — 按集取弹幕,输出 XML 或 JSON
影视站调用时:
1. /api/v2/search/anime?anime=xxx → 并发搜多个平台 → 合并去重
2. /api/v2/comment/:id → 向匹配的平台取弹幕 → 返回
搜索和弹幕取回都设了缓存(搜索 30min,弹幕 24h),避免频繁调上游接口被限流。
Token 鉴权
弹幕 API 不需要用户登录,但也不能谁都能调。URL 的第一段路径就是 token:
http://localhost:9321/87654321/api/v2/search/anime?anime=xxx
token 不对的请求直接 403。简单但够用——弹幕不是敏感数据,要的是防滥用而不是防攻击。
弹幕前端的 Web Animations 引擎
拿到了弹幕数据(文本、出现时间)之后,要在视频上飘过去。最开始试了一个现成的 danmaku 库,但它用 setInterval + top 属性逐帧移动,手机上根本不流畅,经常飘到一半卡住。
换成自己写的——用 Web Animations API:
element.animate([
{ transform: 'translateX(100vw)' },
{ transform: 'translateX(-100%)' }
], {
duration: 8000,
easing: 'linear',
fill: 'forwards'
})
Web Animations API 在浏览器合成器线程上跑,不经过 JavaScript 主线程,GPU 加速,手机上也 60fps。弹幕通过 createPortal 挂到播放器的全屏层之上,z-index: 40,高于播放器控件遮罩(z-index: 30),确保始终可见但又不挡住按钮。
为什么写死 token 也没事
这属于"够用就好"的设计。弹幕服务只在内网跑(被影视站反向代理),公网用户直接访问不到 9321 端口。token 只是多一层保险——假如哪天端口被意外暴露,至少不会被陌生人拿来批量刷上游平台的弹幕接口。
---
整个弹幕系统从"尝试接入第三方服务→发现不可用→自己写聚合→前端渲染引擎"前后折腾了不少时间,但它解决了核心问题:影视站的弹幕不再依赖于任何一个外部服务,靠自己就能跑。