众所周知,浏览器只支持vtt字幕,但是“本是同根生”的srt压根不理
怎么办?网上99%的教程都是一个套路:使用JS/TS库
的确可以这么做,但是无法体验浏览器带来的高运行效率
不要急,这个时候,我们可以另辟蹊径!且看vList5.7的新特色:原生SRT字幕!
源码
首先如果你赶时间,直接拿走不谢
https://github.com/imzlh/vList5/blob/main/src/utils/subsrt.ts#L1
分析
首先我们比较一下srt和vtt(个人见解)
VTT MDN官方文档
对于字幕,最重要的是定位、时间轴,次要的是动画、各种样式,因此我们首先了解一下SRT字幕格式
该格式基于纯文本,以
CR+LF
作为行分隔符(尽管有时会发现 Unix 样式的LF
换行符)。标题中有时会使用一些 HTML 标签来表示粗体或斜体文本。每个字幕都表示为一组行(用空行与其他字幕分隔)。第一行有一个数字(按顺序分配给每个标题);第二行是视频中字幕的时间戳范围,时间以“小时:分钟:秒,毫秒”的格式表示,范围的开始和结束用
-->
分隔 。时间戳范围后面可以可选地跟随着像素的特定定位,形式为。
X1:number Y1:number X2:number Y2:number
接下来的几行包含实际的字幕文本,以空行结尾。允许使用HTML
<b>
、<i>
、<u>
和<font>
标签。翻译自 http://fileformats.archiveteam.org/wiki/SubRip_text_file_format
比如我拿出我 珍藏的 ffmpeg得来的字幕
435
00:20:53,990 --> 00:20:55,390
<font face="HYXuanSong 75S" size="78">这个重量感…</font>
436
00:20:56,630 --> 00:20:59,490
<font face="HYXuanSong 75S" size="78">祭…祭里</font>
437
00:21:05,580 --> 00:21:06,380
<font face="HYXuanSong 75S" size="78">为什么</font>
438
00:21:07,380 --> 00:21:09,610
<font face="HYXuanSong 75S" size="78">为什么会这么大…</font>
439
00:21:09,610 --> 00:21:10,580
<font face="HYXuanSong 75S" size="78">不对</font>
440
00:21:10,960 --> 00:21:12,580
<font face="HYXuanSong 75S" size="78">为什么会变成女孩子啊</font>
441
00:21:12,920 --> 00:21:15,500
<font face="HYXuanSong 75S" size="78">男生的祭里哪去了?</font>
442
00:21:14,590 --> 00:21:15,010
<font face="HYXuanSong 75S" size="69">{\an8}…不是</font>
443
00:21:16,980 --> 00:21:19,100
<font face="HYXuanSong 75S" size="78">总之 先冷静 铃</font>
444
00:21:19,520 --> 00:21:21,790
<font face="HYXuanSong 75S" size="78">内在姑且还是我本人啦</font>
很好,VTT支持大部分这类标签,于是重点放在了互通上
可以看到,有一个碍眼的 \an
标签在
选择行的对齐方式。如果没有设定 位置 或 移动 ,对齐方式决定了行的位置。如果设定了位置或移动,对齐方式决定了位置和移动的参考点。
\an
标签的pos
参数使用小键盘布局,其值可以取小键盘上的数字,对应的位置就是该数字在小键盘上的相对位置。
- 屏幕左下角
- 屏幕底部中间
- 屏幕右下角
- 屏幕中间左侧
- 屏幕正中央
- 屏幕中间右侧
- 屏幕左上角
- 屏幕顶部中间
- 屏幕右上角
开始写代码
首先我们需要正则分离每个字幕组。考虑到Linux的LF
换行,\r
可选
content.split(/(?:\r?\n){2,}/)
接下来是逐行分析
line.match(/^(\d+)\r?\n(\d{2}):(\d{2}):(\d{2}),(\d{3})\s*-->\s*(\d{2}):(\d{2}):(\d{2}),(\d{3})\s*([\w\W]*)\s*$/);
这个正则看起来很长,其实很简单很简单,你看:
匹配结果
440
00
:21
:10
,960
--> 00
:21
:12
,580
<font face="HYXuanSong 75S" size="78">为什么会变成女孩子啊</font>
- $1
440
- $2
00
- $3
21
- $4
10
- $5
960
- $6
00
- $7
21
- $8
12
- $9
580
- $10
<font face="HYXuanSong 75S" size="78">为什么会变成女孩子啊</font>
于是,我们想要的都有了,导入VttCue
const start = parseInt(res[2]) * 3600 + parseInt(res[3]) * 60 + parseInt(res[4]) + parseInt(res[5]) / 1000,
end = parseInt(res[6]) * 3600 + parseInt(res[7]) * 60 + parseInt(res[8]) + parseInt(res[9]) / 1000,
cue = new VTTCue(start, end, '');
video.textTrack[0].addCue(cue);
完成!撒花撒花
等等,位置跑哪去了
好问题,接下来我们解析一下ASS特色标签
由于VTT可以更改的比较少,想要搭配CSS样式比较麻烦,我们暂且不考虑。如果需要一些特色样式,请参考 Github ASS2VTT
或者在线体验 https://ass2vtt.imzlh.top/
cue.text = res[10].replace(/\{(\\[a-z].+?)+\}/g, (_, match) => {
for (const tag of match.split('\\').filter(Boolean)) {
// \an, \a 字幕位置
if (tag.startsWith('a')) {
const mode = parseInt(tag.substring(2));
switch (Math.floor(mode / 3)) {
case 1:
cue.line = -1;
break;
case 2:
cue.line = 0.5;
break;
case 3:
cue.line = 0;
break;
}
switch (mode % 3) {
case 1:
cue.align = 'left';
break;
case 2:
cue.align = 'center';
break;
case 3:
cue.align = 'right';
break;
}
continue;
}
}
return '';
});
具体我不介绍了,代码使用两个switch,很易理解
本文由 zlh 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。