reghao 5 месяцев назад
Родитель
Сommit
4f62053b07
1 измененных файлов с 240 добавлено и 14 удалено
  1. 240 14
      src/views/home/VideoPage.vue

+ 240 - 14
src/views/home/VideoPage.vue

@@ -15,13 +15,15 @@
                 <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
                 <span><i class="el-icon-watch">{{ video.pubDate }}</i></span>
                 <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
-                <span v-if="videoId !== null && videoId.includes('BV')"><i class="el-icon-apple">
-                  <a target="_blank" :href="`https://bilibili.com/` + videoId">bili</a>
-                </i></span>
+                <span v-if="videoId !== null && videoId.includes('BV')">
+                  <i class="el-icon-apple"><a target="_blank" :href="`https://bilibili.com/` + videoId">bili</a></i>
+                </span>
+                <span v-html="'&nbsp;&nbsp;&nbsp;&nbsp;'" />
+                <span><i class="el-icon-view">{{ realtimeViewCount }} 正在观看</i></span>
               </el-row>
             </div>
             <div class="text item">
-              <video-player :video-prop="video" />
+              <div id="dplayer" ref="dplayer" style="height: 480px;" />
             </div>
           </el-card>
         </el-row>
@@ -202,11 +204,12 @@
               ref="singleTable"
               :data="playlist"
               highlight-current-row
+              style="width: 100%"
               @current-change="handleCurrentRow"
-              style="width: 100%">
+            >
               <el-table-column
-                type="index">
-              </el-table-column>
+                type="index"
+              />
               <el-table-column
                 prop="albumName"
               />
@@ -294,23 +297,24 @@
 
 <script>
 import PermissionDeniedCard from '@/components/card/PermissionDeniedCard'
-import VideoPlayer from 'components/VideoPlayer'
 import SideVideoCard from 'components/card/SideVideoCard'
 import UserAvatarCard from '@/components/card/UserAvatarCard'
 import EditVideoCard from '@/components/card/EditVideoCard'
 import comment from '@/components/comment'
 
-import { similarVideo, videoInfo, downloadVideo, getShortUrl } from '@/api/video'
+import { similarVideo, videoInfo, downloadVideo, getShortUrl, videoUrl } from '@/api/video'
 import { videoErrorReport, videoErrorDelete } from '@/api/video_edit'
 import { collectItem, createAlbum, getUserAlbumList } from '@/api/collect'
 import { getUserInfo } from '@/api/user'
 import { publishComment, getComment } from '@/api/comment'
-import { getAuthedUser } from '@/utils/auth'
+import { getAccessToken, getAuthedUser } from '@/utils/auth'
 import { dislikeVideo } from '@/api/content'
+import flvjs from 'flv.js'
+import DPlayer from 'dplayer'
 
 export default {
   name: 'VideoPage',
-  components: { EditVideoCard, SideVideoCard, VideoPlayer, UserAvatarCard, PermissionDeniedCard, comment },
+  components: { EditVideoCard, SideVideoCard, UserAvatarCard, PermissionDeniedCard, comment },
   data() {
     return {
       // 屏幕宽度, 为了控制分页条的大小
@@ -339,7 +343,7 @@ export default {
         }
       ],
       currentUser: {
-        userId: 9999,
+        userId: -1,
         name: '芒果',
         avatar: '//picx.zhimg.com/v2-a2c89378a6332cbfed3e28b5ab84feb7.jpg',
         author: true
@@ -382,7 +386,22 @@ export default {
       currentRow: null,
       showShareVideoDialog: false,
       showEditDialog: false,
-      showEdit: true
+      showEdit: true,
+      // ****************************************************************************************************************
+      flvjs,
+      DPlayer,
+      danmaku: {
+        api: process.env.VUE_APP_SERVER_URL + '/api/comment/danmaku/'
+      },
+      userToken: null,
+      sendEvent: true,
+      intervalEvent: null,
+      // ****************************************************************************************************************
+      wsUrl: null,
+      realtimeViewCount: 0,
+      wsClient: null,
+      wsConnectStatus: false,
+      wsReconnectLock: false
     }
   },
   watch: {
@@ -392,6 +411,9 @@ export default {
     }
   },
   created() {
+    this.userToken = getAccessToken()
+    this.danmaku.token = this.userToken
+
     const loginUser = getAuthedUser()
     if (loginUser != null) {
       this.currentUser = {
@@ -511,6 +533,7 @@ export default {
               })
             }
           })
+          this.getVideoUrl(videoId)
         } else if (resp.code === 2) {
           this.$router.push('/404')
         } else {
@@ -808,8 +831,211 @@ export default {
         }, 300)
       })
       console.log('deleteComment: ', res)
