<template>
<div class="dyx">
<div class="my-header">
<div class="back-wrap"><span class="iconfont icon-dayuhao3" @click="huitui"></span></div>
<div><span>
发布动态
</span></div>
</div>
<div class="content">
<div class="video-wrap">
<video src="" x5-playsinline="" playsinline="" webkit-playsinline="" preload="auto" class="video"
ref="getVideoDom" @click="playHandler"></video>
<p class="video-guide" v-show="xin">点击上传或者在下方输入url,推荐使用url</p>
<input type="file" id="file" accept="video/*" class="video-input" @change="change">
</div>
<div class="content-item"><input placeholder="请输入视频链接(如本地上传可不填)" type="text" class="input"
v-model="videoObj.videoUrl"></div>
<div class="content-item" ref="yincang"><input placeholder="请输入封面链接(如本地上传默认第一帧)" type="text" class="input"></div>
<div class="content-item"><textarea placeholder="请输入视频描述" rows="10" cols="30" class="input"></textarea>
</div>
<div class="content-item">
<div class="btn">预览</div>
<div class="btn" @click="upload">发布</div>
</div>
</div>
<div class="des" v-show="lodingdh">
<div id="cssLoader17" class="main-wrap main-wrap--white">
<div class="cssLoader17"></div>
</div>
<div id="cssLoader1" class="main-wrap">
<div class="child-common child1"></div>
<div class="child-common child2"></div>
<div class="child-common child3"></div>
<div class="child-common child4"></div>
<div class="child-common child5"></div>
<div class="child-common child6"></div>
<div class="child-common child7"></div>
<div class="child-common child8"></div>
<div class="child-common child9"></div>
<div class="child-common child10"></div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
// 三个上传视频接口
import { upLoadVideoAPI, upLoadCoverVideoAPI, publishVideoAPI } from '../api/upLoadVideo.js'
let videoObj = reactive({
videoDesc: "",
});
let getVideoDom = ref(null);
let yincang = ref(null);
let lodingdh = ref(false);
let router = useRouter()
function huitui() {
router.go(-1)
}
let xin = ref(true)
// 文件类型检测
function checkFileType(file, Callback) {
// 创建 FileReader 对象
var reader = new FileReader();
// 读取文件
reader.readAsArrayBuffer(file);
// 文件读取完成时触发
reader.onloadend = function () {
// 获取文件的类型
var type = getFileType(new Uint8Array(reader.result));
// 判断文件类型
Callback(type)
};
}
// 监听用户选择文件的操作
function change(e) {
let files = e.target.files
// 如果没有选择文件终止后续代码的执行
if (!files.length) return;
// 把文件对象信息给到videoObj.realVideo
videoObj.realVideo = files[0];
// 判断选中的文件类型
checkFileType(videoObj.realVideo, (type) => {
if (type !== "mp4") {
alert("文件类型不是mp4格式,别想糊弄我");
return
}
// 限制文件上传大小
if (videoObj.realVideo.size > 100 * 1024 * 1024) {
alert("上传的视频不能大于2MB");
return;
}
// 该方法返回一个blob视频地址
videoObj.videoUrl = getObjectURL(videoObj.realVideo);
setSrcAndCaptureImage();
})
}
// 根据文件头判断文件类型
function getFileType(bytes) {
if (
bytes[0] === 0x00 &&
bytes[1] === 0x00 &&
bytes[2] === 0x00 &&
bytes[3] === 0x20 &&
bytes[4] === 0x66
) {
return "mp4";
} else {
return "unknown";
}
}
// 获取视频地址
function getObjectURL(file) {
let url = null;
if (window.createObjectURL !== undefined) {
url = window.createObjectURL(file);
} else if (window.URL !== undefined) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL !== undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
}
// 设置url和截图
function setSrcAndCaptureImage() {
xin.value = false
// 视频地址赋值给video的src属性
getVideoDom.value.src = videoObj.videoUrl;
if (getVideoDom.value.src !== '') {
yincang.value.style = 'display:none;height:0px;'
}
// loadeddata当前帧的数据是可用的
getVideoDom.value.addEventListener("loadeddata", captureImage);
// 截图视频的第一帧作为封面图
function captureImage() {
// 自动播放
getVideoDom.value.play();
let scale = 1;
// 创建canvas画布
let canvas = document.createElement("canvas");
// canvas画布大小宽度设置
canvas.width = getVideoDom.value.videoWidth * scale;
// canvas画布大小宽度设置
canvas.height = getVideoDom.value.videoHeight * scale;
// 开启2D绘图空间 drawImage()方法绘制一张图像
canvas
.getContext("2d")
.drawImage(getVideoDom.value, 0, 0, canvas.width, canvas.height);
// 返回一个包含图片展示的 data URI可以理解为是base64编码的图片
videoObj.coverUrl = canvas.toDataURL("image/png");
console.log(videoObj);
// 移除事件
getVideoDom.value.removeEventListener("loadeddata", captureImage);
}
}
// 视频播放/暂停
function playHandler() {
getVideoDom.value.paused
? getVideoDom.value.play()
: getVideoDom.value.pause();
}
// 图片转成Buffer(用来处理二进制的一个接口,后端通过fs模块,读取一张图片获取到图片的文件流)google(上传图片buffer)
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(",")[1]);
var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
// 上传方法
async function upload() {
// 判断是否上传了视频
if (!videoObj.realVideo) {
alert("请先选择要上传的文件");
return
}
lodingdh.value = true
// 把文件传递到服务器
let formData = new FormData();
// 后端需要videoPath参数,videoObj.realVideo是视频文件
formData.append("videoPath", videoObj.realVideo);
// 请求上传接口
let result = await upLoadVideoAPI(formData);
// 返回上传后的结果
console.log(result);
if (result.status == 200) {
console.log(11111);
let filename = result.data.filename;
// 视频的id截取(要.前面的作为视频的id)
const videoId = filename.substr(0, filename.indexOf("."));
let blob = dataURItoBlob(videoObj.coverUrl);
let coverPic = new FormData();
coverPic.append("videoId", videoId);
coverPic.append("videoCover", blob);
console.log(coverPic);
const resultCover = await upLoadCoverVideoAPI(coverPic);
console.log(resultCover);
if (resultCover.status === 200) {
const publishResult = await publishVideoAPI(localStorage.getItem('userId'), {
videoId,
videoCover: `http://43.138.15.137:3000/assets/videoCover/${videoId}.jpg`,
videoPath: `http://43.138.15.137:3000/assets/videoPath/${videoId}.${filename.substr(
filename.indexOf(".") + 1
)}`,
// videoId代表视频名字;
// videoId后面的.点,就是一个字符串点
// filename.substr(filename.indexOf('.') + 1)运行结果是后缀名(mp4等等)
videoDesc: videoObj.videoDesc,
});
console.log(publishResult);
lodingdh.value = false
router.push('/user')
}
}
}
</script>
<style scoped>
.des {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(41, 40, 37, 0.4);
z-index: 2400;
}
.dyx {
color: white;
background-color: #161622;
position: fixed;
left: 0;
top: 0;
right: 0;
z-index: 1600;
width: 100vw;
height: 100vh;
/* background-color: red; */
}
.my-header {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: #e8e8e9;
height: 44px;
line-height: 44px;
font-size: 16px;
z-index: 33;
border-bottom: 0.5px solid rgba(41, 40, 37, 0.8);
background: #161622;
}
.my-header .back-wrap {
position: absolute;
left: 10px;
}
.my-header .back-wrap .icon-left {
padding: 10px;
}
.content {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.content .video-wrap {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
background: #000;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
height: 50vh;
}
.content .video-wrap .video {
width: 100%;
height: 100%;
}
.content .video-wrap .video-guide {
position: absolute;
}
.content .video-wrap .video-input {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
opacity: 0;
}
.content .content-item {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 10px 20px;
line-height: 44px;
height: 44px;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.content .content-item .input {
width: 100%;
background: #161622;
color: #e8e8e9;
border: none;
font-size: 14px;
}
.content .content-item:last-of-type {
-ms-flex-pack: distribute;
justify-content: space-around;
}
.content .content-item .btn {
padding: 5px;
text-align: center;
line-height: 25px;
font-size: 12px;
width: 70px;
height: 25px;
}
.content .content-item .btn {
padding: 5px;
text-align: center;
line-height: 25px;
font-size: 12px;
width: 70px;
height: 25px;
}
.cssLoader17:before,
.cssLoader17:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
display: block;
width: 0.5em;
height: 0.5em;
border-radius: 0.25em;
transform: translate(-50%, -50%);
}
.cssLoader17:before {
animation: before 2s infinite;
}
.cssLoader17:after {
animation: after 2s infinite;
}
@keyframes before {
0% {
width: 0.5em;
box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
}
35% {
width: 2.5em;
box-shadow: 0 -0.5em rgba(225, 20, 98, 0.75), 0 0.5em rgba(111, 202, 220, 0.75);
}
70% {
width: 0.5em;
box-shadow: -1em -0.5em rgba(225, 20, 98, 0.75), 1em 0.5em rgba(111, 202, 220, 0.75);
}
100% {
box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
}
}
@keyframes after {
0% {
height: 0.5em;
box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
}
35% {
height: 2.5em;
box-shadow: 0.5em 0 rgba(61, 184, 143, 0.75), -0.5em 0 rgba(233, 169, 32, 0.75);
}
70% {
height: 0.5em;
box-shadow: 0.5em -1em rgba(61, 184, 143, 0.75), -0.5em 1em rgba(233, 169, 32, 0.75);
}
100% {
box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
}
}
.loader {
position: absolute;
top: calc(50% - 1.25em);
left: calc(50% - 1.25em);
}
</style>