npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

douyudm

v3.2.0

Published

实时获取斗鱼弹幕

Readme

douyudm

基于 WebSocket 实时获取斗鱼弹幕,支持 Node.js 与浏览器。

安装

作为库使用

# npm
npm i douyudm

# pnpm
pnpm add douyudm

全局 CLI 工具

# npm
npm i -g douyudm

# pnpm
pnpm add -g douyudm

CLI 使用

# 监听房间弹幕
douyudm -i 9999

# 忽略指定事件
douyudm -i 9999 --ignore mrkl,uenter

# 查看所有选项
douyudm --help

录制与 ASS 字幕导出

# 边看边录制为 JSONL(默认只录 chatmsg,Ctrl+C 停止)
douyudm -i 9999 --record live.jsonl

# 追加录制其他事件
douyudm -i 9999 --record live.jsonl --record-events chatmsg,uenter,gdp

# 转换为 ASS 字幕(配合录播视频加载)
douyudm convert live.jsonl -o live.ass

# 裁剪时间段 + 整体延迟(对齐视频)
douyudm convert live.jsonl --from 10:00 --to 1:30:00 --delay=-2.5

# 过滤:正则剔除弹幕/用户(可重复,支持 /pattern/flags)
douyudm convert live.jsonl --filter '/666+/' --filter-user '^bot'

# 可编程过滤(如接大模型批量判定),脚本 default export 二选一:
#   (msg) => boolean | Promise<boolean>          逐条,true 保留
#   { batch: async (msgs) => msgs的保留子集 }     批量
douyudm convert live.jsonl --filter-script ./my-filter.mjs

# 画布/样式调整
douyudm convert live.jsonl --width 1280 --height 720 --fontsize 36 --duration 8 --opacity 0.6

录制文件为 JSONL 格式:第一行记录房间号和开始时刻,之后每行一条消息(收到时刻 ts + 消息原始字段)。文件只追加不改写,中途崩溃最多丢正在写的一行。过滤只在 convert 时生效,原始录制文件不会被改动,可以反复用不同条件重新导出。过滤脚本示例见 examples/filter-scripts/

录制/转换在浏览器里同样可用(解析、过滤、排版、渲染都是纯逻辑,已打进浏览器构建):examples/browser/ 的页面支持连接时录制(写入浏览器本地数据库,刷新不丢)、下载 .jsonl、本地转换出 .ass

API 使用

Node.js

// CJS
const { Client } = require('douyudm')

const client = new Client(9999)

client.on('connect', (client) => console.log(`[connect] roomId=${client.roomId}`))
client.on('disconnect', (client) => console.log(`[disconnect] roomId=${client.roomId}`))
client.on('error', (client, err) => console.error(`[error] roomId=${client.roomId}`, err))

client.on('chatmsg', (res) => console.log(`<lv ${res.level}> [${res.nn}] ${res.txt}`))
client.on('uenter', (res) => console.log(`${res.nn} 进入房间`))

client.run()
// ESM / TypeScript
import { Client } from 'douyudm'

const client = new Client(9999, { ignore: ['mrkl'] })
client.on('chatmsg', (res) => console.log(`[${res.nn}] ${res.txt}`))
client.run()

浏览器

<script src="https://unpkg.com/douyudm/dist/douyudm.browser.min.js"></script>
<script>
  const client = new douyudm.Client(9999)
  client.on('chatmsg', (res) => console.log(res.nn, res.txt))
  client.run()
</script>

完整示例见 examples/ 目录。

选项

new Client(roomId, opts?)

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | roomId | string \| number | — | 房间号 | | opts.ignore | string[] | [] | 忽略的消息事件列表 | | opts.retries | number | 5 | 连接建立前失败的最大重试次数(自动轮换 6 个弹幕端口),0 关闭 | | opts.retryDelay | number | 1000 | 相邻两次连接尝试的间隔(ms) |

