Vue+flask realizes video synthesis function (drag and drop upload)

Vue+flask realizes video synthesis function (drag and drop upload)

The video synthesis effect achieved by vue+flask is as follows

insert image description here

We have written about drag and drop upload in a previous article

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

The principle is to listen to the drop event to get the dragged file list

insert image description here
insert image description here

Upload files

Upload files via axios

this,.fileList is our file list

let files = this.fileList;
let formd = new FormData();
let i = 1;

//Add upload list files.forEach(item => {
	formd.append(i + "", item, item.name)
	i++;
})
formd.append("type", i)
let config = {
	headers: {
		"Content-Type": "multipart/form-data"
	}
}

//Upload file request axios.post("/qwe", formd, config).then(res => {
	console.log(res.data)
})

Flask processes files

See the bottom for the complete code

The logic is as follows: Receive files, randomly generate a folder for each synthesis request, temporarily save files, stitch videos, return file path

@app.route("/file",methods=['POST'])
def test():

 #Get files files = request.files
 #Synthesis queue videoL = []
 #Random string dirs = sjs()
 #Generate folder os.mkdir(dirs)
 #Save the file and add it to the synthesis queue for file in files.values():
  print(file)
  dst = dirs + "/" + file.name + ".mp4"
  file.save(dst)
  video = VideoFileClip(dirs + "/" + file.name + ".mp4")
  videoL.append(video)
 
 #Splice video final = concatenate_videoclips(videoL)
 #File path fileName = dirs + "/" + "{}.mp4".format(sjs())
 #Generate video final.to_videofile(fileName)
 
 #Destroy folder def sc():
  shutil.rmtree(dirs)
 
 #Destroy the folder after 30 seconds timer = threading.Timer(30, sc)
 timer.start()

 # Return the file path return fileName

Splicing to get the file path

First, let's look at flask

The logic is as follows: Get the file by file name and return the file

app.route("/getvoi",methods=['GET'])
def getImg():
 #Get the file name ss = request.args['name']
 #Add the file to the returned response response = make_response(
  send_file(ss)

 #delete file def sc():
  os.remove(ss)
 
 #Delete the file after 30 seconds timer = threading.Timer(30, sc)
 timer.start()
 
 return response

Front-end acquisition

Download via tag a

<as :href="herfs" rel="external nofollow" rel="external nofollow" :download="fileName">Download</a>

herfs are as follows

insert image description here

After uploading the file, we process the returned file path through falsk and then obtain the file address

Adding the download attribute to the a tag can name the downloaded file

If you have any questions about /qwe /voi, please see the following proxy configuration instructions

Configuration Proxy Instructions

The purpose of configuring a proxy is to solve cross-domain issues. The development environment can be configured in vue.config.js and can be used. The production environment requires additional configuration of nginx

insert image description here

/qwe is actually http://127.0.0.1:8087/file
/voi is actually http://127.0.0.1:8087/getvoi
Corresponding to our flask

insert image description here

Additional Notes (if you use uni-app)

If you use uni-app, please refer to the documentation to use the api
Upload file api https://uniapp.dcloud.io/api/request/network-file?id=uploadfile
Download file API https://uniapp.dcloud.io/api/request/network-file?id=downloadfile
Or it is more convenient to directly use the plug-ins packaged by others.

Complete code

If you don't want to copy them one by one, you can download them from Download path 1: https://download.csdn.net/download/qq_42027681/15561897
Download path 2: https://github.com/dmhsq/vue-flask-videoSynthesis

flask code

md5random.py is used to generate random strings

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 service code

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():

 #Get files files = request.files
 #Synthesis queue videoL = []
 #Random string dirs = sjs()
 #Generate folder os.mkdir(dirs)
 #Save the file and add it to the synthesis queue for file in files.values():
  print(file)
  dst = dirs + "/" + file.name + ".mp4"
  file.save(dst)
  video = VideoFileClip(dirs + "/" + file.name + ".mp4")
  videoL.append(video)

 #Splice video final = concatenate_videoclips(videoL)
 #File path fileName = dirs + "/" + "{}.mp4".format(sjs())
 #Generate video final.to_videofile(fileName)

 #Destroy folder def sc():
  shutil.rmtree(dirs)

 #Destroy the folder after 30 seconds timer = threading.Timer(30, sc)
 timer.start()

 # Return the file path return fileName


@app.route("/getvoi",methods=['GET'])
def getImg():
 #Get the file name ss = request.args['name']
 #Add the file to the returned response response = make_response(
  send_file(ss)

 #delete file def sc():
  os.remove(ss)

 #Delete the file after 30 seconds timer = threading.Timer(30, sc)
 timer.start()

 return response

if __name__ == '__main__':
 app.run(host='0.0.0.0',port=8087)

vue code

Demo file code

<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)">Delete</button>
 </div>
 <!-- Here is the last uploaded file to be displayed-->
<!-- <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">Synthesis</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">Download</span></el-button></a>
 <div style="position: relative;top: 100px">File download validity time {{times}}s</div>
 </div>
