DPlayer/src/DPlayer.js

1068 lines
37 KiB
JavaScript

import './DPlayer.scss';
import utils, { isMobile } from './utils';
import handleOption from './options';
import i18n from './i18n';
import Template from './template';
import SvgCollection from './svg';
import Danmaku from './danmaku';
import Thumbnails from './thumbnails';
import Events from './events';
import FullScreen from './fullscreen';
import User from './user';
import Subtitle from './subtitle';
import Bar from './bar';
import Time from './time';
import Bezel from './bezel';
let index = 0;
const instances = [];
class DPlayer {
/**
* DPlayer constructor function
*
* @param {Object} options - See README
* @constructor
*/
constructor (options) {
this.options = handleOption(options);
if (this.options.video.quality) {
this.qualityIndex = this.options.video.defaultQuality;
this.quality = this.options.video.quality[this.options.video.defaultQuality];
}
this.tran = new i18n(this.options.lang).tran;
this.icons = new SvgCollection(this.options);
this.events = new Events();
this.user = new User(this);
this.container = this.options.container;
this.container.classList.add('dplayer');
if (!this.options.danmaku) {
this.container.classList.add('dplayer-no-danmaku');
}
if (this.options.live) {
this.container.classList.add('dplayer-live');
}
if (isMobile) {
this.container.classList.add('dplayer-mobile');
}
this.arrow = this.container.offsetWidth <= 500;
if (this.arrow) {
this.container.classList.add('dplayer-arrow');
}
this.template = new Template({
container: this.container,
options: this.options,
index: index,
tran: this.tran,
icons: this.icons
});
this.video = this.template.video;
this.bar = new Bar(this.template);
this.bezel = new Bezel(this.template.bezel);
if (this.options.danmaku) {
this.danmaku = new Danmaku({
container: this.template.danmaku,
opacity: this.user.get('opacity'),
callback: () => {
setTimeout(() => {
this.template.danmakuLoading.style.display = 'none';
// autoplay
if (this.options.autoplay && !isMobile) {
this.play();
}
else if (isMobile) {
this.pause();
}
}, 0);
},
error: (msg) => {
this.notice(msg);
},
apiBackend: this.options.apiBackend,
borderColor: this.options.theme,
height: this.arrow ? 24 : 30,
time: () => this.video.currentTime,
unlimited: this.user.get('unlimited'),
api: {
id: this.options.danmaku.id,
address: this.options.danmaku.api,
token: this.options.danmaku.token,
maximum: this.options.danmaku.maximum,
addition: this.options.danmaku.addition,
user: this.options.danmaku.user,
},
events: this.events
});
}
document.addEventListener('click', () => {
this.focus = false;
}, true);
this.container.addEventListener('click', () => {
this.focus = true;
}, true);
// play and pause button
this.paused = true;
this.template.playButton.addEventListener('click', () => {
this.toggle();
});
if (!isMobile) {
this.template.videoWrap.addEventListener('click', () => {
this.toggle();
});
this.template.controllerMask.addEventListener('click', () => {
this.toggle();
});
}
else {
const toggleController = () => {
if (this.container.classList.contains('dplayer-hide-controller')) {
this.container.classList.remove('dplayer-hide-controller');
}
else {
this.container.classList.add('dplayer-hide-controller');
}
};
this.template.videoWrap.addEventListener('click', toggleController);
this.template.controllerMask.addEventListener('click', toggleController);
}
this.time = new Time(this);
if (this.options.video.thumbnails) {
this.initThumbnails();
}
this.isTimeTipsShow = true;
this.mouseHandler = this.mouseHandler(this.template.playedBarWrap, this.template.playedBarTime).bind(this);
this.template.playedBarWrap.addEventListener('mousemove', this.mouseHandler);
this.template.playedBarWrap.addEventListener('mouseenter', this.mouseHandler);
this.template.playedBarWrap.addEventListener('mouseleave', this.mouseHandler);
let barWidth;
const thumbMove = (e) => {
let percentage = (e.clientX - utils.getElementViewLeft(this.template.playedBarWrap)) / barWidth;
percentage = Math.max(percentage, 0);
percentage = Math.min(percentage, 1);
this.bar.set('played', percentage, 'width');
this.template.ptime.innerHTML = utils.secondToTime(percentage * this.video.duration);
};
const thumbUp = (e) => {
document.removeEventListener('mouseup', thumbUp);
document.removeEventListener('mousemove', thumbMove);
let percentage = (e.clientX - utils.getElementViewLeft(this.template.playedBarWrap)) / barWidth;
percentage = Math.max(percentage, 0);
percentage = Math.min(percentage, 1);
this.bar.set('played', percentage, 'width');
this.seek(this.bar.get('played') * this.video.duration);
this.time.enable('progress');
};
this.template.playedBarWrap.addEventListener('mousedown', () => {
barWidth = this.template.playedBarWrap.clientWidth;
this.time.disable('progress');
document.addEventListener('mousemove', thumbMove);
document.addEventListener('mouseup', thumbUp);
});
/**
* control volume
*/
const vWidth = 35;
this.switchVolumeIcon = () => {
if (this.volume() >= 0.95) {
this.template.volumeIcon.innerHTML = this.icons.get('volume-up');
}
else if (this.volume() > 0) {
this.template.volumeIcon.innerHTML = this.icons.get('volume-down');
}
else {
this.template.volumeIcon.innerHTML = this.icons.get('volume-off');
}
};
const volumeMove = (event) => {
const e = event || window.event;
const percentage = (e.clientX - utils.getElementViewLeft(this.template.volumeBarWrap) - 5.5) / vWidth;
this.volume(percentage);
};
const volumeUp = () => {
document.removeEventListener('mouseup', volumeUp);
document.removeEventListener('mousemove', volumeMove);
this.template.volumeButton.classList.remove('dplayer-volume-active');
};
this.template.volumeBarWrapWrap.addEventListener('click', (event) => {
const e = event || window.event;
const percentage = (e.clientX - utils.getElementViewLeft(this.template.volumeBarWrap) - 5.5) / vWidth;
this.volume(percentage);
});
this.template.volumeBarWrapWrap.addEventListener('mousedown', () => {
document.addEventListener('mousemove', volumeMove);
document.addEventListener('mouseup', volumeUp);
this.template.volumeButton.classList.add('dplayer-volume-active');
});
this.template.volumeIcon.addEventListener('click', () => {
if (this.video.muted) {
this.video.muted = false;
this.switchVolumeIcon();
this.bar.set('volume', this.volume(), 'width');
}
else {
this.video.muted = true;
this.template.volumeIcon.innerHTML = this.icons.get('volume-off');
this.bar.set('volume', 0, 'width');
}
});
/**
* auto hide controller
*/
this.hideTime = 0;
const hideController = () => {
this.container.classList.remove('dplayer-hide-controller');
clearTimeout(this.hideTime);
this.hideTime = setTimeout(() => {
if (this.video.played.length && !this.disableHideController) {
this.container.classList.add('dplayer-hide-controller');
closeSetting();
closeComment();
}
}, 2000);
};
if (!isMobile) {
this.container.addEventListener('mousemove', hideController);
this.container.addEventListener('click', hideController);
}
/**
* setting
*/
// toggle setting box
const closeSetting = () => {
if (this.template.settingBox.classList.contains('dplayer-setting-box-open')) {
this.template.settingBox.classList.remove('dplayer-setting-box-open');
this.template.mask.classList.remove('dplayer-mask-show');
setTimeout(() => {
this.template.settingBox.classList.remove('dplayer-setting-box-narrow');
this.template.settingBox.classList.remove('dplayer-setting-box-speed');
}, 300);
}
this.disableHideController = false;
};
const openSetting = () => {
this.disableHideController = true;
this.template.settingBox.classList.add('dplayer-setting-box-open');
this.template.mask.classList.add('dplayer-mask-show');
};
this.template.mask.addEventListener('click', () => {
closeSetting();
});
this.template.settingButton.addEventListener('click', () => {
openSetting();
});
this.loop = this.options.loop;
let showdan = this.user.get('danmaku');
if (!showdan) {
this.danmaku && this.danmaku.hide();
}
let unlimitDan = this.user.get('unlimited');
// loop control
this.template.loopToggle.checked = this.loop;
this.template.loop.addEventListener('click', () => {
this.template.loopToggle.checked = !this.template.loopToggle.checked;
if (this.template.loopToggle.checked) {
this.loop = true;
}
else {
this.loop = false;
}
closeSetting();
});
// show danmaku control
this.template.showDanmakuToggle.checked = showdan;
this.template.showDanmaku.addEventListener('click', () => {
this.template.showDanmakuToggle.checked = !this.template.showDanmakuToggle.checked;
if (this.template.showDanmakuToggle.checked) {
showdan = true;
if (!this.paused) {
this.danmaku.show();
}
}
else {
showdan = false;
this.danmaku.hide();
}
this.user.set('danmaku', showdan ? 1 : 0);
closeSetting();
});
// unlimited danmaku control
this.template.unlimitDanmakuToggle.checked = unlimitDan;
this.template.unlimitDanmaku.addEventListener('click', () => {
this.template.unlimitDanmakuToggle.checked = !this.template.unlimitDanmakuToggle.checked;
if (this.template.unlimitDanmakuToggle.checked) {
unlimitDan = true;
this.danmaku.unlimit(true);
}
else {
unlimitDan = false;
this.danmaku.unlimit(false);
}
this.user.set('unlimited', unlimitDan ? 1 : 0);
closeSetting();
});
// speed control
this.template.speed.addEventListener('click', () => {
this.template.settingBox.classList.add('dplayer-setting-box-narrow');
this.template.settingBox.classList.add('dplayer-setting-box-speed');
for (let i = 0; i < this.template.speedItem.length; i++) {
this.template.speedItem[i].addEventListener('click', () => {
this.video.playbackRate = this.template.speedItem[i].dataset.speed;
closeSetting();
});
}
});
if (this.danmaku) {
// danmaku opacity
const dWidth = 130;
this.on('danmaku_opacity', (percentage) => {
this.bar.set('danmaku', percentage, 'width');
this.user.set('opacity', percentage);
});
this.danmaku.opacity(this.user.get('opacity'));
const danmakuMove = (event) => {
const e = event || window.event;
let percentage = (e.clientX - utils.getElementViewLeft(this.template.danmakuOpacityBarWrap)) / dWidth;
percentage = Math.max(percentage, 0);
percentage = Math.min(percentage, 1);
this.danmaku.opacity(percentage);
};
const danmakuUp = () => {
document.removeEventListener('mouseup', danmakuUp);
document.removeEventListener('mousemove', danmakuMove);
this.template.danmakuOpacityBox.classList.remove('dplayer-setting-danmaku-active');
};
this.template.danmakuOpacityBarWrapWrap.addEventListener('click', (event) => {
const e = event || window.event;
let percentage = (e.clientX - utils.getElementViewLeft(this.template.danmakuOpacityBarWrap)) / dWidth;
percentage = Math.max(percentage, 0);
percentage = Math.min(percentage, 1);
this.danmaku.opacity(percentage);
});
this.template.danmakuOpacityBarWrapWrap.addEventListener('mousedown', () => {
document.addEventListener('mousemove', danmakuMove);
document.addEventListener('mouseup', danmakuUp);
this.template.danmakuOpacityBox.classList.add('dplayer-setting-danmaku-active');
});
}
// set duration time
if (this.video.duration !== 1) { // compatibility: Android browsers will output 1 at first
this.template.dtime.innerHTML = this.video.duration ? utils.secondToTime(this.video.duration) : '00:00';
}
if (!this.danmaku) {
// autoplay
if (this.options.autoplay && !isMobile) {
this.play();
}
else if (isMobile) {
this.pause();
}
}
/**
* comment
*/
const closeCommentSetting = () => {
if (this.template.commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
this.template.commentSettingBox.classList.remove('dplayer-comment-setting-open');
}
};
const toggleCommentSetting = () => {
if (this.template.commentSettingBox.classList.contains('dplayer-comment-setting-open')) {
this.template.commentSettingBox.classList.remove('dplayer-comment-setting-open');
}
else {
this.template.commentSettingBox.classList.add('dplayer-comment-setting-open');
}
};
const closeComment = () => {
if (!this.template.controller.classList.contains('dplayer-controller-comment')) {
return;
}
this.template.controller.classList.remove('dplayer-controller-comment');
this.template.mask.classList.remove('dplayer-mask-show');
this.container.classList.remove('dplayer-show-controller');
closeCommentSetting();
this.disableHideController = false;
};
const openComment = () => {
this.disableHideController = true;
if (!this.template.controller.classList.contains('dplayer-controller-comment')) {
this.template.controller.classList.add('dplayer-controller-comment');
this.template.mask.classList.add('dplayer-mask-show');
this.container.classList.add('dplayer-show-controller');
this.template.commentInput.focus();
}
};
this.template.mask.addEventListener('click', () => {
closeComment();
});
this.template.commentButton.addEventListener('click', () => {
openComment();
});
this.template.commentSettingButton.addEventListener('click', () => {
toggleCommentSetting();
});
// comment setting box
this.template.commentColorSettingBox.addEventListener('click', () => {
const sele = this.template.commentColorSettingBox.querySelector(`input:checked+span`);
if (sele) {
const color = this.template.commentColorSettingBox.querySelector(`input:checked`).value;
this.template.commentSettingFill.style.fill = color;
this.template.commentInput.style.color = color;
this.template.commentSendFill.style.fill = color;
}
});
const sendComment = () => {
this.template.commentInput.blur();
// text can't be empty
if (!this.template.commentInput.value.replace(/^\s+|\s+$/g, '')) {
this.notice(this.tran('Please input danmaku content!'));
return;
}
this.danmaku.send({
text: this.template.commentInput.value,
color: this.container.querySelector('.dplayer-comment-setting-color input:checked').value,
type: this.container.querySelector('.dplayer-comment-setting-type input:checked').value
}, () => {
this.template.commentInput.value = '';
closeComment();
});
};
this.template.commentInput.addEventListener('click', () => {
closeCommentSetting();
});
this.template.commentInput.addEventListener('keydown', (e) => {
const event = e || window.event;
if (event.keyCode === 13) {
sendComment();
}
});
this.template.commentSendButton.addEventListener('click', sendComment);
this.fullScreen = new FullScreen(this);
// browser full screen
this.template.browserFullButton.addEventListener('click', () => {
this.fullScreen.toggle('browser');
});
// web full screen
this.template.webFullButton.addEventListener('click', () => {
this.fullScreen.toggle('web');
});
/**
* hot key
*/
const handleKeyDown = (e) => {
if (this.focus) {
const tag = document.activeElement.tagName.toUpperCase();
const editable = document.activeElement.getAttribute('contenteditable');
if (tag !== 'INPUT' && tag !== 'TEXTAREA' && editable !== '' && editable !== 'true') {
const event = e || window.event;
let percentage;
switch (event.keyCode) {
case 32:
event.preventDefault();
this.toggle();
break;
case 37:
event.preventDefault();
this.seek(this.video.currentTime - 5);
hideController();
break;
case 39:
event.preventDefault();
this.seek(this.video.currentTime + 5);
hideController();
break;
case 38:
event.preventDefault();
percentage = this.volume() + 0.1;
this.volume(percentage);
break;
case 40:
event.preventDefault();
percentage = this.volume() - 0.1;
this.volume(percentage);
break;
}
}
}
};
if (this.options.hotkey) {
document.addEventListener('keydown', handleKeyDown);
}
document.addEventListener('keydown', (e) => { // Press ESC to quit web full screen
const event = e || window.event;
switch (event.keyCode) {
case 27:
if (this.fullScreen.isFullScreen('web')) {
this.fullScreen.cancel('web');
}
break;
}
});
/**
* right key
*/
this.container.addEventListener('contextmenu', (e) => {
const event = e || window.event;
event.preventDefault();
this.template.menu.classList.add('dplayer-menu-show');
const clientRect = this.container.getBoundingClientRect();
const menuLeft = event.clientX - clientRect.left;
const menuTop = event.clientY - clientRect.top;
if (menuLeft + this.template.menu.offsetWidth >= clientRect.width) {
this.template.menu.style.right = clientRect.width - menuLeft + 'px';
this.template.menu.style.left = 'initial';
}
else {
this.template.menu.style.left = event.clientX - this.container.getBoundingClientRect().left + 'px';
this.template.menu.style.right = 'initial';
}
if (menuTop + this.template.menu.offsetHeight >= clientRect.height) {
this.template.menu.style.bottom = clientRect.height - menuTop + 'px';
this.template.menu.style.top = 'initial';
}
else {
this.template.menu.style.top = event.clientY - this.container.getBoundingClientRect().top + 'px';
this.template.menu.style.bottom = 'initial';
}
this.template.mask.classList.add('dplayer-mask-show');
this.events.trigger('contextmenu_show');
this.template.mask.addEventListener('click', () => {
this.template.mask.classList.remove('dplayer-mask-show');
this.template.menu.classList.remove('dplayer-menu-show');
this.events.trigger('contextmenu_hide');
});
});
/**
* Switch quality
*/
if (this.options.video.quality) {
this.template.qualityList.addEventListener('click', (e) => {
if (e.target.classList.contains('dplayer-quality-item')) {
this.switchQuality(e.target.dataset.index);
}
});
}
/**
* Screenshot
*/
if (this.options.screenshot) {
this.template.camareButton.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);
const dataURL = canvas.toDataURL();
this.template.camareButton.href = dataURL;
this.template.camareButton.download = "DPlayer.png";
this.events.trigger('screenshot', dataURL);
});
}
/**
* Toggle subtitle
*/
if (this.options.subtitle) {
this.events.on('subtitle_show', () => {
this.template.subtitleButton.dataset.balloon = this.tran('Hide subtitle');
this.template.subtitleButtonInner.style.opacity = '';
this.user.set('subtitle', 1);
});
this.events.on('subtitle_hide', () => {
this.template.subtitleButton.dataset.balloon = this.tran('Show subtitle');
this.template.subtitleButtonInner.style.opacity = '0.4';
this.user.set('subtitle', 0);
});
this.template.subtitleButton.addEventListener('click', () => {
this.subtitle.toggle();
});
}
this.initVideo(this.video, this.quality && this.quality.type || this.options.video.type);
index++;
instances.push(this);
}
/**
* Seek video
*/
seek (time) {
time = Math.max(time, 0);
if (this.video.duration) {
time = Math.min(time, this.video.duration);
}
if (this.video.currentTime < time) {
this.notice(`${this.tran('FF')} ${(time - this.video.currentTime).toFixed(0)} ${this.tran('s')}`);
}
else if (this.video.currentTime > time) {
this.notice(`${this.tran('REW')} ${(this.video.currentTime - time).toFixed(0)} ${this.tran('s')}`);
}
this.video.currentTime = time;
if (this.danmaku) {
this.danmaku.seek();
}
this.bar.set('played', time / this.video.duration, 'width');
}
/**
* Play video
*/
play () {
this.paused = false;
if (this.video.paused) {
this.bezel.switch(this.icons.get('play'));
}
this.template.playButton.innerHTML = this.icons.get('pause');
this.video.play();
this.time.enable();
this.container.classList.add('dplayer-playing');
if (this.danmaku) {
this.danmaku.play();
}
if (this.options.mutex) {
for (let i = 0; i < instances.length; i++) {
if (this !== instances[i]) {
instances[i].pause();
}
}
}
}
/**
* Pause video
*/
pause () {
this.paused = true;
this.container.classList.remove('dplayer-loading');
if (!this.video.paused) {
this.bezel.switch(this.icons.get('pause'));
}
this.ended = false;
this.template.playButton.innerHTML = this.icons.get('play');
this.video.pause();
this.time.disable();
this.container.classList.remove('dplayer-playing');
if (this.danmaku) {
this.danmaku.pause();
}
}
/**
* Set volume
*/
volume (percentage, nostorage, nonotice) {
percentage = parseFloat(percentage);
if (!isNaN(percentage)) {
percentage = Math.max(percentage, 0);
percentage = Math.min(percentage, 1);
this.bar.set('volume', percentage, 'width');
const formatPercentage = `${(percentage * 100).toFixed(0)}%`;
this.template.volumeBarWrapWrap.dataset.balloon = formatPercentage;
if (!nostorage) {
this.user.set('volume', percentage);
}
if (!nonotice) {
this.notice(`${this.tran('Volume')} ${(percentage * 100).toFixed(0)}%`);
}
this.video.volume = percentage;
if (this.video.muted) {
this.video.muted = false;
}
this.switchVolumeIcon();
}
return this.video.volume;
}
/**
* Toggle between play and pause
*/
toggle () {
if (this.video.paused) {
this.play();
}
else {
this.pause();
}
}
/**
* attach event
*/
on (name, callback) {
this.events.on(name, callback);
}
/**
* Switch to a new video
*
* @param {Object} video - new video info
* @param {Object} danmaku - new danmaku info
*/
switchVideo (video, danmakuAPI) {
this.pause();
this.video.poster = video.pic ? video.pic : '';
this.video.src = video.url;
this.initMSE(this.video, video.type || 'auto');
if (danmakuAPI) {
this.template.danmakuLoading.style.display = 'block';
this.bar.set('played', 0, 'width');
this.bar.set('loaded', 0, 'width');
this.template.ptime.innerHTML = '00:00';
this.template.danmaku.innerHTML = '';
if (this.danmaku) {
this.danmaku.reload({
id: danmakuAPI.id,
address: danmakuAPI.api,
token: danmakuAPI.token,
maximum: danmakuAPI.maximum,
addition: danmakuAPI.addition,
user: danmakuAPI.user,
});
}
}
}
initMSE (video, type) {
this.type = type;
if (this.type === 'auto') {
if (/m3u8(#|\?|$)/i.exec(video.src)) {
this.type = 'hls';
}
else if (/.flv(#|\?|$)/i.exec(video.src)) {
this.type = 'flv';
}
else if (/.mpd(#|\?|$)/i.exec(video.src)) {
this.type = 'dash';
}
else {
this.type = 'normal';
}
}
// HTTP Live Streaming
if (this.type === 'hls' && Hls && Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
}
// FLV
if (this.type === 'flv' && flvjs && flvjs.isSupported()) {
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: video.src
});
flvPlayer.attachMediaElement(video);
flvPlayer.load();
}
// MPEG DASH
if (this.type === 'dash' && dashjs) {
dashjs.MediaPlayer().create().initialize(video, video.src, false);
}
}
initVideo (video, type) {
this.initMSE(video, type);
/**
* video events
*/
// show video time: the metadata has loaded or changed
this.on('durationchange', () => {
if (video.duration !== 1) { // compatibility: Android browsers will output 1 at first
this.template.dtime.innerHTML = utils.secondToTime(video.duration);
}
});
// show video loaded bar: to inform interested parties of progress downloading the media
this.on('progress', () => {
const percentage = video.buffered.length ? video.buffered.end(video.buffered.length - 1) / video.duration : 0;
this.bar.set('loaded', percentage, 'width');
});
// video download error: an error occurs
this.on('error', () => {
this.tran && this.notice && this.notice(this.tran('This video fails to load'), -1);
});
// video end
this.ended = false;
this.on('ended', () => {
this.bar.set('played', 1, 'width');
if (!this.loop) {
this.ended = true;
this.pause();
}
else {
this.seek(0);
video.play();
}
if (this.danmaku) {
this.danmaku.danIndex = 0;
}
});
this.on('play', () => {
if (this.paused) {
this.play();
}
});
this.on('pause', () => {
if (!this.paused) {
this.pause();
}
});
for (let i = 0; i < this.events.videoEvents.length; i++) {
video.addEventListener(this.events.videoEvents[i], () => {
this.events.trigger(this.events.videoEvents[i]);
});
}
this.volume(this.user.get('volume'), true, true);
if (this.options.subtitle) {
this.subtitle = new Subtitle(this.template.subtitle, this.video, this.options.subtitle, this.events);
if (!this.user.get('subtitle')) {
this.subtitle.hide();
}
}
}
switchQuality (index) {
if (this.qualityIndex === index || this.switchingQuality) {
return;
}
else {
this.qualityIndex = index;
}
this.switchingQuality = true;
this.quality = this.options.video.quality[index];
this.template.qualityButton.innerHTML = this.quality.name;
const paused = this.video.paused;
this.video.pause();
const videoHTML = this.template.tplVideo(false, null, this.options.screenshot, 'auto', this.quality.url, this.options.subtitle);
const videoEle = new DOMParser().parseFromString(videoHTML, 'text/html').body.firstChild;
this.template.videoWrap.insertBefore(videoEle, this.template.videoWrap.getElementsByTagName('div')[0]);
this.prevVideo = this.video;
this.video = videoEle;
this.initVideo(this.video, this.quality.type || this.options.video.type);
this.seek(this.prevVideo.currentTime);
this.notice(`${this.tran('Switching to')} ${this.quality.name} ${this.tran('quality')}`, -1);
this.events.trigger('quality_start', this.quality);
this.on('canplay', () => {
if (this.prevVideo) {
if (this.video.currentTime !== this.prevVideo.currentTime) {
this.seek(this.prevVideo.currentTime);
return;
}
this.template.videoWrap.removeChild(this.prevVideo);
this.video.classList.add('dplayer-video-current');
if (!paused) {
this.video.play();
}
this.prevVideo = null;
this.notice(`${this.tran('Switched to')} ${this.quality.name} ${this.tran('quality')}`);
this.switchingQuality = false;
this.events.trigger('quality_end');
}
});
}
mouseHandler (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;
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return {
top: top,
left: left
};
};
return (e) => {
if (!this.video.duration) {
return;
}
const { clientX } = e;
const px = cumulativeOffset(pbar).left;
const tx = clientX - px;
if (tx < 0 || tx > pbar.offsetWidth) {
return;
}
const time = this.video.duration * (tx / pbar.offsetWidth);
timeTips.style.left = `${(tx - 20)}px`;
switch (e.type) {
case 'mouseenter':
this.thumbnails && this.thumbnails.show();
break;
case 'mousemove':
this.thumbnails && this.thumbnails.move(tx);
timeTips.innerText = utils.secondToTime(time);
this.timeTipsDisplay(true, timeTips);
break;
case 'mouseleave':
this.thumbnails && this.thumbnails.hide();
this.timeTipsDisplay(false, timeTips);
break;
}
};
}
timeTipsDisplay (show, timeTips) {
if (show) {
if (this.isTimeTipsShow) {
return;
}
timeTips.classList.remove('hidden');
this.isTimeTipsShow = true;
} else {
if (!this.isTimeTipsShow) {
return;
}
timeTips.classList.add('hidden');
this.isTimeTipsShow = false;
}
}
initThumbnails () {
this.thumbnails = new Thumbnails(this.template.barPreview, this.template.barWrap.offsetWidth, this.options.video.thumbnails, this.events);
this.on('loadedmetadata', () => {
this.thumbnails.resize(160, 90);
});
}
notice (text, time = 2000, opacity = 0.8) {
this.template.notice.innerHTML = text;
this.template.notice.style.opacity = opacity;
if (this.noticeTime) {
clearTimeout(this.noticeTime);
}
this.events.trigger('notice_show', text);
this.noticeTime = setTimeout(() => {
this.template.notice.style.opacity = 0;
this.events.trigger('notice_hide');
}, time);
}
resize () {
if (this.danmaku) {
this.danmaku.resize();
}
this.events.trigger('resize');
}
destroy () {
instances.splice(instances.indexOf(this), 1);
this.pause();
clearTimeout(this.hideTime);
this.time.destroy();
this.video.src = '';
this.container.innerHTML = '';
this.events.trigger('destroy');
for (const key in this) {
if (this.hasOwnProperty(key) && key !== 'paused') {
delete this[key];
}
}
}
}
module.exports = DPlayer;