这里以vue为例啦
第一次外挂字幕需求,mark一下~
一、主要函数,将文本转化为易用的数组
1、获取srt内容(本次srt是get获取的)
async getSrt(url,index){
let srtText = await fileApi.getStr(url)
if(srtText.success){
let srtItem = this.createSrtArr(srtText.data)
//对应的多种语言的srt字幕的map,序号为key,值为转化的srt字幕分时数组
this.srtMap[index] = srtItem
}
}
2、将字符串转化为方便使用的数组
createSrtArr(srt){
let arr = srt.split(/\n\n|\r\r|\r\n\r\n/)
let result = []
arr.forEach(item => {
let srtObj = {}
let containArr = item.split(/\n/)
if(containArr[1]){
//此处正则用于取出00:00:00,213 --> 00:00:00,213这种结构,防止可能存在于此行的x,y坐标对后续处理造成影响
var reg = /^(\d{2}):(\d{2}):(\d{2})[\.,](\d{1,3}) --\> (\d{2}):(\d{2}):(\d{2})[\.,](\d{1,3})/g
let regResult = reg.exec(containArr[1])
if(regResult){
let timeSplit = regResult[0].split(' --> ')
srtObj.from = this.getSeconds(timeSplit[0])
srtObj.to = this.getSeconds(timeSplit[1])
//这里的两个replace主要是将srt中可能携带的font标签转化为易用的span,当时遇到了如果是font标签的话没办法继承父元素的字体大小的问题,题外话:本次字母字体大小采用了媒体查询进行设置
srtObj.htmlText = containArr.slice(2).join(`<br/>`).replace(/\<font/g,'<span').replace(/\<\/font/g,'</span')
result.push(srtObj)
}
}
})
return result
},
//将srt中的字符串时间转化为所需要的格式,这里转化成了秒数
getSeconds(val){
let arr = val.split(/\,|\./)
let sec = 0
let a = arr[0].split(':')
sec = Number(a[0])*60*60+Number(a[1])*60+Number(a[2])+arr[1]/1000
return sec
}
二、监听当前播放的时间,二分法找到对应的进行显示
1、watch
watch:{
currentTime(){
//根据字幕切换选择所需要的字幕数组
let arr = this.srtMap[this.subtitleIndex]
//赋值给subtitleText,此值用v-html进行了绑定,绑定到了对应的字幕显示区域
this.subtitleText = this.getSubtitle(this.currentTime,arr)
}
},
2、二分查找
getSubtitle(currentTime,arr){
let low = 0,high = arr.length
let mid,htmlText
while(low <= high){
mid = parseInt((low+high)/2)
if(arr[mid].from <= currentTime && arr[mid].to >= currentTime){
htmlText = arr[mid].htmlText
break
}
if(arr[mid].from > currentTime){
high = mid - 1
}
if(arr[mid].to < currentTime){
low = mid + 1
}
}
return htmlText
}
这里查找时间对应的字幕感觉二分查找,是否能够继续优化,如果有更好的策略,欢迎指导~