</template>

<script>
import axios from "axios";

export default {
 name: "trs",
 data() {
 return {
  dt: "", //Upload reminder "Drag here to upload the file" or "Upload completed, you can continue uploading"
  fileList: [], // file list loading: false,
  srcs: "", //Picture/video/audio base64
  isImage: false, //Is it an image? isAudio: false, //Is it an audio? isVideo: false, //Is it a video? isCan: true, //Can it be synthesized? isCans: true, //Can it be downloaded? herfs: "", //Download address fileName: "", //File name times: 25 //Download validity period };
 },
 filters:
 //Format file size 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);

 //Global monitoring when there is a file drag reminder in the page drag here document.addEventListener("dragover", function() {
  console.log(111);
  vm.dt = "Drag here to upload files";
  console.log(vm.dt);
 });
 },
 methods: {
 //Display files are mainly of three types: picture/video/audio 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("Not a picture/video/audio");
  }
  vm.srcs = reader.result;
  // this.$nextTick(()=>{
  //
  // })
  };
 },
 //Globally monitor the trigger event of drop to cancel the drop pop-up window display resource testfunc(event) {
  alert("dragdrop!");

  //Cancel the drop pop-up window display resource event.stopPropagation();
  event.preventDefault();
 },
 del(index) {
  this.fileList.splice(index, 1);
  if (this.fileList.length === 0) {
  this.dt = "";
  }
 },
 //Monitor the div upload box and display "Drag here to upload the file" when a file is dragged
 tts(e) {
  console.log(e);
  this.dt = "Drag here to upload the file";
 },
 //Listen for the div upload box drop event to trigger ttrs(e) {
  console.log(e);
  console.log(e.dataTransfer.files);

  //Get files let datas = e.dataTransfer.files;

  //Cancel the drop pop-up window display resource e.stopPropagation();
  e.preventDefault();
  datas.forEach(item => {
  if(item.type=="video/mp4"){
   this.fileList.push(item);
  }
  });

  //Read files. If you don't want to display pictures/videos/audios, you can ignore this.readFile(this.fileList[this.fileList.length - 1]);



  this.dt = "Upload completed, you can continue uploading";
 },

 //Upload files to the server ups(){
  if(this.fileList.length==0){
  this.$message('The file list is empty');
  return ;
  }
  this.loading = true;
  this.isCan = false;
  this.isCans = true;
  let files = this.fileList;
  let formd = new FormData();
  let i = 1;

  //Add upload list files.forEach(item=>{
  formd.append(i+"",item,item.name)
  i++;
  })
  formd.append("type",i)
  let config={
  headers:{"Content-Type":"multipart/form-data"}
  }

  //Upload file request axios.post("/qwe",formd,config).then(res=>{
  console.log(res.data)
  this.loading = false
  //Synthesized download path this.herfs = "/voi?name="+res.data

  this.fileName = res.data.split('/')[1]
  //Synthesis is prohibited this.isCan = false

  this.isCans = false

  //Set the download validity period. After the time is up, the download cannot be completed but the synthesis can continue. 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": ""
  }
  }
 }
 }
};

This is the end of this article about vue+flask to realize video synthesis function (drag and drop upload). For more related vue video synthesis content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Vue implements drag and drop or click to upload pictures
  • Realize mobile image upload, compression, drag-and-drop sorting, and drag-and-drop deletion functions based on Vue2
  • Full-screen drag upload component based on Vue3

<<:  MySQL 5.7.18 installation tutorial and problem summary

>>:  Problems and solutions when installing MySQL8.0.13 on Win10 system

Recommend

Detailed explanation of the principles of Vue's responsive system

Table of contents The basic principles of Vue'...

The difference between MySQL user management and PostgreSQL user management

1. MySQL User Management [Example 1.1] Log in to ...

JavaScript canvas to achieve scratch lottery example

This article shares the specific code of JavaScri...

How to implement the @person function through Vue

This article uses vue, and adds mouse click event...

Detailed explanation of nginx optimization in high concurrency scenarios

In daily operation and maintenance work, nginx se...

Solve the problem of mysql data loss when docker restarts redis

Official documentation: So mysql should be starte...

How to configure Linux firewall and open ports 80 and 3306

Port 80 is also configured. First enter the firew...

Implementing a simple student information management system based on VUE

Table of contents 1. Main functions 2. Implementa...

How to deeply understand React's ref attribute

Table of contents Overview 1. Creation of Refs ob...

MySQL data compression performance comparison details

Table of contents 1. Test environment 1.1 Hardwar...

Detailed explanation of how to install MySQL on Alibaba Cloud

As a lightweight open source database, MySQL is w...

MySQL trigger syntax and application examples

This article uses examples to illustrate the synt...

Why MySQL does not recommend using null columns with default values

The answer you often hear is that using a NULL va...

js dynamically implements table addition and deletion operations

This article example shares the specific code for...