Skip to content

Repository files navigation

DyHub Logo

DyHub · 抖音直播弹幕中台

自研采集内核 · 事件全链路标准化 · 消费端与抖音私有协议完全解耦

License Node.js TypeScript Docker Platform GitHub Stars


DyHub 是一个抖音直播弹幕采集与分发中台:双采集内核自研(轻量纯代码直连 + 浏览器 CDP 旁观),产出统一事件协议DanmakuEvent),并通过 WebSocket / SSE / Webhook 三种通道分发。上游改协议不碰消费端,下游接弹幕墙、弹幕游戏、AI 助理、数据看板只认一种事件。

架构总览

DyHub 架构总览

主数据流(自上而下):浏览器采集 → CDP 旁观帧 → 解码归一化 → 去重 → 事件总线 → 三通道分发 → 消费端;控制面(管理 API / 控制台 UI)以旁路方式管理房间与统计,不落在主数据流上。


✨ 特性

  • 双采集内核:① 浏览器内核(默认)—— 真实 Chrome headless + CDP 旁观,最稳、抗风控、抖音改协议自动跟随;② 轻量内核 —— 纯代码直连 wss,连接秒级、零浏览器进程,适合资源受限环境
  • 统一事件协议:抖音私有 protobuf → 标准化 DanmakuEvent,消费端零感知
  • 三通道分发:WebSocket(低延迟实时)、SSE(浏览器一行接入)、Webhook(HMAC-SHA256 签名鉴权)
  • 多房间并发:单浏览器实例多页面,支持同时采集多个直播间,控制台一键切换查看
  • 房间生命周期管理:连接过程分步进度展示(浏览器启动 → 订阅监听 → 连接成功),支持停止保留 / 一键恢复 / 彻底删除
  • 可视化控制台:实时弹幕流(头像 / 事件类型 / 来源房间 / 昵称)、事件筛选、房间管理、对接演示与在线测试
  • 可插拔扩展:新增平台只需写一个 collector 适配器,复用同一套事件协议与分发层

🖼️ 界面预览

实时监控:多房间同时采集,事件流实时展示(头像 / 事件类型 / 来源房间 / 昵称),支持按房间切换查看与事件类型筛选。

控制台-实时监控

对接演示:WS / SSE / Webhook 三种通道的接入地址、参数与代码示例,底部可在线测试分发通道。

控制台-对接演示


🧠 采集原理:两种采集内核

早坑提示:Spike 阶段早期用「Node fetch + 手工签名 + 简易 Cookie」直连时被 DEVICE_BLOCKED(HTTP 415)风控拦截,一度以为纯代码方案已失效;后来补齐完整 cookie 链(ttwid + __ac_nonce + __ac_signature)后实测打通。两种内核的差异如下:

浏览器内核DYHUB_COLLECTOR=browser,默认)—— 最稳、抗风控,适合多数场景:

  1. 启动系统 Chrome(headless=new)打开直播间页面,页面自行完成签名 / 指纹 / Cookie
  2. 通过 CDP Network.webSocketFrameReceived 旁观弹幕 WebSocket 帧数据,不改写页面逻辑
  3. 帧经 gzip 解压 → PushFrame → Response → Message[] 解码为原始消息
  4. 按 method 匹配 ChatMessage / GiftMessage / MemberMessage 等,标准化为统一事件

无头模式需一次点击手势触发播放器初始化,弹幕 wss 才会建立(已自动处理)。