斗鱼的 6 个弹幕端口在部分网络下不是每个都能连上。连接建立之前失败时会自动换一个端口重试,重试过程中不触发 error 事件,次数全部用完还连不上才触发。连接建立之后的断开不会自动重连。

事件列表

系统事件

回调签名:(client: Client, err?: Error) => void

| 事件 | 描述 | |:----:|:----:| | connect | 连接成功 | | disconnect | 连接断开 | | error | 连接错误 |

client.on('connect', (client) => console.log(`[connect] roomId=${client.roomId}`))
client.on('error', (client, err) => console.error(`[error] roomId=${client.roomId}`, err))

消息事件

回调签名:(res: STTObject, client?: Client) => void

第二个参数 client 为可选,需要访问实例时才传入。

| 事件 | 描述 | |:----:|:----:| | loginres | 登录响应 | | chatmsg | 弹幕消息 | | uenter | 用户进入房间 | | upgrade | 用户等级提升 | | rss | 房间开播/关播提醒 | | bc_buy_deserve | 赠送酬勤通知 | | ssd | 超级弹幕 | | spbc | 全站礼物广播(大额礼物,不限本房间)| | dgb | 赠送礼物(原始事件)| | gdp | 本房间礼物事件(xx 赠送礼物 xN)| | onlinegift | 领取在线鱼丸 | | ggbb | 房间用户抢红包 | | rankup | 房间 Top10 变化 | | ranklist | 广播排行榜 | | mrkl | 心跳 | | blab | 粉丝等级升级 | | frank | 粉丝排行榜变化 | | anbc | 全站礼物广播 | | cthn | 跨房间弹幕 | | configscreen | 全屏广播 | | nlkstatus | 大乱斗状态 | | tsgs | 宝箱礼物 | | tsboxb | 宝箱广播 | | ro_game_succ | 游戏成功 | | pandoraboxinfo | 潘多拉盒子 | | lucky_wheel_star_pool | 幸运转盘 | | noble_num_info | 贵族数量 | | synexp | 经验同步 | | wirt | 直播间互动 | | rnewbc | 新广播 |

// 只用消息数据
client.on('chatmsg', (res) => console.log(`[${res.nn}] ${res.txt}`))

// 同时访问 Client 实例
client.on('chatmsg', (res, client) => console.log(`roomId=${client.roomId} [${res.nn}] ${res.txt}`))

STT 协议

斗鱼自定义序列化格式,规则如下:

  • 键值对使用 @= 分隔:key@=value
  • 字段使用 / 分隔
  • @ 转义为 @A/ 转义为 @S
import { STT } from 'douyudm'

// 序列化
STT.serialize({ type: 'mrkl' })  // => 'type@=mrkl/'

// 反序列化
STT.deserialize('type@=chatmsg/nn@=用户/txt@=hello/')
// => { type: 'chatmsg', nn: '用户', txt: 'hello' }

开发

# 构建
npm run build

# 测试(含覆盖率)
npm run test:coverage

后话

坑太多了,github上的库大部分都是不能使用的,如果近期更新的可以判断使用的新接口,review了几乎所有相关的库,都是依据斗鱼自己官方平台的方法发起tcp连接?但根本连不上,一直拒绝...

看了下能使用的库,都是通过websocket建立的连接,立马修改,不出片刻撸完,发现发送数据的格式有点难搞,虽说示意图挺清楚的,但是用Buffer传输死活没有相应的消息,调试太磨人心性了,玛德,直接去把斗鱼网页上的方法扒下来。

通过webpack打包混淆代码乍一眼看去很混乱,其实仔细观察还是有规律寻找的。

文档中编码的几个固定参数均为数字,在webpack中数字的混淆我还没见过,按这个思路精准的找到这段代码。经过我十几分钟的理解,提取出二进制编解码逻辑,斗鱼自有的序列化、反序列化方法可以查看 STT 协议 章节。

License

MIT