ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Bilibili-Old的gRPC与Protobuf实战:如何在浏览器里恢复APP播放流与弹幕

Bilibili-Old的gRPC与Protobuf实战:如何在浏览器里恢复APP播放流与弹幕 Bilibili-Old的gRPC与Protobuf实战如何在浏览器里恢复APP播放流与弹幕【免费下载链接】Bilibili-Old恢复旧版Bilibili页面为了那些念旧的人。项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-OldBilibili-Old 是一个「恢复旧版Bilibili页面」的开源项目它的核心技术之一就是让浏览器直接说gRPC协议、用Protobuf解码APP播放流和弹幕数据。这篇文章用尽量少的代码带你读懂这套「浏览器调用APP私有接口」的完整实现思路并附关键源码路径。一、为什么浏览器也要会 gRPC 普通网页接口大多是JSON但 B 站 APP 的播放流接口走的是gRPC over HTTP/2请求体是Protobuf 二进制不是 JSON外层还包了一层gRPC 帧格式压缩标记 4字节长度设备信息放在自定义请求头x-bili-metadata-bin里好消息是gRPC 的本质就是「带特定头的 HTTP POST 二进制体」所以只要自己拼帧、自己编解码浏览器就能调用 APP 接口。这正是项目「解除播放限制APP/HDR/杜比/AV1 源」的关键。相关模块集中在src/io/grpc/目录gRPC 通用基类src/io/grpc/BAPIMetadata/metadata.tsAPP 播放流接口src/io/grpc/BAPIAppPlayurl/v1/playurl.ts弹幕接口src/io/grpc/api-dm-web.ts二、Protobuf 在浏览器里怎么用传统项目需要.proto文件 代码生成器Bilibili-Old 用了更轻的方案protobufjs 的 JSON 定义格式。把.proto编译成「类型定义 JSON」直接import进 TS用Root.fromJSON()在运行时构建消息类型用Type.fromObject()编码请求、Type.decode()解码响应播放流的类型定义就存在这两个文件里请求/响应类型定义src/io/grpc/BAPIAppPlayurl/v1/playurl.json弹幕类型定义src/json/dm-web.json这样就不需要本地编译 protobuf打包后依然可以在浏览器/油猴环境直接运行。三、APP播放流一次 gRPC 请求的全过程 核心逻辑在基类 BAPIMetadata.request() 中整个流程可以拆成 5 步1️⃣ 请求参数 Protobuf 编码以「获取播放地址」的PlayURL方法为例playurl.ts只需传入aid稿件ID、cid分P ID等字段基类负责编码、压缩、发请求、解码子类只描述「我要调哪个方法」。2️⃣ 拼上 gRPC 帧头5 个字节响应体先gzip压缩然后手工拼一个 5 字节的帧头第 1 字节压缩标记1 gzip第 2~5 字节4 字节大端长度// 简化示意压缩标记 长度 压缩后的 protobuf 体 uInt8[0] 1; dataview.setUint32(1, body.length);接收响应时也要先剔除这 5 个字节再解压解码这是调试时最常见的坑。3️⃣ 设备信息放请求头设备伪装信息buvid、平台、构建号等本身也是一个 Protobuf 消息Metadata编码后Base64放进x-bili-metadata-bin头定义见 metadata.json。登录态则附加Authorization: identify_v1 token头token 的获取逻辑在 src/core/accesskey.ts。4️⃣ 关键请求头一览请求头作用Content-Type: application/grpc声明 gRPC 协议grpc-encoding: gzip声明消息体已 gzip 压缩x-bili-metadata-binBase64 的 Protobuf 设备信息authorization登录鉴权可选5️⃣ 错误处理grpc-status 头gRPC 的错误不放在响应体而放在响应头里。基类优先检查grpc-status-details-bin一个 Protobuf 的Status消息把业务错误码抛出来没有则检查grpc-message。画质控制的小巧思fnval 位运算fnval是一个「按位或」的功能位组合数一个整数就能表达想要的流格式定义在 src/io/fnval.ts16DASH-H265、64HDR、1284K、256杜比音频、2048AV1项目默认值把这些位全部加起来qn 1278K——一步到位请求最高规格拿不到就自动降级这就是为什么装上 Bilibili-Old 后网页能播 APP 端的 HDR/杜比源。四、弹幕获取Protobuf 两段式解码 弹幕接口的实现类是 ApiDmWeb流程是典型的「先查目录再拉分片」第一步DmWebViewReply —— 弹幕总览请求dm/web/view拿回dmSge分页配置每页 3600 条、共几页specialDms高级弹幕图片/代码弹幕的 CDN 地址列表弹幕区开关、云屏蔽等配置第二步DmSegMobileReply —— 按页拉取弹幕本体弹幕按segment_index分段存储。这里有个性能细节如果是当前正在播放的视频直接用「视频总时长 ÷ 每页覆盖时长」算出需要的页数少走网络请求所有分页请求用Promise.all并发发出单页失败只console.warn丢包提示不阻塞整体高级弹幕与正文弹幕合并后统一按id排序去重解码方式统一为「fetch拿ArrayBuffer→Type.decode()→toObject()」三行搞定一条 Protobuf 消息。拿到弹幕后src/core/danmaku.ts 会把它转换成旧版 XML 格式交给播放器装填也支持下载为 XML/JSON 文件。五、这套架构的设计亮点总结抽象分层BAPIMetadata基类封装 gRPC 帧、压缩、鉴权、错误子类只写方法名和默认参数新增接口成本极低无代码生成protobufjs 的 JSON 定义格式绕过了.proto编译工具链对浏览器脚本非常友好位掩码参数设计fnval用整数按位组合表达能力是 APP 接口常见的省流量手法并发 降级弹幕分段并发拉取、单片失败容错保证体验流畅六、核心源码索引 模块路径gRPC 基类帧/压缩/鉴权/错误src/io/grpc/BAPIMetadata/metadata.ts播放流方法封装src/io/grpc/BAPIAppPlayurl/v1/playurl.ts播放流类型定义src/io/grpc/BAPIAppPlayurl/v1/playurl.json设备/状态 Protobuf 定义src/io/grpc/BAPIMetadata/metadata.json弹幕接口实现src/io/grpc/api-dm-web.ts弹幕类型定义src/json/dm-web.jsonfnval 画质位定义src/io/fnval.ts弹幕业务入口src/core/danmaku.ts下载调用播放流src/core/download.ts登录 token 管理src/core/accesskey.ts 想自己动手先安装 Tampermonkey到 GreasyFork 搜索安装 Bilibili-Old 脚本扩展版可用「加载已解压的扩展程序」安装详见 README.md。读懂了这些你就不止是在「用」Bilibili-Old而是真正看懂了浏览器调用 gRPC 私有接口、用 Protobuf 还原 APP 播放流与弹幕的全过程 —— 这也是前端逆向工程里非常实用的一套方法论。【免费下载链接】Bilibili-Old恢复旧版Bilibili页面为了那些念旧的人。项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Old创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表