-    }
+    },
+    // ****************************************************************************************************************
+    getVideoUrl(videoId) {
+      videoUrl(videoId).then(res => {
+        if (res.code === 0) {
+          if (this.userToken != null && this.sendEvent) {
+            this.wsUrl = 'wss:' + process.env.VUE_APP_SERVER_URL + '/ws/media?' +
+              'userToken=' + this.userToken + '&videoId=' + videoId
+            this.initWebSocket()
+          }
+
+          const coverUrl = this.video.coverUrl
+          const loginUserId = this.currentUser.userId
+          const urlType = res.data.type
+          if (urlType === 'mp4') {
+            const urls = res.data.urls
+            for (const url of urls) {
+              url.type = 'normal'
+            }
+            this.initMp4Player(loginUserId, videoId, coverUrl, urls, res.data.currentTime)
+          } else if (urlType === 'flv') {
+            const urls = res.data.urls
+            this.initFlvPlayer(loginUserId, videoId, coverUrl, urls, res.data.currentTime)
+          } else {
+            this.$notify.error({
+              message: '视频 url 类型不合法',
+              type: 'warning',
+              duration: 3000
+            })
+          }
+        } else {
+          this.$notify.error({
+            message: '视频 url 获取失败',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify.error({
+          message: error.message,
+          type: 'error',
+          duration: 3000
+        })
+      })
+    },
+    danmakuConfig() {
+      // TODO 获取弹幕配置,将 videoUrl 作为本函数的回调
+    },
+    initMp4Player(userId, videoId, coverUrl, urls, pos) {
+      const player = new DPlayer({
+        container: document.querySelector('#dplayer'),
+        lang: 'zh-cn',
+        screenshot: true,
+        autoplay: false,
+        volume: 0.1,
+        mutex: true,
+        video: {
+          pic: coverUrl,
+          defaultQuality: 0,
+          quality: urls,
+          hotkey: true
+        },
+        danmaku: {
+          id: videoId,
+          maximum: 10000,
+          api: this.danmaku.api,
+          token: this.userToken,
+          bottom: '15%',
+          unlimited: true
+        }
+      })
+
+      // 设置音量
+      // player.volume(0.1, true, false)
+      // 跳转到上次看到的位置
+      player.seek(pos)
+
+      var ended = false
+      /* 事件绑定 */
+      const that = this
+      player.on('play', function() {
+        if (that.sendEvent) {
+          clearInterval(that.intervalEvent)
+          that.intervalEvent = setInterval(() => {
+            if (!ended) {
+              const jsonData = {}
+              jsonData.type = 'progress'
+              jsonData.direction = 'c2s'
+              jsonData.data = {
+                mediaId: videoId,
+                mediaType: 1,
+                currentTime: player.video.currentTime,
+                ended: ended
+              }
+              that.sendJsonMessage(jsonData)
+            }
+          }, 5000)
+        }
+      })
+      player.on('ended', () => {
+        clearInterval(that.intervalEvent)
+        ended = true
+        if (that.sendEvent) {
+          const jsonData = {}
+          jsonData.type = 'progress'
+          jsonData.direction = 'c2s'
+          jsonData.data = {
+            mediaId: videoId,
+            mediaType: 1,
+            currentTime: player.video.currentTime,
+            ended: ended
+          }
+          that.sendJsonMessage(jsonData)
+        }
+      })
+      player.on('volumechange', () => {
+        console.log('声音改变')
+      })
+    },
+    initFlvPlayer(userId, videoId, coverUrl, urls, pos) {
+      const player = new DPlayer({
+        container: document.getElementById('dplayer'),
+        lang: 'zh-cn',
+        screenshot: true,
+        autoplay: false,
+        volume: 0.1,
+        mutex: true,
+        video: {
+          pic: coverUrl,
+          defaultQuality: 0,
+          quality: urls,
+          hotkey: true,
+          type: 'customFlv',
+          customType: {
+            customFlv: function(video, player) {
+              const flvPlayer = flvjs.createPlayer({
+                type: 'flv',
+                url: video.src
+              })
+              flvPlayer.attachMediaElement(video)
+              flvPlayer.load()
+            }
+          }
+        }
+      })
+
+      // 跳转到上次看到的位置
+      player.seek(pos)
+      /* 事件绑定 */
+      player.on('ended', () => {
+      })
+      player.on('volumechange', () => {
+        console.log('声音改变')
+      })
+    },
     // ****************************************************************************************************************
+    // websocket
+    initWebSocket() {
+      if ('WebSocket' in window) {
+        this.wsClient = new WebSocket(this.wsUrl)
+        const that = this
+        this.wsClient.onopen = function() {
+          that.setOnline()
+        }
+        this.wsClient.onclose = function() {
+          that.setOffline()
+          that.reconnect()
+        }
+        this.wsClient.onerror = function() {
+          that.setOffline()
+          console.log('websocket connection error...')
+          that.reconnect()
+        }
+        this.wsClient.onmessage = function(evt) {
+          that.processMessage(evt.data)
+        }
+      } else {
+        // 浏览器不支持 WebSocket
+        this.$message.error('您的浏览器不支持 WebSocket!')
+      }
+    },
+    setOnline() {
+      this.wsConnectStatus = true
+    },
+    setOffline() {
+      this.wsConnectStatus = false
+    },
+    reconnect() {
+      if (this.wsReconnectLock) return
+      this.wsReconnectLock = true
+      const that = this
+      setTimeout(function() {
+        console.log('websocket reconnecting...')
+        that.initWebSocket()
+        that.wsReconnectLock = false
+      }, 5000)
+    },
+    sendJsonMessage(message) {
+      const jsonStr = JSON.stringify(message)
+      this.wsClient.send(jsonStr)
+    },
+    processMessage(message) {
+      const jsonMessage = JSON.parse(message)
+      this.realtimeViewCount = jsonMessage.viewCount
+    }
   }
 }
 </script>