diff --git a/package.json b/package.json index edcdeed..e2f57ad 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "vuedraggable": "^2.24.3", "vuex": "^3.6.0", "xgplayer": "^2.16.0", - "xgplayer-hls.js": "^2.3.0" + "xgplayer-hls.js": "^2.3.0", + "xgplayer-mp4": "^1.2.0" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.9", diff --git a/src/components/Play.vue b/src/components/Play.vue index 70f15d4..50f6ec6 100644 --- a/src/components/Play.vue +++ b/src/components/Play.vue @@ -181,7 +181,7 @@
@@ -244,6 +244,7 @@ import { star, history, setting, shortcut, mini, channelList, sites } from '../l import zy from '../lib/site/tools' import Player from 'xgplayer' import HlsJsPlayer from 'xgplayer-hls.js' +import 'xgplayer-mp4' import mt from 'mousetrap' import Clickoutside from 'element-ui/src/utils/clickoutside' import { exec, execFile } from 'child_process' @@ -332,7 +333,7 @@ export default { videoTitle: true, airplay: true, closeVideoTouch: true, - ignores: ['cssFullscreen', 'replay'], + ignores: ['cssFullscreen', 'replay', 'error'], // 为了切换播放器类型时避免显示错误刷新,暂时忽略错误 preloadTime: 300 }, state: { @@ -361,7 +362,8 @@ export default { endPosition: { min: '00', sec: '00' }, skipendStatus: false, // 是否跳过了片尾 currentShortcutList: [], - onlineUrl: '' + onlineUrl: '', + playerType: 'hls' } }, filters: { @@ -557,6 +559,16 @@ export default { }, playChannel (channel) { this.isLive = true + if (this.playerType !== 'hls') { + this.xg.src = '' + this.config.url = '' + this.xg.destroy() + this.xg = null + this.xg = new HlsJsPlayer(this.config) + this.playerInstall() + this.bindEvent() + this.playerType = 'hls' + } if (channel.channels) { this.right.sources = channel.channels.filter(e => e.isActive) channel = channel.prefer ? channel.channels.find(e => e.id === channel.prefer) : channel.channels.filter(e => e.isActive)[0] @@ -576,40 +588,59 @@ export default { }, playVideo (index = 0, time = 0) { this.isLive = false - if (document.querySelector('xg-btn-showhistory')) document.querySelector('xg-btn-showhistory').style.display = 'block' - if (document.querySelector('.xgplayer-playbackrate')) document.querySelector('.xgplayer-playbackrate').style.display = 'inline-block' - this.fetchM3u8List().then(async (m3u8Arr) => { - const url = m3u8Arr[index] - if (!url.endsWith('.m3u8')) { + this.fetchPlaylist().then(async (playlistUrls) => { + const url = playlistUrls[index] + if (!url.endsWith('.m3u8') && !url.endsWith('.mp4')) { const currentSite = await sites.find({ key: this.video.key }) if (currentSite.jiexiUrl) { this.onlineUrl = currentSite.jiexiUrl + url } else { this.onlineUrl = 'https://jx.7kjx.com/?url=' + url } - } else { - this.xg.src = m3u8Arr[index] - const key = this.video.key + '@' + this.video.info.id - const startTime = VIDEO_DETAIL_CACHE[key].startPosition || 0 - this.xg.play() - this.xg.once('playing', () => { - this.xg.currentTime = time > startTime ? time : startTime - if (VIDEO_DETAIL_CACHE[key].startPosition) this.xg.addProgressDot(VIDEO_DETAIL_CACHE[key].startPosition, '片头') - if (VIDEO_DETAIL_CACHE[key].endPosition) this.xg.addProgressDot(this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition, '片尾') - }) - this.videoPlaying() - this.skipendStatus = false - this.xg.once('ended', () => { - if (m3u8Arr.length > 1 && (m3u8Arr.length - 1 > index)) { - this.video.info.time = 0 - this.video.info.index++ - } - this.xg.off('ended') // 明明是once为何会触发多次,得注销掉以真正只执行一次 - }) + return } + if (url.endsWith('.mp4') && this.playerType !== 'mp4') { + this.xg.src = '' + this.config.url = '' + this.xg.destroy() + this.xg = null + this.xg = new Player(this.config) + this.playerInstall() + this.bindEvent() + this.playerType = 'mp4' + } else if (url.endsWith('.m3u8') && this.playerType !== 'hls') { + this.xg.src = '' + this.config.url = '' + this.xg.destroy() + this.xg = null + this.xg = new HlsJsPlayer(this.config) + this.playerInstall() + this.bindEvent() + this.playerType = 'hls' + } + this.xg.src = url + const key = this.video.key + '@' + this.video.info.id + const startTime = VIDEO_DETAIL_CACHE[key].startPosition || 0 + this.xg.play() + if (document.querySelector('xg-btn-showhistory')) document.querySelector('xg-btn-showhistory').style.display = 'block' + if (document.querySelector('.xgplayer-playbackrate')) document.querySelector('.xgplayer-playbackrate').style.display = 'inline-block' + this.xg.once('playing', () => { + this.xg.currentTime = time > startTime ? time : startTime + if (VIDEO_DETAIL_CACHE[key].startPosition) this.xg.addProgressDot(VIDEO_DETAIL_CACHE[key].startPosition, '片头') + if (VIDEO_DETAIL_CACHE[key].endPosition) this.xg.addProgressDot(this.xg.duration - VIDEO_DETAIL_CACHE[key].endPosition, '片尾') + }) + this.videoPlaying() + this.skipendStatus = false + this.xg.once('ended', () => { + if (playlistUrls.length > 1 && (playlistUrls.length - 1 > index)) { + this.video.info.time = 0 + this.video.info.index++ + } + this.xg.off('ended') // 明明是once为何会触发多次,得注销掉以真正只执行一次 + }) }) }, - fetchM3u8List () { + fetchPlaylist () { return new Promise((resolve) => { const cacheKey = this.video.key + '@' + this.video.info.id if (VIDEO_DETAIL_CACHE[cacheKey] && VIDEO_DETAIL_CACHE[cacheKey].list && VIDEO_DETAIL_CACHE[cacheKey].list.length) { @@ -618,28 +649,28 @@ export default { } zy.detail(this.video.key, this.video.info.id).then(res => { this.name = res.name - const m3u8Txt = res.m3u8List - this.right.list = m3u8Txt - const m3u8Arr = [] - for (const i of m3u8Txt) { + const playlist = res.m3u8List.length ? res.m3u8List : res.mp4List + this.right.list = playlist + const playlistUrls = [] + for (const i of playlist) { const j = i.split('$') if (j.length > 1) { for (let m = 0; m < j.length; m++) { if (j[m].startsWith('http')) { - m3u8Arr.push(j[m]) + playlistUrls.push(j[m]) break } } } else { - m3u8Arr.push(j[0]) + playlistUrls.push(j[0]) } } VIDEO_DETAIL_CACHE[cacheKey] = Object.assign(VIDEO_DETAIL_CACHE[cacheKey] || {}, { - list: m3u8Arr, + list: playlistUrls, name: res.name }) - resolve(m3u8Arr) + resolve(playlistUrls) }) }) }, @@ -892,20 +923,27 @@ export default { } return } - this.fetchM3u8List().then(m3u8Arr => { + this.fetchPlaylist().then(playlistUrls => { var externalPlayer = this.setting.externalPlayer if (!externalPlayer) { this.$message.error('请设置第三方播放器路径') // 在线播放该视频 - var link = 'https://www.m3u8play.com/?play=' + m3u8Arr[this.video.info.index] - const open = require('open') - open(link) + if (playlistUrls[this.video.info.index].endsWith('.m3u8')) { + var link = 'https://www.m3u8play.com/?play=' + playlistUrls[this.video.info.index] + const open = require('open') + open(link) + } } else { - var m3uFile = this.generateM3uFile(this.video.info.name, m3u8Arr, this.video.info.index) - if (fs.existsSync(externalPlayer)) { - execFile(externalPlayer, [m3uFile]) + let playlist + if (playlistUrls.every(e => e.endsWith('.m3u8'))) { + playlist = this.generateM3uFile(this.video.info.name, playlistUrls, this.video.info.index) } else { - exec(externalPlayer, [m3uFile]) + playlist = playlistUrls[this.video.info.index] + } + if (fs.existsSync(externalPlayer)) { + execFile(externalPlayer, [playlist]) + } else { + exec(externalPlayer, [playlist]) } } }) @@ -1456,7 +1494,7 @@ export default { this.video.key = '' this.xg.src = '' this.config.url = '' - this.xg.destroy(false) + this.xg.destroy() this.xg = null this.name = '' this.isLive = false diff --git a/src/lib/site/tools.js b/src/lib/site/tools.js index 5625d1e..74207ac 100644 --- a/src/lib/site/tools.js +++ b/src/lib/site/tools.js @@ -238,6 +238,7 @@ const zy = { const videoList = jsondata.list.video // Parse m3u8List var m3u8List = [] + let mp4List = [] const dd = videoList.dl.dd const type = Object.prototype.toString.call(dd) if (type === '[object Array]') { @@ -245,12 +246,18 @@ const zy = { // 如果含有多个视频列表的话, 仅获取m3u8列表 if (i._flag.includes('m3u8') || i._t.includes('.m3u8')) { m3u8List = i._t.split('#') + break + // 获取不到m3u8时,尝试获取mp4列表 + } else if (i._flag.includes('mp4') || i._t.includes('.mp4')) { + mp4List = i._t.split('#') + break } } } else { m3u8List = dd._t.split('#') } videoList.m3u8List = m3u8List + if (mp4List.length) videoList.mp4List = mp4List resolve(videoList) }).catch(err => { reject(err)