vue+flask实现视频合成功能(拖拽上传)

2022-04-15 0 733
目录
  • 拖拽上传我们之前一个文章有写过
  • 上传文件
  • flask处理文件
  • 拼接获取文件路径
    • 首先我们看flask
    • 前端获取
      • 配置代理说明
  • 额外说明(如果你使用uni-app)
    • 完整代码
      • flask代码
        • md5random.py 用于随机字符串生成
        • app_service.py 服务代码
      • vue代码

      vue+flask实现视频合成
      效果如下

      vue+flask实现视频合成功能(拖拽上传)

      拖拽上传我们之前一个文章有写过

      //www.jb51.net/article/206543.htm

      原理就是 监听drop事件 来获取拖拽的文件列表

      vue+flask实现视频合成功能(拖拽上传)
      vue+flask实现视频合成功能(拖拽上传)

      上传文件

      通过axios 上传文件

      this,.fileList就是我们的文件列表

      let files = this.fileList;
      let formd = new FormData();
      let i = 1;
      
      //添加上传列表
      files.forEach(item => {
      	formd.append(i + "", item, item.name)
      	i++;
      })
      formd.append("type", i)
      let config = {
      	headers: {
      		"Content-Type": "multipart/form-data"
      	}
      }
      
      //上传文件请求
      axios.post("/qwe", formd, config).then(res => {
      	console.log(res.data)
      })

      flask处理文件

      完整代码见最底部

      逻辑如下
      接收文件
      为每次合成请求随机生成一个文件夹 临时保存文件
      拼接视频
      返回文件路径

      @app.route("/file",methods=['POST'])
      def test():
      
       #获取文件
       files = request.files
       #合成队列
       videoL = []
       #随机字符串
       dirs = sjs()
       #生成文件夹
       os.mkdir(dirs)
       #保存文件并添加至合成队列
       for file in files.values():
        print(file)
        dst = dirs + "/" + file.name + ".mp4"
        file.save(dst)
        video = VideoFileClip(dirs + "/" + file.name + ".mp4")
        videoL.append(video)
       
       #拼接视频
       final = concatenate_videoclips(videoL)
       #文件路径
       fileName = dirs + "/" +"{}.mp4".format(sjs())
       #生成视频
       final.to_videofile(fileName)
       
       #销毁文件夹
       def sc():
        shutil.rmtree(dirs)
       
       #30秒后销毁文件夹
       timer = threading.Timer(30, sc)
       timer.start()
      
       # 返回文件路径
       return fileName

      拼接获取文件路径

      首先我们看flask

      逻辑如下
      通过文件名 获取文件 返回文件

      app.route("/getvoi",methods=['GET'])
      def getImg():
       #获取文件名
       ss = request.args['name']
       #文件加至返回响应
       response = make_response(
        send_file(ss))
      
       #删除文件
       def sc():
        os.remove(ss)
       
       #30秒后删除文件
       timer = threading.Timer(30, sc)
       timer.start()
       
       return response

      前端获取

      通过a标签下载

      <a s :href="herfs" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" rel="external nofollow" :download="fileName">下载</a>

      herfs如下

      vue+flask实现视频合成功能(拖拽上传)

      我们上传文件后 通过falsk处理返回文件路径 拼接后获取文件地址

      a标签添加download属性可以给下载的文件命名

      如果你对/qwe /voi有疑惑 请看下面的配置代理说明

      配置代理说明

      配置代理是为了解决跨域问题 开发环境可在vue.config.js配置即可使用
      生产环境需要额外配置nginx

      vue+flask实现视频合成功能(拖拽上传)

      /qwe实际上就是 http://127.0.0.1:8087/file
      /voi实际上就是 http://127.0.0.1:8087/getvoi
      对应我们flask中的

      vue+flask实现视频合成功能(拖拽上传)

      额外说明(如果你使用uni-app)

      如果你使用uni-app 可参照文档使用api
      上传文件api https://uniapp.dcloud.io/api/request/network-file?id=uploadfile
      下载文件api https://uniapp.dcloud.io/api/request/network-file?id=downloadfile
      或者直接使用别人封装好的 插件毕竟比较方便

      完整代码

      如果你不想一个一个复制可以去下载
      下载途径1: https://download.csdn.net/download/qq_42027681/15561897
      下载途径2:https://github.com/dmhsq/vue-flask-videoSynthesis

      flask代码

      md5random.py 用于随机字符串生成

      import random
      import hashlib
      def sjs():
       a = random.randint(0, 100)
       a = "a" + str(a);
       b = random.randint(100, 10000);
       b = "b" + str(b);
       c = hashlib.md5(a.encode(encoding='UTF-8')).hexdigest() + hashlib.md5(b.encode(encoding='UTF-8')).hexdigest();
       c = "c" + str(c);
       d = random.randint(10, 100);
       d = "d" + str(d);
       e = hashlib.md5(c.encode(encoding='UTF-8')).hexdigest() + hashlib.md5(d.encode(encoding='UTF-8')).hexdigest();
       e = hashlib.md5(e.encode(encoding='UTF-8')).hexdigest()
       return e;

      app_service.py 服务代码

      from flask import Flask,request,send_file,make_response
      import os,json,threading,shutil
      from moviepy.editor import *
      from md5random import sjs
      
      app = Flask(__name__)
      
      @app.route("/file",methods=['POST'])
      def test():
      
       #获取文件
       files = request.files
       #合成队列
       videoL = []
       #随机字符串
       dirs = sjs()
       #生成文件夹
       os.mkdir(dirs)
       #保存文件并添加至合成队列
       for file in files.values():
        print(file)
        dst = dirs + "/" + file.name + ".mp4"
        file.save(dst)
        video = VideoFileClip(dirs + "/" + file.name + ".mp4")
        videoL.append(video)
      
       #拼接视频
       final = concatenate_videoclips(videoL)
       #文件路径
       fileName = dirs + "/" +"{}.mp4".format(sjs())
       #生成视频
       final.to_videofile(fileName)
      
       #销毁文件夹
       def sc():
        shutil.rmtree(dirs)
      
       #30秒后销毁文件夹
       timer = threading.Timer(30, sc)
       timer.start()
      
       # 返回文件路径
       return fileName
      
      
      @app.route("/getvoi",methods=['GET'])
      def getImg():
       #获取文件名
       ss = request.args['name']
       #文件加至返回响应
       response = make_response(
        send_file(ss))
      
       #删除文件
       def sc():
        os.remove(ss)
      
       #30秒后删除文件
       timer = threading.Timer(30, sc)
       timer.start()
      
       return response
      
      if __name__ == '__main__':
       app.run(host='0.0.0.0',port=8087)

      vue代码

      演示文件代码

      <template>
       <div>
       <div
        v-on:dragover="tts"
        v-on:drop="ttrs"
        style="width: 800px;height: 200px;border: 1px solid black;font-size: 40px;line-height: 200px"
       >
        {{ dt }}
       </div>
       <div
        v-for="(item, index) in fileList"
        :key="index"
        style="width: 800px;height: 200px;border: 1px solid black;font-size: 40px;position: relative;top:10px"
       >
        <p
        style="font-size: 20px;float: left;position: relative;left: 20pxword-wrap:break-word;word-break:normal;"
        >
        {{ item.name }}
        </p>
        <h5 style="float:right;position: absolute;top: 80px;right: 20px">
        {{ item.type }}
        </h5>
        <h6 style="position: absolute;top: 80px;float: left;left: 20px">
        {{ item.size | sizeType }}
        </h6>
        <button style="float: right" @click="del(index)">删除</button>
       </div>
       <!-- 此处为展示最后一个上传的文件 -->
      <!-- <div style="position:relative;top: 100px">-->
      <!--  <img v-if="isImage" :src="srcs" style="width: 800px" />-->
      <!--  <video v-if="isVideo" controls :src="srcs" style="width: 800px"></video>-->
      <!--  <audio v-if="isAudio" controls :src="srcs" style="width: 800px"></audio>-->
      <!-- </div>-->
      
       <el-button style="position: relative;top: 50px" type="success" @click="ups()" :disabled="!isCan">合成</el-button>
       <el-button style="position: relative;top: 50px" v-loading="loading" type="success" >。。。</el-button>
       <a style="position: relative;top: 50px;left: 15px;" type="success" :href="herfs" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" rel="external nofollow" :download="fileName"><el-button :disabled="isCans"><span style="color: black">下载</span></el-button></a>
       <div style="position: relative;top: 100px">文件下载有效时间{{times}}s</div>
       </div>
      </template>
      
      <script>
      import axios from "axios";
      
      export default {
       name: "trs",
       data() {
       return {
        dt: "",//上传提醒 "拖动到此处上传文件“或者"上传完成,可继续上传"
        fileList: [],//文件列表
        loading:false,
        srcs: "",//图片/视频/音频 base64
        isImage: false,//是否是图片
        isAudio: false,//是否是音频
        isVideo: false,//是否是视频
        isCan: true,//是否能合成
        isCans:true,//是否能下载
        herfs: "",//下载地址
        fileName: "",//文件名
        times: 25//下载有效时间
       };
       },
       filters: {
       //格式化文件大小
       sizeType(val) {
        let kbs = val / 1024;
        let mbs = 0;
        let gbs = 0;
        if (kbs >= 1024) {
        mbs = kbs / 1024;
        }
        if (mbs >= 1024) {
        gbs = mbs / 1024;
        return gbs.toFixed(2) + "GB";
        } else if (mbs >= 1) {
        return mbs.toFixed(2) + "MB";
        } else {
        return kbs.toFixed(2) + "KB";
        }
       }
       },
       mounted() {
       let vm = this;
       window.addEventListener("dragdrop", this.testfunc, false);
      
       //全局监听 当页面内有文件拖动 提醒拖动到此处
       document.addEventListener("dragover", function() {
        console.log(111);
        vm.dt = "拖动到此处上传文件";
        console.log(vm.dt);
       });
       },
       methods: {
       //展示文件 主要为三个类型 图片/视频/音频
       readFile(file) {
        let vm = this;
        let reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function() {
        let type = file.type.substr(0, 5);
        if (type == "image") {
         vm.isImage = true;
         vm.isAudio = false;
         vm.isVideo = false;
        } else if (type == "audio") {
         vm.isImage = false;
         vm.isAudio = true;
         vm.isVideo = false;
        } else if (type == "video") {
         vm.isImage = false;
         vm.isAudio = false;
         vm.isVideo = true;
        } else {
         alert("不是图片/视频/音频");
        }
        vm.srcs = reader.result;
        // this.$nextTick(()=>{
        //
        // })
        };
       },
       //全局监听drop的触发事件 取消drop弹窗显示资源
       testfunc(event) {
        alert("dragdrop!");
      
        //取消drop弹窗显示资源
        event.stopPropagation();
        event.preventDefault();
       },
       del(index) {
        this.fileList.splice(index, 1);
        if (this.fileList.length === 0) {
        this.dt = "";
        }
       },
       //监听div上传框 当有文件拖动时 显示"拖动到此处上传文件"
       tts(e) {
        console.log(e);
        this.dt = "拖动到此处上传文件";
       },
       //监听div上传框 drop事件触发
       ttrs(e) {
        console.log(e);
        console.log(e.dataTransfer.files);
      
        //获取文件
        let datas = e.dataTransfer.files;
      
        //取消drop弹窗显示资源
        e.stopPropagation();
        e.preventDefault();
        datas.forEach(item => {
        if(item.type=="video/mp4"){
         this.fileList.push(item);
        }
        });
      
        //读取文件 如果不想展示图片/视频/音频可忽略
        this.readFile(this.fileList[this.fileList.length - 1]);
      
      
      
        this.dt = "上传完成,可继续上传";
       },
      
       //上传文件到服务器
       ups(){
        if(this.fileList.length==0){
        this.$message('文件列表为空');
        return ;
        }
        this.loading = true;
        this.isCan = false;
        this.isCans = true;
        let files = this.fileList;
        let formd = new FormData();
        let i = 1;
      
        //添加上传列表
        files.forEach(item=>{
        formd.append(i+"",item,item.name)
        i++;
        })
        formd.append("type",i)
        let config={
        headers:{"Content-Type":"multipart/form-data"}
        }
      
        //上传文件请求
        axios.post("/qwe",formd,config).then(res=>{
        console.log(res.data)
        this.loading = false
        //合成下载路径
        this.herfs = "/voi?name="+res.data
      
        this.fileName = res.data.split('/')[1]
        //禁止合成
        this.isCan = false
      
        this.isCans = false
      
        //设置下载有效时间 时间到后无法下载但可以继续合成
        let timer = setInterval(()=>{
         this.times--;
        },1000)
        this.setCans(timer)
        })
       },
       setCans(timer){
        setTimeout(()=>{
        this.isCans = true
        this.isCan = true
        this.fileName =""
        clearInterval(timer)
        this.times = 25
        },25000)
       }
       }
      };
      </script>
      
      <style scoped></style>

      vue.config.js

      module.exports = {
       devServer: {
       // assetsSubDirectory: 'static',
       // assetsPublicPath: '/',
       proxy: {
        "/qwe": {
        target: "http://127.0.0.1:8087/file",
        changeOrigin: true,
        pathRewrite: {
         "^/qwe": ""
        }
        },
        "/voi": {
        target: "http://127.0.0.1:8087/getvoi",
        changeOrigin: true,
        pathRewrite: {
         "^/voi": ""
        }
        }
       }
       }
      };

      到此这篇关于vue+flask实现视频合成功能(拖拽上传)的文章就介绍到这了,更多相关vue视频合成内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!

      免责声明:
      1、本网站所有发布的源码、软件和资料均为收集各大资源网站整理而来;仅限用于学习和研究目的,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 不得使用于非法商业用途,不得违反国家法律。否则后果自负!

      2、本站信息来自网络,版权争议与本站无关。一切关于该资源商业行为与www.niceym.com无关。
      如果您喜欢该程序,请支持正版源码、软件,购买注册,得到更好的正版服务。
      如有侵犯你版权的,请邮件与我们联系处理(邮箱:skknet@qq.com),本站将立即改正。

      NICE源码网 JavaScript vue+flask实现视频合成功能(拖拽上传) https://www.niceym.com/31970.html