support segmented videos

This commit is contained in:
DIYgod 2017-06-08 00:34:16 +08:00
parent 15e770c988
commit a042b39550
No known key found for this signature in database
GPG Key ID: EC0B76A252D3EF67
11 changed files with 297 additions and 122 deletions

View File

@ -17,7 +17,6 @@
"no-implicit-globals": 1,
"no-labels": 1,
"no-multi-str": 1,
"no-unused-expressions": 1,
"comma-spacing": 1,
"comma-style": 1,
"func-call-spacing": 1,

View File

@ -46,7 +46,6 @@
<link rel="stylesheet" href="../dist/DPlayer.min.css">
</head>
<body>
<a href="https://github.com/DIYgod/DPlayer" target="_blank" class="github-corner"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
<div class="container">
<h1>DPlayer</h1>
<h2>Wow, such a lovely HTML5 danmaku video player</h2>
@ -61,6 +60,8 @@
<div class="dplayer" id="dplayer3"></div>
<h3>FLV format support</h3>
<div class="dplayer" id="dplayer4"></div>
<h3>Segmented videos</h3>
<div class="dplayer" id="dplayer5"></div>
</div>
<script src="https://rawgit.com/mrdoob/stats.js/master/build/stats.min.js"></script>
<script src="../plugin/flv.min.js"></script>
@ -180,6 +181,28 @@
}
});
// Segmented videos
var dp5 = new DPlayer({
element: document.getElementById('dplayer5'),
autoplay: false,
theme: '#FADFA3',
loop: true,
screenshot: true,
hotkey: true,
preload: 'metadata',
video: {
url: ['http://devtest.qiniudn.com/若能绽放光芒0.mp4', 'http://devtest.qiniudn.com/若能绽放光芒1.mp4', 'http://devtest.qiniudn.com/若能绽放光芒2.mp4', 'http://devtest.qiniudn.com/若能绽放光芒3.mp4', 'http://devtest.qiniudn.com/若能绽放光芒4.mp4', 'http://devtest.qiniudn.com/若能绽放光芒5.mp4', 'http://devtest.qiniudn.com/若能绽放光芒6.mp4', 'http://devtest.qiniudn.com/若能绽放光芒7.mp4', 'http://devtest.qiniudn.com/若能绽放光芒8.mp4'],
pic: 'http://devtest.qiniudn.com/若能绽放光芒.png',
type: 'normal',
},
danmaku: {
id: '9E2E3368B56CDBB40',
api: 'https://api.prprpr.me/dplayer/',
token: 'tokendemo',
maximum: 3000
}
});
// stats.js: JavaScript Performance Monitor
var stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
@ -193,5 +216,6 @@
}
requestAnimationFrame(animate);
</script>
<a href="https://github.com/DIYgod/DPlayer" target="_blank" class="github-corner"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
</body>
</html>

File diff suppressed because one or more lines are too long

