微信小程序实现vtt视频字幕

微信小程序没有原生的视频字幕,由于需要,自己实现了字幕,字幕是由组件实现的,直接复制插件即可,index是引用Demo

代码地址

我在这里用了两行字幕,可控制中文和英文,如有需要,可删掉一个

1. 项目结构

|–components (组件)
|        ~~~~~~       |–track
|        ~~~~~~       |        ~~~~~~       |–track.js
|        ~~~~~~       |        ~~~~~~       |–track.json
|        ~~~~~~       |        ~~~~~~       |-track.wxml
|        ~~~~~~       |        ~~~~~~       L track.wxss
|–pages (示例页面)
|        ~~~~~~       |–index
|        ~~~~~~       |        ~~~~~~       |–index.js
|        ~~~~~~       |        ~~~~~~       |–index.json
|        ~~~~~~       |        ~~~~~~       |-index.wxml
|        ~~~~~~       |        ~~~~~~       L index.wxss
|–app.js
|–app.json
|–app.wxss

2. 组件

track.wxml
<view class="zimu">
    <view>{{enableEn ? en : ''}}</view>
    <view>{{enableZh ? zh : ''}}</view>
</view>
track.js
// components/track/track.js
var zimuList = []; // 字幕集合
var currentZimuIndex = -1;  // 当前字幕位置,-1表示还未开始
var fileSystemManager = wx.getFileSystemManager();

Component({
    /**
     * 组件的属性列表
     */
    properties: {

    },

    /**
     * 组件的初始数据
     */
    data: {
        enableEn: true,
        enableZh: true
    },

    /**
     * 组件的方法列表
     */
    methods: {
        // 视频触发事件
        videoChangeEvent: function (time) {
            this.setZimu(time, currentZimuIndex)
        },
        
        // 设置字幕(展示字幕的重要环节)
        setZimu: function(time, index) {
            if (index >= zimuList.length) {
                return;
            }
            // 如果需要移动字幕指针(即当前指向-1 或 当前视频进度大于当前字幕结尾的时间)
            if (index == -1 || zimuList[index][2] < time) {
                this.hideZimu();
                this.setZimu(time, index + 1)
                return;
            }
            else if (index != 0 && index != -1 && zimuList[index][1] > time && zimuList[index - 1][2] > time) {
                this.hideZimu();
                this.setZimu(time, (index - 1 < -1) ? -1 : (index - 1))
                return;
            }
            // 如果未来指针大于当前指针并且当前视频进度 > 未来指针字幕的开始时间(-200ms)
            if (index != currentZimuIndex && time > zimuList[index][1] - 250) {
                currentZimuIndex = index;
                this.showZimu(currentZimuIndex);
            }
        },
        /**
         * 字幕相关
         */
        loadZimu: function (path, fileName) {
            zimuList = [];
            this.downloadZimu(path, fileName);
        },
        readZimu: function (fileName) {
            console.info(wx.env.USER_DATA_PATH + '/' + fileName)
            let fileStr = fileSystemManager.readFileSync(wx.env.USER_DATA_PATH + '/' + fileName, 'utf-8')
            // 换行符转换
            fileStr = fileStr.replace(new RegExp("\r\n", "gm"), '\n')
            let list = fileStr.split('WEBVTT\n\n')[1].split('\n\n');

            for (let i = 0; i < list.length; i++) {
                if (list[i]) {
                    // 去除首位换行符
                    list[i] = list[i].replace(/^(\s|\n)+|(\s|\n)+$/g, '');
                    let a = list[i].split('\n');
                    let timeFrom = a[1].split(' --> ')[0];
                    let timeTo = a[1].split(' --> ')[1];
                    zimuList.push([a[0], this.getCurrentTime(timeFrom), this.getCurrentTime(timeTo), a[2], a[3]]);
                }
            }
        },
        downloadZimu: function (path, fileName) {
            var that = this;
            wx.downloadFile({
                "url": path + fileName,
                "filePath": wx.env.USER_DATA_PATH + '/' + fileName,
                success: function (e) {
                    that.readZimu(fileName);
                }
            })
        },
        // 改变字幕
        changeZimu: function (zh, en) {
            this.setData({
                zh,
                en
            })
        },
        // 隐藏字幕
        hideZimu: function () {
            this.changeZimu('', '');
        },
        // 展示字幕
        showZimu: function (index) {
            this.changeZimu(zimuList[index][4], zimuList[index][3]);
        },
        // 获取当前时间戳
        getCurrentTime: function (time) {
            let timeSplit = time.split(".");
            let a = new Date('1970/01/01 ' + timeSplit[0]).getTime() + parseInt(timeSplit[1]) + 28800000; // 兼容iphone下的处理方法
            return a;
        },
    }
})

track.json
{
    "component": true,
    "usingComponents": {}
}
track.wxss
/* components/track/track.wxss */
.zimu{
    bottom:12px;
    font-size: 22rpx;
    position:absolute;
    color:#fff;
    width:80%;
    padding:0 10%;
    pointer-events:none;
    text-align: center;
}

.zimu view{
    pointer-events:none;
    white-space: pre-wrap;
}

view {
    display:block;
    line-height:1.2;
    overflow:hidden;
    font-family:-apple-system;
}

示例页面 (部分)

index.html
<video src='https://www.lpsql.top/static/en/video/1.mp4' autoplay show-center-play-btn show-fullscreen-btn enable-progress-gesture bindtimeupdate="videoChange" >
	<track id="track"/>
</video>
index.js
//index.js
Page({
  data: {

  },
  onLoad: function () {
      this.init();
  },
  // 初始化
  init: function(){
		// 加载字幕
        this.selectComponent("#track").loadZimu('https://www.lpsql.top/static/en/s/', '1.vtt');
  },
    videoChange: function(e){
    	// 视频触发事件
        this.selectComponent("#track").videoChangeEvent(e.detail.currentTime * 1000);
    }
})

index.json
{
  "usingComponents": {
      "track":"/components/track/track"
  }
}
index.wxss
/**index.wxss**/
video {
    width: 100%;
}

效果

字幕格式
WEBVTT


1
00:00:01.600 --> 00:00:03.600
ACT 1
第一幕

2
00:00:06.900 --> 00:00:09.200
In New York Harbor
纽约港

3
00:00:11.900 --> 00:00:15.000
Excuse me. My name is Richard Stewart.
打扰一下  我叫理查德·斯图尔特

4
00:00:15.000 --> 00:00:16.000
I'm a photographer.
我是一名摄影师

5
00:00:16.000 --> 00:00:18.000
May I take a picture of you and your little boy?
我可以替你和你的小男孩拍张照片吗?

6
00:00:18.000 --> 00:00:19.000
What's it for?
是做什么用的?

7
00:00:19.000 --> 00:00:20.000
It's for a book.
是为一本书拍的

8
00:00:20.000 --> 00:00:21.000
You're writing a book?
你在写一本书吗?

9
00:00:21.400 --> 00:00:23.000
It's a book of pictures.
这是一本摄影集

10
00:00:23.000 --> 00:00:25.000
I call it Family Album, U.S.A.
我称之为《走遍美国》

11
00:00:25.000 --> 00:00:27.000
Oh, that's a nice idea.
噢  这想法不错
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值