服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - vue.js - vue+flask实现视频合成功能(拖拽上传)

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

2022-02-10 16:28代码哈士奇 vue.js

这篇文章主要介绍了vue+flask实现视频合成功能(拖拽上传),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

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

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

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

//www.tuohang.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" :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" :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视频合成内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_42027681/article/details/114367729

延伸 · 阅读

精彩推荐
  • vue.jsvue 页面跳转的实现方式

    vue 页面跳转的实现方式

    这篇文章主要介绍了vue 页面跳转的实现方式,帮助大家更好的理解和使用vue,感兴趣的朋友可以了解下...

    青小记11712021-12-30
  • vue.jsvue-cli中实现响应式布局的方法

    vue-cli中实现响应式布局的方法

    这篇文章主要介绍了vue-cli中实现响应式布局的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    我叫胡八一5402022-01-25
  • vue.jsVue如何实现变量表达式选择器

    Vue如何实现变量表达式选择器

    这篇文章主要介绍了Vue如何实现变量表达式选择器,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    紫圣6642022-01-20
  • vue.js基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能

    基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能

    这篇文章主要介绍了基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一...

    前端小白菜~5082021-12-27
  • vue.js详解vue 表单绑定与组件

    详解vue 表单绑定与组件

    这篇文章主要介绍了vue 表单绑定与组件的相关资料,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    Latteitcjz5582022-02-12
  • vue.jsVue自定义v-has指令实现按钮权限判断

    Vue自定义v-has指令实现按钮权限判断

    这篇文章主要给大家介绍了关于Vue自定义v-has指令实现按钮权限判断的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    OrzR34552022-03-02
  • vue.jsvue中配置scss全局变量的步骤

    vue中配置scss全局变量的步骤

    这篇文章主要介绍了vue中配置scss全局变量的步骤,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...

    吃火鸡的馒头4452021-12-21
  • vue.jsvue实现拖拽进度条

    vue实现拖拽进度条

    这篇文章主要为大家详细介绍了vue实现拖拽进度条,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    前端菜鸡日常6312022-01-24