说在前面
之前看剧习惯了看字幕,最近在 b 站看直播,有时候会觉得没有字幕有点不太习惯,所以突发奇想,能不能给 b 站直播加一个实时字幕?然后就写了这么一个插件。
本插件是基于之前开发的一个插件进行迭代开发新增的功能,有兴趣的可以看看这篇文章:《因为懒得点鼠标,我给B站做了个语音助手》
插件实现
编写一个字幕类
class Subtitle {
constructor(config = {}) {
// 字幕示例id,唯一DOM标识
this.id = "bilibiliVoiceAssistantSubtitle";
// 直播容器选择器
this.contentSelector = ".live-player-mounter";
// 可配置化扩展
Object.assign(this, config);
this.timer = null;
this.subtitle = null;
this.showTime = 3000;
}
}
复制代码
直播容器选择器获取
首先我们需要获取到 b 站直播视频容器的选择器,直接在页面打开控制台。
如上图,我们可以得到 b 站直播视频容器的选择器为 .live-player-mounter ,这里直接设置为默认值。
可扩展性设计
通过 config 参数开放样式配置接口,可以修改 contentSelector 属性来快速适配其他直播或视频字幕。
生成一个字幕元素
获取直播容器
通过对控制台元素进行分析,我们不难发现 b 站直播有两种呈现方式:
第一种就是视频的 video 标签就是直接在当前页面中编写,这时候我们可以直接通过前面定义的 contentSelector 来获取直播视频容器。
let content = document.querySelector(this.contentSelector);
复制代码
还有一种是通过 iframe 来将直播视频内嵌到当前页面,这时候我们需要获取到 iframe 内部的元素,那我们就不能按前面的方法来获取了,需要先获取 iframe 内部的 document 对象。
const iframes = document.querySelectorAll("iframe");
let iframe = null;
for (let i = 0; i < iframes.length; i++) {
if (iframes[i].src.includes("live.bilibili.com")) {
iframe = iframes[i];
break;
}
}
let content = document.querySelector(this.contentSelector);
if (!content) {
if (!iframe) return;
content = iframe.contentDocument.querySelector(this.contentSelector);
}
复制代码
创建字幕元素
直接创建一个 div 标签,使用绝对定位让其处于直播容器的下方。
if (this.subtitle) return this.subtitle;
const subtitle = document.createElement("div");
subtitle.style.position = "absolute";
subtitle.style.bottom = "10px";
subtitle.style.left = "5%";
subtitle.style.color = "white";
subtitle.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
subtitle.style.borderRadius = "5px";
subtitle.style.fontSize = "32px";
subtitle.style.zIndex = "9999";
subtitle.innerText = "";
subtitle.id = this.id;
subtitle.style.width = "90%";
subtitle.style.textAlign = "center";
subtitle.style.display = "none";
subtitle.style.fontWeight = "bold";
subtitle.style.color = "skyblue";
content.appendChild(subtitle);
this.subtitle = subtitle;
return subtitle;
复制代码
更新字幕文本
直接修改创建好的字幕元素的 innerText ,并根据之前设置的显示时间(showTime)来控制字幕显示时长。
updateSubtitle(text) {
let subtitle = this.subtitle;
if (!subtitle) {
subtitle = this.generateSubtitle();
}
if (!subtitle || !text) return;
subtitle.innerText = text;
subtitle.style.display = "block";
clearTimeout(this.timer);
this.timer = setTimeout(() => {
subtitle.style.display = "none";
}, this.showTime);
}
复制代码
实时语音识别
这里我们直接使用浏览器自带的 webkitSpeechRecognition 方法来实现实时语音识别功能。
浏览器兼容性检测
if (!("webkitSpeechRecognition" in window)) {
alert("当前浏览器不支持语音识别功能,请使用Chrome或Edge");
}
复制代码
Web Speech API 的浏览器支持现状(截至 2025 年)
Chrome/Edge:完全支持 webkitSpeechRecognition
Firefox:需启用 media.webspeech.recognition.enable 标志
Safari:仅限 macOS Monterey 及以上版本
语音识别引擎初始化
const recognition = new webkitSpeechRecognition();
// 关键参数配置
recognition.continuous = true; // 持续监听模式
recognition.interimResults = true;// 返回中间结果
recognition.lang = "zh-CN"; // 中文普通话识别
复制代码
页面状态判断
只在页面显示的时候开启语音监听,页面被切到后台的时候关闭语音监听。
document.addEventListener("visibilitychange", () => {
if (isBrowserTabActive()) { // 自定义页面可见性判断
recognition.start();
} else {
recognition.stop();
}
});
复制代码
实时更新字幕
recognition.onresult = (event) => {
const results = event.results;
let fullText = "";
for (let i = event.resultIndex; i < results.length; i++) {
fullText += results[i][0].transcript;
}
if (location.hostname === "live.bilibili.com") {
if (!subtitle) {
subtitle = new Subtitle();
}
subtitle.updateSubtitle(fullText);
}
};
复制代码
将获取到的语音文本片段进行拼接,然后调用 subtitle 实例的 updateSubtitle 更新实时字幕文本。
插件使用
局限性
API 限制
由于语音识别 API 限制,暂时只能在 edge 浏览器使用,chrome 中使用的话需要🪜
识别准确性
因为用的是浏览器内置的 API,免费的 API 终究不会那么完美,一些同音字或专有名称可能会识别不准确。
杂音干扰
因为是基于外部声源进行识别,所以需要将视频声音外放到浏览器可以识别的音量,而且外部环境杂音过大时,会影响识别结果。
插件源码
插件源码也已经上传到 gitee,有兴趣的也可以到这里看看:https://gitee.com/zheng_yongtao/chrome-plug-in/tree/master/bilibiliVoiceAssistant
🌟觉得有帮助的可以点个 star~
🖊有什么问题或错误可以指出,欢迎 pr~
📬有什么想要实现的功能或想法可以联系我~
插件安装
本插件是基于之前开发的一个插件进行迭代开发新增的功能,有兴趣的可以看看这篇文章:《因为懒得点鼠标,我给B站做了个语音助手》
源码下载
直接下载一份源码到本地。
插件引入
打开 edge 扩展管理页面:edge://extensions/
选择 bilibiliVoiceAssistant 这个目录:
再打开 B 站刷新页面,就可以看到插件图标了,将插件图标选择固定显示
记得打开语音助手开关
然后你就有了一个 b 站语音助手了~
最后选择一个 B 站直播打开,将音量调整到适度大小,然后你就可以看到实时字幕了
公众号
关注公众号『 前端也能这么有趣 』,获取更多有趣内容。
发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。
评论