|
|
@@ -15,13 +15,15 @@
|
|
|
<span v-html="' '" />
|
|
|
<span><i class="el-icon-watch">{{ video.pubDate }}</i></span>
|
|
|
<span v-html="' '" />
|
|
|
- <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="' '" />
|
|
|
+ <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>
|