Bilibili-Evolved 弹幕下载功能深度解析:XML / JSON / ASS 三种格式的获取原理与播放器设置联动
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
导读
本文基于 Bilibili-Evolved 仓库中registry/lib/components/video/danmaku/download组件的实现,完整解析"下载弹幕"功能的三种输出格式(XML、JSON、ASS)、基于 protobuf 的分段拉取流程,以及 ASS 转换如何自动继承哔哩哔哩播放器内的屏蔽与显示设置。读完本文,你将掌握该功能从功能面板点击到文件落盘的全链路原理,并能在此基础上自行扩展弹幕导出能力。
功能定位与使用入口
在视频(含番剧)页面中,启用该功能后即可从功能面板下载当前视频的弹幕。组件元数据定义在 index.ts,其关键字段如下:
name: 'downloadDanmaku'、displayName: '下载弹幕',标签为componentsTags.video,属于视频类组件;urlInclude: videoAndBangumiUrls,即仅在视频与番剧页面生效;widget.condition: hasVideo,功能面板图标仅在检测到视频时显示;- 组件无独立入口(
entry: none),下载能力完全通过功能面板按钮与"下载视频"插槽两种途径暴露。
功能面板:三种格式一键下载
功能面板组件 DownloadDanmaku.vue 渲染了三个并列的DefaultWidget按钮,分别对应:
| 按钮名称 | 触发类型 |
|---|---|
| 下载弹幕 (XML) | download('xml') |
| 下载弹幕 (JSON) | download('json') |
| 下载弹幕 (ASS) | download('ass') |
点击后,组件通过getFriendlyTitle()取得页面友好标题,调用getBlobByType(type)生成 Blob,再交给DownloadPackage.single直接下载,文件名形如视频标题.xml。下载过程中按钮会置灰(disabled)以防止重复触发,异常则通过logError记录。
与"下载视频"功能的集成
除独立下载外,该组件还以插件形式注册到视频下载流程中(index.ts 中的plugin.setup):
- 通过
addData('downloadVideo.assets', ...)向下载视频功能注册一个"额外产物"(DownloadVideoAssets,其类型定义见 types.ts); - 在批量下载视频时,对每个视频输入调用
getBlobByType获取对应格式的弹幕 Blob,并返回{ name: \${title}.${type}`, data: blob }` 作为下载包条目; - 使用
Promise.allSettled并发处理多个视频,实时通过 Toast 显示进度(获取弹幕中... (n/m)),完成后提示成功与失败数量; - 格式选择由 Plugin.vue 提供,下拉项为
['无', 'ass', 'json', 'xml'],选择结果写入downloadVideo组件的options.danmakuType。
三种下载格式及其数据来源
DanmakuDownloadType = 'json' | 'xml' | 'ass'(定义于 utils.ts)。所有格式都基于同一份内存数据模型JsonDanmaku,它保存了每条弹幕的id / progress / mode / fontsize / color / midHash / content / ctime / weight / pool / attr等字段——这与下文的 protobuf 响应字段一一对应。
getBlobByType(type, { aid, cid })的最终分发逻辑:
- JSON:直接将
jsonDanmakus数组序列化为缩进 2 空格的美化 JSON,MIME 类型text/json,保留弹幕最原始的结构化信息; - XML:通过
convertToXmlFromJson重新生成符合哔哩哔哩标准的 XML 文档,MIME 类型text/xml; - ASS:先经
convertToAssFromJson调用DanmakuConverter做完整字幕转换,MIME 类型text/ass。
JSON 格式
JSON 是最忠实的原始数据形态,每条弹幕包含progress(毫秒)、mode(弹幕类型)、fontsize、color(十进制颜色值)、midHash(用户哈希)、ctime(发送时间戳)等全部字段,适合程序化二次处理,例如做弹幕统计、情感分析或自建弹幕库。
XML 格式
convertToXmlFromJson生成的 XML 文档结构如下(danmaku.cid作为chatid,maxlimit为弹幕总数):
<?xml version="1.0" encoding="UTF-8"?> <i> <chatserver>chat.bilibili.com</chatserver> <chatid>123456</chatid> <mission>0</mission> <maxlimit>2048</maxlimit> <state>0</state> <real_name>0</real_name> <source>k-v</source> <d p="10.60800,5,25,16724991,1544806627,0,6d16be9f,9261260365889536">biu</d> </i>其中每条<d>标签的属性顺序由JsonDanmaku.xmlDanmakus映射而来:发送时间(秒) / 弹幕类型 / 字体相对大小 / 颜色 / Unix时间戳 / 弹幕池 / 用户Hash / 行序号,各字段含义可参考仓库内的格式设计笔记 danmaku-converter.md。生成的 XML 可直接被第三方播放器(如 PotPlayer、mpv 弹幕插件)加载。
ASS 格式与内置限制
ASS 是最适合直接作为字幕文件使用的格式,但需要注意组件说明中明确写出的限制:
请注意 ASS 弹幕下载不会包含高级弹幕, 字幕弹幕等。
该限制的实现依据在转换配置中:默认blockTypes: [7, 8],而 7~8 正是"高级弹幕"类型(见 danmaku-converter.md 的弹幕类型表:1~3 普通、4 底端、5 顶端、6 逆向、7~8 高级)。DanmakuConverter.xmlDanmakuToAssDocument(danmaku-converter.ts)在处理时会跳过这些类型,同时也会跳过命中用户屏蔽词/屏蔽用户的弹幕。
底层数据获取:基于 protobuf 的分段弹幕拉取
弹幕原始数据并非一次接口调用即可获取,而是先请求配置接口获知分段总数,再并发拉取各分段。这一流程封装在JsonDanmaku.fetchInfo()中,实际网络请求位于 danmaku-segment.ts:
- 获取弹幕配置:
getDanmakuView(aid, cid)请求https://api.bilibili.com/x/v2/dm/web/view?type=1&oid={cid}&pid={aid},得到DmWebViewReply,其中dmSge.total表示弹幕分段总数; - 并发拉取分段:
getDanmakuSegment(aid, cid, index)请求https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid={cid}&pid={aid}&segment_index={index+1},返回DmSegMobileReply,elems为该段弹幕列表; - 解码与合并:响应为 protobuf 二进制,通过运行时加载的 protobuf 库(
protobufLibrary)按proto中定义的消息结构解码,再flat()合并全部分段,按progress升序排序后存入jsonDanmakus。
从源码结构可以推断,分段并发拉取的方式对大弹幕量的视频(如热门番剧、演唱会)能显著缩短等待时间;任何一段失败都会向上抛出,由调用方的Promise.allSettled汇总为"失败 n 个"的提示。
ASS 转换原理:自动继承播放器设置
ASS 下载的独特价值在于转换结果并非固定模板,而是自动继承用户当前播放器内的弹幕显示与屏蔽设置。这一逻辑集中在getUserDanmakuConfig()(utils.ts),其读取链路为:调用loadDanmakuSettingsPanel()确保设置就绪 → 读取localStorage中的bilibili_player_settings→ 通过playerAgent.getPlayerConfig逐项读取。
默认配置(无播放器设置时的兜底)
| 配置项 | 默认值 | 含义 |
|---|---|---|
font | '微软雅黑' | 弹幕字体 |
alpha | 0.4 | 弹幕透明度 |
duration | 顶部/底端 4 秒,其余 6 秒 | 单条弹幕持续时长 |
blockTypes | [7, 8] | 屏蔽的弹幕类型(高级弹幕) |
resolution | 1920 × 1080 | 字幕画布分辨率 |
bottomMarginPercent | 0.15 | 底部留白比例(防挡字幕) |
bold | false | 是否加粗 |
与播放器设置的联动项
- 屏蔽类型:读取
block.type_scroll / type_top / type_bottom / type_color四项开关,分别映射为滚动(1,2,3)、顶端(5)、底端(4)、彩色弹幕,未屏蔽的类型才参与转换,并始终追加 7、8(高级弹幕不转换); - 加粗:
dmSetting.bold; - 透明度:
alpha = 1 - dmSetting.opacity,经lodash.clamp(…, 0, 1)约束范围; - 分辨率:由
dmSetting.fontsize计算缩放因子resolutionFactor = 1.4 - 0.4 × fontsize(默认 1),再乘以 1920×1080 得到画布尺寸——播放器字号越大,导出的 ASS 画布越大,以保持视觉比例一致; - 持续时长:滚动弹幕时长按
18 - 3 × speed计算,speed取自dmSetting.speedplus(或组件隐藏选项downloadDanmakuOptions.speed手动指定,见 options.ts,默认'auto'),顶部/底端固定 4 秒; - 底部间距:
dmSetting.danmakuArea小于 100 时按百分比换算,等于 100(无区域限制)时归零;此时若开启防挡字幕dmSetting.preventshade,则回退为 0.15; - 用户屏蔽:读取
block.list,逐条支持三种屏蔽类型——keyword(内容包含关键词)、regexp(正则匹配)、user(按userHash匹配),命中即从 ASS 中剔除,且只应用处于开启状态(s: true)的条目; - 字体:直接从页面 DOM 中读取播放器弹幕设置面板当前选中的字体文本(选择器为
.bilibili-player-video-danmaku-setting-right-font或新版.bpx-player-dm-setting-right-content-fontfamily下的.bui-select-result),因为 localStorage 中保存的是更复杂的 font-family 解析串。
若读取失败或未找到播放器设置(bilibili_player_settings不存在),则整体回退到上表默认配置,保证任何环境下都能正常导出。
XML → ASS 的格式转换细节
转换器 DanmakuConverter 按 danmaku-converter.md 中记录的 ASS 规范生成字幕:
- 按字体大小(18/25/30/36/45)映射为 Small/Medium/Large/Larger/ExtraLarge 五种样式,字号分别为 36/52/64/72/90,并通过
alpha生成形如&H66FFFFFF的 ASS 颜色(&HAA为透明度十六进制); - 颜色以
\c&H<bb><gg><rr>&形式输出(注意 BGR 字节序),边框色用\2c; - 滚动弹幕使用
\move(x1,y1,x2,y2)标签,固定弹幕使用\pos(X,Y),底部留白由DanmakuStack依据bottomMarginPercent计算纵向位置,避免弹幕堆叠重叠; - 弹幕内容经
normalizeContent规范化处理,避免非法字符破坏字幕文件。
相关源码文件索引
- 组件入口与插件注册
- 下载逻辑与配置读取
- 功能面板按钮
- 下载视频集成面板
- 组件隐藏选项
- protobuf 弹幕接口与解码
- ASS 转换器
- XML / ASS 格式设计笔记
- 视频下载额外产物类型定义
以上即可完整回答"下载弹幕"功能的三个核心问题:数据从哪来(protobuf 分段接口)、能导出成什么(JSON / XML / ASS)、导出时如何继承用户设置(播放器设置联动与 ASS 转换器)。
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考