浏览代码

视频文件直传到 OSS

reghao 3 年之前
父节点
当前提交
0cd6cf4e4c
共有 2 个文件被更改,包括 104 次插入110 次删除
  1. 10 0
      src/api/media/file.js
  2. 94 110
      src/components/upload/publish-video.vue

+ 10 - 0
src/api/media/file.js

@@ -0,0 +1,10 @@
+import $axios from '../index'
+
+const fileApi = {
+  videoIdApi: '/api/file/id/video'
+}
+
+// 获取视频文件 ID 和 URL ID
+export function getVideoId() {
+  return $axios.post(fileApi.videoIdApi)
+}

+ 94 - 110
src/components/upload/publish-video.vue

@@ -28,10 +28,10 @@
         <v-row justify="center">
           <v-col cols="5">
             <v-card outlined>
-              <v-img :src="videoPost.imageUrl" aspect-ratio="1.77" contain max-height="150" alt="封面图,推荐16:9" />
+              <v-img :src="coverUrl" aspect-ratio="1.77" contain max-height="150" alt="封面图,推荐16:9" />
             </v-card>
           </v-col>
-          <v-col cols="5">
+          <!--          <v-col cols="5">
             <v-file-input
               :rules="rules"
               accept="image/png, image/jpeg, image/bmp"
@@ -43,7 +43,7 @@
             <v-btn color="primary" @click="uploadVideoCover">
               上传
             </v-btn>
-          </v-col>
+          </v-col>-->
         </v-row>
         <v-divider />
         <v-row justify="center">
@@ -137,30 +137,22 @@
 
 <script>
 import { videoCategory, submitVideoPost } from '@/api/media/video'
