news 2026/9/19 16:52:55

Bilibili-Evolved 直播马赛克遮罩移除组件(remove-mask-panel)源码级解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bilibili-Evolved 直播马赛克遮罩移除组件(remove-mask-panel)源码级解析

Bilibili-Evolved 直播马赛克遮罩移除组件(remove-mask-panel)源码级解析

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

本文围绕 Bilibili-Evolved 在线功能仓库中的直播组件remove-mask-panel(删除直播马赛克遮罩)展开,从组件注册、DOM 监听原理到与同主题 CSS 方案的对比进行逐层拆解。读完你将理解该组件如何借助 MutationObserver 精准识别并移除 B 站直播页的动态遮罩节点,掌握脚本组件entry/reload生命周期与urlInclude匹配机制的实际用法。

功能定位:删除观看直播时某些分区的马赛克遮罩

该组件在仓库中的描述原文为(见 index.md):

删除观看直播时某些分区的马赛克遮罩。

它属于「直播」+「样式」两个标签(tags)下的功能,用于解决 B 站直播页面中部分分区播放器上覆盖马赛克遮罩(mosaic mask)的问题。从功能分类看,它并不改变直播流的清晰度,也不影响直播数据请求,而是纯粹针对页面 DOM 中一个特定遮罩节点进行移除,属于界面层面的增强功能,因此同时被归类为直播类(live)与样式类(style)组件。

组件元信息与注册方式

组件的完整定义位于 registry/lib/components/live/remove-mask-panel/index.ts,通过defineComponentMetadata进行声明式注册:

export const component = defineComponentMetadata({ name: 'removeLiveMaskPanel', displayName: '删除直播马赛克遮罩', author: { name: 'Liki4', link: 'https://github.com/Liki4', }, tags: [componentsTags.live, componentsTags.style], entry, reload: entry, urlInclude: liveUrls, })

各字段含义如下(对应类型定义见 src/components/types.ts):

字段说明
nameremoveLiveMaskPanel组件内部唯一标识,供脚本内核引用
displayName删除直播马赛克遮罩设置面板中展示的名称
authorLiki4组件作者及其主页链接
tagslivestyle组件分类标签,决定其在设置面板中的分组(componentsTags定义于 src/components/types.ts)
entry异步函数组件启用时执行的入口逻辑
reloadentry组件重新开启时执行的回调,此处复用入口函数
urlIncludeliveUrls仅在这些 URL 匹配的页面上运行

defineComponentMetadata本身是一个泛型工厂函数,用于在编译期提供类型推导与校验,其定义见 src/components/define.ts。该组件未声明options(无可配置子选项)、未声明unload钩子,也未显式声明enabledByDefault——按类型定义中「省略时默认为true」的约定(见 src/components/types.ts),可以推断它默认处于开启状态。

核心实现:MutationObserver 动态移除遮罩节点

入口函数是理解该组件原理的关键。B 站的马赛克遮罩节点带有固定 IDweb-player-module-area-mask-panel,且通常是直播页运行过程中异步动态插入的,因此组件选择用MutationObserver监听 DOM 变化,而不是在页面加载时一次性查询:

const id = 'web-player-module-area-mask-panel' const entry = async () => { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if ((node as Element).id === id) { node.parentNode?.removeChild(node) observer.disconnect() } }) }) }) observer.observe(document.body, { childList: true, subtree: true }) }

其工作流程可拆解为四步:

  1. 定义目标标识:用常量id记录遮罩节点的元素 IDweb-player-module-area-mask-panel,作为唯一匹配依据。
  2. 注册观察器new MutationObserver(...)创建观察器,回调遍历每次 mutation 中的addedNodes(新增节点列表)。
  3. 条件移除:一旦发现新增节点的id等于目标 ID,立即通过node.parentNode?.removeChild(node)将该节点从 DOM 中摘除,从而让马赛克遮罩消失。
  4. 及时收尾:命中后调用observer.disconnect()停止观察,避免观察器在后续页面生命周期中持续占用资源。

观察配置为{ childList: true, subtree: true }childList表示监听子节点的新增/移除,subtree表示递归监听所有后代节点,确保无论遮罩节点被插入到播放器内部多深的层级都能被捕获。disconnect()只移除已匹配到的第一个节点便停止,说明页面在同一时刻只会存在一个该 ID 的遮罩节点,整个处理是「命中一次即完成」的幂等设计。

生效范围:urlInclude 与直播 URL 匹配规则

组件通过urlInclude: liveUrls限定仅在直播页面运行。liveUrls定义于 src/core/utils/urls.ts:

export const liveUrls = [/^https:\/\/live\.bilibili\.com\/(blanc\/)?[\d]+/]

这是一个正则表达式测试模式(TestPattern),匹配规则为:

  • 协议与域名固定为https://live.bilibili.com
  • 路径部分允许可选的前缀blanc/(即直播页的「全屏/纯净」模式 URL)后跟一串纯数字(直播间房号)。

也就是说,该组件只会在形如https://live.bilibili.com/12345https://live.bilibili.com/blanc/12345的直播间页面内被激活,在其他页面(如主站、动态、视频页)即使组件处于开启状态也不会运行。urlInclude与优先级更高的urlExclude的类型说明见 src/components/types.ts。

同主题方案的对比:DOM 移除 vs CSS 层叠

仓库中还有一个与它高度相关的组件hide-player-blur(隐藏直播马赛克),二者针对的是同一个元素 ID#web-player-module-area-mask-panel,但采用了截然不同的实现思路:

