这篇文章给大家介绍怎么在vue中使用flask实现一个视频合成功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
Vue是一套用于构建用户界面的渐进式JavaScript框架,Vue与其它大型框架的区别是,使用Vue可以自底向上逐层应用,其核心库只关注视图层,方便与第三方库和项目整合,且使用Vue可以采用单文件组件和Vue生态系统支持的库开发复杂的单页应用。
原理:监听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)
})
完整代码见最底部
逻辑如下
接收文件
为每次合成请求随机生成一个文件夹 临时保存文件
拼接视频
返回文件路径
@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
通过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 可参照文档使用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
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;
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)
演示文件代码
<template>
<div>
<div
v-on:dragover="tts"
v-on:drop="ttrs"
>
{{ dt }}
</div>
<div
v-for="(item, index) in fileList"
:key="index"
>
<p
>
{{ item.name }}
</p>
<h6 >
{{ item.type }}
</h6>
<h7 >
{{ item.size | sizeType }}
</h7>
<button @click="del(index)">删除</button>
</div>
<!-- 此处为展示最后一个上传的文件 -->
<!-- <div >-->
<!-- <img v-if="isImage" :src="srcs" />-->
<!-- <video v-if="isVideo" controls :src="srcs" ></video>-->
<!-- <audio v-if="isAudio" controls :src="srcs" ></audio>-->
<!-- </div>-->
<el-button type="success" @click="ups()" :disabled="!isCan">合成</el-button>
<el-button v-loading="loading" type="success" >。。。</el-button>
<a type="success" :href="herfs" rel="external nofollow" rel="external nofollow" :download="fileName"><el-button :disabled="isCans"><span >下载</span></el-button></a>
<div >文件下载有效时间{{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实现一个视频合成功能就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。