- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
导读
本文聚焦 Bilibili-Evolved 仓库中「快捷键扩展 - 开关 CC 字幕」这一内置插件,围绕其唯一职责——在快捷键动作列表中添加「开关 CC 字幕」动作——展开源码级剖析。通过阅读本文,你将掌握该插件的注册机制(addData('keymap.actions', ...)与addData('keymap.presets', ...)数据注入)、底层播放器字幕切换逻辑(playerAgent.toggleSubtitle())以及如何在「快捷键设置」面板中查看、绑定与自定义这一动作,并了解它与其他快捷键类插件的扩展范式差异。
一、插件概述:一句话的文档,一整套快捷键扩展链路
该插件的官方说明(registry/lib/plugins/utils/keymap-toggle-subtitle/index.md)非常精炼,全文只有一句:
在快捷键的动作列表里添加一个 "开关 CC 字幕"。
这短短一句话的背后,是 Bilibili-Evolved 完整的功能插件(PluginMetadata)与快捷键组件(keymap)之间的数据通信机制。插件本身不渲染任何 UI,也不直接操作 DOM 上的字幕按钮,而是通过「数据注入」向快捷键组件追加一个动作定义和若干预设键位,真正的开关逻辑由播放器适配层(player-agent)统一承担。
二、插件源码逐行解析
插件完整实现位于 registry/lib/plugins/utils/keymap-toggle-subtitle/index.ts(共 33 行),核心结构如下:
import { PluginMetadata } from '@/plugins/plugin' import { playerAgent } from '@/components/video/player-agent' import type { KeyBindingAction } from '../../../components/utils/keymap/bindings' export const plugin: PluginMetadata = { name: 'keymap.actions.toggleSubtitle', displayName: '快捷键扩展 - 开关 CC 字幕', setup: ({ addData }) => { addData('keymap.actions', (actions: Record<string, KeyBindingAction>) => { actions.toggleSubtitle = { displayName: '开关 CC 字幕', run: async ({ showTip }) => { const { result } = playerAgent.toggleSubtitle() if (result === 'no-subtitle-configured') { showTip('当前视频没有可选字幕', 'mdi-subtitles') } }, } }) addData( 'keymap.presets', ( presetBase: Record<string, string>, builtInPresets: Record<string, Record<string, string>>, ) => { presetBase.toggleSubtitle = 'shift c' builtInPresets.YouTube.toggleSubtitle = 'c' builtInPresets.YouTube.coin = '' builtInPresets.PotPlayer.toggleSubtitle = 'alt h' }, ) }, }2.1 插件元数据
name: 'keymap.actions.toggleSubtitle':全局唯一的插件名,遵循「数据 key + 动作名」的命名惯例(与keymap.actions.toggleDanmakuList等插件一致)。displayName: '快捷键扩展 - 开关 CC 字幕':在组件/插件管理界面展示的名称。setup:插件初始化函数,接收PluginSetupParameters,此处解构出addData用于向快捷键组件注入数据(src/plugins/plugin.ts)。
2.2 注入动作:addData('keymap.actions', ...)
addData是 Bilibili-Evolved 的数据注入 API(src/plugins/data.ts),其语义是:向以key标识的数据对象添加一个 provider,provider 会在getData(数据被加载)时被一次性应用并立即丢弃。
keymap组件在加载时通过registerAndGetData('keymap.actions', builtInActions)注册动作集合(registry/lib/components/utils/keymap/actions.ts),任何插件随后通过addData('keymap.actions', provider)即可向该集合追加新的KeyBindingAction。
KeyBindingAction接口定义在 registry/lib/components/utils/keymap/bindings.ts:
export interface KeyBindingAction { displayName: string run: (context: KeyBindingActionContext) => unknown prevent?: boolean ignoreTyping?: boolean ignoreFocus?: boolean }本插件只使用了displayName与run两个字段:
displayName: '开关 CC 字幕':在快捷键设置界面中展示的动作名。run: async ({ showTip }) => ...:动作执行函数,解构出上下文中的showTip(播放器区域内的提示框,见 registry/lib/components/utils/keymap/actions.ts)。执行时调用playerAgent.toggleSubtitle(),若返回result === 'no-subtitle-configured',则向用户提示「当前视频没有可选字幕」,并附带mdi-subtitles图标。
2.3 注入预设键位:addData('keymap.presets', ...)
keymap.presets的数据结构是「基础预设presetBase+ 若干内置预设builtInPresets」的二元组,由 registry/lib/components/utils/keymap/presets.ts 通过registerAndGetData('keymap.presets', presetBase, builtInPresets)注册。
本插件向三处写入了键位:
| 预设 | 键位 | 说明 |
|---|---|---|
presetBase.toggleSubtitle | shift c | 所有预设共用的默认键位(优先级最低) |
builtInPresets.YouTube.toggleSubtitle | c | YouTube 风格预设 |
builtInPresets.YouTube.coin | '' | 清空 YouTube 预设中的投币键(避免与c冲突,因为原预设中coin默认是c) |
builtInPresets.PotPlayer.toggleSubtitle | alt h | PotPlayer 风格预设 |
这里的冲突处理值得注意:默认基础预设(registry/lib/components/utils/keymap/presets.ts)中coin: 'c',而 YouTube 预设又把字幕开关映射到c,因此插件显式将YouTube.coin置空(空字符串表示该动作在该预设下永不触发),保证两套动作互不打架。这体现了「组合优先级」机制:实际生效的键位由presetBase、所选预设、用户自定义按键三者按优先级从低到高合并(registry/lib/components/utils/keymap/index.ts)。
三、底层原理:playerAgent.toggleSubtitle()如何工作
动作本体并不直接点击页面元素,而是委托给播放器适配层。实现位于 src/components/video/player-agent/base.ts,完整状态机逻辑如下:
- 查询关闭开关:查找
.bpx-player-ctrl-subtitle-close-switch元素(CC 字幕的关闭开关)。 - 无字幕判定:若该元素不存在,说明当前视频未配置可选字幕,返回
{ result: 'no-subtitle-configured' }。 - 当前处于开启状态:若关闭开关带
bpx-state-active类(表示字幕当前被关闭),则直接click()关闭开关并返回success。 - 当前处于关闭状态:遍历
.bpx-player-ctrl-subtitle-major .bpx-player-ctrl-subtitle-language-item获取所有可选字幕语言项;若列表为空,同样返回no-subtitle-configured。 - 语言选择优先级:
- 读取播放器配置
subtitle.preferred_language或subtitle.lan(src/components/video/player-agent/base.ts); - 若无配置,直接点击列表第一项;
- 若有配置,则按「同语言人工字幕 → 同基础语言的任意人工字幕 → 同语言的 AI 字幕(
ai-前缀)→ 列表第一项」的顺序依次匹配(src/components/video/player-agent/base.ts),点击命中项并返回success。
- 读取播放器配置
返回值类型由 src/components/video/player-agent/types.ts 约束,仅包含success与no-subtitle-configured两种结果,插件据此决定是否提示用户。
这套逻辑意味着:该快捷键并非简单开关,而是智能地在「打开字幕(优先用户偏好语言)→ 关闭字幕」之间切换,与 B 站原生 CC 字幕控制面板的行为一一对应。
四、使用方式:在「快捷键设置」中查看与配置
「开关 CC 字幕」动作随插件安装后自动出现在快捷键动作列表中,具体位置与配置入口如下:
- 打开脚本设置 → 组件「快捷键扩展」(registry/lib/components/utils/keymap/index.ts);
- 通过「快捷键扩展 - 搜索支持」插件提供的启动栏动作,或组件内的设置面板打开「快捷键设置」弹窗(registry/lib/components/utils/keymap/settings/KeymapSettings.vue);
- 在「快捷键设置」表格中找到「开关 CC 字幕」行,每一行包含三列键位:默认按键(
shift c)、预设按键(随预设切换,如 YouTube 为c、PotPlayer 为alt h)、自定义按键(用户输入,优先级最高)。
4.1 键位书写语法
自定义按键输入遵循 registry/lib/components/utils/keymap/help.md 定义的规则:
- 留空表示禁用该动作(永不触发);
- 直接写按键名称,对应
KeyboardEvent的code或key属性; - 多个按键用空格分隔,空格键本身写作
space; - 组合键支持
shift/ctrl/alt/meta(Windows 上是 Win 键,macOS 上是 Command 键); - 组合键为精确匹配,
Ctrl + Shift + A不会触发配置为shift a的快捷键; - 可选的组合键用
[]包裹,如[ctrl] shift a同时匹配Ctrl + Shift + A与Shift + A。
4.2 键位匹配的执行细节
最终键位会在每次keydown时由loadKeyBindings注册的处理器匹配(registry/lib/components/utils/keymap/bindings.ts),其要点包括:输入框打字时默认忽略快捷键(ignoreTyping)、播放器控制按钮聚焦时不拦截、按修饰键精确比对后再匹配key或code,命中后调用动作的run并视返回值决定是否preventDefault。
五、同类插件对比与扩展范式
该插件是 Bilibili-Evolved 快捷键扩展体系中「动作扩展插件」的典型样本。仓库中还存在同族插件,如「快捷键扩展 - 开关弹幕列表」(registry/lib/plugins/utils/keymap-toggle-danmaku-list/index.ts):它同样注入keymap.actions与keymap.presets,但动作体直接通过dq('.bui-collapse-header')?.click()操作 DOM,并为HTML5Player、PotPlayer预设清空键位。
两者对比可见设计取舍:
- 涉及播放器状态切换的动作(字幕、弹幕开关、音量等)统一走
playerAgent适配层,兼容 B 站播放器的多次改版(v2/v3/v4适配); - 涉及页面 UI 元素的动作可直接操作 DOM 选择器,如投币、收藏等按钮点击。
从源码结构看,任何第三方插件开发者都可以复制本插件的骨架,通过addData('keymap.actions', ...)+addData('keymap.presets', ...)在几行代码内为 Bilibili-Evolved 的快捷键系统扩展自定义动作,这正是该项目插件化数据通信设计的初衷。
结语
「开关 CC 字幕」插件虽然文档仅一句话,却是理解 Bilibili-Evolved 插件体系的最佳切片之一:一个PluginMetadata定义、两次addData调用、一次对playerAgent.toggleSubtitle()的委托,便完成了从动作注册、预设键位到播放器字幕状态机的完整链路。掌握这一范式,即可触类旁通地开发或理解仓库中其余数十个快捷键扩展类插件。
- 前端
- 音视频
【免费下载链接】Bilibili-Evolved
强大的哔哩哔哩增强脚本
相关推荐
Bilibili-Evolved 快捷键扩展插件实战:「开关弹幕列表」动作的实现与按键体系解析
Bilibili Evolved 快捷键扩展插件实战:「开关弹幕列表」动作的实现与按键体系解析 本文以 Bilibili Evolved 仓库中 registr
前端音视频Bilibili-Evolved 快捷键扩展实战:为动作列表添加"夜间模式"切换(keymap-dark-mode 插件解析)
Bilibili Evolved 快捷键扩展实战:为动作列表添加"夜间模式"切换(keymap dark mode 插件解析) 导读 本文围绕 Bilibili
前端音视频Bilibili-Evolved 快捷键扩展实战:剖析"开关灯"插件从注册到触发播放器灯光的完整链路
Bilibili Evolved 快捷键扩展实战:剖析"开关灯"插件从注册到触发播放器灯光的完整链路 本篇技术指南以 Bilibili Evolved 仓库中的
前端音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考