mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 08:51:20 -08:00
分离部分工具函数
This commit is contained in:
1 parent
d6e35781ca
commit
748ce304e6
15 files changed
+244
-417
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { setStyle } from '../utils';
|
||||
import componentMethod from '../utils/componentMethod';
|
||||
import component from '../utils/component';
|
||||
import playbackRate from './playbackRate';
|
||||
import aspectRatio from './aspectRatio';
|
||||
import info from './info';
|
||||
@@ -71,7 +71,7 @@ export default class Contextmenu {
|
||||
|
||||
add(item, callback) {
|
||||
const { $contextmenu } = this.art.refs;
|
||||
componentMethod(this.art, this, $contextmenu, item, callback, 'contextmenu');
|
||||
component(this.art, this, $contextmenu, item, callback, 'contextmenu');
|
||||
}
|
||||
|
||||
setPos(event) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import componentMethod from '../utils/componentMethod';
|
||||
import component from '../utils/component';
|
||||
import fullscreen from './fullscreen';
|
||||
import fullscreenWeb from './fullscreenWeb';
|
||||
import pip from './pip';
|
||||
@@ -156,7 +156,7 @@ export default class Controls {
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
componentMethod(this.art, this, parent, option, callback, 'control');
|
||||
component(this.art, this, parent, option, callback, 'control');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class Info {
|
||||
const { $info, $infoPanel } = this.art.refs;
|
||||
setStyle($info, 'display', 'block');
|
||||
if (!$infoPanel.innerHTML) {
|
||||
append($infoPanel, this.creatInfo());
|
||||
append($infoPanel, Info.creatInfo());
|
||||
this.getHeader();
|
||||
}
|
||||
clearTimeout(this.timer);
|
||||
@@ -33,7 +33,7 @@ export default class Info {
|
||||
this.art.emit('info:show', $info);
|
||||
}
|
||||
|
||||
creatInfo() {
|
||||
static creatInfo() {
|
||||
const infoHtml = [];
|
||||
|
||||
infoHtml.push(`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { setStyle } from './utils';
|
||||
import componentMethod from './utils/componentMethod';
|
||||
import component from './utils/component';
|
||||
|
||||
export default class Layers {
|
||||
constructor(art) {
|
||||
@@ -13,7 +13,7 @@ export default class Layers {
|
||||
|
||||
add(item, callback) {
|
||||
const { $layers } = this.art.refs;
|
||||
componentMethod(this.art, this, $layers, item, callback, 'layer');
|
||||
component(this.art, this, $layers, item, callback, 'layer');
|
||||
}
|
||||
|
||||
show() {
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
import { ArtPlayerError, errorHandle, getExt } from './utils';
|
||||
import config from './config';
|
||||
|
||||
export default class Mse {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.setMimeCodec();
|
||||
this.init();
|
||||
this.eventBind();
|
||||
this.eventStart();
|
||||
this.repeat = 0;
|
||||
this.maxRepeat = 5;
|
||||
}
|
||||
|
||||
setMimeCodec() {
|
||||
const { option } = this.art;
|
||||
if (!option.type) {
|
||||
const type = getExt(option.url);
|
||||
errorHandle(
|
||||
Object.keys(config.mimeCodec).includes(type),
|
||||
`Can't find video's type '${type}' from '${option.url}'`,
|
||||
);
|
||||
option.type = type;
|
||||
}
|
||||
|
||||
if (!option.mimeCodec) {
|
||||
const mimeCodec = config.mimeCodec[option.type];
|
||||
errorHandle(mimeCodec, `Can't find video's mimeCodec from ${option.type}`);
|
||||
option.mimeCodec = mimeCodec;
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
option,
|
||||
refs: { $video },
|
||||
} = this.art;
|
||||
errorHandle(
|
||||
MediaSource.isTypeSupported(option.mimeCodec),
|
||||
`Unsupported MIME type or codec: ${option.mimeCodec}`,
|
||||
);
|
||||
this.mediaSource = new MediaSource();
|
||||
$video.src = URL.createObjectURL(this.mediaSource);
|
||||
this.art.events.destroyEvents.push(() => {
|
||||
URL.revokeObjectURL($video.src);
|
||||
});
|
||||
}
|
||||
|
||||
eventBind() {
|
||||
const { proxy } = this.art.events;
|
||||
const { mediaSource, sourceBufferList } = config.mse;
|
||||
|
||||
mediaSource.events.forEach(eventName => {
|
||||
proxy(this.mediaSource, eventName, event => {
|
||||
this.art.emit(`mediaSource:${event.type}`, event);
|
||||
});
|
||||
});
|
||||
|
||||
sourceBufferList.events.forEach(eventName => {
|
||||
proxy(this.mediaSource.sourceBuffers, eventName, event => {
|
||||
this.art.emit(`sourceBuffers:${event.type}`, event);
|
||||
});
|
||||
proxy(this.mediaSource.activeSourceBuffers, eventName, event => {
|
||||
this.art.emit(`activeSourceBuffers:${event.type}`, event);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
eventStart() {
|
||||
const { option } = this.art;
|
||||
const { proxy } = this.art.events;
|
||||
const { sourceBuffer } = config.mse;
|
||||
|
||||
this.art.on('mediaSource:sourceopen', () => {
|
||||
this.sourceBuffer = this.mediaSource.addSourceBuffer(option.mimeCodec);
|
||||
sourceBuffer.events.forEach(eventName => {
|
||||
proxy(this.sourceBuffer, eventName, event => {
|
||||
this.art.emit(`sourceBuffer:${event.type}`, event);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.art.on('sourceBuffer:updateend', () => {
|
||||
this.mediaSource.endOfStream();
|
||||
});
|
||||
|
||||
this.fetchUrl();
|
||||
}
|
||||
|
||||
fetchUrl() {
|
||||
const {
|
||||
option: { url },
|
||||
notice,
|
||||
i18n,
|
||||
loading,
|
||||
} = this.art;
|
||||
this.art.emit('player:fetch:start', url);
|
||||
this.request(url)
|
||||
.then(response => {
|
||||
this.sourceBuffer.appendBuffer(response);
|
||||
this.art.emit('player:fetch:success', url);
|
||||
})
|
||||
.catch(err => {
|
||||
this.repeat += 1;
|
||||
if (this.repeat < this.maxRepeat) {
|
||||
this.fetchUrl();
|
||||
} else {
|
||||
notice.show(i18n.get('Video load failed'));
|
||||
console.warn(err);
|
||||
loading.hide();
|
||||
this.art.emit('player:fetch:failure', url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
request(url) {
|
||||
return fetch(url)
|
||||
.then(response => response.arrayBuffer())
|
||||
.catch(err => {
|
||||
throw new ArtPlayerError(err.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { setStyle } from '../utils';
|
||||
import componentMethod from '../utils/componentMethod';
|
||||
import component from '../utils/component';
|
||||
import flip from './flip';
|
||||
|
||||
export default class Setting {
|
||||
@@ -34,7 +34,7 @@ export default class Setting {
|
||||
|
||||
add(item, callback) {
|
||||
const { $settingBody } = this.art.refs;
|
||||
componentMethod(this.art, this, $settingBody, item, callback, 'setting');
|
||||
component(this.art, this, $settingBody, item, callback, 'setting');
|
||||
}
|
||||
|
||||
show() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { errorHandle, getExt, setStyles, setStyle } from './utils';
|
||||
import { errorHandle, setStyles, setStyle } from './utils';
|
||||
import { srtToVtt, vttToBlob } from './utils/subtitle';
|
||||
|
||||
export default class Subtitle {
|
||||
constructor(art) {
|
||||
@@ -7,7 +8,6 @@ export default class Subtitle {
|
||||
this.vttText = '';
|
||||
const { url } = this.art.option.subtitle;
|
||||
if (url) {
|
||||
this.checkExt(url);
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
@@ -55,11 +55,11 @@ export default class Subtitle {
|
||||
})
|
||||
.then(text => {
|
||||
if (/x-subrip/gi.test(type)) {
|
||||
this.vttText = this.srtToVtt(text);
|
||||
this.vttText = srtToVtt(text);
|
||||
} else {
|
||||
this.vttText = text;
|
||||
}
|
||||
return this.vttToBlob(this.vttText);
|
||||
return vttToBlob(this.vttText);
|
||||
})
|
||||
.catch(err => {
|
||||
notice.show(err);
|
||||
@@ -68,34 +68,6 @@ export default class Subtitle {
|
||||
});
|
||||
}
|
||||
|
||||
srtToVtt(text) {
|
||||
return 'WEBVTT \r\n\r\n'.concat(
|
||||
text
|
||||
.replace(/\{\\([ibu])\}/g, '</$1>')
|
||||
.replace(/\{\\([ibu])1\}/g, '<$1>')
|
||||
.replace(/\{([ibu])\}/g, '<$1>')
|
||||
.replace(/\{\/([ibu])\}/g, '</$1>')
|
||||
.replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g, '$1.$2')
|
||||
.concat('\r\n\r\n'),
|
||||
);
|
||||
}
|
||||
|
||||
vttToBlob(vttText) {
|
||||
return URL.createObjectURL(
|
||||
new Blob([vttText], {
|
||||
type: 'text/vtt',
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
checkExt(url) {
|
||||
const ext = getExt(url);
|
||||
errorHandle(
|
||||
ext === 'vtt' || ext === 'srt',
|
||||
`'subtitle.url' option require 'vtt' or 'srt' format, but got '${ext}'.`,
|
||||
);
|
||||
}
|
||||
|
||||
show() {
|
||||
const {
|
||||
refs: { $subtitle },
|
||||
@@ -130,7 +102,6 @@ export default class Subtitle {
|
||||
|
||||
switch(url) {
|
||||
const { $track } = this.art.refs;
|
||||
this.checkExt(url);
|
||||
errorHandle($track, 'You need to initialize the subtitle option first.');
|
||||
this.load(url).then(data => {
|
||||
$track.src = data;
|
||||
|
||||
+28
-28
@@ -1,57 +1,57 @@
|
||||
import { append, insertByIndex, setStyles, setStyle } from './index';
|
||||
|
||||
function commonMethod(art, option, $element, title) {
|
||||
Object.defineProperty(option, '$ref', {
|
||||
get: () => $element,
|
||||
});
|
||||
|
||||
Object.defineProperty(option, 'hide', {
|
||||
value: () => {
|
||||
setStyle($element, 'display', 'none');
|
||||
art.emit(`${title}:hide`, $element);
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(option, 'show', {
|
||||
value: () => {
|
||||
setStyle($element, 'display', 'block');
|
||||
art.emit(`${title}:show`, $element);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default function componentMethod(art, parent, target, component, callback, title) {
|
||||
const { proxy } = art.events;
|
||||
export default function component(art, parent, target, component, callback, title) {
|
||||
const option = typeof component === 'function' ? component(art) : component;
|
||||
if (!option.disable) {
|
||||
if (parent.id === undefined) {
|
||||
parent.id = 0;
|
||||
}
|
||||
parent.id += 1;
|
||||
const name = option.name || `${title}${parent.id}`;
|
||||
const $element = document.createElement('div');
|
||||
$element.classList.value = `art-${title} art-${title}-${name}`;
|
||||
insertByIndex(target, $element, option.index || parent.id);
|
||||
|
||||
if (option.html) {
|
||||
append($element, option.html);
|
||||
}
|
||||
|
||||
if (option.style) {
|
||||
setStyles($element, option.style);
|
||||
}
|
||||
|
||||
if (option.click) {
|
||||
proxy($element, 'click', event => {
|
||||
art.events.proxy($element, 'click', event => {
|
||||
event.preventDefault();
|
||||
option.click.call(parent, event);
|
||||
art.emit(`${title}:click`, $element);
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(option, '$ref', {
|
||||
get: () => $element,
|
||||
});
|
||||
|
||||
Object.defineProperty(option, 'hide', {
|
||||
value: () => {
|
||||
setStyle($element, 'display', 'none');
|
||||
art.emit(`${title}:hide`, $element);
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(option, 'show', {
|
||||
value: () => {
|
||||
setStyle($element, 'display', 'block');
|
||||
art.emit(`${title}:show`, $element);
|
||||
},
|
||||
});
|
||||
|
||||
insertByIndex(target, $element, option.index || parent.id);
|
||||
|
||||
if (option.mounted) {
|
||||
option.mounted($element);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback($element);
|
||||
}
|
||||
commonMethod(art, option, $element, title);
|
||||
|
||||
parent[name] = option;
|
||||
art.emit(`${title}:add`, option);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
export function append(parent, child) {
|
||||
if (child instanceof Element) {
|
||||
parent.appendChild(child);
|
||||
} else {
|
||||
parent.insertAdjacentHTML('beforeend', child);
|
||||
}
|
||||
return parent.lastElementChild;
|
||||
}
|
||||
|
||||
export function insertByIndex(parent, child, index) {
|
||||
const childs = Array.from(parent.children);
|
||||
child.dataset.index = index;
|
||||
const nextChild = childs.find(item => Number(item.dataset.index) >= Number(index));
|
||||
if (nextChild) {
|
||||
nextChild.insertAdjacentElement('beforebegin', child);
|
||||
} else {
|
||||
append(parent, child);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
export function setStyle(element, key, value) {
|
||||
element.style[key] = value;
|
||||
return element;
|
||||
}
|
||||
|
||||
export function setStyles(element, styles) {
|
||||
Object.keys(styles).forEach(key => {
|
||||
setStyle(element, key, styles[key]);
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
export function getStyle(element, key, numberType = true) {
|
||||
const value = window.getComputedStyle(element, null).getPropertyValue(key);
|
||||
return numberType ? parseFloat(value) : value;
|
||||
}
|
||||
|
||||
export function sublings(target) {
|
||||
return Array.from(target.parentElement.children).filter(item => item !== target);
|
||||
}
|
||||
|
||||
export function inverseClass(target, className) {
|
||||
sublings(target).forEach(item => item.classList.remove(className));
|
||||
target.classList.add(className);
|
||||
}
|
||||
|
||||
export function tooltip(target, msg, pos = 'up') {
|
||||
target.setAttribute('data-balloon', msg);
|
||||
target.setAttribute('data-balloon-pos', pos);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export class ArtPlayerError extends Error {
|
||||
constructor(message, context) {
|
||||
super(message);
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, context || this.constructor);
|
||||
}
|
||||
this.name = 'ArtPlayerError';
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandle(condition, msg) {
|
||||
const isFun = typeof condition === 'function';
|
||||
if (isFun ? !isFun() : !condition) {
|
||||
throw new ArtPlayerError(msg);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,6 @@
|
||||
export const instances = [];
|
||||
|
||||
export class ArtPlayerError extends Error {
|
||||
constructor(message, context) {
|
||||
super(message);
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, context || this.constructor);
|
||||
}
|
||||
this.name = 'ArtPlayerError';
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandle(condition, msg) {
|
||||
const isFun = typeof condition === 'function';
|
||||
if (isFun ? !isFun() : !condition) {
|
||||
throw new ArtPlayerError(msg);
|
||||
}
|
||||
}
|
||||
export * from './error';
|
||||
export * from './dom';
|
||||
export * from './subtitle';
|
||||
|
||||
export function clamp(num, a, b) {
|
||||
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
|
||||
@@ -37,44 +22,6 @@ export function getExt(url) {
|
||||
.pop();
|
||||
}
|
||||
|
||||
export function append(parent, child) {
|
||||
if (child instanceof Element) {
|
||||
parent.appendChild(child);
|
||||
} else {
|
||||
parent.insertAdjacentHTML('beforeend', child);
|
||||
}
|
||||
return parent.lastElementChild;
|
||||
}
|
||||
|
||||
export function insertByIndex(parent, child, index) {
|
||||
const childs = Array.from(parent.children);
|
||||
child.dataset.index = index;
|
||||
const nextChild = childs.find(item => Number(item.dataset.index) >= Number(index));
|
||||
if (nextChild) {
|
||||
nextChild.insertAdjacentElement('beforebegin', child);
|
||||
} else {
|
||||
append(parent, child);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
export function setStyle(element, key, value) {
|
||||
element.style[key] = value;
|
||||
return element;
|
||||
}
|
||||
|
||||
export function setStyles(element, styles) {
|
||||
Object.keys(styles).forEach(key => {
|
||||
setStyle(element, key, styles[key]);
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
export function getStyle(element, key, numberType = true) {
|
||||
const value = window.getComputedStyle(element, null).getPropertyValue(key);
|
||||
return numberType ? parseFloat(value) : value;
|
||||
}
|
||||
|
||||
export function secondToTime(second) {
|
||||
const add0 = num => (num < 10 ? `0${num}` : String(num));
|
||||
const hour = Math.floor(second / 3600);
|
||||
@@ -83,24 +30,10 @@ export function secondToTime(second) {
|
||||
return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':');
|
||||
}
|
||||
|
||||
export function tooltip(target, msg, pos = 'up') {
|
||||
target.setAttribute('data-balloon', msg);
|
||||
target.setAttribute('data-balloon-pos', pos);
|
||||
}
|
||||
|
||||
export function sleep(ms = 0) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function sublings(target) {
|
||||
return Array.from(target.parentElement.children).filter(item => item !== target);
|
||||
}
|
||||
|
||||
export function inverseClass(target, className) {
|
||||
sublings(target).forEach(item => item.classList.remove(className));
|
||||
target.classList.add(className);
|
||||
}
|
||||
|
||||
export function debounce(func, wait, context) {
|
||||
let timeout;
|
||||
function fn(...args) {
|
||||
@@ -118,14 +51,3 @@ export function debounce(func, wait, context) {
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
export function show(target, display) {
|
||||
target.classList.remove('art-hide');
|
||||
if (display) {
|
||||
target.style.display = display;
|
||||
}
|
||||
}
|
||||
|
||||
export function hide(target) {
|
||||
target.classList.add('art-hide');
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export function srtToVtt(srtText) {
|
||||
return 'WEBVTT \r\n\r\n'.concat(
|
||||
srtText
|
||||
.replace(/\{\\([ibu])\}/g, '</$1>')
|
||||
.replace(/\{\\([ibu])1\}/g, '<$1>')
|
||||
.replace(/\{([ibu])\}/g, '<$1>')
|
||||
.replace(/\{\/([ibu])\}/g, '</$1>')
|
||||
.replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g, '$1.$2')
|
||||
.concat('\r\n\r\n'),
|
||||
);
|
||||
}
|
||||
|
||||
export function vttToBlob(vttText) {
|
||||
return URL.createObjectURL(
|
||||
new Blob([vttText], {
|
||||
type: 'text/vtt',
|
||||
}),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user