对比维度remove-mask-panelhide-player-blur
实现方式MutationObserver 动态删除 DOM 节点注入 CSS 样式
样式内容z-index: -100 !important
效果遮罩节点从 DOM 中彻底移除遮罩仍存在,但被压到页面层级之下不可见
运行时机entry监听 DOM 变化后处理instantStyles尽早注入样式

hide-player-blur的完整定义见 registry/lib/components/live/hide-player-blur/index.ts,其样式文件 hide-player-blur.scss 内容为:

#web-player-module-area-mask-panel { z-index: -100 !important; }

两者对比可以得出两个值得注意的结论:

  • remove-mask-panel 更彻底:直接摘除节点,不依赖元素层级关系,也不受后续样式优先级变化影响;
  • hide-player-blur 更轻量:纯 CSS 方案无运行时 JS 开销,instantStyles会在页面较早阶段注入(instantStyles的语义见 src/components/types.ts),但对页面 z-index 体系有依赖,一旦遮罩元素处于更高层级的层叠上下文中,z-index: -100未必能将其完全压住。

这也解释了为何仓库同时保留两个功能相近的组件:前者适合「彻底眼不见为净」的需求,后者适合希望保留节点结构、仅做视觉隐藏的场景,用户可按需二选一或同时启用。

生命周期与热重载:entry / reload 复用

reload: entry是该组件行为上的一个关键细节。在 Bilibili-Evolved 的组件模型中:

  • entry:主入口,组件启用时运行,重新开启时不会再运行(见 src/components/types.ts);
  • reload:组件「重新开启」时执行的回调(见 src/components/types.ts)。

此处将reload直接指向entry,意味着当用户在设置面板中切换开关、重新应用该组件时,入口函数会再次执行:重新创建一个新的MutationObserver并开始监听。由于首次执行时观察器已被disconnect(),重新开启后需要重新建立观察,这种reload复用entry的写法正好保证了组件在多次开关后仍能恢复监听能力。

同时,从组件声明看它没有提供unload钩子(unload类型定义见 src/components/types.ts),可以推断:关闭组件时脚本不会主动恢复已被移除的遮罩节点,也不会主动断开尚未命中的观察器——对前者而言,DOM 移除操作本身不可逆;对后者而言,观察器会在下一次命中或页面刷新时自然结束。

安装与使用

该组件位于项目的在线功能仓库(registry)中,遵循 registry 组件的标准使用方式:

  1. 在 Bilibili-Evolved 脚本的设置面板中打开「在线仓库」子页面(对应实现见 src/components/settings-panel/sub-pages/online-registry),添加并获取该组件;
  2. 安装后,在「组件管理」中找到「删除直播马赛克遮罩」(归属于直播/样式标签)并确保开关处于开启状态;
  3. 打开任意直播间(URL 形如https://live.bilibili.com/房间号)即可生效——若某些分区的直播页存在马赛克遮罩节点,它会在节点插入的瞬间被移除;对没有该遮罩节点的直播间则不会有任何可见影响。

由于组件通过urlInclude限定了匹配范围,即使开关保持开启,也只会影响直播间页面,不会干扰其他站内页面;而reload复用entry的设计保证了设置变更后无需刷新页面即可恢复监听,属于典型的「一次注册、按需触发」的轻量 DOM 增强组件。

【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 16:52:37

MCP自定义服务器进阶实战:错误处理、流式输出与部署全解析

我最早接触 MCP 自定义服务器,是从官方那个三行代码的示例开始的。注册一个工具,server.tool(...)一写,客户端立刻就能调用,感觉这玩意儿太简单了。直到我把服务器从“能跑”推向“能用”,才意识到真正的坑全在后面&am…

作者头像 李华
网站建设 2026/9/19 16:36:12

Android蓝牙协议栈bta_sys_sendmsg事件机制深度解析

简介:本资源是一份深度解析Android蓝牙协议栈核心消息机制的技术文档,专为初学蓝牙协议栈的开发者设计,解决阅读源码时因不熟悉bta_sys_sendmsg()调用链而无法追踪event发送路径的典型痛点。文档以设备搜索(BTA_DM_API_SEARCH_EVT…

作者头像 李华
网站建设 2026/9/19 16:36:10

ADB安装与使用全指南:从环境配置到深度调试

1. ADB到底是什么?为什么它值得你花两小时认真学透 ADB,全称Android Debug Bridge,中文叫安卓调试桥。它不是某个App,也不是一个图形界面工具,而是一套运行在电脑端的命令行程序组合——包括adb client(你…

作者头像 李华
网站建设 2026/9/19 16:35:40

HAR文件分析实战:从抓包到性能与安全诊断

1. HAR 文件不是“文档”,而是一份 HTTP 通信的完整录像带别人发来一个.har文件,第一反应往往是双击——结果弹出记事本,满屏密密麻麻的 JSON,缩进混乱、字段嵌套七八层、时间戳全是毫秒、headers 里混着 base64 编码的 cookie………

作者头像 李华
网站建设 2026/9/19 16:33:27

Atlas 300V 部署 YOLO 实战:从 ONNX 到 OM 的完整推理流程

从零开始在 Atlas 300V 上部署 YOLO:一张推理卡的实战手记手里正好有一张 Atlas 300V 24G,最近又把 YOLOv5/v8 在它上面完整跑了一遍流水线,中间踩了不少坑,也把 ASCEND 工具链的脾气摸了个七七八八。这篇文章就把整个流程掰开揉碎…

作者头像 李华