- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
本篇技术指南以 Bilibili-Evolved 仓库中的快捷键扩展插件 keymap-toggle-player-light 为切入点,深入讲解该插件如何在"快捷键扩展(keymap)"组件的动作列表中添加一个"开关灯"动作,以及该动作如何经由播放器适配层最终切换 B 站播放器的灯光模式。读完本文,你将掌握 Bilibili-Evolved 中"插件注册快捷键动作 + 预设默认键位"的完整机制,并能举一反三,为自己的功能扩展编写同类插件。
插件文档与插件本体
该插件的说明文档 index.md 非常简短,只有一句话:
在快捷键的动作列表里添加一个 "开关灯"。
这寥寥数语描述的,其实是一个完整的"插件式扩展"案例:它不修改 keymap 组件的任何源码,而是通过 Bilibili-Evolved 的插件数据总线(addData),向"快捷键扩展"组件动态注册一个新的动作条目,并为其配置默认快捷键。插件的全部实现都在 index.ts 中,全篇约 20 行,结构清晰:
import { PluginMetadata } from '@/plugins/plugin' import { toggleLight } from '@/components/video/player-light' import type { KeyBindingAction } from '../../../components/utils/keymap/bindings' export const plugin: PluginMetadata = { name: 'keymap.actions.togglePlayerLight', displayName: '快捷键扩展 - 开关灯', setup: ({ addData }) => { addData('keymap.actions', (actions: Record<string, KeyBindingAction>) => { actions.togglePlayerLight = { displayName: '开关灯', run: async () => { toggleLight() }, } }) addData('keymap.presets', (presetBase: Record<string, string>) => { presetBase.togglePlayerLight = 'shift l' }) }, }从源码结构可以看到,这是一个标准插件(PluginMetadata)的完整形态:
name:keymap.actions.togglePlayerLight,是插件在注册表中的唯一标识;displayName:快捷键扩展 - 开关灯,展示在用户组件的插件管理界面中;setup:接收addData函数,向两个数据槽(data slot)注入内容。
数据槽机制:插件如何"接管"组件的内部数据
理解这个插件,首先要理解addData与registerAndGetData这对配套机制。在 Bilibili-Evolved 中,组件可以通过 registerAndGetData 声明"可被插件扩展的数据槽",插件则通过addData向这些槽位追加数据。
在 keymap 组件中,共有两个与本文相关的数据槽:
keymap.actions:承载动作集合Record<string, KeyBindingAction>。keymap 组件在 actions.ts 中通过registerAndGetData('keymap.actions', builtInActions)注册内置动作(如全屏、宽屏、静音、投币、收藏、暂停/播放等),插件即可向该集合追加自己的动作。keymap.presets:承载预设键位。在 presets.ts 中通过registerAndGetData('keymap.presets', presetBase, builtInPresets)注册默认键位表与内置预设(Default、YouTube、HTML5Player、PotPlayer)。
插件keymap-toggle-player-light正是向这两个槽位各注入一份数据:
- 向
keymap.actions追加togglePlayerLight动作,其displayName为"开关灯",run回调直接调用播放器灯光切换函数; - 向
keymap.presets的presetBase追加默认键位togglePlayerLight = 'shift l',即默认按下Shift + L即可开关灯(也可在设置中修改,见下文)。
这种设计的好处在于:插件与组件完全解耦,keymap 组件本身并不知道"开关灯"动作的存在,两者通过数据总线松耦合连接,插件可以独立启用/禁用,且不影响组件主体。
动作执行的底层链路:从快捷键到播放器灯光
动作的run回调只有一行:toggleLight(),它来自 src/components/video/player-light.ts。该文件对外导出三个函数:
export const lightOn = setLight(true) export const lightOff = setLight(false) export const toggleLight = setLight()setLight工厂函数做了两件事:
- 页面匹配检查:通过
playerUrls.some(url => matchUrlPattern(url))判断当前页面是否为播放器页面,非播放器页面直接返回空值(不触发); - 惰性加载设置面板并切换灯光:在播放器页面中,先调用
loadLazyPlayerSettingsPanel(buttons.settings.selector, settings.wrap.selector)确保播放器设置面板资源已就绪,再调用playerAgentInstance.toggleLight(on)执行实际切换。
其中toggleLight未传参数,表示"无指定参数时直接翻转当前状态"。
再往下,灯光切换的真正执行者是播放器 Agent 的 toggleLight 方法:
/** true 开灯,false 关灯 */ async toggleLight(on?: boolean) { if (!this.nativeApi) { return null } const isCurrentLightOff = this.nativeApi.getLightOff() // 无指定参数, 直接 toggle if (on === undefined) { this.nativeApi.setLightOff(!isCurrentLightOff) return !isCurrentLightOff } // 关灯状态 && 要开灯 -> 开灯 if (on && isCurrentLightOff) { this.nativeApi.setLightOff(false) return true } if (!on && !isCurrentLightOff) { this.nativeApi.setLightOff(true) return false } // ... }这里体现了完整的三层调用链:
快捷键 Shift+L 按下 → keymap 动作 togglePlayerLight.run() → player-light.ts 的 toggleLight()(页面匹配 + 惰性加载设置面板) → playerAgent.toggleLight(on)(无参即翻转) → nativeApi.getLightOff() / setLightOff()(读写 B 站原生播放器灯光状态)需要特别说明的是:playerAgent是适配了 B 站多版本播放器的统一代理(见 src/components/video/player-agent/),nativeApi会随播放器版本(如 v2/v3/v4、BPX)解析出对应的原生接口。因此插件无需关心播放器内部实现差异,统一通过playerAgent这一抽象层操作即可。
快捷键触发与按键匹配机制
动作注册后,如何被"按出来"?这由 keymap 组件的 bindings.ts 负责。其核心逻辑如下:
KeyBindingAction接口定义了动作的结构:displayName(动作显示名)、run(执行函数)、prevent(是否阻止默认行为)、ignoreTyping(是否在打字时忽略)等;loadKeyBindings在document.body与所有被观察的 shadow DOM 上以capture: true方式监听keydown;- 每次按键事件,会依次经过多道过滤:是否启用、打字状态忽略(默认
ignoreTyping !== false时跳过)、聚焦元素判断(允许播放器控制按钮、设置项输入框等场景下继续响应)、全景视频禁用 WASD; - 修饰键匹配支持可选修饰键语法:
binding.keys中写[shift]表示该修饰键按或不按均可(见 bindings.ts 的optionalModifyKey处理); - 主键匹配同时支持
e.key(按键字符)与e.code(物理按键码),例如l与L、方向键arrowUp等均能正确命中; - 动作执行后,若返回非空值或显式声明
prevent: true,则调用stopImmediatePropagation()与preventDefault()阻止页面默认行为(如按空格暂停播放等场景)。
插件注册的togglePlayerLight动作未设置prevent与ignoreTyping,因此行为为默认:按键在打字时被忽略,匹配成功且动作返回非空值时阻止默认事件。
默认键位、预设与自定义键位
keymap 组件的预设系统分三层合并(见 presets.ts 与 index.ts):
最终键位 = presetBase(基础默认) ⊕ presets[preset](用户选中的预设,如 Default / YouTube / HTML5Player / PotPlayer) ⊕ settings.options.customKeyBindings(用户自定义键位)插件向presetBase注入的shift l属于第一层,意味着:
- 默认情况下
Shift + L即可开关灯; - 若用户切换到 YouTube 等预设且预设中覆盖了
togglePlayerLight,则以预设值为准; - 若用户在"快捷键设置"面板中手动自定义了该动作的键位,则最终以自定义值为准(自定义优先级最高)。
键位字符串以空格分隔,例如shift l会被解析为['shift', 'l']两个按键的组合(见 index.ts 的parseBindings)。因此该插件注册的键位语义是"同时按下 Shift 与 L"。
在设置面板中查看与修改
keymap 组件本身是一个可配置组件,其设置界面由 settings/ 目录下的 Vue 组件提供:
KeymapSettings.vue:快捷键设置弹窗主体,列出全部动作与当前绑定键位;KeymapSettingsRow.vue:单个动作的键位行,支持录制/修改按键;vm.ts:提供loadKeymapSettings与toggleKeymapSettings,其中toggleKeymapSettings可由启动栏(Launch Bar)动作keymapSettings触发(见 index.ts)。
keymap 组件的核心选项定义在 index.ts 中:
| 选项 | 默认值 | 说明 |
|---|---|---|
longJumpSeconds | 85 | 长前进/长后退的跳跃秒数(校验最小值为 1) |
volumeStep | 10 | 音量调整幅度,范围 1–100 |
showSeekShortcuts | true | 是否显示跳转快捷键 |
customKeyBindings | {} | 用户自定义键位表(隐藏项) |
preset | Default | 键位预设(隐藏项) |
启用该插件后,打开播放器页面,在"快捷键扩展"设置面板中即可看到新增的"开关灯"动作及其默认键位Shift + L,也可录制自定义键位覆盖之。
小结与扩展思路
从这一句话的文档出发,我们还原了一个完整的功能链路:
- 插件通过
addData('keymap.actions', ...)注册名为togglePlayerLight的快捷键动作,通过addData('keymap.presets', ...)注册默认键位shift l; - 动作触发后调用 player-light.ts 的
toggleLight(),经页面匹配与设置面板惰性加载后,委托播放器 Agent 的toggleLight方法; - Agent 再通过
nativeApi.getLightOff()/setLightOff()读写 B 站原生播放器灯光状态,完成开灯/关灯切换。
对于希望为 Bilibili-Evolved 编写同类扩展的开发者,本插件是一个极佳的模板:只需实现PluginMetadata,在setup中向对应数据槽addData注入动作与键位即可,无需改动 keymap 组件本体。动作的run可以是任意异步逻辑——切换灯光、跳转进度、调用playerAgent的其他能力(如fullscreen、togglePlay、changeTime等,详见 actions.ts 的内置动作)——从而实现与 B 站原生气播放器无缝集成的自定义快捷键体系。
- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
相关推荐
Bilibili-Evolved 播放时自动关灯功能全解析:源码实现、事件流与星光动画
Bilibili Evolved 播放时自动关灯功能全解析:源码实现、事件流与星光动画 导读 本文围绕 Bilibili Evolved 中的「播放时自动关灯」
前端音视频Bilibili-Evolved 快捷键扩展(keymap)完全指南:三套按键体系、自定义语法与插件扩展 API
Bilibili Evolved 快捷键扩展(keymap)完全指南:三套按键体系、自定义语法与插件扩展 API 导读 「快捷键扩展(keymap)」是 Bil
前端音视频Bilibili-Evolved 快捷键扩展(keymap)完整指南:按键语法、预设切换与自定义动作开发
Bilibili Evolved 快捷键扩展(keymap)完整指南:按键语法、预设切换与自定义动作开发 Bilibili Evolved 的「快捷键扩展」(组
前端音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考