2
dist/DPlayer.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,12 @@
console.log('\n %c DPlayer 1.2.0 %c http://dplayer.js.org \n\n', 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');
require('./DPlayer.scss');
const utils = require('./utils.js');
const svg = require('./svg.js');
const handleOption = require('./option.js');
const i18n = require('./i18n.js');
const html = require('./html.js');
const Video = require('./video.js');
const isMobile = /mobile/i.test(window.navigator.userAgent);
let index = 0;
@ -65,8 +67,8 @@ class DPlayer {
document.head.appendChild(arrowStyle);
}
// get this video object
this.video = this.element.getElementsByClassName('dplayer-video')[0];
// get this video manager
this.video = new Video(this.element.getElementsByClassName('dplayer-video'));
// Support HTTP Live Streaming
let enablehls;
@ -82,7 +84,7 @@ class DPlayer {
if (enablehls && Hls.isSupported()) {
// this.element.getElementsByClassName('dplayer-time')[0].style.display = 'none';
const hls = new Hls();
hls.attachMedia(this.video);
hls.attachMedia(this.video.current);
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
hls.loadSource(this.option.video.url);
hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
@ -107,7 +109,7 @@ class DPlayer {
type: 'flv',
url: this.option.video.url
});
flvPlayer.attachMediaElement(this.video);
flvPlayer.attachMediaElement(this.video.current);
flvPlayer.load();
}
@ -146,43 +148,6 @@ class DPlayer {
conMask.addEventListener('click', toggleController);
}
/**
* Parse second to 00:00 format
*
* @param {Number} second
* @return {String} 00:00 format
*/
const secondToTime = (second) => {
const add0 = (num) => num < 10 ? '0' + num : '' + num;
const min = parseInt(second / 60);
const sec = parseInt(second - min * 60);
return add0(min) + ':' + add0(sec);
};
/**
* control play progress
*/
// get element's view position
const getElementViewLeft = (element) => {
let actualLeft = element.offsetLeft;
let current = element.offsetParent;
const elementScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) {
while (current !== null) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
}
else {
while (current !== null && current !== this.element) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
}
return actualLeft - elementScrollLeft;
};
const bar = {};
bar.playedBar = this.element.getElementsByClassName('dplayer-played')[0];
bar.loadedBar = this.element.getElementsByClassName('dplayer-loaded')[0];
@ -191,9 +156,9 @@ class DPlayer {
let barWidth;
if (this.option.danmaku) {
this.video.addEventListener('seeking', () => {
this.video.on('all', 'seeking', () => {
for (let i = 0; i < this.dan.length; i++) {
if (this.dan[i].time >= this.video.currentTime) {
if (this.dan[i].time >= this.video.currentTime()) {
this.danIndex = i;
return;
}
@ -209,30 +174,30 @@ class DPlayer {
this.setTime = () => {
this.playedTime = setInterval(() => {
// whether the video is buffering
currentPlayPos = this.video.currentTime;
currentPlayPos = this.video.currentTime();
if (!bufferingDetected
&& currentPlayPos < lastPlayPos + 0.01
&& !this.video.paused) {
&& !this.video.attr('paused')) {
this.element.classList.add('dplayer-loading');
bufferingDetected = true;
}
if (bufferingDetected
&& currentPlayPos > lastPlayPos + 0.01
&& !this.video.paused) {
&& !this.video.attr('paused')) {
this.element.classList.remove('dplayer-loading');
bufferingDetected = false;
}
lastPlayPos = currentPlayPos;
this.updateBar('played', this.video.currentTime / this.video.duration, 'width');
this.element.getElementsByClassName('dplayer-ptime')[0].innerHTML = secondToTime(this.video.currentTime);
this.updateBar('played', this.video.currentTime() / this.video.duration, 'width');
this.element.getElementsByClassName('dplayer-ptime')[0].innerHTML = utils.secondToTime(this.video.currentTime());
this.trigger('playing');
}, 100);
if (this.option.danmaku && showdan) {
danmakuTime = setInterval(() => {
if (this.dan) {
let item = this.dan[this.danIndex];
while (item && this.video.currentTime > parseFloat(item.time)) {
while (item && this.video.currentTime() > parseFloat(item.time)) {
this.pushDanmaku(item.text, item.color, item.type);
item = this.dan[++this.danIndex];
}
@ -250,16 +215,16 @@ class DPlayer {
pbar.addEventListener('click', (event) => {
const e = event || window.event;
barWidth = pbar.clientWidth;
let percentage = (e.clientX - getElementViewLeft(pbar)) / barWidth;
let percentage = (e.clientX - utils.getElementViewLeft(pbar)) / barWidth;
percentage = percentage > 0 ? percentage : 0;
percentage = percentage < 1 ? percentage : 1;
this.updateBar('played', percentage, 'width');
this.video.currentTime = parseFloat(bar.playedBar.style.width) / 100 * this.video.duration;
this.video.seek(parseFloat(bar.playedBar.style.width) / 100 * this.video.duration);
});
this.isTipsShow = false;
this.timeTipsHandler = this.timeTipsHandler(
pbar, pbarTimeTips, secondToTime).bind(this);
pbar, pbarTimeTips).bind(this);
pbar.addEventListener('mousemove', this.timeTipsHandler);
pbar.addEventListener('mouseover', this.timeTipsHandler);
pbar.addEventListener('mouseenter', this.timeTipsHandler);
@ -268,17 +233,17 @@ class DPlayer {
const thumbMove = (event) => {
const e = event || window.event;
let percentage = (e.clientX - getElementViewLeft(pbar)) / barWidth;
let percentage = (e.clientX - utils.getElementViewLeft(pbar)) / barWidth;
percentage = percentage > 0 ? percentage : 0;
percentage = percentage < 1 ? percentage : 1;
this.updateBar('played', percentage, 'width');
this.element.getElementsByClassName('dplayer-ptime')[0].innerHTML = secondToTime(percentage * this.video.duration);
this.element.getElementsByClassName('dplayer-ptime')[0].innerHTML = utils.secondToTime(percentage * this.video.duration);
};
const thumbUp = () => {
document.removeEventListener('mouseup', thumbUp);
document.removeEventListener('mousemove', thumbMove);
this.video.currentTime = parseFloat(bar.playedBar.style.width) / 100 * this.video.duration;
this.video.seek(parseFloat(bar.playedBar.style.width) / 100 * this.video.duration);
this.setTime();
};
@ -302,10 +267,10 @@ class DPlayer {
this.switchVolumeIcon = () => {
const volumeicon = this.element.getElementsByClassName('dplayer-volume-icon')[0];
if (this.video.volume >= 0.8) {
if (this.video.attr('volume') >= 0.8) {
volumeicon.innerHTML = svg('volume-up');
}
else if (this.video.volume > 0) {
else if (this.video.attr('volume') > 0) {
volumeicon.innerHTML = svg('volume-down');
}
else {
@ -314,7 +279,7 @@ class DPlayer {
};
const volumeMove = (event) => {
const e = event || window.event;
const percentage = (e.clientX - getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
const percentage = (e.clientX - utils.getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
this.volume(percentage);
};
const volumeUp = () => {
@ -325,7 +290,7 @@ class DPlayer {
volumeBarWrapWrap.addEventListener('click', (event) => {
const e = event || window.event;
const percentage = (e.clientX - getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
const percentage = (e.clientX - utils.getElementViewLeft(volumeBarWrap) - 5.5) / vWidth;
this.volume(percentage);
});
volumeBarWrapWrap.addEventListener('mousedown', () => {
@ -334,13 +299,13 @@ class DPlayer {
volumeEle.classList.add('dplayer-volume-active');
});
volumeicon.addEventListener('click', () => {
if (this.video.muted) {
this.video.muted = false;
if (this.video.attr('muted')) {
this.video.attr('muted', false);
this.switchVolumeIcon();
this.updateBar('volume', this.video.volume, 'width');
this.updateBar('volume', this.video.attr('volume'), 'width');
}
else {
this.video.muted = true;
this.video.attr('muted', true);
volumeicon.innerHTML = svg('volume-off');
this.updateBar('volume', 0, 'width');
}
@ -356,7 +321,7 @@ class DPlayer {
this.element.classList.remove('dplayer-hide-controller');
clearTimeout(hideTime);
hideTime = setTimeout(() => {
if (this.video.played.length) {
if (this.video.attr('played').length) {
this.element.classList.add('dplayer-hide-controller');
closeSetting();
closeComment();
@ -417,11 +382,9 @@ class DPlayer {
loopToggle.checked = !loopToggle.checked;
if (loopToggle.checked) {
loop = true;
this.video.loop = loop;
}
else {
loop = false;
this.video.loop = loop;
}
closeSetting();
});
@ -438,7 +401,7 @@ class DPlayer {
showdan = true;
if (this.option.danmaku) {
for (let i = 0; i < this.dan.length; i++) {
if (this.dan[i].time >= this.video.currentTime) {
if (this.dan[i].time >= this.video.currentTime()) {
this.danIndex = i;
break;
}
@ -446,7 +409,7 @@ class DPlayer {
}
danmakuTime = setInterval(() => {
let item = this.dan[this.danIndex];
while (item && this.video.currentTime >= parseFloat(item.time)) {
while (item && this.video.currentTime() >= parseFloat(item.time)) {
this.pushDanmaku(item.text, item.color, item.type);
item = this.dan[++this.danIndex];
}
@ -478,7 +441,7 @@ class DPlayer {
const speedItem = settingBox.getElementsByClassName('dplayer-setting-speed-item');
for (let i = 0; i < speedItem.length; i++) {
speedItem[i].addEventListener('click', () => {
this.video.playbackRate = speedItem[i].dataset.speed;
this.video.attr('playbackRate', speedItem[i].dataset.speed);
closeSetting();
});
}
@ -495,7 +458,7 @@ class DPlayer {
const danmakuMove = (event) => {
const e = event || window.event;
let percentage = (e.clientX - getElementViewLeft(danmakuBarWrap)) / dWidth;
let percentage = (e.clientX - utils.getElementViewLeft(danmakuBarWrap)) / dWidth;
percentage = percentage > 0 ? percentage : 0;
percentage = percentage < 1 ? percentage : 1;
this.updateBar('danmaku', percentage, 'width');
@ -514,7 +477,7 @@ class DPlayer {
danmakuBarWrapWrap.addEventListener('click', (event) => {
const e = event || window.event;
let percentage = (e.clientX - getElementViewLeft(danmakuBarWrap)) / dWidth;
let percentage = (e.clientX - utils.getElementViewLeft(danmakuBarWrap)) / dWidth;
percentage = percentage > 0 ? percentage : 0;
percentage = percentage < 1 ? percentage : 1;
this.updateBar('danmaku', percentage, 'width');
@ -539,61 +502,65 @@ class DPlayer {
* video events
*/
// show video time: the metadata has loaded or changed
this.video.addEventListener('durationchange', () => {
if (this.video.duration !== 1) { // compatibility: Android browsers will output 1 at first
this.element.getElementsByClassName('dplayer-dtime')[0].innerHTML = secondToTime(this.video.duration);
this.video.on('all', 'durationchange', (i, video) => {
if (video.duration !== 1) { // compatibility: Android browsers will output 1 at first
this.element.getElementsByClassName('dplayer-dtime')[0].innerHTML = utils.secondToTime(this.video.duration);
}
});
// show video loaded bar: to inform interested parties of progress downloading the media
this.video.addEventListener('progress', () => {
const percentage = this.video.buffered.length ? this.video.buffered.end(this.video.buffered.length - 1) / this.video.duration : 0;
this.video.on('current', 'progress', (i, video) => {
const percentage = video.buffered.length ? video.buffered.end(video.buffered.length - 1) / video.duration : 0;
this.updateBar('loaded', percentage, 'width');
});
// video download error: an error occurs
this.video.addEventListener('error', () => {
this.video.on('all', 'error', () => {
this.element.getElementsByClassName('dplayer-ptime')[0].innerHTML = `Error happens ╥﹏╥`;
this.trigger('pause');
});
// video can play: enough data is available that the media can be played
this.video.addEventListener('canplay', () => {
this.video.on('current', 'canplay', () => {
this.trigger('canplay');
});
// music end
this.ended = false;
this.video.addEventListener('ended', () => {
this.updateBar('played', 1, 'width');
if (!loop) {
this.ended = true;
this.pause();
this.trigger('ended');
this.video.on('all', 'ended', (i) => {
if (i === this.video.videos.length - 1) {
this.updateBar('played', 1, 'width');
console.log(loop);
if (!loop) {
this.ended = true;
this.pause();
this.trigger('ended');
}
else {
this.video.switch(0);
this.video.play();
}
}
});
this.video.addEventListener('play', () => {
this.video.on('current', 'play', () => {
if (this.paused) {
this.play();
}
});
this.video.addEventListener('pause', () => {
this.video.on('current', 'pause', () => {
if (!this.paused) {
this.pause();
}
});
// control volume
this.video.volume = parseInt(this.element.getElementsByClassName('dplayer-volume-bar-inner')[0].style.width) / 100;
// loop
this.video.loop = loop;
this.video.attr('volume', parseInt(this.element.getElementsByClassName('dplayer-volume-bar-inner')[0].style.width) / 100);
// set duration time
if (this.video.duration !== 1) { // compatibility: Android browsers will output 1 at first
this.element.getElementsByClassName('dplayer-dtime')[0].innerHTML = this.video.duration ? secondToTime(this.video.duration) : '00:00';
this.element.getElementsByClassName('dplayer-dtime')[0].innerHTML = this.video.duration ? utils.secondToTime(this.video.duration) : '00:00';
}
// danmaku
@ -650,7 +617,7 @@ class DPlayer {
token: this.option.danmaku.token,
player: this.option.danmaku.id,
author: this.option.danmaku.user,
time: this.video.currentTime,
time: this.video.currentTime(),
text: commentInput.value,
color: this.element.querySelector('.dplayer-comment-setting-color input:checked').value,
type: this.element.querySelector('.dplayer-comment-setting-type input:checked').value
@ -774,8 +741,8 @@ class DPlayer {
else if (this.element.webkitRequestFullscreen) {
this.element.webkitRequestFullscreen();
}
else if (this.video.webkitEnterFullscreen) { // Safari for iOS
this.video.webkitEnterFullscreen();
else if (this.video.attr('webkitEnterFullscreen')) { // Safari for iOS
this.video.current.webkitEnterFullscreen();
}
}
else {
@ -818,20 +785,20 @@ class DPlayer {
break;
case 37:
event.preventDefault();
this.video.currentTime = this.video.currentTime - 5;
this.video.seek(this.video.currentTime() - 5);
break;
case 39:
event.preventDefault();
this.video.currentTime = this.video.currentTime + 5;
this.video.seek(this.video.currentTime() + 5);
break;
case 38:
event.preventDefault();
percentage = this.video.volume + 0.1;
percentage = this.video.attr('volume') + 0.1;
this.volume(percentage);
break;
case 40:
event.preventDefault();
percentage = this.video.volume - 0.1;
percentage = this.video.attr('volume') - 0.1;
this.volume(percentage);
break;
}
@ -896,9 +863,9 @@ class DPlayer {
const camareIcon = this.element.getElementsByClassName('dplayer-camera-icon')[0];
camareIcon.addEventListener('click', () => {
const canvas = document.createElement("canvas");
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas.getContext('2d').drawImage(this.video, 0, 0, canvas.width, canvas.height);
canvas.width = this.video.attr('videoWidth');
canvas.height = this.video.attr('videoHeight');
canvas.getContext('2d').drawImage(this.video.current, 0, 0, canvas.width, canvas.height);
camareIcon.href = canvas.toDataURL();
camareIcon.download = "DPlayer.png";
@ -913,10 +880,10 @@ class DPlayer {
*/
play (time) {
if (Object.prototype.toString.call(time) === '[object Number]') {
this.video.currentTime = time;
this.video.seek(time);
}
this.paused = false;
if (this.video.paused) {
if (this.video.attr('paused')) {
this.bezel.innerHTML = svg('play');
this.bezel.classList.add('dplayer-bezel-transition');
}
@ -939,7 +906,7 @@ class DPlayer {
this.paused = true;
this.element.classList.remove('dplayer-loading');
if (!this.video.paused) {
if (!this.video.attr('paused')) {
this.bezel.innerHTML = svg('pause');
this.bezel.classList.add('dplayer-bezel-transition');
}
@ -959,9 +926,9 @@ class DPlayer {
percentage = percentage > 0 ? percentage : 0;
percentage = percentage < 1 ? percentage : 1;
this.updateBar('volume', percentage, 'width');
this.video.volume = percentage;
if (this.video.muted) {
this.video.muted = false;
this.video.attr('volume', percentage);
if (this.video.attr('muted')) {
this.video.attr('muted', false);
}
this.switchVolumeIcon();
}
@ -970,7 +937,7 @@ class DPlayer {
* Toggle between play and pause
*/
toggle () {
if (this.video.paused) {
if (this.video.attr('paused')) {
this.play();
}
else {
@ -981,9 +948,9 @@ class DPlayer {
/**
* attach event
*/
on (name, func) {
if (typeof func === 'function') {
this.event[name].push(func);
on (event, callback) {
if (typeof callback === 'function') {
this.event[event].push(callback);
}
}
@ -1147,6 +1114,7 @@ class DPlayer {
* @param {Object} video - new video info
* @param {Object} danmaku - new danmaku info
*/
// TODO
switchVideo (video, danmaku) {
this.video.src = video.url;
this.video.poster = video.pic ? video.pic : '';
@ -1171,7 +1139,7 @@ class DPlayer {
}
}
timeTipsHandler (pbar, timeTips, secondToTime) {
timeTipsHandler (pbar, timeTips) {
// http://stackoverflow.com/questions/1480133/how-can-i-get-an-objects-absolute-position-on-the-page-in-javascript
const cumulativeOffset = (element) => {
let top = 0, left = 0;
@ -1194,7 +1162,7 @@ class DPlayer {
const { clientX } = e;
const px = cumulativeOffset(pbar).left;
const tx = clientX - px;
timeTips.innerText = secondToTime(this.video.duration * (tx / pbar.offsetWidth));
timeTips.innerText = utils.secondToTime(this.video.duration * (tx / pbar.offsetWidth));
timeTips.style.left = `${(tx - 20)}px`;
switch (e.type) {
case 'mouseenter':

View File

@ -161,6 +161,11 @@
.dplayer-video {
width: 100%;
height: 100%;
display: none;
}
.dplayer-video-current {
display: block;
}
}

View File

@ -1,10 +1,15 @@
const svg = require('./svg.js');
module.exports = {
main: (option, index, tran) => `
main: (option, index, tran) => {
let videos = ``;
for (let i = 0; i < option.video.url.length; i++) {
videos += `<video class="dplayer-video ${i === 0 ? `dplayer-video-current"` : ``}" ${option.video.pic ? `poster="${option.video.pic}"` : ``} webkit-playsinline playsinline ${option.screenshot ? `crossorigin="anonymous"` : ``} preload="${option.video.url.length ? 'metadata' : option.preload}" src="${option.video.url[i]}"></video>`;
}
return `
<div class="dplayer-mask"></div>
<div class="dplayer-video-wrap">
<video class="dplayer-video" ${option.video.pic ? `poster="${option.video.pic}"` : ``} webkit-playsinline playsinline ${option.screenshot ? `crossorigin="anonymous"` : ``} preload="${option.preload}" src="${option.video.url}"></video>
${videos}
<div class="dplayer-danmaku">
<div class="dplayer-danmaku-item dplayer-danmaku-item--demo"></div>
</div>
@ -154,8 +159,8 @@ module.exports = {
<div class="dplayer-menu-item"><span class="dplayer-menu-label"><a target="_blank" href="http://diygod.me/">${tran('About author')}</a></span></div>
<div class="dplayer-menu-item"><span class="dplayer-menu-label"><a target="_blank" href="https://github.com/DIYgod/DPlayer/issues">${tran('DPlayer feedback')}</a></span></div>
<div class="dplayer-menu-item"><span class="dplayer-menu-label"><a target="_blank" href="https://github.com/DIYgod/DPlayer">${tran('About DPlayer')}</a></span></div>
</div>
`,
</div>`;
},
setting: (tran) => ({
'original': `

View File

@ -24,6 +24,9 @@ module.exports = (option) => {
option[defaultKey] = defaultOption[defaultKey];
}
}
if (Object.prototype.toString.call(option.video.url) !== '[object Array]') {
option.video.url = [option.video.url];
}
if (option.video && !option.video.hasOwnProperty('type')) {
option.video.type = 'auto';
}

38
src/utils.js Normal file
View File

@ -0,0 +1,38 @@
module.exports = {
/**
* Parse second to 00:00 format
*
* @param {Number} second
* @return {String} 00:00 format
*/
secondToTime: (second) => {
const add0 = (num) => num < 10 ? '0' + num : '' + num;
const min = parseInt(second / 60);
const sec = parseInt(second - min * 60);
return add0(min) + ':' + add0(sec);
},
/**
* control play progress
*/
// get element's view position
getElementViewLeft: (element) => {
let actualLeft = element.offsetLeft;
let current = element.offsetParent;
const elementScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) {
while (current !== null) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
}
else {
while (current !== null && current !== this.element) {
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
}
return actualLeft - elementScrollLeft;
},
};

133
src/video.js Normal file
View File

@ -0,0 +1,133 @@
class Video {
constructor (videos) {
this.videos = videos;
this.multi = this.videos.length > 1;
this.index = 0;
this.current = this.videos[this.index];
this.duration = 0;
this.durationArr = [];
this.eventAll = [];
this.eventCurrent = [];
this.on('all', 'durationchange', (i, video) => {
if (video.duration !== 1) { // some Android browsers will output 1 at first
this.durationArr[i] = video.duration;
this.duration = this.durationArr.reduce((sum, cur) => sum + cur);
}
});
this.on('current', 'end', () => {
this.switch(this.index + 1);
});
}
switch (index, time) {
if (this.index !== index) {
this.videos[index].classList.add('dplayer-video-current');
if (!this.current.paused) {
this.videos[index].play();
}
this.current.classList.remove('dplayer-video-current');
this.current.pause();
this.index = index;
this.current = this.videos[this.index];
this.videos[index].currentTime = time ? time : 0;
}
else {
this.videos[index].currentTime = time ? time : 0;
}
}
// bind event
on (type, event, callback) {
if (typeof callback === 'function') {
if (type === 'all') {
if (!this.eventAll[event]) {
this.eventAll[event] = [];
}
this.eventAll[event].push(callback);
}
else {
if (!this.eventCurrent[event]) {
this.eventCurrent[event] = [];
}
this.eventCurrent[event].push(callback);
}
if (['seeking'].indexOf(event) === -1) {
for (let i = 0; i < this.videos.length; i++) {
this.videos[i].addEventListener(event, () => {
if (type === 'all' || this.videos[i] === this.current) {
callback(i, this.videos[i]);
}
});
}
}
}
}
// trigger event
trigger (type, event) {
const events = type === 'all' ? this.eventAll : this.eventCurrent;
for (let i = 0; i < events[event].length; i++) {
events[event][i]();
}
}
currentTime () {
if (this.durationArr.slice(0, this.index).length) {
return this.durationArr.slice(0, this.index).reduce((sum, cur) => sum + cur) + this.current.currentTime;
}
else {
return this.current.currentTime;
}
}
seek (time) {
time = Math.max(time, 0);
time = Math.min(time, this.duration);
let i = 0;
let tmptime = 0;
while (tmptime <= time) {
tmptime += this.durationArr[i];
i++;
}
let currentTime;
if (this.durationArr.slice(0, this.index).length) {
currentTime = time - this.durationArr.slice(0, i - 1).reduce((sum, cur) => sum + cur);
}
else {
currentTime = time;
}
this.switch(i - 1, currentTime);
this.trigger('all', 'seeking');
}
attr (option, value) {
if (value !== undefined) {
for (let i = 0; i < this.videos.length; i++) {
this.videos[i][option] = value;
}
}
return this.current[option];
}
play () {
this.current.play();
}
pause () {
this.current.pause();
}
toggle () {
this.current.paused ? this.play() : this.pause();
}
}
module.exports = Video;