vue+flask實現視頻合成功能(拖拽上傳)
vue+flask實現視頻合成
效果如下
拖拽上傳我們之前一個文章有寫過
//www.jb51.net/article/206543.htm
原理就是 監聽drop事件 來獲取拖拽的文件列表
上傳文件
通過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如下
我們上傳文件後 通過falsk處理返回文件路徑 拼接後獲取文件地址
a標簽添加download屬性可以給下載的文件命名
如果你對/qwe /voi有疑惑 請看下面的配置代理說明
配置代理說明
配置代理是為瞭解決跨域問題 開發環境可在vue.config.js配置即可使用
生產環境需要額外配置nginx
/qwe實際上就是 http://127.0.0.1:8087/file
/voi實際上就是 http://127.0.0.1:8087/getvoi
對應我們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視頻合成內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- vue實現桌面向網頁拖動文件的示例代碼(可顯示圖片/音頻/視頻)
- vue項目中form data形式傳參方式
- vue使用element實現上傳圖片和修改圖片功能
- 用python實現監控視頻人數統計
- 解決el-upload批量上傳隻執行一次成功回調on-success的問題