简易脚本开发过程:自动查询B站弹幕点赞数并显示在弹幕旁
本帖最后由 啦la啦 于 2026-1-4 02:07 编辑此笔记记录脚本(https://scriptcat.org/zh-CN/script-show-page/5016) 开发过程
### B站弹幕DOM探索
F12 → 元素 → 查找 搜索弹幕文本,找到弹幕元素
```html
<!--典型弹幕元素-->
<div aria-live="polite" role="comment"
class="bili-danmaku-x-dm bili-danmaku-x-roll bili-danmaku-x-show"
style="--opacity: 0.8; --fontSize: 25px; --fontFamily: SimHei, 'Microsoft JhengHei', Arial, Helvetica, sans-serif; --fontWeight: bold; --color: #ffffff; --textShadow: 1px 0 1px #000000,0 1px 1px #000000,0 -1px 1px #000000,-1px 0 1px #000000; --offset: 730.5388359130914px; --translateX: -861px; --duration: 8.21s; --top: 33.125px;"
>
哈哈哈
</div>
```
经研究得到以下结论:
1. 所有弹幕都有`bili-danmaku-x-dm`类
2. 显示中的弹幕有`bili-danmaku-x-show`类,显示结束后不会把弹幕元素从DOM移除,而是移除`bili-danmaku-x-show`类,等待复用
3. 外层弹幕容器的类名为`bpx-player-row-dm-wrap`
### B站弹幕加工探索
由以上DOM探索可知弹幕DOM元素并不含弹幕的id等信息,得找到弹幕是如何加工成DOM元素的。
在DevTools(F12)中右键弹幕容器(`bpx-player-row-dm-wrap`) → 中断于 → 子树修改
播放视频,结果中断于ndp.223.xxxxxx.js文件的一个名为`render`方法中(有时中断于名为`init`的方法,F8继续运行一下),此方法根据弹幕信息,为弹幕DOM元素添加各种style属性。
```javascript
e.prototype.render = function(t, e) {
var n, r, o, i = this.textData, a = i.color, s = i.border, c = i.borderColor, u = i.colorfulImg, l = i.isHighLike, f = i.likes, p = this.config.setting, h = p.bold, d = p.fontFamily, m = p.fontBorder, y = p.opacity, g = Ft(this.outlineColor(a)), v = "".concat(H, "-dm ").concat(H, "-roll"), b = "";
s && "transparent" !== c && !(null === (n = this.modeInfo) || void 0 === n ? void 0 : n.isUpSlogan) ? (b += "border: 1px solid ".concat(Ft(c), ";"),
this.width += 4,
this.height += 4) : (null === (r = this.modeInfo) || void 0 === r ? void 0 : r.isUpSlogan) && (v += " ".concat(H, "-upslogan"),
this.width += 12),
this.font = (h ? "bold" : "normal") + " " + 2 * this.fontSize + "px " + d,
b += "--opacity: ".concat(Math.max(y, .1) + "", ";"),
b += "--fontSize: ".concat(this.fontSize, "px;"),
b += "--fontFamily: ".concat(d, ", Arial, Helvetica, sans-serif;"),
b += "--fontWeight: ".concat(h ? "bold" : "normal", ";"),
b += "--color: ".concat(Ft(a), ";"),
this.element.setAttribute("aria-live", "polite"),
this.element.setAttribute("role", "comment"),
u || (b += "--textShadow: ".concat(this.getShadow(g, m), ";")),
b += this.renderRealTimeOptimization(null === (o = this.textData) || void 0 === o ? void 0 : o.isRealTime),
l || f || u ? this.renderSpecialType(e || v, b) : (this.hasEmoji || this.textData.prefix || this.textData.suffix ? this.element.innerHTML = lt(this.text) : this.element.textContent = lt(this.text),
this.element.className = e || v,
this.element.style.cssText = b),
this.textData.prefix && this.textData.prefix instanceof HTMLElement && (this.textData.prefix.style.height = "".concat(1.2 * this.fontSize, "px"),
this.textData.prefix.style.width = "auto",
this.element.insertBefore(this.textData.prefix, this.element.firstChild)),
this.textData.suffix && this.textData.suffix instanceof HTMLElement && (this.textData.suffix.style.height = "".concat(1.2 * this.fontSize, "px"),
this.textData.suffix.style.width = "auto",
this.element.appendChild(this.textData.suffix))
}
```
this.textData包含各种弹幕信息。具体含义参考 (https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md) DanmakuElem
```javascript
{
"stime": 884.647, // 发送时进度条时间
"mode": 5,
"size": 25,
"color": 16646914,
"uhash": "6a3439b",
"text": "哈哈哈",
"date": 1766993886,
"weight": 10,
"dmid": "2012449591689219328",// 弹幕唯一id(查询点赞数需要)
"attr": 1048576,
"oid": 35045576155, // 视频唯一chatid(查询点赞数需要)
"dmFrom": 1,
"likes": undefine,
"rawMode": 5,
"modeInfo": {
"cid": 35045576155
},
"pool": 0,
"uname": "",
"id_str": "2012449591689219328", // 弹幕id通常超出Number范围
"border": false,
"borderColor": 6750207,
"isHighLike": false,
"isMine": false,
"prefix": null,
"suffix": null,
"on": true
}
```
到此为止就很简单了,~~交给AI即可~~。hook `render` 函数,把需要的弹幕信息塞入弹幕DOM元素的dataset里;然后MutationObserver监控弹幕的DOM元素,有新弹幕出现就从dataset里获取oid、dmid查询点赞数,显示在弹幕旁。
### 其他
***
**点赞数查询API**:(https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/thumbup.md)
***
**角标使用的SVG**:
1. 发送图标:(https://www.iconfont.cn/search/index?searchType=icon&q=%E5%8F%91%E9%80%81)找了一个
2. 点赞图标:B站自带点赞弹幕图标(悬浮于弹幕上,右键点赞图标 → 检查 → svg复制下来)
***
**角标按热度增亮公式**:
高亮角标即角标添加背景色,亮度即背景色不透明度(0~1),选用公式 $1-e^{-kx}$
由于合并数与点赞数不在一个数量级,热度为合并数与点赞数的加权和:
$hot=(sendCount-1)\\cdot sendMul+likes\\cdot likeMul$
> 发送次数为1相当于合并数为0,因此sendCount需减1
热度为0时也要有一定的亮度,设为b0,公式修正为:
$brightness=1-(1-b0)e^{-k \\cdot hot}$
还剩参数k决定曲线上升速率,设参数h90表示亮度达到90%时的热度值,计算k:
$$
\\begin{aligned}
0.9 &= 1-(1-b\_0)e^{-k \\cdot h\_{90}} \\
e^{-k \\cdot h\_{90}} &= \\frac{0.1}{1-b\_0} \\
k &= -\\frac{1}{h\_{90}}\\ln\\left(\\frac{0.1}{1-b\_0}\\right) \\
k &= \\frac{1}{h\_{90}}\\ln(10-10\\cdot b\_0)
\\end{aligned}
$$
最终四个参数决定亮度曲线:
| 参数 | 含义 | 默认 |
| --- | --- | --- |
| b0 | 热度为0时的亮度 | 0.2 |
| h90 | 亮度为90%时的热度 | 500 |
| sendMul | 合并数倍率 | 5 |
| likeMul | 点赞数倍率 | 1 |
这几个参数没给UI,可通过控制台 `__DM_ADAPT__.setBadgeHighlightCurve(0.2, 500, 5, 1)` 控制。
页:
[1]