+import { getVideoId } from '@/api/media/file'
 /* import { hashFile } from '@/utils/hash' */
 
 export default {
   data() {
     return {
       options: {
-        target: '//api.reghao.cn' + '/api/file/upload/video',
-        chunkSize: 1024 * 1024 * 1024 * 5, // 分片大小 5GiB
-        forceChunkSize: true,
+        target: '//oss.reghao.cn',
+        chunkSize: 1024 * 1024 * 1024 * 5, // 5GiB
         fileParameterName: 'file',
-        maxChunkRetries: 3,
-        testChunks: true,
-        checkChunkUploadedByResponse: function(chunk, message) {
-          const objMessage = JSON.parse(message)
-          console.log('分片文件检验')
-          console.log(objMessage)
-          if (objMessage.skipUpload) {
-            return true
-          }
-
-          return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
+        testChunks: false,
+        query: (file, chunk) => {
+          const key = 'video/playback/' + this.videoPost.videoUrlId
+          return { key: key }
         },
         headers: {
-          Authorization: 'Bearer ' + this.$store.getters.token
         }
       },
       attrs: {
@@ -169,9 +161,11 @@ export default {
       rules: [
         value => !value || value.size < 2000000 || 'Avatar size should be less than 2 MB!'
       ],
+      coverUrl: null,
       // 提交给后端的数据
       videoPost: {
         videoFileId: null,
+        videoUrlId: null,
         coverFileId: null,
         title: null,
         description: null,
@@ -203,12 +197,13 @@ export default {
     }
   },
   created() {
+    this.getVideoIdWrapper()
     this.getVideoCategory()
   },
   methods: {
     // 选择视频后获取视频的分辨率和时长, 并截取第一秒的内容作为封面
     processVideo(file) {
-      return new Promise(function(resolve, reject) {
+      return new Promise((resolve, reject) => {
         const canvas = document.createElement('canvas')
         const canvasCtx = canvas.getContext('2d')
 
@@ -224,71 +219,71 @@ export default {
         // 设置 auto 预加载数据, 否则会出现截图为黑色图片的情况
         videoElem.setAttribute('preload', 'auto')
         videoElem.src = dataUrl
-        videoElem.addEventListener('canplay', function() {
-          setTimeout(() => {
-            // 视频视频分辨率
-            const videoWidth = videoElem.videoWidth
-            const videoHeight = videoElem.videoHeight
+        // 预加载完成后才会获取到视频的宽高和时长数据
+        videoElem.addEventListener('canplay', this.onCanPlay(videoElem, canvas, canvasCtx))
+      })
+    },
+    onCanPlay(videoElem, canvas, canvasCtx) {
+      setTimeout(() => {
+        // 视频视频分辨率
+        const videoWidth = videoElem.videoWidth
+        const videoHeight = videoElem.videoHeight
+        this.videoPost.width = videoWidth
+        this.videoPost.height = videoHeight
+        this.videoPost.duration = videoElem.duration
 
-            videoElem.pause()
-            /* const ratio = window.devicePixelRatio || 1
-            canvasCtx.scale(ratio, ratio)*/
-            // 设置画布尺寸
-            canvas.width = videoWidth
-            canvas.height = videoHeight
-            canvasCtx.drawImage(videoElem, 0, 0, canvas.width, canvas.height)
-            // 把图标base64编码后变成一段url字符串
-            const urlData = canvas.toDataURL('image/jpeg')
-            if (typeof urlData !== 'string') {
-              alert('urlData不是字符串')
-              return
-            }
+        videoElem.pause()
+        /* const ratio = window.devicePixelRatio || 1
+        canvasCtx.scale(ratio, ratio)*/
+        // 设置画布尺寸
+        canvas.width = videoWidth
+        canvas.height = videoHeight
+        canvasCtx.drawImage(videoElem, 0, 0, canvas.width, canvas.height)
+        // 把图标base64编码后变成一段url字符串
+        const urlData = canvas.toDataURL('image/jpeg')
+        if (typeof urlData !== 'string') {
+          alert('urlData不是字符串')
+          return
+        }
 
-            var arr = urlData.split(',')
-            var bstr = atob(arr[1])
-            var n = bstr.length
-            var u8arr = new Uint8Array(n)
-            while (n--) {
-              u8arr[n] = bstr.charCodeAt(n)
-            }
-            const coverFile = new File([u8arr], 'cover.jpg', { type: 'image/jpeg' })
+        var arr = urlData.split(',')
+        var bstr = atob(arr[1])
+        var n = bstr.length
+        var u8arr = new Uint8Array(n)
+        while (n--) {
+          u8arr[n] = bstr.charCodeAt(n)
+        }
+        const coverFile = new File([u8arr], 'cover.jpg', { type: 'image/jpeg' })
 
-            if (coverFile instanceof File) {
-              const formData = new FormData()
-              formData.append('file', coverFile)
-              fetch(`//api.reghao.cn/api/file/upload/image`, {
-                headers: {},
-                method: 'POST',
-                credentials: 'include',
-                body: formData
-              }).then(response => response.json())
-                .then(json => {
-                  if (json.code === 0) {
-                    this.message = '封面已上传'
-                    this.showMessage = true
-                    this.videoPost.coverFileId = json.data.imageFileId
-                  } else {
-                    this.message = '上传失败,请重试!' + json.message
-                    this.showMessage = true
-                  }
-                })
-                .catch(e => {
-                  return null
-                })
-            }
-          }, 1000) // 1000毫秒,就是截取第一秒,2000毫秒就是截取第2秒,视频1秒通常24帧,也可以换算成截取第几帧。
-          // 防止拖动进度条的时候重复触发
-          // videoElem.removeEventListener('canplay', arguments.callee)
-        })
-      })
+        if (coverFile instanceof File) {
+          const formData = new FormData()
+          formData.append('file', coverFile)
+          fetch(`//api.reghao.cn/api/file/upload/image`, {
+            headers: {},
+            method: 'POST',
+            credentials: 'include',
+            body: formData
+          }).then(response => response.json())
+            .then(json => {
+              if (json.code === 0) {
+                this.videoPost.coverFileId = json.data.imageFileId
+                this.coverUrl = json.data.imageUrl
+              } else {
+                this.message = '视频封面上传失败,请重试!' + json.message
+                this.showMessage = true
+              }
+            })
+            .catch(e => {
+              return null
+            })
+        }
+      }, 1000) // 1000毫秒,就是截取第一秒,2000毫秒就是截取第2秒,视频1秒通常24帧,也可以换算成截取第几帧。
+      // 防止拖动进度条的时候重复触发
+      // videoElem.removeEventListener('canplay', arguments.callee)
     },
     onFileAdded(file) {
       this.setTitle(file.file.name)
-      this.processVideo(file.file).then(video => {
-        this.videoPost.width = video.videoWidth
-        this.videoPost.height = video.videoHeight
-        this.videoPost.duration = video.duration
-      })
+      this.processVideo(file.file)
       /* file.pause()
       hashFile(file.file).then(res => {
         const formData = new FormData()
@@ -325,12 +320,8 @@ export default {
     onFileSuccess(rootFile, file, response, chunk) {
       const res = JSON.parse(response)
       if (res.code === 0) {
-        const resData = res.data
-        if (resData.merged) {
-          this.message = '视频已上传'
-          this.showMessage = true
-          this.videoPost.videoFileId = resData.videoFileId
-        }
+        this.message = '视频已上传'
+        this.showMessage = true
       }
     },
     onFileError(rootFile, file, response, chunk) {
@@ -388,35 +379,12 @@ export default {
     setTitle(title) {
       if (title.length > 50) {
         this.videoPost.title = title.substring(0, 50)
+        this.videoPost.description = title
       } else {
         this.videoPost.title = title
       }
     },
-    uploadVideoCover1(coverFile) {
-      const formData = new FormData()
-      formData.append('file', coverFile)
-      fetch(`//api.reghao.cn/api/file/upload/image`, {
-        headers: {
-          'Authorization': 'Bearer ' + this.$store.getters.token
-        },
-        method: 'POST',
-        credentials: 'include',
-        body: formData
-      }).then(response => response.json())
-        .then(json => {
-          if (json.code === 0) {
-            this.message = '封面已上传'
-            this.showMessage = true
-          } else {
-            this.message = '上传失败,请重试!' + json.message
-            this.showMessage = true
-          }
-        })
-        .catch(e => {
-          return null
-        })
-    },
-    uploadVideoCover() {
+    /* uploadVideoCover() {
       if (this.coverFile === null) {
         this.message = '请先选择视频封面,然后上传!'
         this.showMessage = true
@@ -454,7 +422,7 @@ export default {
         .catch(e => {
           return null
         })
-    },
+    },*/
     getVideoCategory() {
       videoCategory()
         .then(res => {
@@ -503,6 +471,22 @@ export default {
       } else if (scope === '仅自己可见') {
         this.videoPost.scope = 4
       }
+    },
+    getVideoIdWrapper() {
+      getVideoId(this.videoPost)
+        .then(res => {
+          if (res.code === 0) {
+            console.log(res.data)
+            this.videoPost.videoFileId = res.data.videoFileId
+            this.videoPost.videoUrlId = res.data.videoUrlId
+          } else {
+            this.message = res.msg
+            this.showMessage = true
+          }
+        })
+        .catch(error => {
+          console.error(error.message)
+        })
     }
   }
 }