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):
| 字段 | 值 | 说明 |
|---|---|---|
name | removeLiveMaskPanel | 组件内部唯一标识,供脚本内核引用 |
displayName | 删除直播马赛克遮罩 | 设置面板中展示的名称 |
author | Liki4 | 组件作者及其主页链接 |
tags | live、style | 组件分类标签,决定其在设置面板中的分组(componentsTags定义于 src/components/types.ts) |
entry | 异步函数 | 组件启用时执行的入口逻辑 |
reload | entry | 组件重新开启时执行的回调,此处复用入口函数 |
urlInclude | liveUrls | 仅在这些 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 }) }其工作流程可拆解为四步:
- 定义目标标识:用常量
id记录遮罩节点的元素 IDweb-player-module-area-mask-panel,作为唯一匹配依据。 - 注册观察器:
new MutationObserver(...)创建观察器,回调遍历每次 mutation 中的addedNodes(新增节点列表)。 - 条件移除:一旦发现新增节点的
id等于目标 ID,立即通过node.parentNode?.removeChild(node)将该节点从 DOM 中摘除,从而让马赛克遮罩消失。 - 及时收尾:命中后调用
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/12345或https://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-panel | hide-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 组件的标准使用方式:
- 在 Bilibili-Evolved 脚本的设置面板中打开「在线仓库」子页面(对应实现见 src/components/settings-panel/sub-pages/online-registry),添加并获取该组件;
- 安装后,在「组件管理」中找到「删除直播马赛克遮罩」(归属于直播/样式标签)并确保开关处于开启状态;
- 打开任意直播间(URL 形如
https://live.bilibili.com/房间号)即可生效——若某些分区的直播页存在马赛克遮罩节点,它会在节点插入的瞬间被移除;对没有该遮罩节点的直播间则不会有任何可见影响。
由于组件通过urlInclude限定了匹配范围,即使开关保持开启,也只会影响直播间页面,不会干扰其他站内页面;而reload复用entry的设计保证了设置变更后无需刷新页面即可恢复监听,属于典型的「一次注册、按需触发」的轻量 DOM 增强组件。
【免费下载链接】Bilibili-Evolved强大的哔哩哔哩增强脚本项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考