在前端中获取视频video的md5 - SparkMD5

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

在有些场景中,会遇到需要获取文件,比如图片、视频的md5,那么在前端中如何做呢,这里和大家分享一下。

背景

在我的项目开发过程中,需要获取视频的md5,用以做视频校验以及安全性相关的策略。

md5策略

我选择使用spark-md5这个库来做md5,原因是这个库相对来说是性能比较良好的md5算法库,具体的介绍,大家可以通过npm package中去查看:https://www.npmjs.com/package/spark-md5

spark-md5 介绍

md5的具体用法

package主页已经介绍了一些具体用法,我这里简要介绍一下:

js 复制代码
// 常用字符串整体md5
var hexHash = SparkMD5.hash('Hi there');        // hex hash
var rawHash = SparkMD5.hash('Hi there', true);  // OR raw hash (binary string)

// 动态字符串md5
var spark = new SparkMD5();
spark.append('Hi');
spark.append(' there');
var hexHash = spark.end();                      // hex hash
var rawHash = spark.end(true);                  // OR raw hash (binary string)

官方给出了一个file的md5示例:

js 复制代码
document.getElementById('file').addEventListener('change', function () {
    var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
        file = this.files[0],
        chunkSize = 2097152,                             // Read in chunks of 2MB
        chunks = Math.ceil(file.size / chunkSize),
        currentChunk = 0,
        spark = new SparkMD5.ArrayBuffer(),
        fileReader = new FileReader();

    fileReader.onload = function (e) {
        console.log('read chunk nr', currentChunk + 1, 'of', chunks);
        spark.append(e.target.result);                   // Append array buffer
        currentChunk++;

        if (currentChunk < chunks) {
            loadNext();
        } else {
            console.log('finished loading');
            console.info('computed hash', spark.end());  // Compute hash
        }
    };

    fileReader.onerror = function () {
        console.warn('oops, something went wrong.');
    };

    function loadNext() {
        var start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;

        fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
    }

    loadNext();
});

但其实我们往往是在vue或者react的框架下做文件选取(图片、视频选取),所以我的用法很简单,下面是我的使用代码,仅供参考:

js 复制代码
import SparkMD5 from 'spark-md5'

const readMp4Md5 = (file, callback) => {
    var fileReader = new FileReader();
    var spark = new SparkMD5.ArrayBuffer();
    fileReader.readAsArrayBuffer(file);
    fileReader.onload = (e) => {
        spark.append(e.target.result);
        var md5 = spark.end();
        callback(md5);
    };
}

文件上传部分

我直接使用了elemnt-plus中的el-upload组件,这里我贴出部分代码,用于做记录:

vue 复制代码
<el-upload
   v-loading="appMp4Loading"
   v-model:file-list="row.appMp4List"
   :data="{index: 3}"
   :http-request="requestUpload"
   accept=".mp4"
   :on-success="handleRowUploadChange(row, 3)"
   :show-file-list="false"
>
    <div v-if="row.data.mp4.trim().length > 0">
        <video
           :src="row.data.mp4"
           controls
           controlslist="nodownload noplaybackrate"
           disablePictureInPicture 
           preload="metadata"
           width="200"
           height="200"
       >
       </video>
       <div style="font-size: 16px; color: #409eff;">替换</div>
   </div>
   <el-button v-else type="primary" link>+上传mp4视频</el-button>
</el-upload>

...
const requestUpload = (option)=>{
      const { index } = option.data;
      let param = {
        course_id: 0,
        file_name: option.file.name,
      }
      showUploadLoading(true, index);
      return uploadCourseInfoApi(param).then((rst) => {
            request({
                url: rst.data.url,
                method: 'put',
                timeout: 360000,
                data: option.file,
                headers: { 'Content-Type': option.file.type },
            }).then(res => {
                if(res?.status>=200&&res?.status<=300) {
                    //上传成功 调用onSuccess方法,否则没有完成图标
                    option.onSuccess(rst)
                    ElMessage.success('上传成功');
                }
                showUploadLoading(false, index);
            }).catch(err=>{
                ElMessage.error('上传文件失败');
                deleteUploadFailFielist(index);
                showUploadLoading(false, index);
            })
        })
        .catch(err=>{
            ElMessage.error('获取上传地址失败');
            deleteUploadFailFielist(index);
            showUploadLoading(false, index);
            option.onError()
        })
}

const handleRowUploadChange = (row, index) => {
    let fileList = [];
    if (index == 0) {
        fileList = row.pngList || [];
    } else if (index == 1) {
        fileList = row.appGifList || [];
    } else if (index == 2) {
        fileList = row.keepGifList || [];
    } else if (index == 3) {
        fileList = row.appMp4List || [];
    }
    if (fileList.length == 0) return;
    const firstResponse = fileList[fileList.length - 1].response;
    if (!firstResponse) return;
    const { code, data, msg } = firstResponse;
    if (code == 0 && data && data.cdn_url) {
        if (index == 0) {
            row.data.png = data.cdn_url;
        } else if (index == 1) {
            row.data.app_gif = data.cdn_url;
        } else if (index == 2) {
            row.data.tool_gif = data.cdn_url;
        } else if (index == 3) {
            row.data.mp4 = data.cdn_url;
            if (fileList.length > 0 && fileList[fileList.length - 1].raw) {
                readMp4Md5(fileList[fileList.length - 1].raw, (md5) => {
                    row.data.mp4_md5 = md5;
                });
            }
        }
    }
}
...

实用很简单,希望对大家有帮助。

也希望大家多多关注公众号“新卫网络科技”。

暂无评论,快来发表第一条评论吧