轻量内核DYHUB_COLLECTOR=lightweight)—— 纯代码直连,适合资源受限 / 追求连接速度的场景:

  1. HTTP 获取 cookie 三件套(ttwid / __ac_nonce / __ac_signature
  2. 从直播间页解析内部 room_id
  3. 生成 a_bogus(HTTP 签名)与 signature(wss 签名,X-Bogus)后直连 wss://webcast100-ws-web-lq.douyin.com/webcast/im/push/v2/
  4. 自行维护心跳(5s)与 ack 应答,帧解码链路与浏览器内核共用

两种内核产出完全相同的标准化事件,管道 / 分发 / 消费端无感知。

如何切换采集内核

通过环境变量 DYHUB_COLLECTOR 设置,默认 browser(浏览器内核)。

# 本地 / 服务器:启动前指定环境变量
DYHUB_COLLECTOR=lightweight npm run dev     # 使用轻量内核
DYHUB_COLLECTOR=browser npm start           # 使用浏览器内核(默认,可省略)

# Docker Compose:在 docker-compose.yml 的 environment 段添加
#   environment:
#     DYHUB_COLLECTOR: "lightweight"
# 然后 docker compose up -d --build

# Docker run
docker run -d -p 8757:8757 --shm-size=2g -e DYHUB_COLLECTOR=lightweight dyhub

两种内核对比与选型

浏览器内核(browser,默认) 轻量内核(lightweight
原理 真实 Chrome 打开直播间页,CDP 旁观 wss 帧 纯代码直连 wss,自行签名 / 心跳 / ack
稳定性 高 —— 页面自动跟随抖音协议变更 中 —— 依赖第三方签名脚本,抖音改签名可能失效
抗风控 强 —— 完整浏览器指纹,被动旁观不发请求 弱 —— 纯 HTTP 逆向,数据中心 / 容器 IP 易被风控
资源占用 高 —— 需运行 Chromium(~200MB 内存 / 房间) 极低 —— 无浏览器进程(~20MB / 房间)
连接速度 慢 —— Chrome 冷启动 + 页面加载 3~15s 快 —— 秒级建立 wss
依赖 系统 Chrome / Chromium 无(签名脚本已内置)
适用场景 生产环境、长期稳定采集、本机 / 桌面部署 资源受限(小机器 / 容器)、快速验证、短期采集

建议:生产环境用默认 browser;仅在机器无 Chrome、资源紧张或需要快速连接时用 lightweight。轻量内核被风控时可用 DYHUB_COOKIE 注入浏览器复制的 Cookie 绕过,或随时回退 browser


🚀 快速开始

前置要求

  • Node.js ≥ 20
  • Chrome / Chromium(macOS、Windows 直接装 Chrome;Linux 安装 Chromium 后用 DYHUB_CHROME 指定路径)

安装与运行

npm install
npm run build && npm start   # 生产模式(或 npm run dev 开发模式)

连接直播间

# 打开控制台
open http://localhost:8757

# 连接直播间(示例:东方甄选)
curl -X POST http://localhost:8757/api/rooms/connect \
  -H 'Content-Type: application/json' \
  -d '{"roomId":"708764876300"}'

控制台左侧可连接多个房间,通过「查看房间」下拉在全部房间混流单房间之间切换;事件行展示头像、事件类型、来源房间与昵称。

环境变量

变量 说明 默认
DYHUB_PORT 管理端口 8757
DYHUB_HOST 监听地址 0.0.0.0
DYHUB_CHROME Chrome/Chromium 可执行文件路径 自动探测
DYHUB_HEADED 设为 1 打开有头浏览器(调试用) 无(默认无头)
DYHUB_COLLECTOR 采集内核:browser(默认,浏览器 + CDP,最稳抗风控)/ lightweight(纯代码直连,轻量快速) browser
DYHUB_COOKIE 浏览器复制的 Cookie(含 sessionid_ss 登录态),用于获取礼物事件绕过容器 IP 风控;也可启动后在控制台填写 → 详见 Cookie 配置指南 无(游客态)

📦 事件协议

所有消费端只看到统一事件,不感知抖音 protobuf:

{
  "id": "7681626144000791846",
  "roomId": "708764876300",
  "platform": "douyin",
  "type": "chat",
  "ts": 1788517960528,
  "receivedAt": 1788517960528,
  "user": {
    "id": "101652211600",
    "nickname": "田💕心",
    "avatar": "https://p3.douyinpic.com/aweme/100x100/...",
    "secUid": "MS4wLjAB..."
  },
  "data": { "content": "劲道牛肉丸,3袋立享88折!" }
}

roomId 统一为用户连接的房间号(web_rid),与房间管理 / 订阅过滤一致。

事件类型

type 含义 data 关键字段
chat 弹幕 content
gift 礼物 giftName / diamondCount / repeatCount / comboCount(需登录态 Cookie,见 Cookie 指南
member 进场 memberCount
like 点赞 count / total
follow 关注 action
room 直播间统计 total(在线)/ popularity / totalUser
unknown 未识别消息透传 method

🔌 消费端接入

WebSocket(网页弹幕墙 / 弹幕游戏)

const ws = new WebSocket('ws://localhost:8757/ws?roomId=708764876300&types=chat,gift,member');

ws.onmessage = (m) => {
  const ev = JSON.parse(m.data);
  if (ev.type === '__hello') return; // 握手消息
  console.log(ev.user?.nickname, ev.data?.content ?? ev.type);
};

SSE(浏览器一行接入)

const es = new EventSource('http://localhost:8757/api/events?types=chat,gift');

es.onmessage = (e) => {
  const ev = JSON.parse(e.data);
  console.log(ev);
};

Webhook(服务端消费,HMAC 签名)

curl -X POST http://localhost:8757/api/webhooks \
  -H 'Content-Type: application/json' \
  -d '{"roomId":"708764876300","url":"https://your-server/hook","secret":"your-secret"}'

# 事件将 POST 到 url,带签名头:
# X-DyHub-Signature: sha256=<HMAC-SHA256(secret, body)>

通用参数(WS / SSE):roomId(选填,订阅指定房间,缺省全部)、types(选填,逗号分隔的事件类型过滤)。


📡 API 参考

方法 路径 说明
GET / 控制台(实时监控 + 多房间切换 + 对接演示)
GET /api/rooms 已连接直播间列表(含主播信息与连接进度)
POST /api/rooms/connect 连接直播间 {roomId}
POST /api/rooms/:roomId/disconnect 停止采集(房间保留,可随时恢复)
DELETE /api/rooms/:roomId 彻底删除房间
GET /api/rooms/:roomId 单房间详情
GET /api/stats 全局统计(WS 客户端数 / 房间 / 事件量)
GET/POST/DELETE /api/cookie 登录 Cookie 管理(查看状态 / 设置 / 清除),详见 Cookie 配置指南
GET /api/events?types=chat,gift&roomId=xxx SSE 实时事件流
GET/POST/DELETE /api/webhooks Webhook 订阅管理

🗂️ 项目结构

src/
├── index.ts                 # 入口:装配采集 → 管道 → 分发 → API
├── types/events.ts          # 标准化事件协议(消费端唯一依赖)
├── proto/douyin.proto.ts    # protobuf 解码器(帧/消息体)
├── collector/
│   ├── browser.ts           # 浏览器内核:Chrome 探测 / 页面 / CDP / Cookie 注入
│   ├── lightweightSession.ts # 轻量内核:纯代码 wss 直连(cookie 链 / 签名 / 心跳 / ack)
│   ├── cookieStore.ts       # 运行时 Cookie 存储(登录态注入,两种内核共用)
│   ├── liveSession.ts       # 单直播间会话(帧监听 / 状态机)
│   ├── roomMeta.ts          # 主播信息解析(昵称 / 头像 / 简介)
│   └── collector.ts         # 采集器门面(多房间管理)
├── pipeline/
│   ├── normalizer.ts        # 抖音私有协议 → 统一事件(翻译层)
│   ├── dedupe.ts            # 滑动窗口去重
│   └── eventBus.ts          # 事件总线(订阅 / 发布,解耦核心)
├── dispatch/
│   ├── wsServer.ts          # WebSocket 实时推送
│   ├── sseServer.ts         # SSE 推送
│   └── webhook.ts           # Webhook 投递(HMAC 签名)
├── api/server.ts            # Fastify 管理 API
└── ui/dashboard.html        # 控制台单页应用

🐳 Docker 一键部署

镜像内置 Chromium + 中文字体(弹幕昵称 / 内容渲染),无需在宿主机安装任何浏览器。

方式一:Docker Compose(推荐)

docker compose up -d --build

# 打开控制台
open http://localhost:8757

# 连接直播间(示例:东方甄选)
curl -X POST http://localhost:8757/api/rooms/connect \
  -H 'Content-Type: application/json' \
  -d '{"roomId":"708764876300"}'

# 查看日志
docker compose logs -f dyhub

方式二:docker run

docker build -t dyhub .
docker run -d --name dyhub -p 8757:8757 --shm-size=2g dyhub

为什么需要 --shm-size=2g:Chromium 渲染依赖共享内存 /dev/shm,Docker 默认仅 64MB,会导致采集页面崩溃。Compose 已内置该配置。

配置说明

说明
DYHUB_PORT / DYHUB_HOST 默认 8757 / 0.0.0.0,改端口时同步改端口映射
DYHUB_HEADED 容器内保持 0(无头),不要打开有头
DYHUB_CHROME 镜像已内置 /usr/bin/chromium
DYHUB_COOKIE 容器 IP 被风控或需获取礼物事件时,填入浏览器复制的登录 Cookie → 详见 Cookie 配置指南
健康检查 每 30s 探测 /api/statsdocker ps 可查状态

🧩 扩展点 / Roadmap

  • 规则引擎:事件总线 + type + user + content 规则匹配 → 触发动作
  • AI 助理:消费 chat 事件喂给 LLM,回复经 OBS / 弹幕回发
  • 弹幕游戏member / chat 事件驱动游戏状态机
  • 数据看板room 事件做在线趋势、gift 做营收统计
  • 多平台:新增 collector/bilibili.ts 等适配器,复用同一事件协议

欢迎提 Issue / PR。


❓ 常见问题

Q:npm run buildUnable to resolve @typescript/typescript-darwin-x64

TypeScript 7 使用原生平台包,npm 按安装时的 Node 架构选择(arm64 / x64)。若运行 tsc 的 Node 与安装依赖时的架构不一致,会缺对应平台包。修复:

npm install -f @typescript/typescript-darwin-x64   # 或 -arm64,按实际报错
# 更推荐:统一 Node 版本后重新 npm install

Q:连接后房间一直 connecting(0 帧)?

多为首次启动采集浏览器较慢(页面加载 + 播放器初始化),等待 10~30 秒(控制台会展示分步连接进度);若持续不进入 live,检查直播间是否在直播、以及 DYHUB_CHROME 指向的浏览器版本。

Q:会被抖音风控吗?

方案为「真实浏览器被动旁观」,不发送业务请求,风险显著低于纯 HTTP 逆向。但仍请遵守平台规则、控制采集规模,仅采集自有或已授权直播间。

Q:礼物事件获取不到?

抖音 webcast 服务端只向已登录的连接推送礼物事件,游客态只收到弹幕 / 进场 / 点赞等。需在控制台填入含 sessionid_ss 的登录 Cookie → 详见 Cookie 配置指南


⚠️ 合规声明

  • 仅采集自有或已获授权的直播间;请遵守抖音平台规则与相关法律法规
  • 采集为被动旁观(不发送业务请求),请控制并发、合理使用
  • 抖音接口可能随时调整,本方案因浏览器自动跟随而具备较强韧性

📄 License

MIT

🙏 致谢

设计思路参考了以下优秀开源项目:

About

抖音直播弹幕中台 (Douyin Live Danmaku Hub):双采集内核(浏览器+CDP / 轻量直连)、多房间并发、WS/SSE/Webhook 三通道分发、可视化控制台、Docker 一键部署

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages