From e987ecc44684a2559dae3ae975057ad1aa022a61 Mon Sep 17 00:00:00 2001 From: hectorqin Date: Tue, 28 Jul 2020 10:21:14 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=99=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Play.vue | 363 ++++++++++++++++++++++++++++++++++++---- src/lib/site/server.js | 2 +- 2 files changed, 332 insertions(+), 33 deletions(-) diff --git a/src/components/Play.vue b/src/components/Play.vue index fec8448..163b6c5 100644 --- a/src/components/Play.vue +++ b/src/components/Play.vue @@ -102,10 +102,39 @@ import { mapMutations } from 'vuex' import { star, history, setting, shortcut, mini } from '../lib/dexie' import zy from '../lib/site/tools' -import 'xgplayer' +import Player from 'xgplayer' import Hls from 'xgplayer-hls.js' import mt from 'mousetrap' const { remote, ipcRenderer } = require('electron') + +const VIDEO_DETAIL_CACHE = {} + +const addPlayerBtn = function (event, svg) { + const player = this + console.log(player) + const util = Player.util + const controlEl = player.controls + const btnConfig = player.config[event] + if (btnConfig) { + let btn + const btnName = 'xg-btn-' + event + if (btnConfig.type === 'img') { + btn = util.createImgBtn(btnName, btnConfig.url, btnConfig.width, btnConfig.height) + } else { + btn = util.createDom(btnName, svg || btnConfig.svg, {}, btnName) + } + controlEl.appendChild(btn) + const ev = ['click', 'touchend'] + ev.forEach(item => { + btn.addEventListener(item, function (e) { + e.preventDefault() + e.stopPropagation() + player.emit(event) + }, false) + }) + } +} + export default { name: 'play', data () { @@ -130,7 +159,15 @@ export default { crossOrigin: true, cssFullscreen: true, defaultPlaybackRate: 1, - playbackRate: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 5] + playbackRate: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 5], + playPrev: true, + playNextOne: true, + showList: true, + showHistory: true + }, + state: { + showList: false, + showHistory: false }, name: '', length: 0, @@ -234,36 +271,7 @@ export default { }) }, playVideo (index = 0, time = 0) { - const id = this.video.info.id - zy.detail(this.video.key, id).then(res => { - this.name = res.name - const dd = res.dl.dd - const type = Object.prototype.toString.call(dd) - let m3u8Txt = [] - if (type === '[object Array]') { - for (const i of dd) { - if (i._t.indexOf('m3u8') >= 0) { - m3u8Txt = i._t.split('#') - } - } - } else { - m3u8Txt = dd._t.split('#') - } - this.right.list = m3u8Txt - const m3u8Arr = [] - for (const i of m3u8Txt) { - const j = i.split('$') - if (j.length > 1) { - for (let m = 0; m < j.length; m++) { - if (j[m].indexOf('m3u8') >= 0) { - m3u8Arr.push(j[m]) - } - } - } else { - m3u8Arr.push(j[0]) - } - } - + this.fetchM3u8List().then(m3u8Arr => { this.xg.src = m3u8Arr[index] this.showNext = m3u8Arr.length > 1 @@ -285,6 +293,102 @@ export default { this.xg.off('ended') }) }) + // const id = this.video.info.id + // zy.detail(this.video.key, id).then(res => { + // this.name = res.name + // const dd = res.dl.dd + // const type = Object.prototype.toString.call(dd) + // let m3u8Txt = [] + // if (type === '[object Array]') { + // for (const i of dd) { + // if (i._t.indexOf('m3u8') >= 0) { + // m3u8Txt = i._t.split('#') + // } + // } + // } else { + // m3u8Txt = dd._t.split('#') + // } + // this.right.list = m3u8Txt + // const m3u8Arr = [] + // for (const i of m3u8Txt) { + // const j = i.split('$') + // if (j.length > 1) { + // for (let m = 0; m < j.length; m++) { + // if (j[m].indexOf('m3u8') >= 0) { + // m3u8Arr.push(j[m]) + // } + // } + // } else { + // m3u8Arr.push(j[0]) + // } + // } + + // this.xg.src = m3u8Arr[index] + // this.showNext = m3u8Arr.length > 1 + + // if (time !== 0) { + // this.xg.play() + // this.xg.once('playing', () => { + // this.xg.currentTime = time + // }) + // } else { + // this.xg.play() + // } + + // this.videoPlaying() + // 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') + // }) + // }) + }, + fetchM3u8List () { + return new Promise((resolve) => { + const cacheKey = this.video.key + '@' + this.video.info.id + if (VIDEO_DETAIL_CACHE[cacheKey]) { + this.name = VIDEO_DETAIL_CACHE[cacheKey].name + resolve(VIDEO_DETAIL_CACHE[cacheKey].list) + return + } + zy.detail(this.video.key, this.video.info.id).then(res => { + this.name = res.name + const dd = res.dl.dd + const type = Object.prototype.toString.call(dd) + let m3u8Txt = [] + if (type === '[object Array]') { + for (const i of dd) { + if (i._t.indexOf('m3u8') >= 0) { + m3u8Txt = i._t.split('#') + } + } + } else { + m3u8Txt = dd._t.split('#') + } + this.right.list = m3u8Txt + const m3u8Arr = [] + for (const i of m3u8Txt) { + const j = i.split('$') + if (j.length > 1) { + for (let m = 0; m < j.length; m++) { + if (j[m].indexOf('m3u8') >= 0) { + m3u8Arr.push(j[m]) + } + } + } else { + m3u8Arr.push(j[0]) + } + } + + VIDEO_DETAIL_CACHE[cacheKey] = { + list: m3u8Arr, + name: res.name + } + resolve(m3u8Arr) + }) + }) }, videoPlaying () { this.changeVideo() @@ -636,6 +740,92 @@ export default { }, changeSetting () { this.mtEvent() + }, + toggleList () { + if (this.state.showList) { + document.querySelector('xg-btn-showlist ul').style.display = 'none' + this.state.showList = false + } else { + this.refreshList() + document.querySelector('xg-btn-showlist ul').style.display = 'block' + this.state.showList = true + } + }, + refreshList () { + let ul = document.querySelector('xg-btn-showlist ul') + if (!ul) { + ul = document.createElement('ul') + document.querySelector('xg-btn-showlist').appendChild(ul) + ul.addEventListener('click', (ev) => { + ev = ev || window.event + const target = ev.target || ev.srcElement // target表示在事件冒泡中触发事件的源元素,在IE中是srcElement + if (target.nodeName.toLowerCase() === 'li') { + this.listItemEvent(parseInt(target.dataset.index)) + } + }) + } + ul.style.display = 'none' + let li = '' + if (this.right.list.length === 0) { + li = '
  • 无数据
  • ' + } else { + for (let index = 0; index < this.right.list.length; index++) { + const item = this.right.list[index] + const num = item.split('$') + let title + if (num.length > 1) { + title = num[0] + } else { + title = `第${(index + 1)}集` + } + if (index === this.video.info.index) { + li += `
  • ${title}
  • ` + } else { + li += `
  • ${title}
  • ` + } + } + } + ul.innerHTML = li + }, + toggleHistory () { + if (this.state.showHistory) { + document.querySelector('xg-btn-showhistory ul').style.display = 'none' + this.state.showHistory = false + } else { + this.refreshHistory() + document.querySelector('xg-btn-showhistory ul').style.display = 'block' + this.state.showHistory = true + } + }, + refreshHistory () { + let ul = document.querySelector('xg-btn-showhistory ul') + if (!ul) { + ul = document.createElement('ul') + document.querySelector('xg-btn-showhistory').appendChild(ul) + ul.addEventListener('click', (ev) => { + ev = ev || window.event + const target = ev.target || ev.srcElement // target表示在事件冒泡中触发事件的源元素,在IE中是srcElement + if (target.nodeName.toLowerCase() === 'li') { + this.historyItemEvent(this.right.history[parseInt(target.dataset.index)]) + } + }) + } + ul.style.display = 'none' + let li = '' + if (this.right.history.length === 0) { + li = '
  • 无数据
  • ' + } else { + window.historyItemEvent = this.historyItemEvent.bind(this) + for (let index = 0; index < this.right.history.length; index++) { + const item = this.right.history[index] + if (this.video.info.id === item.ids) { + li += `
  • ${item.name}
  • ` + } else { + li += `
  • ${item.name}
  • ` + } + } + } + ul.innerHTML = li } }, created () { @@ -643,18 +833,127 @@ export default { this.mtEvent() }, mounted () { + Player.install('playPrev', function () { + addPlayerBtn.bind(this, 'playPrev', '')() + }) + Player.install('playNextOne', function () { + addPlayerBtn.bind(this, 'playNextOne', '')() + }) + Player.install('showList', function () { + addPlayerBtn.bind(this, 'showList', '')() + }) + Player.install('showHistory', function () { + addPlayerBtn.bind(this, 'showHistory', '')() + }) + this.xg = new Hls(this.config) ipcRenderer.on('miniClosed', () => { this.xg.destroy() this.xg = new Hls(this.config) this.getUrls() }) + this.xg.on('playNextOne', () => { + this.nextEvent() + }) + + this.xg.on('playPrev', () => { + this.prevEvent() + }) + + this.xg.on('showList', () => { + this.toggleList() + }) + + this.xg.on('showHistory', () => { + this.toggleHistory() + }) }, beforeDestroy () { clearInterval(this.timer) } } +