mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-24 23:23:18 -08:00
build all
Refactor utility functions for improved readability and consistency - Updated compatibility.js to use consistent line endings and formatting. - Refactored component.js for better readability and structure, including consistent use of arrow functions and binding. - Simplified dom.js functions with consistent formatting and improved readability. - Enhanced emitter.js with consistent formatting and arrow function usage. - Streamlined error.js for improved readability and consistency. - Refactored file.js to use consistent formatting and improved readability. - Improved format.js functions for better readability and consistency. - Updated index.js to maintain consistent export formatting. - Refactored property.js for improved readability and consistency. - Enhanced subtitle.js with consistent formatting and improved readability. - Refactored time.js for better readability and consistent formatting. fix: update lint script to target only source files for consistency Revert "fix: restore export statements for various plugins and update type definitions for better clarity" This reverts commit b5e969d81ec765cd8a34b06e6ef4f232ef25087f. fix: restore export statements for various plugins and update type definitions for better clarity Refactor type definitions to use interfaces instead of type aliases for better extensibility and clarity across i18n, icons, option, player, quality, setting, subtitle, template, and utils modules.
This commit is contained in:
1 parent
532dd67cfd
commit
35ad9883af
447 files changed
+18248
-17946
No files matched your search
@@ -1,81 +1,81 @@
|
||||
export default {
|
||||
properties: [
|
||||
'audioTracks',
|
||||
'autoplay',
|
||||
'buffered',
|
||||
'controller',
|
||||
'controls',
|
||||
'crossOrigin',
|
||||
'currentSrc',
|
||||
'currentTime',
|
||||
'defaultMuted',
|
||||
'defaultPlaybackRate',
|
||||
'duration',
|
||||
'ended',
|
||||
'error',
|
||||
'loop',
|
||||
'mediaGroup',
|
||||
'muted',
|
||||
'networkState',
|
||||
'paused',
|
||||
'playbackRate',
|
||||
'played',
|
||||
'preload',
|
||||
'readyState',
|
||||
'seekable',
|
||||
'seeking',
|
||||
'src',
|
||||
'startDate',
|
||||
'textTracks',
|
||||
'videoTracks',
|
||||
'volume',
|
||||
],
|
||||
methods: ['addTextTrack', 'canPlayType', 'load', 'play', 'pause'],
|
||||
events: [
|
||||
'abort',
|
||||
'canplay',
|
||||
'canplaythrough',
|
||||
'durationchange',
|
||||
'emptied',
|
||||
'ended',
|
||||
'error',
|
||||
'loadeddata',
|
||||
'loadedmetadata',
|
||||
'loadstart',
|
||||
'pause',
|
||||
'play',
|
||||
'playing',
|
||||
'progress',
|
||||
'ratechange',
|
||||
'seeked',
|
||||
'seeking',
|
||||
'stalled',
|
||||
'suspend',
|
||||
'timeupdate',
|
||||
'volumechange',
|
||||
'waiting',
|
||||
],
|
||||
prototypes: [
|
||||
'width',
|
||||
'height',
|
||||
'videoWidth',
|
||||
'videoHeight',
|
||||
'poster',
|
||||
'webkitDecodedFrameCount',
|
||||
'webkitDroppedFrameCount',
|
||||
'playsInline',
|
||||
'webkitSupportsFullscreen',
|
||||
'webkitDisplayingFullscreen',
|
||||
'onenterpictureinpicture',
|
||||
'onleavepictureinpicture',
|
||||
'disablePictureInPicture',
|
||||
'cancelVideoFrameCallback',
|
||||
'requestVideoFrameCallback',
|
||||
'getVideoPlaybackQuality',
|
||||
'requestPictureInPicture',
|
||||
'webkitEnterFullScreen',
|
||||
'webkitEnterFullscreen',
|
||||
'webkitExitFullScreen',
|
||||
'webkitExitFullscreen',
|
||||
],
|
||||
};
|
||||
properties: [
|
||||
'audioTracks',
|
||||
'autoplay',
|
||||
'buffered',
|
||||
'controller',
|
||||
'controls',
|
||||
'crossOrigin',
|
||||
'currentSrc',
|
||||
'currentTime',
|
||||
'defaultMuted',
|
||||
'defaultPlaybackRate',
|
||||
'duration',
|
||||
'ended',
|
||||
'error',
|
||||
'loop',
|
||||
'mediaGroup',
|
||||
'muted',
|
||||
'networkState',
|
||||
'paused',
|
||||
'playbackRate',
|
||||
'played',
|
||||
'preload',
|
||||
'readyState',
|
||||
'seekable',
|
||||
'seeking',
|
||||
'src',
|
||||
'startDate',
|
||||
'textTracks',
|
||||
'videoTracks',
|
||||
'volume',
|
||||
],
|
||||
methods: ['addTextTrack', 'canPlayType', 'load', 'play', 'pause'],
|
||||
events: [
|
||||
'abort',
|
||||
'canplay',
|
||||
'canplaythrough',
|
||||
'durationchange',
|
||||
'emptied',
|
||||
'ended',
|
||||
'error',
|
||||
'loadeddata',
|
||||
'loadedmetadata',
|
||||
'loadstart',
|
||||
'pause',
|
||||
'play',
|
||||
'playing',
|
||||
'progress',
|
||||
'ratechange',
|
||||
'seeked',
|
||||
'seeking',
|
||||
'stalled',
|
||||
'suspend',
|
||||
'timeupdate',
|
||||
'volumechange',
|
||||
'waiting',
|
||||
],
|
||||
prototypes: [
|
||||
'width',
|
||||
'height',
|
||||
'videoWidth',
|
||||
'videoHeight',
|
||||
'poster',
|
||||
'webkitDecodedFrameCount',
|
||||
'webkitDroppedFrameCount',
|
||||
'playsInline',
|
||||
'webkitSupportsFullscreen',
|
||||
'webkitDisplayingFullscreen',
|
||||
'onenterpictureinpicture',
|
||||
'onleavepictureinpicture',
|
||||
'disablePictureInPicture',
|
||||
'cancelVideoFrameCallback',
|
||||
'requestVideoFrameCallback',
|
||||
'getVideoPlaybackQuality',
|
||||
'requestPictureInPicture',
|
||||
'webkitEnterFullScreen',
|
||||
'webkitEnterFullscreen',
|
||||
'webkitExitFullScreen',
|
||||
'webkitExitFullscreen',
|
||||
],
|
||||
}
|
||||
@@ -1,38 +1,38 @@
|
||||
import { inverseClass, query, queryAll } from '../utils';
|
||||
import { inverseClass, query, queryAll } from '../utils'
|
||||
|
||||
export default function aspectRatio(option) {
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { ASPECT_RATIO },
|
||||
} = art;
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { ASPECT_RATIO },
|
||||
} = art
|
||||
|
||||
const html = ASPECT_RATIO.map(
|
||||
(item) => `<span data-value="${item}">${item === 'default' ? i18n.get('Default') : item}</span>`,
|
||||
).join('');
|
||||
const html = ASPECT_RATIO.map(
|
||||
item => `<span data-value="${item}">${item === 'default' ? i18n.get('Default') : item}</span>`,
|
||||
).join('')
|
||||
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Aspect Ratio')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset;
|
||||
if (value) {
|
||||
art.aspectRatio = value;
|
||||
contextmenu.show = false;
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="default"]', $panel);
|
||||
if ($default) {
|
||||
inverseClass($default, 'art-current');
|
||||
}
|
||||
art.on('aspectRatio', (value) => {
|
||||
const $current = queryAll('span', $panel).find((item) => item.dataset.value === value);
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Aspect Ratio')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset
|
||||
if (value) {
|
||||
art.aspectRatio = value
|
||||
contextmenu.show = false
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="default"]', $panel)
|
||||
if ($default) {
|
||||
inverseClass($default, 'art-current')
|
||||
}
|
||||
art.on('aspectRatio', (value) => {
|
||||
const $current = queryAll('span', $panel).find(item => item.dataset.value === value)
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current')
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
export default function close(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
html: art.i18n.get('Close'),
|
||||
click: (contextmenu) => {
|
||||
contextmenu.show = false;
|
||||
},
|
||||
});
|
||||
return art => ({
|
||||
...option,
|
||||
html: art.i18n.get('Close'),
|
||||
click: (contextmenu) => {
|
||||
contextmenu.show = false
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,36 +1,36 @@
|
||||
import { inverseClass, query, queryAll, capitalize } from '../utils';
|
||||
import { capitalize, inverseClass, query, queryAll } from '../utils'
|
||||
|
||||
export default function flip(option) {
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { FLIP },
|
||||
} = art;
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { FLIP },
|
||||
} = art
|
||||
|
||||
const html = FLIP.map((item) => `<span data-value="${item}">${i18n.get(capitalize(item))}</span>`).join('');
|
||||
const html = FLIP.map(item => `<span data-value="${item}">${i18n.get(capitalize(item))}</span>`).join('')
|
||||
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Video Flip')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset;
|
||||
if (value) {
|
||||
art.flip = value.toLowerCase();
|
||||
contextmenu.show = false;
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="normal"]', $panel);
|
||||
if ($default) {
|
||||
inverseClass($default, 'art-current');
|
||||
}
|
||||
art.on('flip', (value) => {
|
||||
const $current = queryAll('span', $panel).find((item) => item.dataset.value === value);
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Video Flip')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset
|
||||
if (value) {
|
||||
art.flip = value.toLowerCase()
|
||||
contextmenu.show = false
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="normal"]', $panel)
|
||||
if ($default) {
|
||||
inverseClass($default, 'art-current')
|
||||
}
|
||||
art.on('flip', (value) => {
|
||||
const $current = queryAll('span', $panel).find(item => item.dataset.value === value)
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current')
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +1,119 @@
|
||||
import { setStyles, includeFromEvent, isMobile, getRect } from '../utils';
|
||||
import Component from '../utils/component';
|
||||
import playbackRate from './playbackRate';
|
||||
import aspectRatio from './aspectRatio';
|
||||
import flip from './flip';
|
||||
import info from './info';
|
||||
import version from './version';
|
||||
import close from './close';
|
||||
import { getRect, includeFromEvent, isMobile, setStyles } from '../utils'
|
||||
import Component from '../utils/component'
|
||||
import aspectRatio from './aspectRatio'
|
||||
import close from './close'
|
||||
import flip from './flip'
|
||||
import info from './info'
|
||||
import playbackRate from './playbackRate'
|
||||
import version from './version'
|
||||
|
||||
export default class Contextmenu extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
constructor(art) {
|
||||
super(art)
|
||||
|
||||
this.name = 'contextmenu';
|
||||
this.$parent = art.template.$contextmenu;
|
||||
this.name = 'contextmenu'
|
||||
this.$parent = art.template.$contextmenu
|
||||
|
||||
if (!isMobile) {
|
||||
this.init();
|
||||
}
|
||||
if (!isMobile) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
option,
|
||||
proxy,
|
||||
template: { $player, $contextmenu },
|
||||
} = this.art
|
||||
|
||||
if (option.playbackRate) {
|
||||
this.add(
|
||||
playbackRate({
|
||||
name: 'playbackRate',
|
||||
index: 10,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
option,
|
||||
proxy,
|
||||
template: { $player, $contextmenu },
|
||||
} = this.art;
|
||||
|
||||
if (option.playbackRate) {
|
||||
this.add(
|
||||
playbackRate({
|
||||
name: 'playbackRate',
|
||||
index: 10,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.aspectRatio) {
|
||||
this.add(
|
||||
aspectRatio({
|
||||
name: 'aspectRatio',
|
||||
index: 20,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.flip) {
|
||||
this.add(
|
||||
flip({
|
||||
name: 'flip',
|
||||
index: 30,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
this.add(
|
||||
info({
|
||||
name: 'info',
|
||||
index: 40,
|
||||
}),
|
||||
);
|
||||
|
||||
this.add(
|
||||
version({
|
||||
name: 'version',
|
||||
index: 50,
|
||||
}),
|
||||
);
|
||||
|
||||
this.add(
|
||||
close({
|
||||
name: 'close',
|
||||
index: 60,
|
||||
}),
|
||||
);
|
||||
|
||||
for (let index = 0; index < option.contextmenu.length; index++) {
|
||||
this.add(option.contextmenu[index]);
|
||||
}
|
||||
|
||||
proxy($player, 'contextmenu', (event) => {
|
||||
if (!this.art.constructor.CONTEXTMENU) return;
|
||||
event.preventDefault();
|
||||
|
||||
this.show = true;
|
||||
|
||||
const mouseX = event.clientX;
|
||||
const mouseY = event.clientY;
|
||||
const { height: cHeight, width: cWidth, left: cLeft, top: cTop } = getRect($player);
|
||||
const { height: mHeight, width: mWidth } = getRect($contextmenu);
|
||||
let menuLeft = mouseX - cLeft;
|
||||
let menuTop = mouseY - cTop;
|
||||
|
||||
if (mouseX + mWidth > cLeft + cWidth) {
|
||||
menuLeft = cWidth - mWidth;
|
||||
}
|
||||
|
||||
if (mouseY + mHeight > cTop + cHeight) {
|
||||
menuTop = cHeight - mHeight;
|
||||
}
|
||||
|
||||
setStyles($contextmenu, {
|
||||
top: `${menuTop}px`,
|
||||
left: `${menuLeft}px`,
|
||||
});
|
||||
});
|
||||
|
||||
proxy($player, 'click', (event) => {
|
||||
if (!includeFromEvent(event, $contextmenu)) {
|
||||
this.show = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.art.on('blur', () => {
|
||||
this.show = false;
|
||||
});
|
||||
if (option.aspectRatio) {
|
||||
this.add(
|
||||
aspectRatio({
|
||||
name: 'aspectRatio',
|
||||
index: 20,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (option.flip) {
|
||||
this.add(
|
||||
flip({
|
||||
name: 'flip',
|
||||
index: 30,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
this.add(
|
||||
info({
|
||||
name: 'info',
|
||||
index: 40,
|
||||
}),
|
||||
)
|
||||
|
||||
this.add(
|
||||
version({
|
||||
name: 'version',
|
||||
index: 50,
|
||||
}),
|
||||
)
|
||||
|
||||
this.add(
|
||||
close({
|
||||
name: 'close',
|
||||
index: 60,
|
||||
}),
|
||||
)
|
||||
|
||||
for (let index = 0; index < option.contextmenu.length; index++) {
|
||||
this.add(option.contextmenu[index])
|
||||
}
|
||||
|
||||
proxy($player, 'contextmenu', (event) => {
|
||||
if (!this.art.constructor.CONTEXTMENU)
|
||||
return
|
||||
event.preventDefault()
|
||||
|
||||
this.show = true
|
||||
|
||||
const mouseX = event.clientX
|
||||
const mouseY = event.clientY
|
||||
const { height: cHeight, width: cWidth, left: cLeft, top: cTop } = getRect($player)
|
||||
const { height: mHeight, width: mWidth } = getRect($contextmenu)
|
||||
let menuLeft = mouseX - cLeft
|
||||
let menuTop = mouseY - cTop
|
||||
|
||||
if (mouseX + mWidth > cLeft + cWidth) {
|
||||
menuLeft = cWidth - mWidth
|
||||
}
|
||||
|
||||
if (mouseY + mHeight > cTop + cHeight) {
|
||||
menuTop = cHeight - mHeight
|
||||
}
|
||||
|
||||
setStyles($contextmenu, {
|
||||
top: `${menuTop}px`,
|
||||
left: `${menuLeft}px`,
|
||||
})
|
||||
})
|
||||
|
||||
proxy($player, 'click', (event) => {
|
||||
if (!includeFromEvent(event, $contextmenu)) {
|
||||
this.show = false
|
||||
}
|
||||
})
|
||||
|
||||
this.art.on('blur', () => {
|
||||
this.show = false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
export default function info(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
html: art.i18n.get('Video Info'),
|
||||
click: (contextmenu) => {
|
||||
art.info.show = true;
|
||||
contextmenu.show = false;
|
||||
},
|
||||
});
|
||||
return art => ({
|
||||
...option,
|
||||
html: art.i18n.get('Video Info'),
|
||||
click: (contextmenu) => {
|
||||
art.info.show = true
|
||||
contextmenu.show = false
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,38 +1,39 @@
|
||||
import { inverseClass, query, queryAll } from '../utils';
|
||||
import { inverseClass, query, queryAll } from '../utils'
|
||||
|
||||
export default function playbackRate(option) {
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { PLAYBACK_RATE },
|
||||
} = art;
|
||||
return (art) => {
|
||||
const {
|
||||
i18n,
|
||||
constructor: { PLAYBACK_RATE },
|
||||
} = art
|
||||
|
||||
const html = PLAYBACK_RATE.map(
|
||||
(item) => `<span data-value="${item}">${item === 1 ? i18n.get('Normal') : item.toFixed(1)}</span>`,
|
||||
).join('');
|
||||
const html = PLAYBACK_RATE.map(
|
||||
item => `<span data-value="${item}">${item === 1 ? i18n.get('Normal') : item.toFixed(1)}</span>`,
|
||||
).join('')
|
||||
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Play Speed')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset;
|
||||
if (value) {
|
||||
art.playbackRate = Number(value);
|
||||
contextmenu.show = false;
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="1"]', $panel);
|
||||
if ($default) inverseClass($default, 'art-current');
|
||||
art.on('video:ratechange', () => {
|
||||
const $current = queryAll('span', $panel).find(
|
||||
(item) => Number(item.dataset.value) === art.playbackRate,
|
||||
);
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
return {
|
||||
...option,
|
||||
html: `${i18n.get('Play Speed')}: ${html}`,
|
||||
click: (contextmenu, event) => {
|
||||
const { value } = event.target.dataset
|
||||
if (value) {
|
||||
art.playbackRate = Number(value)
|
||||
contextmenu.show = false
|
||||
}
|
||||
},
|
||||
mounted: ($panel) => {
|
||||
const $default = query('[data-value="1"]', $panel)
|
||||
if ($default)
|
||||
inverseClass($default, 'art-current')
|
||||
art.on('video:ratechange', () => {
|
||||
const $current = queryAll('span', $panel).find(
|
||||
item => Number(item.dataset.value) === art.playbackRate,
|
||||
)
|
||||
if ($current) {
|
||||
inverseClass($current, 'art-current')
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { version } from '../../package.json';
|
||||
import { version } from '../../package.json'
|
||||
|
||||
export default function (option) {
|
||||
return {
|
||||
...option,
|
||||
html: `<a href="https://artplayer.org" target="_blank">ArtPlayer ${version}</a>`,
|
||||
};
|
||||
return {
|
||||
...option,
|
||||
html: `<a href="https://artplayer.org" target="_blank">ArtPlayer ${version}</a>`,
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import { append } from '../utils';
|
||||
import { append } from '../utils'
|
||||
|
||||
export default function airplay(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('AirPlay'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art;
|
||||
append($control, icons.airplay);
|
||||
proxy($control, 'click', () => art.airplay());
|
||||
},
|
||||
});
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('AirPlay'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art
|
||||
append($control, icons.airplay)
|
||||
proxy($control, 'click', () => art.airplay())
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import { append, setStyle, tooltip } from '../utils'
|
||||
|
||||
export default function fullscreen(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Fullscreen'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Fullscreen'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art
|
||||
|
||||
const $fullscreenOn = append($control, icons.fullscreenOn);
|
||||
const $fullscreenOff = append($control, icons.fullscreenOff);
|
||||
setStyle($fullscreenOff, 'display', 'none');
|
||||
const $fullscreenOn = append($control, icons.fullscreenOn)
|
||||
const $fullscreenOff = append($control, icons.fullscreenOff)
|
||||
setStyle($fullscreenOff, 'display', 'none')
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
art.fullscreen = !art.fullscreen;
|
||||
});
|
||||
proxy($control, 'click', () => {
|
||||
art.fullscreen = !art.fullscreen
|
||||
})
|
||||
|
||||
art.on('fullscreen', (state) => {
|
||||
if (state) {
|
||||
tooltip($control, i18n.get('Exit Fullscreen'));
|
||||
setStyle($fullscreenOn, 'display', 'none');
|
||||
setStyle($fullscreenOff, 'display', 'inline-flex');
|
||||
} else {
|
||||
tooltip($control, i18n.get('Fullscreen'));
|
||||
setStyle($fullscreenOn, 'display', 'inline-flex');
|
||||
setStyle($fullscreenOff, 'display', 'none');
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
art.on('fullscreen', (state) => {
|
||||
if (state) {
|
||||
tooltip($control, i18n.get('Exit Fullscreen'))
|
||||
setStyle($fullscreenOn, 'display', 'none')
|
||||
setStyle($fullscreenOff, 'display', 'inline-flex')
|
||||
}
|
||||
else {
|
||||
tooltip($control, i18n.get('Fullscreen'))
|
||||
setStyle($fullscreenOn, 'display', 'inline-flex')
|
||||
setStyle($fullscreenOff, 'display', 'none')
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import { append, setStyle, tooltip } from '../utils'
|
||||
|
||||
export default function fullscreenWeb(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Web Fullscreen'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Web Fullscreen'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art
|
||||
|
||||
const $fullscreenWebOn = append($control, icons.fullscreenWebOn);
|
||||
const $fullscreenWebOff = append($control, icons.fullscreenWebOff);
|
||||
setStyle($fullscreenWebOff, 'display', 'none');
|
||||
const $fullscreenWebOn = append($control, icons.fullscreenWebOn)
|
||||
const $fullscreenWebOff = append($control, icons.fullscreenWebOff)
|
||||
setStyle($fullscreenWebOff, 'display', 'none')
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
art.fullscreenWeb = !art.fullscreenWeb;
|
||||
});
|
||||
proxy($control, 'click', () => {
|
||||
art.fullscreenWeb = !art.fullscreenWeb
|
||||
})
|
||||
|
||||
art.on('fullscreenWeb', (value) => {
|
||||
if (value) {
|
||||
tooltip($control, i18n.get('Exit Web Fullscreen'));
|
||||
setStyle($fullscreenWebOn, 'display', 'none');
|
||||
setStyle($fullscreenWebOff, 'display', 'inline-flex');
|
||||
} else {
|
||||
tooltip($control, i18n.get('Web Fullscreen'));
|
||||
setStyle($fullscreenWebOn, 'display', 'inline-flex');
|
||||
setStyle($fullscreenWebOff, 'display', 'none');
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
art.on('fullscreenWeb', (value) => {
|
||||
if (value) {
|
||||
tooltip($control, i18n.get('Exit Web Fullscreen'))
|
||||
setStyle($fullscreenWebOn, 'display', 'none')
|
||||
setStyle($fullscreenWebOff, 'display', 'inline-flex')
|
||||
}
|
||||
else {
|
||||
tooltip($control, i18n.get('Web Fullscreen'))
|
||||
setStyle($fullscreenWebOn, 'display', 'inline-flex')
|
||||
setStyle($fullscreenWebOff, 'display', 'none')
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,281 +1,284 @@
|
||||
import Component from '../utils/component';
|
||||
import fullscreen from './fullscreen';
|
||||
import fullscreenWeb from './fullscreenWeb';
|
||||
import pip from './pip';
|
||||
import playAndPause from './playAndPause';
|
||||
import progress from './progress';
|
||||
import time from './time';
|
||||
import volume from './volume';
|
||||
import setting from './setting';
|
||||
import screenshot from './screenshot';
|
||||
import airplay from './airplay';
|
||||
import {
|
||||
def,
|
||||
sleep,
|
||||
append,
|
||||
addClass,
|
||||
isMobile,
|
||||
removeClass,
|
||||
errorHandle,
|
||||
inverseClass,
|
||||
createElement,
|
||||
includeFromEvent,
|
||||
getComposedPath,
|
||||
} from '../utils';
|
||||
addClass,
|
||||
append,
|
||||
createElement,
|
||||
def,
|
||||
errorHandle,
|
||||
getComposedPath,
|
||||
includeFromEvent,
|
||||
inverseClass,
|
||||
isMobile,
|
||||
removeClass,
|
||||
sleep,
|
||||
} from '../utils'
|
||||
import Component from '../utils/component'
|
||||
import airplay from './airplay'
|
||||
import fullscreen from './fullscreen'
|
||||
import fullscreenWeb from './fullscreenWeb'
|
||||
import pip from './pip'
|
||||
import playAndPause from './playAndPause'
|
||||
import progress from './progress'
|
||||
import screenshot from './screenshot'
|
||||
import setting from './setting'
|
||||
import time from './time'
|
||||
import volume from './volume'
|
||||
|
||||
export default class Control extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
constructor(art) {
|
||||
super(art)
|
||||
|
||||
this.isHover = false;
|
||||
this.name = 'control';
|
||||
this.timer = Date.now();
|
||||
this.isHover = false
|
||||
this.name = 'control'
|
||||
this.timer = Date.now()
|
||||
|
||||
const { constructor } = art;
|
||||
const { $player, $bottom } = this.art.template;
|
||||
const { constructor } = art
|
||||
const { $player, $bottom } = this.art.template
|
||||
|
||||
art.on('mousemove', () => {
|
||||
if (!isMobile) {
|
||||
this.show = true;
|
||||
}
|
||||
});
|
||||
art.on('mousemove', () => {
|
||||
if (!isMobile) {
|
||||
this.show = true
|
||||
}
|
||||
})
|
||||
|
||||
art.on('click', () => {
|
||||
if (isMobile) {
|
||||
this.toggle();
|
||||
} else {
|
||||
this.show = true;
|
||||
}
|
||||
});
|
||||
art.on('click', () => {
|
||||
if (isMobile) {
|
||||
this.toggle()
|
||||
}
|
||||
else {
|
||||
this.show = true
|
||||
}
|
||||
})
|
||||
|
||||
art.on('document:mousemove', (event) => {
|
||||
this.isHover = includeFromEvent(event, $bottom);
|
||||
});
|
||||
art.on('document:mousemove', (event) => {
|
||||
this.isHover = includeFromEvent(event, $bottom)
|
||||
})
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
if (
|
||||
!art.setting.show &&
|
||||
!this.isHover &&
|
||||
!art.isInput &&
|
||||
art.playing &&
|
||||
this.show &&
|
||||
Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME
|
||||
) {
|
||||
this.show = false;
|
||||
}
|
||||
});
|
||||
art.on('video:timeupdate', () => {
|
||||
if (
|
||||
!art.setting.show
|
||||
&& !this.isHover
|
||||
&& !art.isInput
|
||||
&& art.playing
|
||||
&& this.show
|
||||
&& Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME
|
||||
) {
|
||||
this.show = false
|
||||
}
|
||||
})
|
||||
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass($player, 'art-hide-cursor');
|
||||
addClass($player, 'art-hover');
|
||||
this.timer = Date.now();
|
||||
} else {
|
||||
addClass($player, 'art-hide-cursor');
|
||||
removeClass($player, 'art-hover');
|
||||
}
|
||||
});
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass($player, 'art-hide-cursor')
|
||||
addClass($player, 'art-hover')
|
||||
this.timer = Date.now()
|
||||
}
|
||||
else {
|
||||
addClass($player, 'art-hide-cursor')
|
||||
removeClass($player, 'art-hover')
|
||||
}
|
||||
})
|
||||
|
||||
this.init();
|
||||
this.init()
|
||||
}
|
||||
|
||||
init() {
|
||||
const { option } = this.art
|
||||
|
||||
if (!option.isLive) {
|
||||
this.add(
|
||||
progress({
|
||||
name: 'progress',
|
||||
position: 'top',
|
||||
index: 10,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
init() {
|
||||
const { option } = this.art;
|
||||
this.add({
|
||||
name: 'thumbnails',
|
||||
position: 'top',
|
||||
index: 20,
|
||||
})
|
||||
|
||||
if (!option.isLive) {
|
||||
this.add(
|
||||
progress({
|
||||
name: 'progress',
|
||||
position: 'top',
|
||||
index: 10,
|
||||
}),
|
||||
);
|
||||
}
|
||||
this.add(
|
||||
playAndPause({
|
||||
name: 'playAndPause',
|
||||
position: 'left',
|
||||
index: 10,
|
||||
}),
|
||||
)
|
||||
|
||||
this.add({
|
||||
name: 'thumbnails',
|
||||
position: 'top',
|
||||
index: 20,
|
||||
});
|
||||
this.add(
|
||||
volume({
|
||||
name: 'volume',
|
||||
position: 'left',
|
||||
index: 20,
|
||||
}),
|
||||
)
|
||||
|
||||
this.add(
|
||||
playAndPause({
|
||||
name: 'playAndPause',
|
||||
position: 'left',
|
||||
index: 10,
|
||||
}),
|
||||
);
|
||||
|
||||
this.add(
|
||||
volume({
|
||||
name: 'volume',
|
||||
position: 'left',
|
||||
index: 20,
|
||||
}),
|
||||
);
|
||||
|
||||
if (!option.isLive) {
|
||||
this.add(
|
||||
time({
|
||||
name: 'time',
|
||||
position: 'left',
|
||||
index: 30,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.quality.length) {
|
||||
sleep().then(() => {
|
||||
this.art.quality = option.quality;
|
||||
});
|
||||
}
|
||||
|
||||
if (option.screenshot && !isMobile) {
|
||||
this.add(
|
||||
screenshot({
|
||||
name: 'screenshot',
|
||||
position: 'right',
|
||||
index: 20,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.setting) {
|
||||
this.add(
|
||||
setting({
|
||||
name: 'setting',
|
||||
position: 'right',
|
||||
index: 30,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.pip) {
|
||||
this.add(
|
||||
pip({
|
||||
name: 'pip',
|
||||
position: 'right',
|
||||
index: 40,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) {
|
||||
this.add(
|
||||
airplay({
|
||||
name: 'airplay',
|
||||
position: 'right',
|
||||
index: 50,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.fullscreenWeb) {
|
||||
this.add(
|
||||
fullscreenWeb({
|
||||
name: 'fullscreenWeb',
|
||||
position: 'right',
|
||||
index: 60,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (option.fullscreen) {
|
||||
this.add(
|
||||
fullscreen({
|
||||
name: 'fullscreen',
|
||||
position: 'right',
|
||||
index: 70,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.controls.length; index++) {
|
||||
this.add(option.controls[index]);
|
||||
}
|
||||
if (!option.isLive) {
|
||||
this.add(
|
||||
time({
|
||||
name: 'time',
|
||||
position: 'left',
|
||||
index: 30,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
add(getOption) {
|
||||
const option = typeof getOption === 'function' ? getOption(this.art) : getOption;
|
||||
const { $progress, $controlsLeft, $controlsRight } = this.art.template;
|
||||
|
||||
switch (option.position) {
|
||||
case 'top':
|
||||
this.$parent = $progress;
|
||||
break;
|
||||
case 'left':
|
||||
this.$parent = $controlsLeft;
|
||||
break;
|
||||
case 'right':
|
||||
this.$parent = $controlsRight;
|
||||
break;
|
||||
default:
|
||||
errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`);
|
||||
break;
|
||||
}
|
||||
|
||||
super.add(option);
|
||||
if (option.quality.length) {
|
||||
sleep().then(() => {
|
||||
this.art.quality = option.quality
|
||||
})
|
||||
}
|
||||
|
||||
check(target) {
|
||||
target.$control_value.innerHTML = target.html;
|
||||
for (let index = 0; index < target.$control_option.length; index++) {
|
||||
const item = target.$control_option[index];
|
||||
item.default = item === target;
|
||||
if (item.default) {
|
||||
inverseClass(item.$control_item, 'art-current');
|
||||
}
|
||||
}
|
||||
if (option.screenshot && !isMobile) {
|
||||
this.add(
|
||||
screenshot({
|
||||
name: 'screenshot',
|
||||
position: 'right',
|
||||
index: 20,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
selector(option, $ref, events) {
|
||||
const { proxy } = this.art.events;
|
||||
|
||||
addClass($ref, 'art-control-selector');
|
||||
const $value = createElement('div');
|
||||
addClass($value, 'art-selector-value');
|
||||
append($value, option.html);
|
||||
$ref.innerText = '';
|
||||
append($ref, $value);
|
||||
|
||||
const $list = createElement('div');
|
||||
addClass($list, 'art-selector-list');
|
||||
append($ref, $list);
|
||||
|
||||
for (let index = 0; index < option.selector.length; index++) {
|
||||
const item = option.selector[index];
|
||||
const $item = createElement('div');
|
||||
addClass($item, 'art-selector-item');
|
||||
if (item.default) addClass($item, 'art-current');
|
||||
$item.dataset.index = index;
|
||||
$item.dataset.value = item.value;
|
||||
$item.innerHTML = item.html;
|
||||
append($list, $item);
|
||||
|
||||
def(item, '$control_option', {
|
||||
get: () => option.selector,
|
||||
});
|
||||
|
||||
def(item, '$control_item', {
|
||||
get: () => $item,
|
||||
});
|
||||
|
||||
def(item, '$control_value', {
|
||||
get: () => $value,
|
||||
});
|
||||
}
|
||||
|
||||
const event = proxy($list, 'click', async (event) => {
|
||||
const path = getComposedPath(event);
|
||||
const item = option.selector.find(
|
||||
(item) => item.$control_item === path.find(($item) => item.$control_item === $item),
|
||||
);
|
||||
this.check(item);
|
||||
if (option.onSelect) {
|
||||
$value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event);
|
||||
}
|
||||
});
|
||||
|
||||
events.push(event);
|
||||
if (option.setting) {
|
||||
this.add(
|
||||
setting({
|
||||
name: 'setting',
|
||||
position: 'right',
|
||||
index: 30,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (option.pip) {
|
||||
this.add(
|
||||
pip({
|
||||
name: 'pip',
|
||||
position: 'right',
|
||||
index: 40,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) {
|
||||
this.add(
|
||||
airplay({
|
||||
name: 'airplay',
|
||||
position: 'right',
|
||||
index: 50,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (option.fullscreenWeb) {
|
||||
this.add(
|
||||
fullscreenWeb({
|
||||
name: 'fullscreenWeb',
|
||||
position: 'right',
|
||||
index: 60,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (option.fullscreen) {
|
||||
this.add(
|
||||
fullscreen({
|
||||
name: 'fullscreen',
|
||||
position: 'right',
|
||||
index: 70,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.controls.length; index++) {
|
||||
this.add(option.controls[index])
|
||||
}
|
||||
}
|
||||
|
||||
add(getOption) {
|
||||
const option = typeof getOption === 'function' ? getOption(this.art) : getOption
|
||||
const { $progress, $controlsLeft, $controlsRight } = this.art.template
|
||||
|
||||
switch (option.position) {
|
||||
case 'top':
|
||||
this.$parent = $progress
|
||||
break
|
||||
case 'left':
|
||||
this.$parent = $controlsLeft
|
||||
break
|
||||
case 'right':
|
||||
this.$parent = $controlsRight
|
||||
break
|
||||
default:
|
||||
errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`)
|
||||
break
|
||||
}
|
||||
|
||||
super.add(option)
|
||||
}
|
||||
|
||||
check(target) {
|
||||
target.$control_value.innerHTML = target.html
|
||||
for (let index = 0; index < target.$control_option.length; index++) {
|
||||
const item = target.$control_option[index]
|
||||
item.default = item === target
|
||||
if (item.default) {
|
||||
inverseClass(item.$control_item, 'art-current')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selector(option, $ref, events) {
|
||||
const { proxy } = this.art.events
|
||||
|
||||
addClass($ref, 'art-control-selector')
|
||||
const $value = createElement('div')
|
||||
addClass($value, 'art-selector-value')
|
||||
append($value, option.html)
|
||||
$ref.textContent = ''
|
||||
append($ref, $value)
|
||||
|
||||
const $list = createElement('div')
|
||||
addClass($list, 'art-selector-list')
|
||||
append($ref, $list)
|
||||
|
||||
for (let index = 0; index < option.selector.length; index++) {
|
||||
const item = option.selector[index]
|
||||
const $item = createElement('div')
|
||||
addClass($item, 'art-selector-item')
|
||||
if (item.default)
|
||||
addClass($item, 'art-current')
|
||||
$item.dataset.index = index
|
||||
$item.dataset.value = item.value
|
||||
$item.innerHTML = item.html
|
||||
append($list, $item)
|
||||
|
||||
def(item, '$control_option', {
|
||||
get: () => option.selector,
|
||||
})
|
||||
|
||||
def(item, '$control_item', {
|
||||
get: () => $item,
|
||||
})
|
||||
|
||||
def(item, '$control_value', {
|
||||
get: () => $value,
|
||||
})
|
||||
}
|
||||
|
||||
const event = proxy($list, 'click', async (event) => {
|
||||
const path = getComposedPath(event)
|
||||
const item = option.selector.find(
|
||||
item => item.$control_item === path.find($item => item.$control_item === $item),
|
||||
)
|
||||
this.check(item)
|
||||
if (option.onSelect) {
|
||||
$value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event)
|
||||
}
|
||||
})
|
||||
|
||||
events.push(event)
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
import { append, tooltip } from '../utils';
|
||||
import { append, tooltip } from '../utils'
|
||||
|
||||
export default function pip(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('PIP Mode'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('PIP Mode'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art
|
||||
|
||||
append($control, icons.pip);
|
||||
append($control, icons.pip)
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
art.pip = !art.pip;
|
||||
});
|
||||
proxy($control, 'click', () => {
|
||||
art.pip = !art.pip
|
||||
})
|
||||
|
||||
art.on('pip', (value) => {
|
||||
tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode'));
|
||||
});
|
||||
},
|
||||
});
|
||||
art.on('pip', (value) => {
|
||||
tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode'))
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,47 +1,48 @@
|
||||
import { append, tooltip, setStyle } from '../utils';
|
||||
import { append, setStyle, tooltip } from '../utils'
|
||||
|
||||
export default function playAndPause(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art
|
||||
|
||||
const $play = append($control, icons.play);
|
||||
const $pause = append($control, icons.pause);
|
||||
tooltip($play, i18n.get('Play'));
|
||||
tooltip($pause, i18n.get('Pause'));
|
||||
const $play = append($control, icons.play)
|
||||
const $pause = append($control, icons.pause)
|
||||
tooltip($play, i18n.get('Play'))
|
||||
tooltip($pause, i18n.get('Pause'))
|
||||
|
||||
proxy($play, 'click', () => {
|
||||
art.play();
|
||||
});
|
||||
proxy($play, 'click', () => {
|
||||
art.play()
|
||||
})
|
||||
|
||||
proxy($pause, 'click', () => {
|
||||
art.pause();
|
||||
});
|
||||
proxy($pause, 'click', () => {
|
||||
art.pause()
|
||||
})
|
||||
|
||||
function showPlay() {
|
||||
setStyle($play, 'display', 'flex');
|
||||
setStyle($pause, 'display', 'none');
|
||||
}
|
||||
function showPlay() {
|
||||
setStyle($play, 'display', 'flex')
|
||||
setStyle($pause, 'display', 'none')
|
||||
}
|
||||
|
||||
function showPause() {
|
||||
setStyle($play, 'display', 'none');
|
||||
setStyle($pause, 'display', 'flex');
|
||||
}
|
||||
function showPause() {
|
||||
setStyle($play, 'display', 'none')
|
||||
setStyle($pause, 'display', 'flex')
|
||||
}
|
||||
|
||||
if (art.playing) {
|
||||
showPause();
|
||||
} else {
|
||||
showPlay();
|
||||
}
|
||||
if (art.playing) {
|
||||
showPause()
|
||||
}
|
||||
else {
|
||||
showPlay()
|
||||
}
|
||||
|
||||
art.on('video:playing', () => {
|
||||
showPause();
|
||||
});
|
||||
art.on('video:playing', () => {
|
||||
showPause()
|
||||
})
|
||||
|
||||
art.on('video:pause', () => {
|
||||
showPlay();
|
||||
});
|
||||
},
|
||||
});
|
||||
art.on('video:pause', () => {
|
||||
showPlay()
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,36 +1,37 @@
|
||||
import { query, clamp, append, setStyle, secondToTime, includeFromEvent, isMobile, getRect } from '../utils';
|
||||
import { append, clamp, getRect, includeFromEvent, isMobile, query, secondToTime, setStyle } from '../utils'
|
||||
|
||||
export function getPosFromEvent(art, event) {
|
||||
const { $progress } = art.template;
|
||||
const { left } = getRect($progress);
|
||||
const eventLeft = isMobile ? event.touches[0].clientX : event.clientX;
|
||||
const width = clamp(eventLeft - left, 0, $progress.clientWidth);
|
||||
const second = (width / $progress.clientWidth) * art.duration;
|
||||
const time = secondToTime(second);
|
||||
const percentage = clamp(width / $progress.clientWidth, 0, 1);
|
||||
return { second, time, width, percentage };
|
||||
const { $progress } = art.template
|
||||
const { left } = getRect($progress)
|
||||
const eventLeft = isMobile ? event.touches[0].clientX : event.clientX
|
||||
const width = clamp(eventLeft - left, 0, $progress.clientWidth)
|
||||
const second = (width / $progress.clientWidth) * art.duration
|
||||
const time = secondToTime(second)
|
||||
const percentage = clamp(width / $progress.clientWidth, 0, 1)
|
||||
return { second, time, width, percentage }
|
||||
}
|
||||
|
||||
export function setCurrentTime(art, event) {
|
||||
if (art.isRotate) {
|
||||
const percentage = event.touches[0].clientY / art.height;
|
||||
const second = percentage * art.duration;
|
||||
art.emit('setBar', 'played', percentage, event);
|
||||
art.seek = second;
|
||||
} else {
|
||||
const { second, percentage } = getPosFromEvent(art, event);
|
||||
art.emit('setBar', 'played', percentage, event);
|
||||
art.seek = second;
|
||||
}
|
||||
if (art.isRotate) {
|
||||
const percentage = event.touches[0].clientY / art.height
|
||||
const second = percentage * art.duration
|
||||
art.emit('setBar', 'played', percentage, event)
|
||||
art.seek = second
|
||||
}
|
||||
else {
|
||||
const { second, percentage } = getPosFromEvent(art, event)
|
||||
art.emit('setBar', 'played', percentage, event)
|
||||
art.seek = second
|
||||
}
|
||||
}
|
||||
|
||||
export default function progress(options) {
|
||||
return (art) => {
|
||||
const { icons, option, proxy } = art;
|
||||
return (art) => {
|
||||
const { icons, option, proxy } = art
|
||||
|
||||
return {
|
||||
...options,
|
||||
html: `
|
||||
return {
|
||||
...options,
|
||||
html: `
|
||||
<div class="art-control-progress-inner">
|
||||
<div class="art-progress-hover"></div>
|
||||
<div class="art-progress-loaded"></div>
|
||||
@@ -40,154 +41,161 @@ export default function progress(options) {
|
||||
<div class="art-progress-tip"></div>
|
||||
</div>
|
||||
`,
|
||||
mounted: ($control) => {
|
||||
let tipTimer = null;
|
||||
let isDragging = false;
|
||||
mounted: ($control) => {
|
||||
let tipTimer = null
|
||||
let isDragging = false
|
||||
|
||||
const $hover = query('.art-progress-hover', $control);
|
||||
const $loaded = query('.art-progress-loaded', $control);
|
||||
const $played = query('.art-progress-played', $control);
|
||||
const $highlight = query('.art-progress-highlight', $control);
|
||||
const $indicator = query('.art-progress-indicator', $control);
|
||||
const $tip = query('.art-progress-tip', $control);
|
||||
const $hover = query('.art-progress-hover', $control)
|
||||
const $loaded = query('.art-progress-loaded', $control)
|
||||
const $played = query('.art-progress-played', $control)
|
||||
const $highlight = query('.art-progress-highlight', $control)
|
||||
const $indicator = query('.art-progress-indicator', $control)
|
||||
const $tip = query('.art-progress-tip', $control)
|
||||
|
||||
if (icons.indicator) {
|
||||
append($indicator, icons.indicator);
|
||||
} else {
|
||||
setStyle($indicator, 'backgroundColor', 'var(--art-theme)');
|
||||
}
|
||||
if (icons.indicator) {
|
||||
append($indicator, icons.indicator)
|
||||
}
|
||||
else {
|
||||
setStyle($indicator, 'backgroundColor', 'var(--art-theme)')
|
||||
}
|
||||
|
||||
function showHighlight(event) {
|
||||
const { width } = getPosFromEvent(art, event);
|
||||
const { text } = event.target.dataset;
|
||||
$tip.innerText = text;
|
||||
const tipWidth = $tip.clientWidth;
|
||||
if (width <= tipWidth / 2) {
|
||||
setStyle($tip, 'left', 0);
|
||||
} else if (width > $control.clientWidth - tipWidth / 2) {
|
||||
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`);
|
||||
} else {
|
||||
setStyle($tip, 'left', `${width - tipWidth / 2}px`);
|
||||
}
|
||||
}
|
||||
function showHighlight(event) {
|
||||
const { width } = getPosFromEvent(art, event)
|
||||
const { text } = event.target.dataset
|
||||
$tip.textContent = text
|
||||
const tipWidth = $tip.clientWidth
|
||||
if (width <= tipWidth / 2) {
|
||||
setStyle($tip, 'left', 0)
|
||||
}
|
||||
else if (width > $control.clientWidth - tipWidth / 2) {
|
||||
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`)
|
||||
}
|
||||
else {
|
||||
setStyle($tip, 'left', `${width - tipWidth / 2}px`)
|
||||
}
|
||||
}
|
||||
|
||||
function showTime(event, touch) {
|
||||
const { width, time } = touch || getPosFromEvent(art, event);
|
||||
$tip.innerText = time;
|
||||
const tipWidth = $tip.clientWidth;
|
||||
if (width <= tipWidth / 2) {
|
||||
setStyle($tip, 'left', 0);
|
||||
} else if (width > $control.clientWidth - tipWidth / 2) {
|
||||
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`);
|
||||
} else {
|
||||
setStyle($tip, 'left', `${width - tipWidth / 2}px`);
|
||||
}
|
||||
}
|
||||
function showTime(event, touch) {
|
||||
const { width, time } = touch || getPosFromEvent(art, event)
|
||||
$tip.textContent = time
|
||||
const tipWidth = $tip.clientWidth
|
||||
if (width <= tipWidth / 2) {
|
||||
setStyle($tip, 'left', 0)
|
||||
}
|
||||
else if (width > $control.clientWidth - tipWidth / 2) {
|
||||
setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`)
|
||||
}
|
||||
else {
|
||||
setStyle($tip, 'left', `${width - tipWidth / 2}px`)
|
||||
}
|
||||
}
|
||||
|
||||
function updateHighlight() {
|
||||
$highlight.innerText = '';
|
||||
for (let index = 0; index < option.highlight.length; index++) {
|
||||
const item = option.highlight[index];
|
||||
const left = (clamp(item.time, 0, art.duration) / art.duration) * 100;
|
||||
const html = `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`;
|
||||
append($highlight, html);
|
||||
}
|
||||
}
|
||||
function updateHighlight() {
|
||||
$highlight.textContent = ''
|
||||
for (let index = 0; index < option.highlight.length; index++) {
|
||||
const item = option.highlight[index]
|
||||
const left = (clamp(item.time, 0, art.duration) / art.duration) * 100
|
||||
const html = `<span data-text="${item.text}" data-time="${item.time}" style="left: ${left}%"></span>`
|
||||
append($highlight, html)
|
||||
}
|
||||
}
|
||||
|
||||
function setBar(type, percentage, event) {
|
||||
const isMobileDragging = type === 'played' && event && isMobile;
|
||||
function setBar(type, percentage, event) {
|
||||
const isMobileDragging = type === 'played' && event && isMobile
|
||||
|
||||
if (type === 'loaded') {
|
||||
setStyle($loaded, 'width', `${percentage * 100}%`);
|
||||
}
|
||||
if (type === 'loaded') {
|
||||
setStyle($loaded, 'width', `${percentage * 100}%`)
|
||||
}
|
||||
|
||||
if (type === 'hover') {
|
||||
setStyle($hover, 'width', `${percentage * 100}%`);
|
||||
}
|
||||
if (type === 'hover') {
|
||||
setStyle($hover, 'width', `${percentage * 100}%`)
|
||||
}
|
||||
|
||||
if (type === 'played') {
|
||||
setStyle($played, 'width', `${percentage * 100}%`);
|
||||
setStyle($indicator, 'left', `${percentage * 100}%`);
|
||||
}
|
||||
if (type === 'played') {
|
||||
setStyle($played, 'width', `${percentage * 100}%`)
|
||||
setStyle($indicator, 'left', `${percentage * 100}%`)
|
||||
}
|
||||
|
||||
if (isMobileDragging) {
|
||||
setStyle($tip, 'display', 'flex');
|
||||
const width = $control.clientWidth * percentage;
|
||||
const time = secondToTime(percentage * art.duration);
|
||||
showTime(event, { width, time });
|
||||
clearTimeout(tipTimer);
|
||||
tipTimer = setTimeout(() => {
|
||||
setStyle($tip, 'display', 'none');
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
if (isMobileDragging) {
|
||||
setStyle($tip, 'display', 'flex')
|
||||
const width = $control.clientWidth * percentage
|
||||
const time = secondToTime(percentage * art.duration)
|
||||
showTime(event, { width, time })
|
||||
clearTimeout(tipTimer)
|
||||
tipTimer = setTimeout(() => {
|
||||
setStyle($tip, 'display', 'none')
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
art.on('setBar', setBar);
|
||||
art.on('video:loadedmetadata', updateHighlight);
|
||||
art.on('setBar', setBar)
|
||||
art.on('video:loadedmetadata', updateHighlight)
|
||||
|
||||
if (art.constructor.USE_RAF) {
|
||||
art.on('raf', () => {
|
||||
art.emit('setBar', 'played', art.played);
|
||||
art.emit('setBar', 'loaded', art.loaded);
|
||||
});
|
||||
} else {
|
||||
art.on('video:timeupdate', () => {
|
||||
art.emit('setBar', 'played', art.played);
|
||||
});
|
||||
if (art.constructor.USE_RAF) {
|
||||
art.on('raf', () => {
|
||||
art.emit('setBar', 'played', art.played)
|
||||
art.emit('setBar', 'loaded', art.loaded)
|
||||
})
|
||||
}
|
||||
else {
|
||||
art.on('video:timeupdate', () => {
|
||||
art.emit('setBar', 'played', art.played)
|
||||
})
|
||||
|
||||
art.on('video:progress', () => {
|
||||
art.emit('setBar', 'loaded', art.loaded);
|
||||
});
|
||||
art.on('video:progress', () => {
|
||||
art.emit('setBar', 'loaded', art.loaded)
|
||||
})
|
||||
|
||||
art.on('video:ended', () => {
|
||||
art.emit('setBar', 'played', 1);
|
||||
});
|
||||
}
|
||||
art.on('video:ended', () => {
|
||||
art.emit('setBar', 'played', 1)
|
||||
})
|
||||
}
|
||||
|
||||
art.emit('setBar', 'loaded', art.loaded || 0);
|
||||
art.emit('setBar', 'loaded', art.loaded || 0)
|
||||
|
||||
if (!isMobile) {
|
||||
proxy($control, 'click', (event) => {
|
||||
if (event.target !== $indicator) {
|
||||
setCurrentTime(art, event);
|
||||
}
|
||||
});
|
||||
if (!isMobile) {
|
||||
proxy($control, 'click', (event) => {
|
||||
if (event.target !== $indicator) {
|
||||
setCurrentTime(art, event)
|
||||
}
|
||||
})
|
||||
|
||||
proxy($control, 'mousemove', (event) => {
|
||||
const { percentage } = getPosFromEvent(art, event);
|
||||
art.emit('setBar', 'hover', percentage, event);
|
||||
setStyle($tip, 'display', 'flex');
|
||||
if (includeFromEvent(event, $highlight)) {
|
||||
showHighlight(event);
|
||||
} else {
|
||||
showTime(event);
|
||||
}
|
||||
});
|
||||
proxy($control, 'mousemove', (event) => {
|
||||
const { percentage } = getPosFromEvent(art, event)
|
||||
art.emit('setBar', 'hover', percentage, event)
|
||||
setStyle($tip, 'display', 'flex')
|
||||
if (includeFromEvent(event, $highlight)) {
|
||||
showHighlight(event)
|
||||
}
|
||||
else {
|
||||
showTime(event)
|
||||
}
|
||||
})
|
||||
|
||||
proxy($control, 'mouseleave', (event) => {
|
||||
setStyle($tip, 'display', 'none');
|
||||
art.emit('setBar', 'hover', 0, event);
|
||||
});
|
||||
proxy($control, 'mouseleave', (event) => {
|
||||
setStyle($tip, 'display', 'none')
|
||||
art.emit('setBar', 'hover', 0, event)
|
||||
})
|
||||
|
||||
proxy($control, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0;
|
||||
});
|
||||
proxy($control, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0
|
||||
})
|
||||
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
const { second, percentage } = getPosFromEvent(art, event);
|
||||
art.emit('setBar', 'played', percentage, event);
|
||||
art.seek = second;
|
||||
}
|
||||
});
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
const { second, percentage } = getPosFromEvent(art, event)
|
||||
art.emit('setBar', 'played', percentage, event)
|
||||
art.seek = second
|
||||
}
|
||||
})
|
||||
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import { append } from '../utils';
|
||||
import { append } from '../utils'
|
||||
|
||||
export default function screenshot(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Screenshot'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Screenshot'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art
|
||||
|
||||
append($control, icons.screenshot);
|
||||
proxy($control, 'click', () => {
|
||||
art.screenshot();
|
||||
});
|
||||
},
|
||||
});
|
||||
append($control, icons.screenshot)
|
||||
proxy($control, 'click', () => {
|
||||
art.screenshot()
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
import { append, tooltip } from '../utils';
|
||||
import { append, tooltip } from '../utils'
|
||||
|
||||
export default function setting(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Show Setting'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
tooltip: art.i18n.get('Show Setting'),
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons, i18n } = art
|
||||
|
||||
append($control, icons.setting);
|
||||
append($control, icons.setting)
|
||||
|
||||
proxy($control, 'click', () => {
|
||||
art.setting.toggle();
|
||||
art.setting.resize();
|
||||
});
|
||||
proxy($control, 'click', () => {
|
||||
art.setting.toggle()
|
||||
art.setting.resize()
|
||||
})
|
||||
|
||||
art.on('setting', (value) => {
|
||||
tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting'));
|
||||
});
|
||||
},
|
||||
});
|
||||
art.on('setting', (value) => {
|
||||
tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting'))
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
import { secondToTime, isMobile } from '../utils';
|
||||
import { isMobile, secondToTime } from '../utils'
|
||||
|
||||
export default function time(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
style: isMobile
|
||||
? {
|
||||
fontSize: '12px',
|
||||
padding: '0 5px',
|
||||
}
|
||||
: {
|
||||
cursor: 'auto',
|
||||
padding: '0 10px',
|
||||
},
|
||||
mounted: ($control) => {
|
||||
function getTime() {
|
||||
const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`;
|
||||
if (newTime !== $control.innerText) {
|
||||
$control.innerText = newTime;
|
||||
}
|
||||
}
|
||||
|
||||
getTime();
|
||||
|
||||
const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress'];
|
||||
for (let index = 0; index < events.length; index++) {
|
||||
art.on(events[index], getTime);
|
||||
}
|
||||
return art => ({
|
||||
...option,
|
||||
style: isMobile
|
||||
? {
|
||||
fontSize: '12px',
|
||||
padding: '0 5px',
|
||||
}
|
||||
: {
|
||||
cursor: 'auto',
|
||||
padding: '0 10px',
|
||||
},
|
||||
});
|
||||
mounted: ($control) => {
|
||||
function getTime() {
|
||||
const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`
|
||||
if (newTime !== $control.textContent) {
|
||||
$control.textContent = newTime
|
||||
}
|
||||
}
|
||||
|
||||
getTime()
|
||||
|
||||
const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress']
|
||||
for (let index = 0; index < events.length; index++) {
|
||||
art.on(events[index], getTime)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,77 +1,79 @@
|
||||
import { append, setStyle, isMobile, getRect } from '../utils';
|
||||
import { append, getRect, isMobile, setStyle } from '../utils'
|
||||
|
||||
export default function volume(option) {
|
||||
return (art) => ({
|
||||
...option,
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art;
|
||||
return art => ({
|
||||
...option,
|
||||
mounted: ($control) => {
|
||||
const { proxy, icons } = art
|
||||
|
||||
const $volume = append($control, icons.volume);
|
||||
const $close = append($control, icons.volumeClose);
|
||||
const $panel = append($control, '<div class="art-volume-panel"></div>');
|
||||
const $inner = append($panel, '<div class="art-volume-inner"></div>');
|
||||
const $value = append($inner, `<div class="art-volume-val"></div>`);
|
||||
const $slider = append($inner, `<div class="art-volume-slider"></div>`);
|
||||
const $handle = append($slider, `<div class="art-volume-handle"></div>`);
|
||||
const $loaded = append($handle, `<div class="art-volume-loaded"></div>`);
|
||||
const $indicator = append($slider, `<div class="art-volume-indicator"></div>`);
|
||||
const $volume = append($control, icons.volume)
|
||||
const $close = append($control, icons.volumeClose)
|
||||
const $panel = append($control, '<div class="art-volume-panel"></div>')
|
||||
const $inner = append($panel, '<div class="art-volume-inner"></div>')
|
||||
const $value = append($inner, `<div class="art-volume-val"></div>`)
|
||||
const $slider = append($inner, `<div class="art-volume-slider"></div>`)
|
||||
const $handle = append($slider, `<div class="art-volume-handle"></div>`)
|
||||
const $loaded = append($handle, `<div class="art-volume-loaded"></div>`)
|
||||
const $indicator = append($slider, `<div class="art-volume-indicator"></div>`)
|
||||
|
||||
function getVolumeFromEvent(event) {
|
||||
const { top, height } = getRect($slider);
|
||||
return 1 - (event.clientY - top) / height;
|
||||
}
|
||||
function getVolumeFromEvent(event) {
|
||||
const { top, height } = getRect($slider)
|
||||
return 1 - (event.clientY - top) / height
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (art.muted || art.volume === 0) {
|
||||
setStyle($volume, 'display', 'none');
|
||||
setStyle($close, 'display', 'flex');
|
||||
setStyle($indicator, 'top', '100%');
|
||||
setStyle($loaded, 'top', '100%');
|
||||
$value.innerText = 0;
|
||||
} else {
|
||||
const percentage = art.volume * 100;
|
||||
setStyle($volume, 'display', 'flex');
|
||||
setStyle($close, 'display', 'none');
|
||||
setStyle($indicator, 'top', `${100 - percentage}%`);
|
||||
setStyle($loaded, 'top', `${100 - percentage}%`);
|
||||
$value.innerText = Math.floor(percentage);
|
||||
}
|
||||
}
|
||||
function update() {
|
||||
if (art.muted || art.volume === 0) {
|
||||
setStyle($volume, 'display', 'none')
|
||||
setStyle($close, 'display', 'flex')
|
||||
setStyle($indicator, 'top', '100%')
|
||||
setStyle($loaded, 'top', '100%')
|
||||
$value.textContent = 0
|
||||
}
|
||||
else {
|
||||
const percentage = art.volume * 100
|
||||
setStyle($volume, 'display', 'flex')
|
||||
setStyle($close, 'display', 'none')
|
||||
setStyle($indicator, 'top', `${100 - percentage}%`)
|
||||
setStyle($loaded, 'top', `${100 - percentage}%`)
|
||||
$value.textContent = Math.floor(percentage)
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
art.on('video:volumechange', update);
|
||||
update()
|
||||
art.on('video:volumechange', update)
|
||||
|
||||
proxy($volume, 'click', () => {
|
||||
art.muted = true;
|
||||
});
|
||||
proxy($volume, 'click', () => {
|
||||
art.muted = true
|
||||
})
|
||||
|
||||
proxy($close, 'click', () => {
|
||||
art.muted = false;
|
||||
});
|
||||
proxy($close, 'click', () => {
|
||||
art.muted = false
|
||||
})
|
||||
|
||||
if (isMobile) {
|
||||
setStyle($panel, 'display', 'none');
|
||||
} else {
|
||||
let isDragging = false;
|
||||
if (isMobile) {
|
||||
setStyle($panel, 'display', 'none')
|
||||
}
|
||||
else {
|
||||
let isDragging = false
|
||||
|
||||
proxy($slider, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0;
|
||||
art.volume = getVolumeFromEvent(event);
|
||||
});
|
||||
proxy($slider, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0
|
||||
art.volume = getVolumeFromEvent(event)
|
||||
})
|
||||
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
art.muted = false;
|
||||
art.volume = getVolumeFromEvent(event);
|
||||
}
|
||||
});
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
art.muted = false
|
||||
art.volume = getVolumeFromEvent(event)
|
||||
}
|
||||
})
|
||||
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,59 +1,62 @@
|
||||
import { includeFromEvent, isMobile } from '../utils';
|
||||
import { includeFromEvent, isMobile } from '../utils'
|
||||
|
||||
export default function clickInit(art, events) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
events.proxy(document, ['click', 'contextmenu'], (event) => {
|
||||
if (includeFromEvent(event, $player)) {
|
||||
art.isInput = event.target.tagName === 'INPUT';
|
||||
art.isFocus = true;
|
||||
art.emit('focus', event);
|
||||
} else {
|
||||
art.isInput = false;
|
||||
art.isFocus = false;
|
||||
art.emit('blur', event);
|
||||
events.proxy(document, ['click', 'contextmenu'], (event) => {
|
||||
if (includeFromEvent(event, $player)) {
|
||||
art.isInput = event.target.tagName === 'INPUT'
|
||||
art.isFocus = true
|
||||
art.emit('focus', event)
|
||||
}
|
||||
else {
|
||||
art.isInput = false
|
||||
art.isFocus = false
|
||||
art.emit('blur', event)
|
||||
}
|
||||
})
|
||||
|
||||
let clickTimes = []
|
||||
events.proxy($video, 'click', (event) => {
|
||||
const now = Date.now()
|
||||
clickTimes.push(now)
|
||||
const { MOBILE_CLICK_PLAY, DBCLICK_TIME, MOBILE_DBCLICK_PLAY, DBCLICK_FULLSCREEN } = constructor
|
||||
|
||||
const clicks = clickTimes.filter(t => now - t <= DBCLICK_TIME)
|
||||
switch (clicks.length) {
|
||||
case 1:
|
||||
art.emit('click', event)
|
||||
|
||||
if (isMobile) {
|
||||
if (!art.isLock && MOBILE_CLICK_PLAY) {
|
||||
art.toggle()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let clickTimes = [];
|
||||
events.proxy($video, 'click', (event) => {
|
||||
const now = Date.now();
|
||||
clickTimes.push(now);
|
||||
const { MOBILE_CLICK_PLAY, DBCLICK_TIME, MOBILE_DBCLICK_PLAY, DBCLICK_FULLSCREEN } = constructor;
|
||||
|
||||
const clicks = clickTimes.filter((t) => now - t <= DBCLICK_TIME);
|
||||
switch (clicks.length) {
|
||||
case 1:
|
||||
art.emit('click', event);
|
||||
|
||||
if (isMobile) {
|
||||
if (!art.isLock && MOBILE_CLICK_PLAY) {
|
||||
art.toggle();
|
||||
}
|
||||
} else {
|
||||
art.toggle();
|
||||
}
|
||||
clickTimes = clicks;
|
||||
break;
|
||||
case 2:
|
||||
art.emit('dblclick', event);
|
||||
|
||||
if (isMobile) {
|
||||
if (!art.isLock && MOBILE_DBCLICK_PLAY) {
|
||||
art.toggle();
|
||||
}
|
||||
} else {
|
||||
if (DBCLICK_FULLSCREEN) {
|
||||
art.fullscreen = !art.fullscreen;
|
||||
}
|
||||
}
|
||||
clickTimes = [];
|
||||
break;
|
||||
default:
|
||||
clickTimes = [];
|
||||
else {
|
||||
art.toggle()
|
||||
}
|
||||
});
|
||||
clickTimes = clicks
|
||||
break
|
||||
case 2:
|
||||
art.emit('dblclick', event)
|
||||
|
||||
if (isMobile) {
|
||||
if (!art.isLock && MOBILE_DBCLICK_PLAY) {
|
||||
art.toggle()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (DBCLICK_FULLSCREEN) {
|
||||
art.fullscreen = !art.fullscreen
|
||||
}
|
||||
}
|
||||
clickTimes = []
|
||||
break
|
||||
default:
|
||||
clickTimes = []
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
export default function documentInit(art, events) {
|
||||
events.proxy(document, 'mousemove', (event) => {
|
||||
art.emit('document:mousemove', event);
|
||||
});
|
||||
events.proxy(document, 'mousemove', (event) => {
|
||||
art.emit('document:mousemove', event)
|
||||
})
|
||||
|
||||
events.proxy(document, 'mouseup', (event) => {
|
||||
art.emit('document:mouseup', event);
|
||||
});
|
||||
events.proxy(document, 'mouseup', (event) => {
|
||||
art.emit('document:mouseup', event)
|
||||
})
|
||||
}
|
||||
@@ -1,101 +1,104 @@
|
||||
import { clamp, secondToTime, isMobile } from '../utils';
|
||||
import { setCurrentTime } from '../control/progress';
|
||||
import { setCurrentTime } from '../control/progress'
|
||||
import { clamp, isMobile, secondToTime } from '../utils'
|
||||
|
||||
function GetSlideAngle(dx, dy) {
|
||||
return (Math.atan2(dy, dx) * 180) / Math.PI;
|
||||
return (Math.atan2(dy, dx) * 180) / Math.PI
|
||||
}
|
||||
|
||||
function GetSlideDirection(startX, startY, endX, endY) {
|
||||
var dy = startY - endY;
|
||||
var dx = endX - startX;
|
||||
var result = 0;
|
||||
const dy = startY - endY
|
||||
const dx = endX - startX
|
||||
let result = 0
|
||||
|
||||
if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
|
||||
return result;
|
||||
}
|
||||
if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
|
||||
return result
|
||||
}
|
||||
|
||||
var angle = GetSlideAngle(dx, dy);
|
||||
if (angle >= -45 && angle < 45) {
|
||||
result = 4;
|
||||
} else if (angle >= 45 && angle < 135) {
|
||||
result = 1;
|
||||
} else if (angle >= -135 && angle < -45) {
|
||||
result = 2;
|
||||
} else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
|
||||
result = 3;
|
||||
}
|
||||
const angle = GetSlideAngle(dx, dy)
|
||||
if (angle >= -45 && angle < 45) {
|
||||
result = 4
|
||||
}
|
||||
else if (angle >= 45 && angle < 135) {
|
||||
result = 1
|
||||
}
|
||||
else if (angle >= -135 && angle < -45) {
|
||||
result = 2
|
||||
}
|
||||
else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
|
||||
result = 3
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
export default function gestureInit(art, events) {
|
||||
if (isMobile && !art.option.isLive) {
|
||||
const { $video, $progress } = art.template;
|
||||
if (isMobile && !art.option.isLive) {
|
||||
const { $video, $progress } = art.template
|
||||
|
||||
let touchTarget = null;
|
||||
let isDragging = false;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let startTime = 0;
|
||||
let touchTarget = null
|
||||
let isDragging = false
|
||||
let startX = 0
|
||||
let startY = 0
|
||||
let startTime = 0
|
||||
|
||||
const onTouchStart = (event) => {
|
||||
if (event.touches.length === 1 && !art.isLock) {
|
||||
if (touchTarget === $progress) {
|
||||
setCurrentTime(art, event);
|
||||
}
|
||||
|
||||
isDragging = true;
|
||||
const { pageX, pageY } = event.touches[0];
|
||||
startX = pageX;
|
||||
startY = pageY;
|
||||
startTime = art.currentTime;
|
||||
}
|
||||
};
|
||||
|
||||
const onTouchMove = (event) => {
|
||||
if (event.touches.length === 1 && isDragging && art.duration) {
|
||||
const { pageX, pageY } = event.touches[0];
|
||||
const direction = GetSlideDirection(startX, startY, pageX, pageY);
|
||||
const isHorizontal = [3, 4].includes(direction);
|
||||
const isVertical = [1, 2].includes(direction);
|
||||
const isLegal = (isHorizontal && !art.isRotate) || (isVertical && art.isRotate);
|
||||
if (isLegal) {
|
||||
const ratioX = clamp((pageX - startX) / art.width, -1, 1);
|
||||
const ratioY = clamp((pageY - startY) / art.height, -1, 1);
|
||||
const ratio = art.isRotate ? ratioY : ratioX;
|
||||
const TOUCH_MOVE_RATIO = touchTarget === $video ? art.constructor.TOUCH_MOVE_RATIO : 1;
|
||||
const currentTime = clamp(startTime + art.duration * ratio * TOUCH_MOVE_RATIO, 0, art.duration);
|
||||
art.seek = currentTime;
|
||||
art.emit('setBar', 'played', clamp(currentTime / art.duration, 0, 1), event);
|
||||
art.notice.show = `${secondToTime(currentTime)} / ${secondToTime(art.duration)}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onTouchEnd = () => {
|
||||
if (isDragging) {
|
||||
startX = 0;
|
||||
startY = 0;
|
||||
startTime = 0;
|
||||
isDragging = false;
|
||||
touchTarget = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (art.option.gesture) {
|
||||
events.proxy($video, 'touchstart', (event) => {
|
||||
touchTarget = $video;
|
||||
onTouchStart(event);
|
||||
});
|
||||
events.proxy($video, 'touchmove', onTouchMove);
|
||||
const onTouchStart = (event) => {
|
||||
if (event.touches.length === 1 && !art.isLock) {
|
||||
if (touchTarget === $progress) {
|
||||
setCurrentTime(art, event)
|
||||
}
|
||||
|
||||
events.proxy($progress, 'touchstart', (event) => {
|
||||
touchTarget = $progress;
|
||||
onTouchStart(event);
|
||||
});
|
||||
|
||||
events.proxy($progress, 'touchmove', onTouchMove);
|
||||
events.proxy(document, 'touchend', onTouchEnd);
|
||||
isDragging = true
|
||||
const { pageX, pageY } = event.touches[0]
|
||||
startX = pageX
|
||||
startY = pageY
|
||||
startTime = art.currentTime
|
||||
}
|
||||
}
|
||||
|
||||
const onTouchMove = (event) => {
|
||||
if (event.touches.length === 1 && isDragging && art.duration) {
|
||||
const { pageX, pageY } = event.touches[0]
|
||||
const direction = GetSlideDirection(startX, startY, pageX, pageY)
|
||||
const isHorizontal = [3, 4].includes(direction)
|
||||
const isVertical = [1, 2].includes(direction)
|
||||
const isLegal = (isHorizontal && !art.isRotate) || (isVertical && art.isRotate)
|
||||
if (isLegal) {
|
||||
const ratioX = clamp((pageX - startX) / art.width, -1, 1)
|
||||
const ratioY = clamp((pageY - startY) / art.height, -1, 1)
|
||||
const ratio = art.isRotate ? ratioY : ratioX
|
||||
const TOUCH_MOVE_RATIO = touchTarget === $video ? art.constructor.TOUCH_MOVE_RATIO : 1
|
||||
const currentTime = clamp(startTime + art.duration * ratio * TOUCH_MOVE_RATIO, 0, art.duration)
|
||||
art.seek = currentTime
|
||||
art.emit('setBar', 'played', clamp(currentTime / art.duration, 0, 1), event)
|
||||
art.notice.show = `${secondToTime(currentTime)} / ${secondToTime(art.duration)}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onTouchEnd = () => {
|
||||
if (isDragging) {
|
||||
startX = 0
|
||||
startY = 0
|
||||
startTime = 0
|
||||
isDragging = false
|
||||
touchTarget = null
|
||||
}
|
||||
}
|
||||
|
||||
if (art.option.gesture) {
|
||||
events.proxy($video, 'touchstart', (event) => {
|
||||
touchTarget = $video
|
||||
onTouchStart(event)
|
||||
})
|
||||
events.proxy($video, 'touchmove', onTouchMove)
|
||||
}
|
||||
|
||||
events.proxy($progress, 'touchstart', (event) => {
|
||||
touchTarget = $progress
|
||||
onTouchStart(event)
|
||||
})
|
||||
|
||||
events.proxy($progress, 'touchmove', onTouchMove)
|
||||
events.proxy(document, 'touchend', onTouchEnd)
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { addClass, removeClass } from '../utils';
|
||||
import { addClass, removeClass } from '../utils'
|
||||
|
||||
export default function hoverInit(art, events) {
|
||||
const { $player } = art.template;
|
||||
const { $player } = art.template
|
||||
|
||||
events.hover(
|
||||
$player,
|
||||
(event) => {
|
||||
addClass($player, 'art-hover');
|
||||
art.emit('hover', true, event);
|
||||
},
|
||||
(event) => {
|
||||
removeClass($player, 'art-hover');
|
||||
art.emit('hover', false, event);
|
||||
},
|
||||
);
|
||||
events.hover(
|
||||
$player,
|
||||
(event) => {
|
||||
addClass($player, 'art-hover')
|
||||
art.emit('hover', true, event)
|
||||
},
|
||||
(event) => {
|
||||
removeClass($player, 'art-hover')
|
||||
art.emit('hover', false, event)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1,61 +1,59 @@
|
||||
import clickInit from './clickInit';
|
||||
import hoverInit from './hoverInit';
|
||||
import moveInit from './moveInit';
|
||||
import resizeInit from './resizeInit';
|
||||
import gestureInit from './gestureInit';
|
||||
import viewInit from './viewInit';
|
||||
import documentInit from './documentInit';
|
||||
import updateInit from './updateInit';
|
||||
import restoreInit from './restoreInit';
|
||||
import clickInit from './clickInit'
|
||||
import documentInit from './documentInit'
|
||||
import gestureInit from './gestureInit'
|
||||
import hoverInit from './hoverInit'
|
||||
import moveInit from './moveInit'
|
||||
import resizeInit from './resizeInit'
|
||||
import updateInit from './updateInit'
|
||||
import viewInit from './viewInit'
|
||||
|
||||
export default class Events {
|
||||
constructor(art) {
|
||||
this.destroyEvents = [];
|
||||
this.proxy = this.proxy.bind(this);
|
||||
this.hover = this.hover.bind(this);
|
||||
constructor(art) {
|
||||
this.destroyEvents = []
|
||||
this.proxy = this.proxy.bind(this)
|
||||
this.hover = this.hover.bind(this)
|
||||
|
||||
clickInit(art, this);
|
||||
hoverInit(art, this);
|
||||
moveInit(art, this);
|
||||
resizeInit(art, this);
|
||||
gestureInit(art, this);
|
||||
viewInit(art, this);
|
||||
documentInit(art, this);
|
||||
updateInit(art, this);
|
||||
restoreInit(art, this);
|
||||
clickInit(art, this)
|
||||
hoverInit(art, this)
|
||||
moveInit(art, this)
|
||||
resizeInit(art, this)
|
||||
gestureInit(art, this)
|
||||
viewInit(art, this)
|
||||
documentInit(art, this)
|
||||
updateInit(art, this)
|
||||
}
|
||||
|
||||
proxy(target, name, callback, option = {}) {
|
||||
if (Array.isArray(name)) {
|
||||
return name.map(item => this.proxy(target, item, callback, option))
|
||||
}
|
||||
|
||||
proxy(target, name, callback, option = {}) {
|
||||
if (Array.isArray(name)) {
|
||||
return name.map((item) => this.proxy(target, item, callback, option));
|
||||
}
|
||||
target.addEventListener(name, callback, option)
|
||||
const destroy = () => target.removeEventListener(name, callback, option)
|
||||
this.destroyEvents.push(destroy)
|
||||
return destroy
|
||||
}
|
||||
|
||||
target.addEventListener(name, callback, option);
|
||||
const destroy = () => target.removeEventListener(name, callback, option);
|
||||
this.destroyEvents.push(destroy);
|
||||
return destroy;
|
||||
hover(target, mouseenter, mouseleave) {
|
||||
if (mouseenter) {
|
||||
this.proxy(target, 'mouseenter', mouseenter)
|
||||
}
|
||||
if (mouseleave) {
|
||||
this.proxy(target, 'mouseleave', mouseleave)
|
||||
}
|
||||
}
|
||||
|
||||
hover(target, mouseenter, mouseleave) {
|
||||
if (mouseenter) {
|
||||
this.proxy(target, 'mouseenter', mouseenter);
|
||||
}
|
||||
if (mouseleave) {
|
||||
this.proxy(target, 'mouseleave', mouseleave);
|
||||
}
|
||||
remove(destroyEvent) {
|
||||
const index = this.destroyEvents.indexOf(destroyEvent)
|
||||
if (index > -1) {
|
||||
destroyEvent()
|
||||
this.destroyEvents.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
remove(destroyEvent) {
|
||||
const index = this.destroyEvents.indexOf(destroyEvent);
|
||||
if (index > -1) {
|
||||
destroyEvent();
|
||||
this.destroyEvents.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (let index = 0; index < this.destroyEvents.length; index++) {
|
||||
this.destroyEvents[index]();
|
||||
}
|
||||
destroy() {
|
||||
for (let index = 0; index < this.destroyEvents.length; index++) {
|
||||
this.destroyEvents[index]()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export default function moveInit(art, events) {
|
||||
const { $player } = art.template;
|
||||
const { $player } = art.template
|
||||
|
||||
events.proxy($player, 'mousemove', (event) => {
|
||||
art.emit('mousemove', event);
|
||||
});
|
||||
events.proxy($player, 'mousemove', (event) => {
|
||||
art.emit('mousemove', event)
|
||||
})
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import { debounce } from '../utils';
|
||||
import { debounce } from '../utils'
|
||||
|
||||
export default function resizeInit(art, events) {
|
||||
const { option, constructor } = art;
|
||||
const { option, constructor } = art
|
||||
|
||||
art.on('resize', () => {
|
||||
const { aspectRatio, notice } = art;
|
||||
if (art.state === 'standard' && option.autoSize) {
|
||||
art.autoSize();
|
||||
}
|
||||
art.aspectRatio = aspectRatio;
|
||||
notice.show = '';
|
||||
});
|
||||
|
||||
const resizeFn = debounce(() => art.emit('resize'), constructor.RESIZE_TIME);
|
||||
events.proxy(window, ['orientationchange', 'resize'], () => resizeFn());
|
||||
if (screen && screen.orientation && screen.orientation.onchange) {
|
||||
events.proxy(screen.orientation, 'change', () => resizeFn());
|
||||
art.on('resize', () => {
|
||||
const { aspectRatio, notice } = art
|
||||
if (art.state === 'standard' && option.autoSize) {
|
||||
art.autoSize()
|
||||
}
|
||||
art.aspectRatio = aspectRatio
|
||||
notice.show = ''
|
||||
})
|
||||
|
||||
const resizeFn = debounce(() => art.emit('resize'), constructor.RESIZE_TIME)
|
||||
events.proxy(window, ['orientationchange', 'resize'], () => resizeFn())
|
||||
if (screen && screen.orientation && screen.orientation.onchange) {
|
||||
events.proxy(screen.orientation, 'change', () => resizeFn())
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function restoreInit(art, events) {
|
||||
//
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
export default function updateInit(art) {
|
||||
if (art.constructor.USE_RAF) {
|
||||
let timer = null;
|
||||
if (art.constructor.USE_RAF) {
|
||||
let timer = null;
|
||||
|
||||
(function update() {
|
||||
if (art.playing) {
|
||||
art.emit('raf');
|
||||
}
|
||||
(function update() {
|
||||
if (art.playing) {
|
||||
art.emit('raf')
|
||||
}
|
||||
|
||||
if (!art.isDestroy) {
|
||||
timer = requestAnimationFrame(update);
|
||||
}
|
||||
})();
|
||||
if (!art.isDestroy) {
|
||||
timer = requestAnimationFrame(update)
|
||||
}
|
||||
})()
|
||||
|
||||
art.on('destroy', () => {
|
||||
cancelAnimationFrame(timer);
|
||||
});
|
||||
}
|
||||
art.on('destroy', () => {
|
||||
cancelAnimationFrame(timer)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
import { throttle, isInViewport } from '../utils';
|
||||
import { isInViewport, throttle } from '../utils'
|
||||
|
||||
export default function viewInit(art, events) {
|
||||
const {
|
||||
option,
|
||||
constructor,
|
||||
template: { $container },
|
||||
} = art;
|
||||
const {
|
||||
option,
|
||||
constructor,
|
||||
template: { $container },
|
||||
} = art
|
||||
|
||||
const scrollFn = throttle(() => {
|
||||
art.emit('view', isInViewport($container, constructor.SCROLL_GAP));
|
||||
}, constructor.SCROLL_TIME);
|
||||
const scrollFn = throttle(() => {
|
||||
art.emit('view', isInViewport($container, constructor.SCROLL_GAP))
|
||||
}, constructor.SCROLL_TIME)
|
||||
|
||||
events.proxy(window, 'scroll', () => scrollFn());
|
||||
events.proxy(window, 'scroll', () => scrollFn())
|
||||
|
||||
art.on('view', (state) => {
|
||||
if (option.autoMini) {
|
||||
art.mini = !state;
|
||||
}
|
||||
});
|
||||
art.on('view', (state) => {
|
||||
if (option.autoMini) {
|
||||
art.mini = !state
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,88 +1,89 @@
|
||||
import { isMobile } from './utils';
|
||||
import { isMobile } from './utils'
|
||||
|
||||
export default class Hotkey {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.keys = {};
|
||||
constructor(art) {
|
||||
this.art = art
|
||||
this.keys = {}
|
||||
|
||||
if (art.option.hotkey && !isMobile) {
|
||||
this.init();
|
||||
}
|
||||
if (art.option.hotkey && !isMobile) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
const { proxy, constructor } = this.art;
|
||||
init() {
|
||||
const { proxy, constructor } = this.art
|
||||
|
||||
this.add('Escape', () => {
|
||||
if (this.art.fullscreenWeb) {
|
||||
this.art.fullscreenWeb = false;
|
||||
this.add('Escape', () => {
|
||||
if (this.art.fullscreenWeb) {
|
||||
this.art.fullscreenWeb = false
|
||||
}
|
||||
})
|
||||
|
||||
this.add('Space', () => {
|
||||
this.art.toggle()
|
||||
})
|
||||
|
||||
this.add('ArrowLeft', () => {
|
||||
this.art.backward = constructor.SEEK_STEP
|
||||
})
|
||||
|
||||
this.add('ArrowUp', () => {
|
||||
this.art.volume += constructor.VOLUME_STEP
|
||||
})
|
||||
|
||||
this.add('ArrowRight', () => {
|
||||
this.art.forward = constructor.SEEK_STEP
|
||||
})
|
||||
|
||||
this.add('ArrowDown', () => {
|
||||
this.art.volume -= constructor.VOLUME_STEP
|
||||
})
|
||||
|
||||
proxy(document, 'keydown', (event) => {
|
||||
if (this.art.isFocus) {
|
||||
const tag = document.activeElement.tagName.toUpperCase()
|
||||
const editable = document.activeElement.getAttribute('contenteditable')
|
||||
if (
|
||||
tag !== 'INPUT'
|
||||
&& tag !== 'TEXTAREA'
|
||||
&& editable !== ''
|
||||
&& editable !== 'true'
|
||||
&& !event.altKey
|
||||
&& !event.ctrlKey
|
||||
&& !event.metaKey
|
||||
&& !event.shiftKey
|
||||
) {
|
||||
const events = this.keys[event.code]
|
||||
if (events) {
|
||||
event.preventDefault()
|
||||
for (let index = 0; index < events.length; index++) {
|
||||
events[index].call(this.art, event)
|
||||
}
|
||||
});
|
||||
|
||||
this.add('Space', () => {
|
||||
this.art.toggle();
|
||||
});
|
||||
|
||||
this.add('ArrowLeft', () => {
|
||||
this.art.backward = constructor.SEEK_STEP;
|
||||
});
|
||||
|
||||
this.add('ArrowUp', () => {
|
||||
this.art.volume += constructor.VOLUME_STEP;
|
||||
});
|
||||
|
||||
this.add('ArrowRight', () => {
|
||||
this.art.forward = constructor.SEEK_STEP;
|
||||
});
|
||||
|
||||
this.add('ArrowDown', () => {
|
||||
this.art.volume -= constructor.VOLUME_STEP;
|
||||
});
|
||||
|
||||
proxy(document, 'keydown', (event) => {
|
||||
if (this.art.isFocus) {
|
||||
const tag = document.activeElement.tagName.toUpperCase();
|
||||
const editable = document.activeElement.getAttribute('contenteditable');
|
||||
if (
|
||||
tag !== 'INPUT' &&
|
||||
tag !== 'TEXTAREA' &&
|
||||
editable !== '' &&
|
||||
editable !== 'true' &&
|
||||
!event.altKey &&
|
||||
!event.ctrlKey &&
|
||||
!event.metaKey &&
|
||||
!event.shiftKey
|
||||
) {
|
||||
const events = this.keys[event.code];
|
||||
if (events) {
|
||||
event.preventDefault();
|
||||
for (let index = 0; index < events.length; index++) {
|
||||
events[index].call(this.art, event);
|
||||
}
|
||||
this.art.emit('hotkey', event);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.art.emit('keydown', event);
|
||||
});
|
||||
}
|
||||
|
||||
add(key, event) {
|
||||
if (this.keys[key]) {
|
||||
this.keys[key].push(event);
|
||||
} else {
|
||||
this.keys[key] = [event];
|
||||
this.art.emit('hotkey', event)
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
this.art.emit('keydown', event)
|
||||
})
|
||||
}
|
||||
|
||||
remove(key, event) {
|
||||
if (this.keys[key]) {
|
||||
const index = this.keys[key].indexOf(event);
|
||||
if (index !== -1) {
|
||||
this.keys[key].splice(index, 1);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
add(key, event) {
|
||||
if (this.keys[key]) {
|
||||
this.keys[key].push(event)
|
||||
}
|
||||
else {
|
||||
this.keys[key] = [event]
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
remove(key, event) {
|
||||
if (this.keys[key]) {
|
||||
const index = this.keys[key].indexOf(event)
|
||||
if (index !== -1) {
|
||||
this.keys[key].splice(index, 1)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const ar = {
|
||||
'Video Info': 'معلومات الفيديو',
|
||||
Close: 'إغلاق',
|
||||
'Video Load Failed': 'فشل تحميل الفيديو',
|
||||
Volume: 'الصوت',
|
||||
Play: 'تشغيل',
|
||||
Pause: 'إيقاف مؤقت',
|
||||
Rate: 'السرعة',
|
||||
Mute: 'كتم الصوت',
|
||||
'Video Flip': 'تدوير الفيديو',
|
||||
Horizontal: 'أفقي',
|
||||
Vertical: 'عمودي',
|
||||
Reconnect: 'إعادة الاتصال',
|
||||
'Show Setting': 'إظهار الإعدادات',
|
||||
'Hide Setting': 'إخفاء الإعدادات',
|
||||
Screenshot: 'لقطة شاشة',
|
||||
'Play Speed': 'سرعة التشغيل',
|
||||
'Aspect Ratio': 'نسبة العرض إلى الارتفاع',
|
||||
Default: 'افتراضي',
|
||||
Normal: 'عادي',
|
||||
Open: 'فتح',
|
||||
'Switch Video': 'تبديل الفيديو',
|
||||
'Switch Subtitle': 'تبديل الترجمة',
|
||||
Fullscreen: 'وضع ملء الشاشة',
|
||||
'Exit Fullscreen': 'الخروج من وضع ملء الشاشة',
|
||||
'Web Fullscreen': 'وضع ملء الشاشة في المتصفح',
|
||||
'Exit Web Fullscreen': 'الخروج من وضع ملء الشاشة في المتصفح',
|
||||
'Mini Player': 'مشغل صغير',
|
||||
'PIP Mode': 'الوضع العائم',
|
||||
'Exit PIP Mode': 'الخروج من الوضع العائم',
|
||||
'PIP Not Supported': 'الوضع العائم غير مدعوم',
|
||||
'Fullscreen Not Supported': 'وضع ملء الشاشة غير مدعوم',
|
||||
'Subtitle Offset': 'إزاحة الترجمة',
|
||||
'Last Seen': 'آخر مشاهدة',
|
||||
'Jump Play': 'التشغيل القافز',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay غير متاح',
|
||||
};
|
||||
'Video Info': 'معلومات الفيديو',
|
||||
'Close': 'إغلاق',
|
||||
'Video Load Failed': 'فشل تحميل الفيديو',
|
||||
'Volume': 'الصوت',
|
||||
'Play': 'تشغيل',
|
||||
'Pause': 'إيقاف مؤقت',
|
||||
'Rate': 'السرعة',
|
||||
'Mute': 'كتم الصوت',
|
||||
'Video Flip': 'تدوير الفيديو',
|
||||
'Horizontal': 'أفقي',
|
||||
'Vertical': 'عمودي',
|
||||
'Reconnect': 'إعادة الاتصال',
|
||||
'Show Setting': 'إظهار الإعدادات',
|
||||
'Hide Setting': 'إخفاء الإعدادات',
|
||||
'Screenshot': 'لقطة شاشة',
|
||||
'Play Speed': 'سرعة التشغيل',
|
||||
'Aspect Ratio': 'نسبة العرض إلى الارتفاع',
|
||||
'Default': 'افتراضي',
|
||||
'Normal': 'عادي',
|
||||
'Open': 'فتح',
|
||||
'Switch Video': 'تبديل الفيديو',
|
||||
'Switch Subtitle': 'تبديل الترجمة',
|
||||
'Fullscreen': 'وضع ملء الشاشة',
|
||||
'Exit Fullscreen': 'الخروج من وضع ملء الشاشة',
|
||||
'Web Fullscreen': 'وضع ملء الشاشة في المتصفح',
|
||||
'Exit Web Fullscreen': 'الخروج من وضع ملء الشاشة في المتصفح',
|
||||
'Mini Player': 'مشغل صغير',
|
||||
'PIP Mode': 'الوضع العائم',
|
||||
'Exit PIP Mode': 'الخروج من الوضع العائم',
|
||||
'PIP Not Supported': 'الوضع العائم غير مدعوم',
|
||||
'Fullscreen Not Supported': 'وضع ملء الشاشة غير مدعوم',
|
||||
'Subtitle Offset': 'إزاحة الترجمة',
|
||||
'Last Seen': 'آخر مشاهدة',
|
||||
'Jump Play': 'التشغيل القافز',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay غير متاح',
|
||||
}
|
||||
|
||||
export default ar;
|
||||
export default ar
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-ar'] = ar;
|
||||
window['artplayer-i18n-ar'] = ar
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const cs = {
|
||||
'Video Info': 'Info o videu',
|
||||
Close: 'Zavřít',
|
||||
'Video Load Failed': 'Nahrání videa selhalo',
|
||||
Volume: 'Hlasitost',
|
||||
Play: 'Přehrát',
|
||||
Pause: 'Pozastavit',
|
||||
Rate: 'Hodnocení',
|
||||
Mute: 'Ztlumit',
|
||||
'Video Flip': 'Otočit video',
|
||||
Horizontal: 'Horizontálně',
|
||||
Vertical: 'Vertikálně',
|
||||
Reconnect: 'Opětovné připojení',
|
||||
'Show Setting': 'Zobrazit nastavení',
|
||||
'Hide Setting': 'Skrýt nastavení',
|
||||
Screenshot: 'Snímek obrazovky',
|
||||
'Play Speed': 'Rychlost přehrávání',
|
||||
'Aspect Ratio': 'Poměr stran',
|
||||
Default: 'Výchozí',
|
||||
Normal: 'Normální',
|
||||
Open: 'Otevřít',
|
||||
'Switch Video': 'Přepnout video',
|
||||
'Switch Subtitle': 'Přepnout titulky',
|
||||
Fullscreen: 'Celá obrazovka',
|
||||
'Exit Fullscreen': 'Opustit režim celé obrazovky',
|
||||
'Web Fullscreen': 'Celá stránka',
|
||||
'Exit Web Fullscreen': 'Zavřít režim celé stránky',
|
||||
'Mini Player': 'Mini přehrávač',
|
||||
'PIP Mode': 'Režim PIP',
|
||||
'Exit PIP Mode': 'Opustit režim PIP',
|
||||
'PIP Not Supported': 'Režim PIP není podporován',
|
||||
'Fullscreen Not Supported': 'Režim celé obrazovky není podporován',
|
||||
'Subtitle Offset': 'Posun titulků',
|
||||
'Last Seen': 'Naposledy viděn',
|
||||
'Jump Play': 'Hra na skok',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay není k dispozici',
|
||||
};
|
||||
'Video Info': 'Info o videu',
|
||||
'Close': 'Zavřít',
|
||||
'Video Load Failed': 'Nahrání videa selhalo',
|
||||
'Volume': 'Hlasitost',
|
||||
'Play': 'Přehrát',
|
||||
'Pause': 'Pozastavit',
|
||||
'Rate': 'Hodnocení',
|
||||
'Mute': 'Ztlumit',
|
||||
'Video Flip': 'Otočit video',
|
||||
'Horizontal': 'Horizontálně',
|
||||
'Vertical': 'Vertikálně',
|
||||
'Reconnect': 'Opětovné připojení',
|
||||
'Show Setting': 'Zobrazit nastavení',
|
||||
'Hide Setting': 'Skrýt nastavení',
|
||||
'Screenshot': 'Snímek obrazovky',
|
||||
'Play Speed': 'Rychlost přehrávání',
|
||||
'Aspect Ratio': 'Poměr stran',
|
||||
'Default': 'Výchozí',
|
||||
'Normal': 'Normální',
|
||||
'Open': 'Otevřít',
|
||||
'Switch Video': 'Přepnout video',
|
||||
'Switch Subtitle': 'Přepnout titulky',
|
||||
'Fullscreen': 'Celá obrazovka',
|
||||
'Exit Fullscreen': 'Opustit režim celé obrazovky',
|
||||
'Web Fullscreen': 'Celá stránka',
|
||||
'Exit Web Fullscreen': 'Zavřít režim celé stránky',
|
||||
'Mini Player': 'Mini přehrávač',
|
||||
'PIP Mode': 'Režim PIP',
|
||||
'Exit PIP Mode': 'Opustit režim PIP',
|
||||
'PIP Not Supported': 'Režim PIP není podporován',
|
||||
'Fullscreen Not Supported': 'Režim celé obrazovky není podporován',
|
||||
'Subtitle Offset': 'Posun titulků',
|
||||
'Last Seen': 'Naposledy viděn',
|
||||
'Jump Play': 'Hra na skok',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay není k dispozici',
|
||||
}
|
||||
|
||||
export default cs;
|
||||
export default cs
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-cs'] = cs;
|
||||
window['artplayer-i18n-cs'] = cs
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const es = {
|
||||
'Video Info': 'Información del video',
|
||||
Close: 'Cerrar',
|
||||
'Video Load Failed': 'Falló carga de video',
|
||||
Volume: 'Volumen',
|
||||
Play: 'Reproduciendo',
|
||||
Pause: 'Pausa',
|
||||
Rate: 'Velocidad',
|
||||
Mute: 'Silencio',
|
||||
'Video Flip': 'Rotar video',
|
||||
Horizontal: 'Horizontal',
|
||||
Vertical: 'Vertical',
|
||||
Reconnect: 'Reconectando',
|
||||
'Show Setting': 'Mostrar ajustes',
|
||||
'Hide Setting': 'Ocultar ajustes',
|
||||
Screenshot: 'Captura de Pantalla',
|
||||
'Play Speed': 'Velocidad de reproducción',
|
||||
'Aspect Ratio': 'Relación de aspecto',
|
||||
Default: 'Por defecto',
|
||||
Normal: 'Normal',
|
||||
Open: 'Abrir',
|
||||
'Switch Video': 'Cambiar video',
|
||||
'Switch Subtitle': 'Cambiar subtítulo',
|
||||
Fullscreen: 'Pantalla completa',
|
||||
'Exit Fullscreen': 'Salir de Pantalla completa',
|
||||
'Web Fullscreen': 'Pantalla completa Web',
|
||||
'Exit Web Fullscreen': 'Salir de Pantalla completa',
|
||||
'Mini Player': 'Mini reproductor',
|
||||
'PIP Mode': 'Modo PiP',
|
||||
'Exit PIP Mode': 'Cerrar modo PiP',
|
||||
'PIP Not Supported': 'Modo PiP no compatible',
|
||||
'Fullscreen Not Supported': 'Pantalla completa no soportada',
|
||||
'Subtitle Offset': 'Ajuste subtítulo',
|
||||
'Last Seen': 'Visto última vez',
|
||||
'Jump Play': 'Saltar',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay no disponible',
|
||||
};
|
||||
'Video Info': 'Información del video',
|
||||
'Close': 'Cerrar',
|
||||
'Video Load Failed': 'Falló carga de video',
|
||||
'Volume': 'Volumen',
|
||||
'Play': 'Reproduciendo',
|
||||
'Pause': 'Pausa',
|
||||
'Rate': 'Velocidad',
|
||||
'Mute': 'Silencio',
|
||||
'Video Flip': 'Rotar video',
|
||||
'Horizontal': 'Horizontal',
|
||||
'Vertical': 'Vertical',
|
||||
'Reconnect': 'Reconectando',
|
||||
'Show Setting': 'Mostrar ajustes',
|
||||
'Hide Setting': 'Ocultar ajustes',
|
||||
'Screenshot': 'Captura de Pantalla',
|
||||
'Play Speed': 'Velocidad de reproducción',
|
||||
'Aspect Ratio': 'Relación de aspecto',
|
||||
'Default': 'Por defecto',
|
||||
'Normal': 'Normal',
|
||||
'Open': 'Abrir',
|
||||
'Switch Video': 'Cambiar video',
|
||||
'Switch Subtitle': 'Cambiar subtítulo',
|
||||
'Fullscreen': 'Pantalla completa',
|
||||
'Exit Fullscreen': 'Salir de Pantalla completa',
|
||||
'Web Fullscreen': 'Pantalla completa Web',
|
||||
'Exit Web Fullscreen': 'Salir de Pantalla completa',
|
||||
'Mini Player': 'Mini reproductor',
|
||||
'PIP Mode': 'Modo PiP',
|
||||
'Exit PIP Mode': 'Cerrar modo PiP',
|
||||
'PIP Not Supported': 'Modo PiP no compatible',
|
||||
'Fullscreen Not Supported': 'Pantalla completa no soportada',
|
||||
'Subtitle Offset': 'Ajuste subtítulo',
|
||||
'Last Seen': 'Visto última vez',
|
||||
'Jump Play': 'Saltar',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay no disponible',
|
||||
}
|
||||
|
||||
export default es;
|
||||
export default es
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-es'] = es;
|
||||
window['artplayer-i18n-es'] = es
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const fa = {
|
||||
'Video Info': 'اطلاعات ویدیو',
|
||||
Close: 'بستن',
|
||||
'Video Load Failed': 'بارگذاری ناموفق',
|
||||
Play: 'پخش',
|
||||
Volume: 'میزان صدا',
|
||||
Pause: 'توقف',
|
||||
Rate: 'نرخ',
|
||||
Mute: 'سکوت',
|
||||
'Video Flip': 'چرخش تصویر',
|
||||
Horizontal: 'افقی',
|
||||
Vertical: 'عمودی',
|
||||
Reconnect: 'اتصال مجدد',
|
||||
'Show Setting': 'تنظیمات',
|
||||
'Hide Setting': 'بستن تنظیمات',
|
||||
Screenshot: 'عکس از صفحه',
|
||||
'Play Speed': 'سرعت پخش',
|
||||
'Aspect Ratio': 'نسبت تصویر',
|
||||
Default: 'حالت پیشفرض',
|
||||
Normal: ' حالت عادی',
|
||||
Open: 'بازکردن',
|
||||
'Switch Video': 'تغییر ویدیو',
|
||||
'Switch Subtitle': 'نغییر زیرنویس',
|
||||
Fullscreen: 'تمام صفحه',
|
||||
'Exit Fullscreen': 'کوچک کردن',
|
||||
'Web Fullscreen': 'حالت تئاتر',
|
||||
'Exit Web Fullscreen': 'خروج از حالت تئاتر',
|
||||
'Mini Player': 'حالت پخش کوچک',
|
||||
'PIP Mode': ' مینی پلیر',
|
||||
'Exit PIP Mode': 'خروج از مینی پلیر',
|
||||
'PIP Not Supported': 'عدم پشتیبانی از مینی پلیر',
|
||||
'Fullscreen Not Supported': 'عدم پشتیبانی از حالت تمام صفحه',
|
||||
'Subtitle Offset': 'افست زیرنویس',
|
||||
'Last Seen': 'آخرین بازدید',
|
||||
'Jump Play': 'جامپ پلی',
|
||||
AirPlay: 'ایر پلی',
|
||||
'AirPlay Not Available': 'عدم پشتیبانی از ایرپلی',
|
||||
};
|
||||
'Video Info': 'اطلاعات ویدیو',
|
||||
'Close': 'بستن',
|
||||
'Video Load Failed': 'بارگذاری ناموفق',
|
||||
'Play': 'پخش',
|
||||
'Volume': 'میزان صدا',
|
||||
'Pause': 'توقف',
|
||||
'Rate': 'نرخ',
|
||||
'Mute': 'سکوت',
|
||||
'Video Flip': 'چرخش تصویر',
|
||||
'Horizontal': 'افقی',
|
||||
'Vertical': 'عمودی',
|
||||
'Reconnect': 'اتصال مجدد',
|
||||
'Show Setting': 'تنظیمات',
|
||||
'Hide Setting': 'بستن تنظیمات',
|
||||
'Screenshot': 'عکس از صفحه',
|
||||
'Play Speed': 'سرعت پخش',
|
||||
'Aspect Ratio': 'نسبت تصویر',
|
||||
'Default': 'حالت پیشفرض',
|
||||
'Normal': ' حالت عادی',
|
||||
'Open': 'بازکردن',
|
||||
'Switch Video': 'تغییر ویدیو',
|
||||
'Switch Subtitle': 'نغییر زیرنویس',
|
||||
'Fullscreen': 'تمام صفحه',
|
||||
'Exit Fullscreen': 'کوچک کردن',
|
||||
'Web Fullscreen': 'حالت تئاتر',
|
||||
'Exit Web Fullscreen': 'خروج از حالت تئاتر',
|
||||
'Mini Player': 'حالت پخش کوچک',
|
||||
'PIP Mode': ' مینی پلیر',
|
||||
'Exit PIP Mode': 'خروج از مینی پلیر',
|
||||
'PIP Not Supported': 'عدم پشتیبانی از مینی پلیر',
|
||||
'Fullscreen Not Supported': 'عدم پشتیبانی از حالت تمام صفحه',
|
||||
'Subtitle Offset': 'افست زیرنویس',
|
||||
'Last Seen': 'آخرین بازدید',
|
||||
'Jump Play': 'جامپ پلی',
|
||||
'AirPlay': 'ایر پلی',
|
||||
'AirPlay Not Available': 'عدم پشتیبانی از ایرپلی',
|
||||
}
|
||||
|
||||
export default fa;
|
||||
export default fa
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-fa'] = fa;
|
||||
window['artplayer-i18n-fa'] = fa
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const fr = {
|
||||
'Video Info': 'Informations de la vidéo',
|
||||
Close: 'Fermer',
|
||||
'Video Load Failed': 'Téléchargement de la vidéo échoué',
|
||||
Volume: 'Volume',
|
||||
Play: 'Lire',
|
||||
Pause: 'Pause',
|
||||
Rate: 'Vitesse',
|
||||
Mute: 'Muet',
|
||||
'Video Flip': 'Rotation de la vidéo',
|
||||
Horizontal: 'Horizontal',
|
||||
Vertical: 'Vertical',
|
||||
Reconnect: 'Reconnexion',
|
||||
'Show Setting': 'Afficher les paramètres',
|
||||
'Hide Setting': 'Cacher les paramètres',
|
||||
Screenshot: "Capture d'écran",
|
||||
'Play Speed': 'Vitesse de lecture',
|
||||
'Aspect Ratio': "Rapport d'aspect",
|
||||
Default: 'Défaut',
|
||||
Normal: 'Normal',
|
||||
Open: 'Ouvrir',
|
||||
'Switch Video': 'Basculer la vidéo',
|
||||
'Switch Subtitle': 'Basculer le sous-titre',
|
||||
Fullscreen: 'Plein écran',
|
||||
'Exit Fullscreen': 'Quitter le plein écran',
|
||||
'Web Fullscreen': 'Plein écran Web',
|
||||
'Exit Web Fullscreen': 'Quitter le plein écran Web',
|
||||
'Mini Player': 'Mini lecteur',
|
||||
'PIP Mode': 'Mode PiP',
|
||||
'Exit PIP Mode': 'Fermer le mode PiP',
|
||||
'PIP Not Supported': 'Mode PiP non supporté',
|
||||
'Fullscreen Not Supported': 'Plein écran non supporté',
|
||||
'Subtitle Offset': 'Réglage des sous-titres',
|
||||
'Last Seen': 'Dernière position',
|
||||
'Jump Play': 'Continuer',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay non disponible',
|
||||
};
|
||||
'Video Info': 'Informations de la vidéo',
|
||||
'Close': 'Fermer',
|
||||
'Video Load Failed': 'Téléchargement de la vidéo échoué',
|
||||
'Volume': 'Volume',
|
||||
'Play': 'Lire',
|
||||
'Pause': 'Pause',
|
||||
'Rate': 'Vitesse',
|
||||
'Mute': 'Muet',
|
||||
'Video Flip': 'Rotation de la vidéo',
|
||||
'Horizontal': 'Horizontal',
|
||||
'Vertical': 'Vertical',
|
||||
'Reconnect': 'Reconnexion',
|
||||
'Show Setting': 'Afficher les paramètres',
|
||||
'Hide Setting': 'Cacher les paramètres',
|
||||
'Screenshot': 'Capture d\'écran',
|
||||
'Play Speed': 'Vitesse de lecture',
|
||||
'Aspect Ratio': 'Rapport d\'aspect',
|
||||
'Default': 'Défaut',
|
||||
'Normal': 'Normal',
|
||||
'Open': 'Ouvrir',
|
||||
'Switch Video': 'Basculer la vidéo',
|
||||
'Switch Subtitle': 'Basculer le sous-titre',
|
||||
'Fullscreen': 'Plein écran',
|
||||
'Exit Fullscreen': 'Quitter le plein écran',
|
||||
'Web Fullscreen': 'Plein écran Web',
|
||||
'Exit Web Fullscreen': 'Quitter le plein écran Web',
|
||||
'Mini Player': 'Mini lecteur',
|
||||
'PIP Mode': 'Mode PiP',
|
||||
'Exit PIP Mode': 'Fermer le mode PiP',
|
||||
'PIP Not Supported': 'Mode PiP non supporté',
|
||||
'Fullscreen Not Supported': 'Plein écran non supporté',
|
||||
'Subtitle Offset': 'Réglage des sous-titres',
|
||||
'Last Seen': 'Dernière position',
|
||||
'Jump Play': 'Continuer',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay non disponible',
|
||||
}
|
||||
|
||||
export default fr;
|
||||
export default fr
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-fr'] = fr;
|
||||
window['artplayer-i18n-fr'] = fr
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const id = {
|
||||
'Video Info': 'Informasi Video',
|
||||
Close: 'Tutup',
|
||||
'Video Load Failed': 'Gagal Memuat Video',
|
||||
Volume: 'Volume',
|
||||
Play: 'Putar',
|
||||
Pause: 'Jeda',
|
||||
Rate: 'Kecepatan',
|
||||
Mute: 'Senyap',
|
||||
'Video Flip': 'Memutar Video',
|
||||
Horizontal: 'Horizontal',
|
||||
Vertical: 'Vertikal',
|
||||
Reconnect: 'Menyambung Kembali',
|
||||
'Show Setting': 'Tampilkan Pengaturan',
|
||||
'Hide Setting': 'Sembunyikan Pengaturan',
|
||||
Screenshot: 'Tangkapan Layar',
|
||||
'Play Speed': 'Kecepatan Putar',
|
||||
'Aspect Ratio': 'Rasio Aspek',
|
||||
Default: 'Default',
|
||||
Normal: 'Normal',
|
||||
Open: 'Buka',
|
||||
'Switch Video': 'Ganti Video',
|
||||
'Switch Subtitle': 'Ganti Subtitle',
|
||||
Fullscreen: 'Layar Penuh',
|
||||
'Exit Fullscreen': 'Keluar dari Layar Penuh',
|
||||
'Web Fullscreen': 'Layar Penuh Web',
|
||||
'Exit Web Fullscreen': 'Keluar dari Layar Penuh Web',
|
||||
'Mini Player': 'Pemutar Mini',
|
||||
'PIP Mode': 'Mode PIP',
|
||||
'Exit PIP Mode': 'Keluar dari Mode PIP',
|
||||
'PIP Not Supported': 'PIP Tidak Didukung',
|
||||
'Fullscreen Not Supported': 'Layar Penuh Tidak Didukung',
|
||||
'Subtitle Offset': 'Pergeseran Subtitle',
|
||||
'Last Seen': 'Terakhir Dilihat',
|
||||
'Jump Play': 'Lompat Putar',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay Tidak Tersedia',
|
||||
};
|
||||
'Video Info': 'Informasi Video',
|
||||
'Close': 'Tutup',
|
||||
'Video Load Failed': 'Gagal Memuat Video',
|
||||
'Volume': 'Volume',
|
||||
'Play': 'Putar',
|
||||
'Pause': 'Jeda',
|
||||
'Rate': 'Kecepatan',
|
||||
'Mute': 'Senyap',
|
||||
'Video Flip': 'Memutar Video',
|
||||
'Horizontal': 'Horizontal',
|
||||
'Vertical': 'Vertikal',
|
||||
'Reconnect': 'Menyambung Kembali',
|
||||
'Show Setting': 'Tampilkan Pengaturan',
|
||||
'Hide Setting': 'Sembunyikan Pengaturan',
|
||||
'Screenshot': 'Tangkapan Layar',
|
||||
'Play Speed': 'Kecepatan Putar',
|
||||
'Aspect Ratio': 'Rasio Aspek',
|
||||
'Default': 'Default',
|
||||
'Normal': 'Normal',
|
||||
'Open': 'Buka',
|
||||
'Switch Video': 'Ganti Video',
|
||||
'Switch Subtitle': 'Ganti Subtitle',
|
||||
'Fullscreen': 'Layar Penuh',
|
||||
'Exit Fullscreen': 'Keluar dari Layar Penuh',
|
||||
'Web Fullscreen': 'Layar Penuh Web',
|
||||
'Exit Web Fullscreen': 'Keluar dari Layar Penuh Web',
|
||||
'Mini Player': 'Pemutar Mini',
|
||||
'PIP Mode': 'Mode PIP',
|
||||
'Exit PIP Mode': 'Keluar dari Mode PIP',
|
||||
'PIP Not Supported': 'PIP Tidak Didukung',
|
||||
'Fullscreen Not Supported': 'Layar Penuh Tidak Didukung',
|
||||
'Subtitle Offset': 'Pergeseran Subtitle',
|
||||
'Last Seen': 'Terakhir Dilihat',
|
||||
'Jump Play': 'Lompat Putar',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay Tidak Tersedia',
|
||||
}
|
||||
|
||||
export default id;
|
||||
export default id
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-id'] = id;
|
||||
window['artplayer-i18n-id'] = id
|
||||
}
|
||||
@@ -1,30 +1,30 @@
|
||||
import { mergeDeep } from '../utils';
|
||||
import zhCn from './zh-cn';
|
||||
import { mergeDeep } from '../utils'
|
||||
import zhCn from './zh-cn'
|
||||
|
||||
export default class I18n {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
constructor(art) {
|
||||
this.art = art
|
||||
|
||||
this.languages = {
|
||||
'zh-cn': zhCn,
|
||||
};
|
||||
|
||||
this.language = {};
|
||||
|
||||
this.update(art.option.i18n);
|
||||
this.languages = {
|
||||
'zh-cn': zhCn,
|
||||
}
|
||||
|
||||
init() {
|
||||
const lang = this.art.option.lang.toLowerCase();
|
||||
this.language = this.languages[lang] || {};
|
||||
}
|
||||
this.language = {}
|
||||
|
||||
get(key) {
|
||||
return this.language[key] || key;
|
||||
}
|
||||
this.update(art.option.i18n)
|
||||
}
|
||||
|
||||
update(value) {
|
||||
this.languages = mergeDeep(this.languages, value);
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
const lang = this.art.option.lang.toLowerCase()
|
||||
this.language = this.languages[lang] || {}
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return this.language[key] || key
|
||||
}
|
||||
|
||||
update(value) {
|
||||
this.languages = mergeDeep(this.languages, value)
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const pl = {
|
||||
'Video Info': 'Informacje o wideo',
|
||||
Close: 'Zamknij',
|
||||
'Video Load Failed': 'Błąd ładowania wideo',
|
||||
Volume: 'Głośność',
|
||||
Play: 'Odtwórz',
|
||||
Pause: 'Wstrzymaj',
|
||||
Rate: 'Oceń',
|
||||
Mute: 'Wycisz',
|
||||
'Video Flip': 'Rotacja wideo',
|
||||
Horizontal: 'Pozioma',
|
||||
Vertical: 'Pionowa',
|
||||
Reconnect: 'Połącz ponownie',
|
||||
'Show Setting': 'Pokaż ustawienia',
|
||||
'Hide Setting': 'Ukryj ustawienia',
|
||||
Screenshot: 'Zrzut ekranu',
|
||||
'Play Speed': 'Prędkość odtwarzania',
|
||||
'Aspect Ratio': 'Współczynnik proporcji',
|
||||
Default: 'Domyślny',
|
||||
Normal: 'Normalny',
|
||||
Open: 'Otwórz',
|
||||
'Switch Video': 'Przełącz wideo',
|
||||
'Switch Subtitle': 'Przełącz napisy',
|
||||
Fullscreen: 'Pełny ekran',
|
||||
'Exit Fullscreen': 'Zamknij pełny ekran',
|
||||
'Web Fullscreen': 'Tryb pełnej strony',
|
||||
'Exit Web Fullscreen': 'Zamknij tryb pełnej strony',
|
||||
'Mini Player': 'Miniodtwarzacz',
|
||||
'PIP Mode': 'Tryb PiP',
|
||||
'Exit PIP Mode': 'Zamknij tryb PiP',
|
||||
'PIP Not Supported': 'Tryb PiP nieobsługiwany',
|
||||
'Fullscreen Not Supported': 'Pełny ekran nieobsługiwany',
|
||||
'Subtitle Offset': 'Przesunięcie napisów',
|
||||
'Last Seen': 'Ostatnio widziany',
|
||||
'Jump Play': 'Skocz do gry',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay nie jest dostępny',
|
||||
};
|
||||
'Video Info': 'Informacje o wideo',
|
||||
'Close': 'Zamknij',
|
||||
'Video Load Failed': 'Błąd ładowania wideo',
|
||||
'Volume': 'Głośność',
|
||||
'Play': 'Odtwórz',
|
||||
'Pause': 'Wstrzymaj',
|
||||
'Rate': 'Oceń',
|
||||
'Mute': 'Wycisz',
|
||||
'Video Flip': 'Rotacja wideo',
|
||||
'Horizontal': 'Pozioma',
|
||||
'Vertical': 'Pionowa',
|
||||
'Reconnect': 'Połącz ponownie',
|
||||
'Show Setting': 'Pokaż ustawienia',
|
||||
'Hide Setting': 'Ukryj ustawienia',
|
||||
'Screenshot': 'Zrzut ekranu',
|
||||
'Play Speed': 'Prędkość odtwarzania',
|
||||
'Aspect Ratio': 'Współczynnik proporcji',
|
||||
'Default': 'Domyślny',
|
||||
'Normal': 'Normalny',
|
||||
'Open': 'Otwórz',
|
||||
'Switch Video': 'Przełącz wideo',
|
||||
'Switch Subtitle': 'Przełącz napisy',
|
||||
'Fullscreen': 'Pełny ekran',
|
||||
'Exit Fullscreen': 'Zamknij pełny ekran',
|
||||
'Web Fullscreen': 'Tryb pełnej strony',
|
||||
'Exit Web Fullscreen': 'Zamknij tryb pełnej strony',
|
||||
'Mini Player': 'Miniodtwarzacz',
|
||||
'PIP Mode': 'Tryb PiP',
|
||||
'Exit PIP Mode': 'Zamknij tryb PiP',
|
||||
'PIP Not Supported': 'Tryb PiP nieobsługiwany',
|
||||
'Fullscreen Not Supported': 'Pełny ekran nieobsługiwany',
|
||||
'Subtitle Offset': 'Przesunięcie napisów',
|
||||
'Last Seen': 'Ostatnio widziany',
|
||||
'Jump Play': 'Skocz do gry',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay nie jest dostępny',
|
||||
}
|
||||
|
||||
export default pl;
|
||||
export default pl
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-pl'] = pl;
|
||||
window['artplayer-i18n-pl'] = pl
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const ru = {
|
||||
'Video Info': 'Информация',
|
||||
Close: 'Закрыть',
|
||||
'Video Load Failed': 'Ошибка загрузки видео',
|
||||
Volume: 'Громкость',
|
||||
Play: 'Играть',
|
||||
Pause: 'Пауза',
|
||||
Rate: 'Скорость',
|
||||
Mute: 'Заглушить',
|
||||
'Video Flip': 'Развернуть видео',
|
||||
Horizontal: 'Горизонтально',
|
||||
Vertical: 'Вертикально',
|
||||
Reconnect: 'Переподключенине',
|
||||
'Show Setting': 'Показать настройки',
|
||||
'Hide Setting': 'Скрыть настройки',
|
||||
Screenshot: 'Скриншот',
|
||||
'Play Speed': 'Скорость воспроизведения',
|
||||
'Aspect Ratio': 'Соотношение сторон',
|
||||
Default: 'По-умолчанию',
|
||||
Normal: 'Нормальный',
|
||||
Open: 'Открыть',
|
||||
'Switch Video': 'Переключить видео',
|
||||
'Switch Subtitle': 'Переключить субтитры',
|
||||
Fullscreen: 'Полноэкранный режим',
|
||||
'Exit Fullscreen': 'Выход из полноэкранного режима',
|
||||
'Web Fullscreen': 'На все окно браузера',
|
||||
'Exit Web Fullscreen': 'Выход из режима полного окна',
|
||||
'Mini Player': 'Мини проигрыватель',
|
||||
'PIP Mode': 'Картинка в картинке',
|
||||
'Exit PIP Mode': 'Закрыть картинку в картинке',
|
||||
'PIP Not Supported': 'Картинка в картинке не поддерживается',
|
||||
'Fullscreen Not Supported': 'Полноэкранный режим не поддерживается',
|
||||
'Subtitle Offset': 'Настройка субтитров',
|
||||
'Last Seen': 'Последнее просмотренное',
|
||||
'Jump Play': 'Перейти',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay недоступен',
|
||||
};
|
||||
'Video Info': 'Информация',
|
||||
'Close': 'Закрыть',
|
||||
'Video Load Failed': 'Ошибка загрузки видео',
|
||||
'Volume': 'Громкость',
|
||||
'Play': 'Играть',
|
||||
'Pause': 'Пауза',
|
||||
'Rate': 'Скорость',
|
||||
'Mute': 'Заглушить',
|
||||
'Video Flip': 'Развернуть видео',
|
||||
'Horizontal': 'Горизонтально',
|
||||
'Vertical': 'Вертикально',
|
||||
'Reconnect': 'Переподключенине',
|
||||
'Show Setting': 'Показать настройки',
|
||||
'Hide Setting': 'Скрыть настройки',
|
||||
'Screenshot': 'Скриншот',
|
||||
'Play Speed': 'Скорость воспроизведения',
|
||||
'Aspect Ratio': 'Соотношение сторон',
|
||||
'Default': 'По-умолчанию',
|
||||
'Normal': 'Нормальный',
|
||||
'Open': 'Открыть',
|
||||
'Switch Video': 'Переключить видео',
|
||||
'Switch Subtitle': 'Переключить субтитры',
|
||||
'Fullscreen': 'Полноэкранный режим',
|
||||
'Exit Fullscreen': 'Выход из полноэкранного режима',
|
||||
'Web Fullscreen': 'На все окно браузера',
|
||||
'Exit Web Fullscreen': 'Выход из режима полного окна',
|
||||
'Mini Player': 'Мини проигрыватель',
|
||||
'PIP Mode': 'Картинка в картинке',
|
||||
'Exit PIP Mode': 'Закрыть картинку в картинке',
|
||||
'PIP Not Supported': 'Картинка в картинке не поддерживается',
|
||||
'Fullscreen Not Supported': 'Полноэкранный режим не поддерживается',
|
||||
'Subtitle Offset': 'Настройка субтитров',
|
||||
'Last Seen': 'Последнее просмотренное',
|
||||
'Jump Play': 'Перейти',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay недоступен',
|
||||
}
|
||||
|
||||
export default ru;
|
||||
export default ru
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-ru'] = ru;
|
||||
window['artplayer-i18n-ru'] = ru
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const tr = {
|
||||
'Video Info': 'Video Bilgisi',
|
||||
Close: 'Kapat',
|
||||
'Video Load Failed': 'Video Yüklenemedi',
|
||||
Volume: 'Ses Seviyesi',
|
||||
Play: 'Oynat',
|
||||
Pause: 'Duraklat',
|
||||
Rate: 'Hız',
|
||||
Mute: 'Sessize Al',
|
||||
'Video Flip': 'Videoyu Çevir',
|
||||
Horizontal: 'Yatay',
|
||||
Vertical: 'Dikey',
|
||||
Reconnect: 'Yeniden Bağlan',
|
||||
'Show Setting': 'Ayarları Göster',
|
||||
'Hide Setting': 'Ayarları Gizle',
|
||||
Screenshot: 'Ekran Görüntüsü',
|
||||
'Play Speed': 'Oynatma Hızı',
|
||||
'Aspect Ratio': 'En Boy Oranı',
|
||||
Default: 'Varsayılan',
|
||||
Normal: 'Normal',
|
||||
Open: 'Aç',
|
||||
'Switch Video': 'Video Değiştir',
|
||||
'Switch Subtitle': 'Altyazı Değiştir',
|
||||
Fullscreen: 'Tam Ekran',
|
||||
'Exit Fullscreen': 'Tam Ekrandan Çık',
|
||||
'Web Fullscreen': 'Web Tam Ekran',
|
||||
'Exit Web Fullscreen': 'Web Tam Ekranından Çık',
|
||||
'Mini Player': 'Küçük Oynatıcı',
|
||||
'PIP Mode': 'PIP Modu',
|
||||
'Exit PIP Mode': 'PIP Modundan Çık',
|
||||
'PIP Not Supported': 'PIP Desteklenmiyor',
|
||||
'Fullscreen Not Supported': 'Tam Ekran Desteklenmiyor',
|
||||
'Subtitle Offset': 'Altyazı Kaydırma',
|
||||
'Last Seen': 'Son İzlenen',
|
||||
'Jump Play': 'Atla ve Oynat',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay Kullanılamıyor',
|
||||
};
|
||||
'Video Info': 'Video Bilgisi',
|
||||
'Close': 'Kapat',
|
||||
'Video Load Failed': 'Video Yüklenemedi',
|
||||
'Volume': 'Ses Seviyesi',
|
||||
'Play': 'Oynat',
|
||||
'Pause': 'Duraklat',
|
||||
'Rate': 'Hız',
|
||||
'Mute': 'Sessize Al',
|
||||
'Video Flip': 'Videoyu Çevir',
|
||||
'Horizontal': 'Yatay',
|
||||
'Vertical': 'Dikey',
|
||||
'Reconnect': 'Yeniden Bağlan',
|
||||
'Show Setting': 'Ayarları Göster',
|
||||
'Hide Setting': 'Ayarları Gizle',
|
||||
'Screenshot': 'Ekran Görüntüsü',
|
||||
'Play Speed': 'Oynatma Hızı',
|
||||
'Aspect Ratio': 'En Boy Oranı',
|
||||
'Default': 'Varsayılan',
|
||||
'Normal': 'Normal',
|
||||
'Open': 'Aç',
|
||||
'Switch Video': 'Video Değiştir',
|
||||
'Switch Subtitle': 'Altyazı Değiştir',
|
||||
'Fullscreen': 'Tam Ekran',
|
||||
'Exit Fullscreen': 'Tam Ekrandan Çık',
|
||||
'Web Fullscreen': 'Web Tam Ekran',
|
||||
'Exit Web Fullscreen': 'Web Tam Ekranından Çık',
|
||||
'Mini Player': 'Küçük Oynatıcı',
|
||||
'PIP Mode': 'PIP Modu',
|
||||
'Exit PIP Mode': 'PIP Modundan Çık',
|
||||
'PIP Not Supported': 'PIP Desteklenmiyor',
|
||||
'Fullscreen Not Supported': 'Tam Ekran Desteklenmiyor',
|
||||
'Subtitle Offset': 'Altyazı Kaydırma',
|
||||
'Last Seen': 'Son İzlenen',
|
||||
'Jump Play': 'Atla ve Oynat',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay Kullanılamıyor',
|
||||
}
|
||||
|
||||
export default tr;
|
||||
export default tr
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-tr'] = tr;
|
||||
window['artplayer-i18n-tr'] = tr
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const vi = {
|
||||
'Video Info': 'Thông tin video',
|
||||
Close: 'Đóng',
|
||||
'Video Load Failed': 'Tải video thất bại',
|
||||
Volume: 'Âm lượng',
|
||||
Play: 'Phát',
|
||||
Pause: 'Tạm dừng',
|
||||
Rate: 'Tốc độ',
|
||||
Mute: 'Tắt tiếng',
|
||||
'Video Flip': 'Lật video',
|
||||
Horizontal: 'Ngang',
|
||||
Vertical: 'Dọc',
|
||||
Reconnect: 'Kết nối lại',
|
||||
'Show Setting': 'Cài đặt',
|
||||
'Hide Setting': 'Ẩn cài đặt',
|
||||
Screenshot: 'Chụp màn hình',
|
||||
'Play Speed': 'Tốc độ phát',
|
||||
'Aspect Ratio': 'Tỷ lệ khung hình',
|
||||
Default: 'Mặc định',
|
||||
Normal: 'Bình thường',
|
||||
Open: 'Mở',
|
||||
'Switch Video': 'Chuyển video',
|
||||
'Switch Subtitle': 'Chuyển phụ đề',
|
||||
Fullscreen: 'Toàn màn hình',
|
||||
'Exit Fullscreen': 'Thoát toàn màn hình',
|
||||
'Web Fullscreen': 'Toàn màn hình trình duyệt',
|
||||
'Exit Web Fullscreen': 'Thoát toàn màn hình trình duyệt',
|
||||
'Mini Player': 'Trình phát mini',
|
||||
'PIP Mode': 'Phát trong hình',
|
||||
'Exit PIP Mode': 'Thoát phát trong hình',
|
||||
'PIP Not Supported': 'Không hỗ trợ phát trong hình',
|
||||
'Fullscreen Not Supported': 'Không hỗ trợ toàn màn hình',
|
||||
'Subtitle Offset': 'Độ trễ phụ đề',
|
||||
'Last Seen': 'Lần xem cuối',
|
||||
'Jump Play': 'Nhảy đến đoạn phát',
|
||||
AirPlay: 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay không khả dụng',
|
||||
};
|
||||
'Video Info': 'Thông tin video',
|
||||
'Close': 'Đóng',
|
||||
'Video Load Failed': 'Tải video thất bại',
|
||||
'Volume': 'Âm lượng',
|
||||
'Play': 'Phát',
|
||||
'Pause': 'Tạm dừng',
|
||||
'Rate': 'Tốc độ',
|
||||
'Mute': 'Tắt tiếng',
|
||||
'Video Flip': 'Lật video',
|
||||
'Horizontal': 'Ngang',
|
||||
'Vertical': 'Dọc',
|
||||
'Reconnect': 'Kết nối lại',
|
||||
'Show Setting': 'Cài đặt',
|
||||
'Hide Setting': 'Ẩn cài đặt',
|
||||
'Screenshot': 'Chụp màn hình',
|
||||
'Play Speed': 'Tốc độ phát',
|
||||
'Aspect Ratio': 'Tỷ lệ khung hình',
|
||||
'Default': 'Mặc định',
|
||||
'Normal': 'Bình thường',
|
||||
'Open': 'Mở',
|
||||
'Switch Video': 'Chuyển video',
|
||||
'Switch Subtitle': 'Chuyển phụ đề',
|
||||
'Fullscreen': 'Toàn màn hình',
|
||||
'Exit Fullscreen': 'Thoát toàn màn hình',
|
||||
'Web Fullscreen': 'Toàn màn hình trình duyệt',
|
||||
'Exit Web Fullscreen': 'Thoát toàn màn hình trình duyệt',
|
||||
'Mini Player': 'Trình phát mini',
|
||||
'PIP Mode': 'Phát trong hình',
|
||||
'Exit PIP Mode': 'Thoát phát trong hình',
|
||||
'PIP Not Supported': 'Không hỗ trợ phát trong hình',
|
||||
'Fullscreen Not Supported': 'Không hỗ trợ toàn màn hình',
|
||||
'Subtitle Offset': 'Độ trễ phụ đề',
|
||||
'Last Seen': 'Lần xem cuối',
|
||||
'Jump Play': 'Nhảy đến đoạn phát',
|
||||
'AirPlay': 'AirPlay',
|
||||
'AirPlay Not Available': 'AirPlay không khả dụng',
|
||||
}
|
||||
|
||||
export default vi;
|
||||
export default vi
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-vi'] = vi;
|
||||
window['artplayer-i18n-vi'] = vi
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const zhCn = {
|
||||
'Video Info': '统计信息',
|
||||
Close: '关闭',
|
||||
'Video Load Failed': '加载失败',
|
||||
Volume: '音量',
|
||||
Play: '播放',
|
||||
Pause: '暂停',
|
||||
Rate: '速度',
|
||||
Mute: '静音',
|
||||
'Video Flip': '画面翻转',
|
||||
Horizontal: '水平',
|
||||
Vertical: '垂直',
|
||||
Reconnect: '重新连接',
|
||||
'Show Setting': '显示设置',
|
||||
'Hide Setting': '隐藏设置',
|
||||
Screenshot: '截图',
|
||||
'Play Speed': '播放速度',
|
||||
'Aspect Ratio': '画面比例',
|
||||
Default: '默认',
|
||||
Normal: '正常',
|
||||
Open: '打开',
|
||||
'Switch Video': '切换',
|
||||
'Switch Subtitle': '切换字幕',
|
||||
Fullscreen: '全屏',
|
||||
'Exit Fullscreen': '退出全屏',
|
||||
'Web Fullscreen': '网页全屏',
|
||||
'Exit Web Fullscreen': '退出网页全屏',
|
||||
'Mini Player': '迷你播放器',
|
||||
'PIP Mode': '开启画中画',
|
||||
'Exit PIP Mode': '退出画中画',
|
||||
'PIP Not Supported': '不支持画中画',
|
||||
'Fullscreen Not Supported': '不支持全屏',
|
||||
'Subtitle Offset': '字幕偏移',
|
||||
'Last Seen': '上次看到',
|
||||
'Jump Play': '跳转播放',
|
||||
AirPlay: '隔空播放',
|
||||
'AirPlay Not Available': '隔空播放不可用',
|
||||
};
|
||||
'Video Info': '统计信息',
|
||||
'Close': '关闭',
|
||||
'Video Load Failed': '加载失败',
|
||||
'Volume': '音量',
|
||||
'Play': '播放',
|
||||
'Pause': '暂停',
|
||||
'Rate': '速度',
|
||||
'Mute': '静音',
|
||||
'Video Flip': '画面翻转',
|
||||
'Horizontal': '水平',
|
||||
'Vertical': '垂直',
|
||||
'Reconnect': '重新连接',
|
||||
'Show Setting': '显示设置',
|
||||
'Hide Setting': '隐藏设置',
|
||||
'Screenshot': '截图',
|
||||
'Play Speed': '播放速度',
|
||||
'Aspect Ratio': '画面比例',
|
||||
'Default': '默认',
|
||||
'Normal': '正常',
|
||||
'Open': '打开',
|
||||
'Switch Video': '切换',
|
||||
'Switch Subtitle': '切换字幕',
|
||||
'Fullscreen': '全屏',
|
||||
'Exit Fullscreen': '退出全屏',
|
||||
'Web Fullscreen': '网页全屏',
|
||||
'Exit Web Fullscreen': '退出网页全屏',
|
||||
'Mini Player': '迷你播放器',
|
||||
'PIP Mode': '开启画中画',
|
||||
'Exit PIP Mode': '退出画中画',
|
||||
'PIP Not Supported': '不支持画中画',
|
||||
'Fullscreen Not Supported': '不支持全屏',
|
||||
'Subtitle Offset': '字幕偏移',
|
||||
'Last Seen': '上次看到',
|
||||
'Jump Play': '跳转播放',
|
||||
'AirPlay': '隔空播放',
|
||||
'AirPlay Not Available': '隔空播放不可用',
|
||||
}
|
||||
|
||||
export default zhCn;
|
||||
export default zhCn
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-zh-cn'] = zhCn;
|
||||
window['artplayer-i18n-zh-cn'] = zhCn
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
const zhTw = {
|
||||
'Video Info': '統計訊息',
|
||||
Close: '關閉',
|
||||
'Video Load Failed': '載入失敗',
|
||||
Volume: '音量',
|
||||
Play: '播放',
|
||||
Pause: '暫停',
|
||||
Rate: '速度',
|
||||
Mute: '靜音',
|
||||
'Video Flip': '畫面翻轉',
|
||||
Horizontal: '水平',
|
||||
Vertical: '垂直',
|
||||
Reconnect: '重新連接',
|
||||
'Show Setting': '顯示设置',
|
||||
'Hide Setting': '隱藏设置',
|
||||
Screenshot: '截圖',
|
||||
'Play Speed': '播放速度',
|
||||
'Aspect Ratio': '畫面比例',
|
||||
Default: '默認',
|
||||
Normal: '正常',
|
||||
Open: '打開',
|
||||
'Switch Video': '切換',
|
||||
'Switch Subtitle': '切換字幕',
|
||||
Fullscreen: '全屏',
|
||||
'Exit Fullscreen': '退出全屏',
|
||||
'Web Fullscreen': '網頁全屏',
|
||||
'Exit Web Fullscreen': '退出網頁全屏',
|
||||
'Mini Player': '迷你播放器',
|
||||
'PIP Mode': '開啟畫中畫',
|
||||
'Exit PIP Mode': '退出畫中畫',
|
||||
'PIP Not Supported': '不支持畫中畫',
|
||||
'Fullscreen Not Supported': '不支持全屏',
|
||||
'Subtitle Offset': '字幕偏移',
|
||||
'Last Seen': '上次看到',
|
||||
'Jump Play': '跳轉播放',
|
||||
AirPlay: '隔空播放',
|
||||
'AirPlay Not Available': '隔空播放不可用',
|
||||
};
|
||||
'Video Info': '統計訊息',
|
||||
'Close': '關閉',
|
||||
'Video Load Failed': '載入失敗',
|
||||
'Volume': '音量',
|
||||
'Play': '播放',
|
||||
'Pause': '暫停',
|
||||
'Rate': '速度',
|
||||
'Mute': '靜音',
|
||||
'Video Flip': '畫面翻轉',
|
||||
'Horizontal': '水平',
|
||||
'Vertical': '垂直',
|
||||
'Reconnect': '重新連接',
|
||||
'Show Setting': '顯示设置',
|
||||
'Hide Setting': '隱藏设置',
|
||||
'Screenshot': '截圖',
|
||||
'Play Speed': '播放速度',
|
||||
'Aspect Ratio': '畫面比例',
|
||||
'Default': '默認',
|
||||
'Normal': '正常',
|
||||
'Open': '打開',
|
||||
'Switch Video': '切換',
|
||||
'Switch Subtitle': '切換字幕',
|
||||
'Fullscreen': '全屏',
|
||||
'Exit Fullscreen': '退出全屏',
|
||||
'Web Fullscreen': '網頁全屏',
|
||||
'Exit Web Fullscreen': '退出網頁全屏',
|
||||
'Mini Player': '迷你播放器',
|
||||
'PIP Mode': '開啟畫中畫',
|
||||
'Exit PIP Mode': '退出畫中畫',
|
||||
'PIP Not Supported': '不支持畫中畫',
|
||||
'Fullscreen Not Supported': '不支持全屏',
|
||||
'Subtitle Offset': '字幕偏移',
|
||||
'Last Seen': '上次看到',
|
||||
'Jump Play': '跳轉播放',
|
||||
'AirPlay': '隔空播放',
|
||||
'AirPlay Not Available': '隔空播放不可用',
|
||||
}
|
||||
|
||||
export default zhTw;
|
||||
export default zhTw
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayer-i18n-zh-tw'] = zhTw;
|
||||
window['artplayer-i18n-zh-tw'] = zhTw
|
||||
}
|
||||
@@ -1,69 +1,69 @@
|
||||
import { def, getIcon } from '../utils';
|
||||
import loading from 'bundle-text:./loading.svg';
|
||||
import state from 'bundle-text:./state.svg';
|
||||
import check from 'bundle-text:./check.svg';
|
||||
import play from 'bundle-text:./play.svg';
|
||||
import pause from 'bundle-text:./pause.svg';
|
||||
import volume from 'bundle-text:./volume.svg';
|
||||
import volumeClose from 'bundle-text:./volume-close.svg';
|
||||
import screenshot from 'bundle-text:./screenshot.svg';
|
||||
import setting from 'bundle-text:./setting.svg';
|
||||
import arrowLeft from 'bundle-text:./arrow-left.svg';
|
||||
import arrowRight from 'bundle-text:./arrow-right.svg';
|
||||
import playbackRate from 'bundle-text:./playback-rate.svg';
|
||||
import aspectRatio from 'bundle-text:./aspect-ratio.svg';
|
||||
import config from 'bundle-text:./config.svg';
|
||||
import pip from 'bundle-text:./pip.svg';
|
||||
import lock from 'bundle-text:./lock.svg';
|
||||
import unlock from 'bundle-text:./unlock.svg';
|
||||
import fullscreenOff from 'bundle-text:./fullscreen-off.svg';
|
||||
import fullscreenOn from 'bundle-text:./fullscreen-on.svg';
|
||||
import fullscreenWebOff from 'bundle-text:./fullscreen-web-off.svg';
|
||||
import fullscreenWebOn from 'bundle-text:./fullscreen-web-on.svg';
|
||||
import switchOn from 'bundle-text:./switch-on.svg';
|
||||
import switchOff from 'bundle-text:./switch-off.svg';
|
||||
import flip from 'bundle-text:./flip.svg';
|
||||
import error from 'bundle-text:./error.svg';
|
||||
import close from 'bundle-text:./close.svg';
|
||||
import airplay from 'bundle-text:./airplay.svg';
|
||||
import airplay from 'bundle-text:./airplay.svg'
|
||||
import arrowLeft from 'bundle-text:./arrow-left.svg'
|
||||
import arrowRight from 'bundle-text:./arrow-right.svg'
|
||||
import aspectRatio from 'bundle-text:./aspect-ratio.svg'
|
||||
import check from 'bundle-text:./check.svg'
|
||||
import close from 'bundle-text:./close.svg'
|
||||
import config from 'bundle-text:./config.svg'
|
||||
import error from 'bundle-text:./error.svg'
|
||||
import flip from 'bundle-text:./flip.svg'
|
||||
import fullscreenOff from 'bundle-text:./fullscreen-off.svg'
|
||||
import fullscreenOn from 'bundle-text:./fullscreen-on.svg'
|
||||
import fullscreenWebOff from 'bundle-text:./fullscreen-web-off.svg'
|
||||
import fullscreenWebOn from 'bundle-text:./fullscreen-web-on.svg'
|
||||
import loading from 'bundle-text:./loading.svg'
|
||||
import lock from 'bundle-text:./lock.svg'
|
||||
import pause from 'bundle-text:./pause.svg'
|
||||
import pip from 'bundle-text:./pip.svg'
|
||||
import play from 'bundle-text:./play.svg'
|
||||
import playbackRate from 'bundle-text:./playback-rate.svg'
|
||||
import screenshot from 'bundle-text:./screenshot.svg'
|
||||
import setting from 'bundle-text:./setting.svg'
|
||||
import state from 'bundle-text:./state.svg'
|
||||
import switchOff from 'bundle-text:./switch-off.svg'
|
||||
import switchOn from 'bundle-text:./switch-on.svg'
|
||||
import unlock from 'bundle-text:./unlock.svg'
|
||||
import volumeClose from 'bundle-text:./volume-close.svg'
|
||||
import volume from 'bundle-text:./volume.svg'
|
||||
import { def, getIcon } from '../utils'
|
||||
|
||||
export default class Icons {
|
||||
constructor(art) {
|
||||
const icons = {
|
||||
loading,
|
||||
state,
|
||||
play,
|
||||
pause,
|
||||
check,
|
||||
volume,
|
||||
volumeClose,
|
||||
screenshot,
|
||||
setting,
|
||||
pip,
|
||||
arrowLeft,
|
||||
arrowRight,
|
||||
playbackRate,
|
||||
aspectRatio,
|
||||
config,
|
||||
lock,
|
||||
flip,
|
||||
unlock,
|
||||
fullscreenOff,
|
||||
fullscreenOn,
|
||||
fullscreenWebOff,
|
||||
fullscreenWebOn,
|
||||
switchOn,
|
||||
switchOff,
|
||||
error,
|
||||
close,
|
||||
airplay,
|
||||
...art.option.icons,
|
||||
};
|
||||
|
||||
for (const key in icons) {
|
||||
def(this, key, {
|
||||
get: () => getIcon(key, icons[key]),
|
||||
});
|
||||
}
|
||||
constructor(art) {
|
||||
const icons = {
|
||||
loading,
|
||||
state,
|
||||
play,
|
||||
pause,
|
||||
check,
|
||||
volume,
|
||||
volumeClose,
|
||||
screenshot,
|
||||
setting,
|
||||
pip,
|
||||
arrowLeft,
|
||||
arrowRight,
|
||||
playbackRate,
|
||||
aspectRatio,
|
||||
config,
|
||||
lock,
|
||||
flip,
|
||||
unlock,
|
||||
fullscreenOff,
|
||||
fullscreenOn,
|
||||
fullscreenWebOff,
|
||||
fullscreenWebOn,
|
||||
switchOn,
|
||||
switchOff,
|
||||
error,
|
||||
close,
|
||||
airplay,
|
||||
...art.option.icons,
|
||||
}
|
||||
|
||||
for (const key in icons) {
|
||||
def(this, key, {
|
||||
get: () => getIcon(key, icons[key]),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
+228
-226
@@ -1,258 +1,260 @@
|
||||
import { version } from '../package.json';
|
||||
import style from 'bundle-text:./style/index.less';
|
||||
import validator from 'option-validator';
|
||||
import Emitter from './utils/emitter';
|
||||
import * as utils from './utils';
|
||||
import scheme from './scheme';
|
||||
import config from './config';
|
||||
import Template from './template';
|
||||
import I18n from './i18n';
|
||||
import Player from './player';
|
||||
import Control from './control';
|
||||
import Contextmenu from './contextmenu';
|
||||
import Info from './info';
|
||||
import Subtitle from './subtitle';
|
||||
import Events from './events';
|
||||
import Hotkey from './hotkey';
|
||||
import Layer from './layer';
|
||||
import Loading from './loading';
|
||||
import Notice from './notice';
|
||||
import Mask from './mask';
|
||||
import Icons from './icons';
|
||||
import Setting from './setting';
|
||||
import Storage from './storage';
|
||||
import Plugins from './plugins';
|
||||
import style from 'bundle-text:./style/index.less'
|
||||
import validator from 'option-validator'
|
||||
import { version } from '../package.json'
|
||||
import config from './config'
|
||||
import Contextmenu from './contextmenu'
|
||||
import Control from './control'
|
||||
import Events from './events'
|
||||
import Hotkey from './hotkey'
|
||||
import I18n from './i18n'
|
||||
import Icons from './icons'
|
||||
import Info from './info'
|
||||
import Layer from './layer'
|
||||
import Loading from './loading'
|
||||
import Mask from './mask'
|
||||
import Notice from './notice'
|
||||
import Player from './player'
|
||||
import Plugins from './plugins'
|
||||
import scheme from './scheme'
|
||||
import Setting from './setting'
|
||||
import Storage from './storage'
|
||||
import Subtitle from './subtitle'
|
||||
import Template from './template'
|
||||
import * as utils from './utils'
|
||||
import Emitter from './utils/emitter'
|
||||
|
||||
let id = 0;
|
||||
const instances = [];
|
||||
let id = 0
|
||||
const instances = []
|
||||
export default class Artplayer extends Emitter {
|
||||
constructor(option, readyCallback) {
|
||||
super();
|
||||
constructor(option, readyCallback) {
|
||||
super()
|
||||
|
||||
this.id = ++id;
|
||||
this.id = ++id
|
||||
|
||||
const mergeOption = utils.mergeDeep(Artplayer.option, option);
|
||||
mergeOption.container = option.container;
|
||||
const mergeOption = utils.mergeDeep(Artplayer.option, option)
|
||||
mergeOption.container = option.container
|
||||
|
||||
this.option = validator(mergeOption, scheme);
|
||||
this.option = validator(mergeOption, scheme)
|
||||
|
||||
this.isLock = false;
|
||||
this.isReady = false;
|
||||
this.isFocus = false;
|
||||
this.isInput = false;
|
||||
this.isRotate = false;
|
||||
this.isDestroy = false;
|
||||
this.isLock = false
|
||||
this.isReady = false
|
||||
this.isFocus = false
|
||||
this.isInput = false
|
||||
this.isRotate = false
|
||||
this.isDestroy = false
|
||||
|
||||
this.template = new Template(this);
|
||||
this.events = new Events(this);
|
||||
this.storage = new Storage(this);
|
||||
this.icons = new Icons(this);
|
||||
this.i18n = new I18n(this);
|
||||
this.notice = new Notice(this);
|
||||
this.player = new Player(this);
|
||||
this.layers = new Layer(this);
|
||||
this.controls = new Control(this);
|
||||
this.contextmenu = new Contextmenu(this);
|
||||
this.subtitle = new Subtitle(this);
|
||||
this.info = new Info(this);
|
||||
this.loading = new Loading(this);
|
||||
this.hotkey = new Hotkey(this);
|
||||
this.mask = new Mask(this);
|
||||
this.setting = new Setting(this);
|
||||
this.plugins = new Plugins(this);
|
||||
this.template = new Template(this)
|
||||
this.events = new Events(this)
|
||||
this.storage = new Storage(this)
|
||||
this.icons = new Icons(this)
|
||||
this.i18n = new I18n(this)
|
||||
this.notice = new Notice(this)
|
||||
this.player = new Player(this)
|
||||
this.layers = new Layer(this)
|
||||
this.controls = new Control(this)
|
||||
this.contextmenu = new Contextmenu(this)
|
||||
this.subtitle = new Subtitle(this)
|
||||
this.info = new Info(this)
|
||||
this.loading = new Loading(this)
|
||||
this.hotkey = new Hotkey(this)
|
||||
this.mask = new Mask(this)
|
||||
this.setting = new Setting(this)
|
||||
this.plugins = new Plugins(this)
|
||||
|
||||
if (typeof readyCallback === 'function') {
|
||||
this.on('ready', () => readyCallback.call(this, this));
|
||||
}
|
||||
|
||||
if (Artplayer.DEBUG) {
|
||||
const log = (msg) => console.log(`[ART.${this.id}] -> ${msg}`);
|
||||
log('Version@' + Artplayer.version);
|
||||
for (let index = 0; index < config.events.length; index++) {
|
||||
this.on('video:' + config.events[index], (event) => log('Event@' + event.type));
|
||||
}
|
||||
}
|
||||
|
||||
instances.push(this);
|
||||
if (typeof readyCallback === 'function') {
|
||||
this.on('ready', () => readyCallback.call(this, this))
|
||||
}
|
||||
|
||||
static get instances() {
|
||||
return instances;
|
||||
if (Artplayer.DEBUG) {
|
||||
// eslint-disable-next-line no-console
|
||||
const log = msg => console.log(`[ART.${this.id}] -> ${msg}`)
|
||||
log(`Version@${Artplayer.version}`)
|
||||
for (let index = 0; index < config.events.length; index++) {
|
||||
this.on(`video:${config.events[index]}`, event => log(`Event@${event.type}`))
|
||||
}
|
||||
}
|
||||
|
||||
static get version() {
|
||||
return version;
|
||||
}
|
||||
instances.push(this)
|
||||
}
|
||||
|
||||
static get config() {
|
||||
return config;
|
||||
}
|
||||
static get instances() {
|
||||
return instances
|
||||
}
|
||||
|
||||
static get utils() {
|
||||
return utils;
|
||||
}
|
||||
static get version() {
|
||||
return version
|
||||
}
|
||||
|
||||
static get scheme() {
|
||||
return scheme;
|
||||
}
|
||||
static get config() {
|
||||
return config
|
||||
}
|
||||
|
||||
static get Emitter() {
|
||||
return Emitter;
|
||||
}
|
||||
static get utils() {
|
||||
return utils
|
||||
}
|
||||
|
||||
static get validator() {
|
||||
return validator;
|
||||
}
|
||||
static get scheme() {
|
||||
return scheme
|
||||
}
|
||||
|
||||
static get kindOf() {
|
||||
return validator.kindOf;
|
||||
}
|
||||
static get Emitter() {
|
||||
return Emitter
|
||||
}
|
||||
|
||||
static get html() {
|
||||
return Template.html;
|
||||
}
|
||||
static get validator() {
|
||||
return validator
|
||||
}
|
||||
|
||||
static get option() {
|
||||
return {
|
||||
id: '',
|
||||
container: '#artplayer',
|
||||
url: '',
|
||||
poster: '',
|
||||
type: '',
|
||||
theme: '#f00',
|
||||
volume: 0.7,
|
||||
isLive: false,
|
||||
muted: false,
|
||||
autoplay: false,
|
||||
autoSize: false,
|
||||
autoMini: false,
|
||||
loop: false,
|
||||
flip: false,
|
||||
playbackRate: false,
|
||||
aspectRatio: false,
|
||||
screenshot: false,
|
||||
setting: false,
|
||||
hotkey: true,
|
||||
pip: false,
|
||||
mutex: true,
|
||||
backdrop: true,
|
||||
fullscreen: false,
|
||||
fullscreenWeb: false,
|
||||
subtitleOffset: false,
|
||||
miniProgressBar: false,
|
||||
useSSR: false,
|
||||
playsInline: true,
|
||||
lock: false,
|
||||
gesture: true,
|
||||
fastForward: false,
|
||||
autoPlayback: false,
|
||||
autoOrientation: false,
|
||||
airplay: false,
|
||||
proxy: undefined,
|
||||
layers: [],
|
||||
contextmenu: [],
|
||||
controls: [],
|
||||
settings: [],
|
||||
quality: [],
|
||||
highlight: [],
|
||||
plugins: [],
|
||||
thumbnails: {
|
||||
url: '',
|
||||
number: 60,
|
||||
column: 10,
|
||||
width: 0,
|
||||
height: 0,
|
||||
scale: 1,
|
||||
},
|
||||
subtitle: {
|
||||
url: '',
|
||||
type: '',
|
||||
style: {},
|
||||
name: '',
|
||||
escape: true,
|
||||
encoding: 'utf-8',
|
||||
onVttLoad: (vtt) => vtt,
|
||||
},
|
||||
moreVideoAttr: {
|
||||
controls: false,
|
||||
preload: utils.isSafari ? 'auto' : 'metadata',
|
||||
},
|
||||
i18n: {},
|
||||
icons: {},
|
||||
cssVar: {},
|
||||
customType: {},
|
||||
lang: navigator?.language.toLowerCase(),
|
||||
};
|
||||
}
|
||||
static get kindOf() {
|
||||
return validator.kindOf
|
||||
}
|
||||
|
||||
get proxy() {
|
||||
return this.events.proxy;
|
||||
}
|
||||
static get html() {
|
||||
return Template.html
|
||||
}
|
||||
|
||||
get query() {
|
||||
return this.template.query;
|
||||
static get option() {
|
||||
return {
|
||||
id: '',
|
||||
container: '#artplayer',
|
||||
url: '',
|
||||
poster: '',
|
||||
type: '',
|
||||
theme: '#f00',
|
||||
volume: 0.7,
|
||||
isLive: false,
|
||||
muted: false,
|
||||
autoplay: false,
|
||||
autoSize: false,
|
||||
autoMini: false,
|
||||
loop: false,
|
||||
flip: false,
|
||||
playbackRate: false,
|
||||
aspectRatio: false,
|
||||
screenshot: false,
|
||||
setting: false,
|
||||
hotkey: true,
|
||||
pip: false,
|
||||
mutex: true,
|
||||
backdrop: true,
|
||||
fullscreen: false,
|
||||
fullscreenWeb: false,
|
||||
subtitleOffset: false,
|
||||
miniProgressBar: false,
|
||||
useSSR: false,
|
||||
playsInline: true,
|
||||
lock: false,
|
||||
gesture: true,
|
||||
fastForward: false,
|
||||
autoPlayback: false,
|
||||
autoOrientation: false,
|
||||
airplay: false,
|
||||
proxy: undefined,
|
||||
layers: [],
|
||||
contextmenu: [],
|
||||
controls: [],
|
||||
settings: [],
|
||||
quality: [],
|
||||
highlight: [],
|
||||
plugins: [],
|
||||
thumbnails: {
|
||||
url: '',
|
||||
number: 60,
|
||||
column: 10,
|
||||
width: 0,
|
||||
height: 0,
|
||||
scale: 1,
|
||||
},
|
||||
subtitle: {
|
||||
url: '',
|
||||
type: '',
|
||||
style: {},
|
||||
name: '',
|
||||
escape: true,
|
||||
encoding: 'utf-8',
|
||||
onVttLoad: vtt => vtt,
|
||||
},
|
||||
moreVideoAttr: {
|
||||
controls: false,
|
||||
preload: utils.isSafari ? 'auto' : 'metadata',
|
||||
},
|
||||
i18n: {},
|
||||
icons: {},
|
||||
cssVar: {},
|
||||
customType: {},
|
||||
lang: navigator?.language.toLowerCase(),
|
||||
}
|
||||
}
|
||||
|
||||
get video() {
|
||||
return this.template.$video;
|
||||
}
|
||||
get proxy() {
|
||||
return this.events.proxy
|
||||
}
|
||||
|
||||
destroy(removeHtml = true) {
|
||||
this.events.destroy();
|
||||
this.template.destroy(removeHtml);
|
||||
instances.splice(instances.indexOf(this), 1);
|
||||
this.isDestroy = true;
|
||||
this.emit('destroy');
|
||||
}
|
||||
get query() {
|
||||
return this.template.query
|
||||
}
|
||||
|
||||
get video() {
|
||||
return this.template.$video
|
||||
}
|
||||
|
||||
destroy(removeHtml = true) {
|
||||
this.events.destroy()
|
||||
this.template.destroy(removeHtml)
|
||||
instances.splice(instances.indexOf(this), 1)
|
||||
this.isDestroy = true
|
||||
this.emit('destroy')
|
||||
}
|
||||
}
|
||||
|
||||
Artplayer.STYLE = style;
|
||||
Artplayer.DEBUG = false;
|
||||
Artplayer.CONTEXTMENU = true;
|
||||
Artplayer.NOTICE_TIME = 2000;
|
||||
Artplayer.SETTING_WIDTH = 250;
|
||||
Artplayer.SETTING_ITEM_WIDTH = 200;
|
||||
Artplayer.SETTING_ITEM_HEIGHT = 35;
|
||||
Artplayer.RESIZE_TIME = 200;
|
||||
Artplayer.SCROLL_TIME = 200;
|
||||
Artplayer.SCROLL_GAP = 50;
|
||||
Artplayer.AUTO_PLAYBACK_MAX = 10;
|
||||
Artplayer.AUTO_PLAYBACK_MIN = 5;
|
||||
Artplayer.AUTO_PLAYBACK_TIMEOUT = 3000;
|
||||
Artplayer.RECONNECT_TIME_MAX = 5;
|
||||
Artplayer.RECONNECT_SLEEP_TIME = 1000;
|
||||
Artplayer.CONTROL_HIDE_TIME = 3000;
|
||||
Artplayer.DBCLICK_TIME = 300;
|
||||
Artplayer.DBCLICK_FULLSCREEN = true;
|
||||
Artplayer.MOBILE_DBCLICK_PLAY = true;
|
||||
Artplayer.MOBILE_CLICK_PLAY = false;
|
||||
Artplayer.AUTO_ORIENTATION_TIME = 200;
|
||||
Artplayer.INFO_LOOP_TIME = 1000;
|
||||
Artplayer.FAST_FORWARD_VALUE = 3;
|
||||
Artplayer.FAST_FORWARD_TIME = 1000;
|
||||
Artplayer.TOUCH_MOVE_RATIO = 0.5;
|
||||
Artplayer.VOLUME_STEP = 0.1;
|
||||
Artplayer.SEEK_STEP = 5;
|
||||
Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2];
|
||||
Artplayer.ASPECT_RATIO = ['default', '4:3', '16:9'];
|
||||
Artplayer.FLIP = ['normal', 'horizontal', 'vertical'];
|
||||
Artplayer.FULLSCREEN_WEB_IN_BODY = false;
|
||||
Artplayer.LOG_VERSION = true;
|
||||
Artplayer.USE_RAF = false;
|
||||
Artplayer.STYLE = style
|
||||
Artplayer.DEBUG = false
|
||||
Artplayer.CONTEXTMENU = true
|
||||
Artplayer.NOTICE_TIME = 2000
|
||||
Artplayer.SETTING_WIDTH = 250
|
||||
Artplayer.SETTING_ITEM_WIDTH = 200
|
||||
Artplayer.SETTING_ITEM_HEIGHT = 35
|
||||
Artplayer.RESIZE_TIME = 200
|
||||
Artplayer.SCROLL_TIME = 200
|
||||
Artplayer.SCROLL_GAP = 50
|
||||
Artplayer.AUTO_PLAYBACK_MAX = 10
|
||||
Artplayer.AUTO_PLAYBACK_MIN = 5
|
||||
Artplayer.AUTO_PLAYBACK_TIMEOUT = 3000
|
||||
Artplayer.RECONNECT_TIME_MAX = 5
|
||||
Artplayer.RECONNECT_SLEEP_TIME = 1000
|
||||
Artplayer.CONTROL_HIDE_TIME = 3000
|
||||
Artplayer.DBCLICK_TIME = 300
|
||||
Artplayer.DBCLICK_FULLSCREEN = true
|
||||
Artplayer.MOBILE_DBCLICK_PLAY = true
|
||||
Artplayer.MOBILE_CLICK_PLAY = false
|
||||
Artplayer.AUTO_ORIENTATION_TIME = 200
|
||||
Artplayer.INFO_LOOP_TIME = 1000
|
||||
Artplayer.FAST_FORWARD_VALUE = 3
|
||||
Artplayer.FAST_FORWARD_TIME = 1000
|
||||
Artplayer.TOUCH_MOVE_RATIO = 0.5
|
||||
Artplayer.VOLUME_STEP = 0.1
|
||||
Artplayer.SEEK_STEP = 5
|
||||
Artplayer.PLAYBACK_RATE = [0.5, 0.75, 1, 1.25, 1.5, 2]
|
||||
Artplayer.ASPECT_RATIO = ['default', '4:3', '16:9']
|
||||
Artplayer.FLIP = ['normal', 'horizontal', 'vertical']
|
||||
Artplayer.FULLSCREEN_WEB_IN_BODY = false
|
||||
Artplayer.LOG_VERSION = true
|
||||
Artplayer.USE_RAF = false
|
||||
|
||||
if (utils.isBrowser) {
|
||||
window['Artplayer'] = Artplayer;
|
||||
window.Artplayer = Artplayer
|
||||
|
||||
utils.setStyleText('artplayer-style', style);
|
||||
utils.setStyleText('artplayer-style', style)
|
||||
|
||||
setTimeout(() => {
|
||||
if (Artplayer.LOG_VERSION) {
|
||||
console.log(
|
||||
`%c ArtPlayer %c ${Artplayer.version} %c https://artplayer.org`,
|
||||
'color: #fff; background: #5f5f5f',
|
||||
'color: #fff; background: #4bc729',
|
||||
'',
|
||||
);
|
||||
}
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
if (Artplayer.LOG_VERSION) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`%c ArtPlayer %c ${Artplayer.version} %c https://artplayer.org`,
|
||||
'color: #fff; background: #5f5f5f',
|
||||
'color: #fff; background: #4bc729',
|
||||
'',
|
||||
)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
@@ -1,43 +1,43 @@
|
||||
import { queryAll, isMobile } from './utils';
|
||||
import Component from './utils/component';
|
||||
import { isMobile, queryAll } from './utils'
|
||||
import Component from './utils/component'
|
||||
|
||||
export default class Info extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
this.name = 'info';
|
||||
constructor(art) {
|
||||
super(art)
|
||||
this.name = 'info'
|
||||
|
||||
if (!isMobile) {
|
||||
this.init();
|
||||
if (!isMobile) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
proxy,
|
||||
constructor,
|
||||
template: { $infoPanel, $infoClose, $video },
|
||||
} = this.art
|
||||
|
||||
proxy($infoClose, 'click', () => {
|
||||
this.show = false
|
||||
})
|
||||
|
||||
let timer = null
|
||||
const $types = queryAll('[data-video]', $infoPanel) || []
|
||||
this.art.on('destroy', () => clearTimeout(timer))
|
||||
|
||||
function loop() {
|
||||
for (let index = 0; index < $types.length; index++) {
|
||||
const item = $types[index]
|
||||
const value = $video[item.dataset.video]
|
||||
const textContent = typeof value === 'number' ? value.toFixed(2) : value
|
||||
if (item.textContent !== textContent) {
|
||||
item.textContent = textContent
|
||||
}
|
||||
}
|
||||
timer = setTimeout(loop, constructor.INFO_LOOP_TIME)
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
proxy,
|
||||
constructor,
|
||||
template: { $infoPanel, $infoClose, $video },
|
||||
} = this.art;
|
||||
|
||||
proxy($infoClose, 'click', () => {
|
||||
this.show = false;
|
||||
});
|
||||
|
||||
let timer = null;
|
||||
const $types = queryAll('[data-video]', $infoPanel) || [];
|
||||
this.art.on('destroy', () => clearTimeout(timer));
|
||||
|
||||
function loop() {
|
||||
for (let index = 0; index < $types.length; index++) {
|
||||
const item = $types[index];
|
||||
const value = $video[item.dataset.video];
|
||||
const innerText = typeof value === 'number' ? value.toFixed(2) : value;
|
||||
if (item.innerText !== innerText) {
|
||||
item.innerText = innerText;
|
||||
}
|
||||
}
|
||||
timer = setTimeout(loop, constructor.INFO_LOOP_TIME);
|
||||
}
|
||||
|
||||
loop();
|
||||
}
|
||||
loop()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
import Component from './utils/component';
|
||||
import Component from './utils/component'
|
||||
|
||||
export default class Layer extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
constructor(art) {
|
||||
super(art)
|
||||
|
||||
const {
|
||||
option,
|
||||
template: { $layer },
|
||||
} = art;
|
||||
const {
|
||||
option,
|
||||
template: { $layer },
|
||||
} = art
|
||||
|
||||
this.name = 'layer';
|
||||
this.$parent = $layer;
|
||||
this.name = 'layer'
|
||||
this.$parent = $layer
|
||||
|
||||
for (let index = 0; index < option.layers.length; index++) {
|
||||
this.add(option.layers[index]);
|
||||
}
|
||||
for (let index = 0; index < option.layers.length; index++) {
|
||||
this.add(option.layers[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +1,153 @@
|
||||
const methodMap = [
|
||||
[
|
||||
'requestFullscreen',
|
||||
'exitFullscreen',
|
||||
'fullscreenElement',
|
||||
'fullscreenEnabled',
|
||||
'fullscreenchange',
|
||||
'fullscreenerror',
|
||||
],
|
||||
// New WebKit
|
||||
[
|
||||
'webkitRequestFullscreen',
|
||||
'webkitExitFullscreen',
|
||||
'webkitFullscreenElement',
|
||||
'webkitFullscreenEnabled',
|
||||
'webkitfullscreenchange',
|
||||
'webkitfullscreenerror',
|
||||
],
|
||||
// Old WebKit
|
||||
[
|
||||
'webkitRequestFullScreen',
|
||||
'webkitCancelFullScreen',
|
||||
'webkitCurrentFullScreenElement',
|
||||
'webkitCancelFullScreen',
|
||||
'webkitfullscreenchange',
|
||||
'webkitfullscreenerror',
|
||||
],
|
||||
[
|
||||
'mozRequestFullScreen',
|
||||
'mozCancelFullScreen',
|
||||
'mozFullScreenElement',
|
||||
'mozFullScreenEnabled',
|
||||
'mozfullscreenchange',
|
||||
'mozfullscreenerror',
|
||||
],
|
||||
[
|
||||
'msRequestFullscreen',
|
||||
'msExitFullscreen',
|
||||
'msFullscreenElement',
|
||||
'msFullscreenEnabled',
|
||||
'MSFullscreenChange',
|
||||
'MSFullscreenError',
|
||||
],
|
||||
];
|
||||
[
|
||||
'requestFullscreen',
|
||||
'exitFullscreen',
|
||||
'fullscreenElement',
|
||||
'fullscreenEnabled',
|
||||
'fullscreenchange',
|
||||
'fullscreenerror',
|
||||
],
|
||||
// New WebKit
|
||||
[
|
||||
'webkitRequestFullscreen',
|
||||
'webkitExitFullscreen',
|
||||
'webkitFullscreenElement',
|
||||
'webkitFullscreenEnabled',
|
||||
'webkitfullscreenchange',
|
||||
'webkitfullscreenerror',
|
||||
],
|
||||
// Old WebKit
|
||||
[
|
||||
'webkitRequestFullScreen',
|
||||
'webkitCancelFullScreen',
|
||||
'webkitCurrentFullScreenElement',
|
||||
'webkitCancelFullScreen',
|
||||
'webkitfullscreenchange',
|
||||
'webkitfullscreenerror',
|
||||
],
|
||||
[
|
||||
'mozRequestFullScreen',
|
||||
'mozCancelFullScreen',
|
||||
'mozFullScreenElement',
|
||||
'mozFullScreenEnabled',
|
||||
'mozfullscreenchange',
|
||||
'mozfullscreenerror',
|
||||
],
|
||||
[
|
||||
'msRequestFullscreen',
|
||||
'msExitFullscreen',
|
||||
'msFullscreenElement',
|
||||
'msFullscreenEnabled',
|
||||
'MSFullscreenChange',
|
||||
'MSFullscreenError',
|
||||
],
|
||||
]
|
||||
|
||||
const nativeAPI = (() => {
|
||||
if (typeof document === 'undefined') {
|
||||
return false;
|
||||
if (typeof document === 'undefined') {
|
||||
return false
|
||||
}
|
||||
|
||||
const unprefixedMethods = methodMap[0]
|
||||
const returnValue = {}
|
||||
|
||||
for (const methodList of methodMap) {
|
||||
const exitFullscreenMethod = methodList[1]
|
||||
if (exitFullscreenMethod in document) {
|
||||
for (const [index, method] of methodList.entries()) {
|
||||
returnValue[unprefixedMethods[index]] = method
|
||||
}
|
||||
|
||||
return returnValue
|
||||
}
|
||||
}
|
||||
|
||||
const unprefixedMethods = methodMap[0];
|
||||
const returnValue = {};
|
||||
|
||||
for (const methodList of methodMap) {
|
||||
const exitFullscreenMethod = methodList[1];
|
||||
if (exitFullscreenMethod in document) {
|
||||
for (const [index, method] of methodList.entries()) {
|
||||
returnValue[unprefixedMethods[index]] = method;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
})();
|
||||
return false
|
||||
})()
|
||||
|
||||
const eventNameMap = {
|
||||
change: nativeAPI.fullscreenchange,
|
||||
error: nativeAPI.fullscreenerror,
|
||||
};
|
||||
|
||||
let screenfull = {
|
||||
request(element = document.documentElement, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const onFullScreenEntered = () => {
|
||||
screenfull.off('change', onFullScreenEntered);
|
||||
resolve();
|
||||
};
|
||||
|
||||
screenfull.on('change', onFullScreenEntered);
|
||||
|
||||
const returnPromise = element[nativeAPI.requestFullscreen](options);
|
||||
|
||||
if (returnPromise instanceof Promise) {
|
||||
returnPromise.then(onFullScreenEntered).catch(reject);
|
||||
}
|
||||
});
|
||||
},
|
||||
exit() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!screenfull.isFullscreen) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const onFullScreenExit = () => {
|
||||
screenfull.off('change', onFullScreenExit);
|
||||
resolve();
|
||||
};
|
||||
|
||||
screenfull.on('change', onFullScreenExit);
|
||||
|
||||
const returnPromise = document[nativeAPI.exitFullscreen]();
|
||||
|
||||
if (returnPromise instanceof Promise) {
|
||||
returnPromise.then(onFullScreenExit).catch(reject);
|
||||
}
|
||||
});
|
||||
},
|
||||
toggle(element, options) {
|
||||
return screenfull.isFullscreen ? screenfull.exit() : screenfull.request(element, options);
|
||||
},
|
||||
onchange(callback) {
|
||||
screenfull.on('change', callback);
|
||||
},
|
||||
onerror(callback) {
|
||||
screenfull.on('error', callback);
|
||||
},
|
||||
on(event, callback) {
|
||||
const eventName = eventNameMap[event];
|
||||
if (eventName) {
|
||||
document.addEventListener(eventName, callback, false);
|
||||
}
|
||||
},
|
||||
off(event, callback) {
|
||||
const eventName = eventNameMap[event];
|
||||
if (eventName) {
|
||||
document.removeEventListener(eventName, callback, false);
|
||||
}
|
||||
},
|
||||
raw: nativeAPI,
|
||||
};
|
||||
|
||||
Object.defineProperties(screenfull, {
|
||||
isFullscreen: {
|
||||
get: () => Boolean(document[nativeAPI.fullscreenElement]),
|
||||
},
|
||||
element: {
|
||||
enumerable: true,
|
||||
get: () => document[nativeAPI.fullscreenElement],
|
||||
},
|
||||
isEnabled: {
|
||||
enumerable: true,
|
||||
get: () => Boolean(document[nativeAPI.fullscreenEnabled]),
|
||||
},
|
||||
});
|
||||
|
||||
if (!nativeAPI) {
|
||||
screenfull = { isEnabled: false };
|
||||
change: nativeAPI.fullscreenchange,
|
||||
error: nativeAPI.fullscreenerror,
|
||||
}
|
||||
|
||||
export default screenfull;
|
||||
const screenfull = {
|
||||
request(element = document.documentElement, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const onFullScreenEntered = () => {
|
||||
screenfull.off('change', onFullScreenEntered)
|
||||
resolve()
|
||||
}
|
||||
|
||||
screenfull.on('change', onFullScreenEntered)
|
||||
|
||||
const returnPromise = element[nativeAPI.requestFullscreen](options)
|
||||
|
||||
if (returnPromise instanceof Promise) {
|
||||
returnPromise.then(onFullScreenEntered).catch(reject)
|
||||
}
|
||||
})
|
||||
},
|
||||
exit() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!screenfull.isFullscreen) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
const onFullScreenExit = () => {
|
||||
screenfull.off('change', onFullScreenExit)
|
||||
resolve()
|
||||
}
|
||||
|
||||
screenfull.on('change', onFullScreenExit)
|
||||
|
||||
const returnPromise = document[nativeAPI.exitFullscreen]()
|
||||
|
||||
if (returnPromise instanceof Promise) {
|
||||
returnPromise.then(onFullScreenExit).catch(reject)
|
||||
}
|
||||
})
|
||||
},
|
||||
toggle(element, options) {
|
||||
return screenfull.isFullscreen ? screenfull.exit() : screenfull.request(element, options)
|
||||
},
|
||||
onchange(callback) {
|
||||
screenfull.on('change', callback)
|
||||
},
|
||||
onerror(callback) {
|
||||
screenfull.on('error', callback)
|
||||
},
|
||||
on(event, callback) {
|
||||
const eventName = eventNameMap[event]
|
||||
if (eventName) {
|
||||
document.addEventListener(eventName, callback, false)
|
||||
}
|
||||
},
|
||||
off(event, callback) {
|
||||
const eventName = eventNameMap[event]
|
||||
if (eventName) {
|
||||
document.removeEventListener(eventName, callback, false)
|
||||
}
|
||||
},
|
||||
raw: nativeAPI,
|
||||
}
|
||||
|
||||
Object.defineProperties(screenfull, {
|
||||
isFullscreen: {
|
||||
get: () => Boolean(document[nativeAPI.fullscreenElement]),
|
||||
},
|
||||
element: {
|
||||
enumerable: true,
|
||||
get: () => document[nativeAPI.fullscreenElement],
|
||||
},
|
||||
isEnabled: {
|
||||
enumerable: true,
|
||||
get: () => Boolean(document[nativeAPI.fullscreenEnabled]),
|
||||
},
|
||||
})
|
||||
|
||||
if (!nativeAPI) {
|
||||
screenfull.isEnabled = false
|
||||
}
|
||||
|
||||
export default screenfull
|
||||
@@ -1,10 +1,10 @@
|
||||
import { append } from './utils';
|
||||
import Component from './utils/component';
|
||||
import { append } from './utils'
|
||||
import Component from './utils/component'
|
||||
|
||||
export default class Loading extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
this.name = 'loading';
|
||||
append(art.template.$loading, art.icons.loading);
|
||||
}
|
||||
constructor(art) {
|
||||
super(art)
|
||||
this.name = 'loading'
|
||||
append(art.template.$loading, art.icons.loading)
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
import { append, setStyle } from './utils';
|
||||
import Component from './utils/component';
|
||||
import { append, setStyle } from './utils'
|
||||
import Component from './utils/component'
|
||||
|
||||
export default class Mask extends Component {
|
||||
constructor(art) {
|
||||
super(art);
|
||||
constructor(art) {
|
||||
super(art)
|
||||
|
||||
this.name = 'mask';
|
||||
const { template, icons, events } = art;
|
||||
this.name = 'mask'
|
||||
const { template, icons, events } = art
|
||||
|
||||
const $state = append(template.$state, icons.state);
|
||||
const $error = append(template.$state, icons.error);
|
||||
const $state = append(template.$state, icons.state)
|
||||
const $error = append(template.$state, icons.error)
|
||||
|
||||
setStyle($error, 'display', 'none');
|
||||
setStyle($error, 'display', 'none')
|
||||
|
||||
art.on('destroy', () => {
|
||||
setStyle($state, 'display', 'none');
|
||||
setStyle($error, 'display', null);
|
||||
});
|
||||
art.on('destroy', () => {
|
||||
setStyle($state, 'display', 'none')
|
||||
setStyle($error, 'display', null)
|
||||
})
|
||||
|
||||
events.proxy(template.$state, 'click', () => art.play());
|
||||
}
|
||||
events.proxy(template.$state, 'click', () => art.play())
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,35 @@
|
||||
import { addClass, removeClass } from './utils';
|
||||
import { addClass, removeClass } from './utils'
|
||||
|
||||
export default class Notice {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.timer = null;
|
||||
}
|
||||
constructor(art) {
|
||||
this.art = art
|
||||
this.timer = null
|
||||
}
|
||||
|
||||
set show(msg) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $noticeInner },
|
||||
} = this.art;
|
||||
set show(msg) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $noticeInner },
|
||||
} = this.art
|
||||
|
||||
if (msg) {
|
||||
$noticeInner.innerText = msg instanceof Error ? msg.message.trim() : msg;
|
||||
addClass($player, 'art-notice-show');
|
||||
clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {
|
||||
$noticeInner.innerText = '';
|
||||
removeClass($player, 'art-notice-show');
|
||||
}, constructor.NOTICE_TIME);
|
||||
} else {
|
||||
removeClass($player, 'art-notice-show');
|
||||
}
|
||||
if (msg) {
|
||||
$noticeInner.textContent = msg instanceof Error ? msg.message.trim() : msg
|
||||
addClass($player, 'art-notice-show')
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
$noticeInner.textContent = ''
|
||||
removeClass($player, 'art-notice-show')
|
||||
}, constructor.NOTICE_TIME)
|
||||
}
|
||||
else {
|
||||
removeClass($player, 'art-notice-show')
|
||||
}
|
||||
}
|
||||
|
||||
get show() {
|
||||
const {
|
||||
template: { $player },
|
||||
} = this.art
|
||||
return $player.classList.contains('art-notice-show')
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,40 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function airplayMix(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
proxy,
|
||||
template: { $video },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
proxy,
|
||||
template: { $video },
|
||||
} = art
|
||||
|
||||
let available = true;
|
||||
let available = true
|
||||
|
||||
if (window.WebKitPlaybackTargetAvailabilityEvent && $video.webkitShowPlaybackTargetPicker) {
|
||||
proxy($video, 'webkitplaybacktargetavailabilitychanged', (event) => {
|
||||
switch (event.availability) {
|
||||
case 'available':
|
||||
available = true;
|
||||
break;
|
||||
case 'not-available':
|
||||
available = false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
available = false;
|
||||
}
|
||||
if (window.WebKitPlaybackTargetAvailabilityEvent && $video.webkitShowPlaybackTargetPicker) {
|
||||
proxy($video, 'webkitplaybacktargetavailabilitychanged', (event) => {
|
||||
switch (event.availability) {
|
||||
case 'available':
|
||||
available = true
|
||||
break
|
||||
case 'not-available':
|
||||
available = false
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
available = false
|
||||
}
|
||||
|
||||
def(art, 'airplay', {
|
||||
value() {
|
||||
if (available) {
|
||||
$video.webkitShowPlaybackTargetPicker();
|
||||
art.emit('airplay');
|
||||
} else {
|
||||
notice.show = i18n.get('AirPlay Not Available');
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'airplay', {
|
||||
value() {
|
||||
if (available) {
|
||||
$video.webkitShowPlaybackTargetPicker()
|
||||
art.emit('airplay')
|
||||
}
|
||||
else {
|
||||
notice.show = i18n.get('AirPlay Not Available')
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,44 +1,47 @@
|
||||
import { setStyle, def } from '../utils';
|
||||
import { def, setStyle } from '../utils'
|
||||
|
||||
export default function aspectRatioMix(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video, $player },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video, $player },
|
||||
} = art
|
||||
|
||||
def(art, 'aspectRatio', {
|
||||
get() {
|
||||
return $player.dataset.aspectRatio || 'default';
|
||||
},
|
||||
set(ratio) {
|
||||
if (!ratio) ratio = 'default';
|
||||
if (ratio === 'default') {
|
||||
setStyle($video, 'width', null);
|
||||
setStyle($video, 'height', null);
|
||||
setStyle($video, 'margin', null);
|
||||
delete $player.dataset.aspectRatio;
|
||||
} else {
|
||||
const ratioArray = ratio.split(':').map(Number);
|
||||
const { clientWidth, clientHeight } = $player;
|
||||
const playerRatio = clientWidth / clientHeight;
|
||||
const setupRatio = ratioArray[0] / ratioArray[1];
|
||||
def(art, 'aspectRatio', {
|
||||
get() {
|
||||
return $player.dataset.aspectRatio || 'default'
|
||||
},
|
||||
set(ratio) {
|
||||
if (!ratio)
|
||||
ratio = 'default'
|
||||
if (ratio === 'default') {
|
||||
setStyle($video, 'width', null)
|
||||
setStyle($video, 'height', null)
|
||||
setStyle($video, 'margin', null)
|
||||
delete $player.dataset.aspectRatio
|
||||
}
|
||||
else {
|
||||
const ratioArray = ratio.split(':').map(Number)
|
||||
const { clientWidth, clientHeight } = $player
|
||||
const playerRatio = clientWidth / clientHeight
|
||||
const setupRatio = ratioArray[0] / ratioArray[1]
|
||||
|
||||
if (playerRatio > setupRatio) {
|
||||
setStyle($video, 'width', `${setupRatio * clientHeight}px`);
|
||||
setStyle($video, 'height', '100%');
|
||||
setStyle($video, 'margin', '0 auto');
|
||||
} else {
|
||||
setStyle($video, 'width', '100%');
|
||||
setStyle($video, 'height', `${clientWidth / setupRatio}px`);
|
||||
setStyle($video, 'margin', 'auto 0');
|
||||
}
|
||||
if (playerRatio > setupRatio) {
|
||||
setStyle($video, 'width', `${setupRatio * clientHeight}px`)
|
||||
setStyle($video, 'height', '100%')
|
||||
setStyle($video, 'margin', '0 auto')
|
||||
}
|
||||
else {
|
||||
setStyle($video, 'width', '100%')
|
||||
setStyle($video, 'height', `${clientWidth / setupRatio}px`)
|
||||
setStyle($video, 'margin', 'auto 0')
|
||||
}
|
||||
|
||||
$player.dataset.aspectRatio = ratio;
|
||||
}
|
||||
$player.dataset.aspectRatio = ratio
|
||||
}
|
||||
|
||||
notice.show = `${i18n.get('Aspect Ratio')}: ${ratio === 'default' ? i18n.get('Default') : ratio}`;
|
||||
art.emit('aspectRatio', ratio);
|
||||
},
|
||||
});
|
||||
notice.show = `${i18n.get('Aspect Ratio')}: ${ratio === 'default' ? i18n.get('Default') : ratio}`
|
||||
art.emit('aspectRatio', ratio)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function attrMix(art) {
|
||||
const {
|
||||
template: { $video },
|
||||
} = art;
|
||||
const {
|
||||
template: { $video },
|
||||
} = art
|
||||
|
||||
def(art, 'attr', {
|
||||
value(key, value) {
|
||||
if (value === undefined) return $video[key];
|
||||
$video[key] = value;
|
||||
},
|
||||
});
|
||||
def(art, 'attr', {
|
||||
value(key, value) {
|
||||
if (value === undefined)
|
||||
return $video[key]
|
||||
$video[key] = value
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { setStyle, def } from '../utils';
|
||||
import { def, setStyle } from '../utils'
|
||||
|
||||
export default function autoHeightMix(art) {
|
||||
const {
|
||||
template: { $container, $video },
|
||||
} = art;
|
||||
const {
|
||||
template: { $container, $video },
|
||||
} = art
|
||||
|
||||
def(art, 'autoHeight', {
|
||||
value() {
|
||||
const { clientWidth } = $container;
|
||||
const { videoHeight, videoWidth } = $video;
|
||||
const height = videoHeight * (clientWidth / videoWidth);
|
||||
setStyle($container, 'height', height + 'px');
|
||||
art.emit('autoHeight', height);
|
||||
},
|
||||
});
|
||||
def(art, 'autoHeight', {
|
||||
value() {
|
||||
const { clientWidth } = $container
|
||||
const { videoHeight, videoWidth } = $video
|
||||
const height = videoHeight * (clientWidth / videoWidth)
|
||||
setStyle($container, 'height', `${height}px`)
|
||||
art.emit('autoHeight', height)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,27 +1,28 @@
|
||||
import { setStyle, def, getRect } from '../utils';
|
||||
import { def, getRect, setStyle } from '../utils'
|
||||
|
||||
export default function autoSizeMix(art) {
|
||||
const { $container, $player, $video } = art.template;
|
||||
const { $container, $player, $video } = art.template
|
||||
|
||||
def(art, 'autoSize', {
|
||||
value() {
|
||||
const { videoWidth, videoHeight } = $video;
|
||||
const { width, height } = getRect($container);
|
||||
const videoRatio = videoWidth / videoHeight;
|
||||
const containerRatio = width / height;
|
||||
if (containerRatio > videoRatio) {
|
||||
const percentage = ((height * videoRatio) / width) * 100;
|
||||
setStyle($player, 'width', `${percentage}%`);
|
||||
setStyle($player, 'height', '100%');
|
||||
} else {
|
||||
const percentage = (width / videoRatio / height) * 100;
|
||||
setStyle($player, 'width', '100%');
|
||||
setStyle($player, 'height', `${percentage}%`);
|
||||
}
|
||||
art.emit('autoSize', {
|
||||
width: art.width,
|
||||
height: art.height,
|
||||
});
|
||||
},
|
||||
});
|
||||
def(art, 'autoSize', {
|
||||
value() {
|
||||
const { videoWidth, videoHeight } = $video
|
||||
const { width, height } = getRect($container)
|
||||
const videoRatio = videoWidth / videoHeight
|
||||
const containerRatio = width / height
|
||||
if (containerRatio > videoRatio) {
|
||||
const percentage = ((height * videoRatio) / width) * 100
|
||||
setStyle($player, 'width', `${percentage}%`)
|
||||
setStyle($player, 'height', '100%')
|
||||
}
|
||||
else {
|
||||
const percentage = (width / videoRatio / height) * 100
|
||||
setStyle($player, 'width', '100%')
|
||||
setStyle($player, 'height', `${percentage}%`)
|
||||
}
|
||||
art.emit('autoSize', {
|
||||
width: art.width,
|
||||
height: art.height,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function cssVarMix(art) {
|
||||
const { $player } = art.template;
|
||||
const { $player } = art.template
|
||||
|
||||
def(art, 'cssVar', {
|
||||
value(key, value) {
|
||||
if (value) {
|
||||
return $player.style.setProperty(key, value);
|
||||
} else {
|
||||
return getComputedStyle($player).getPropertyValue(key);
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'cssVar', {
|
||||
value(key, value) {
|
||||
if (value) {
|
||||
return $player.style.setProperty(key, value)
|
||||
}
|
||||
else {
|
||||
return getComputedStyle($player).getPropertyValue(key)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import { clamp, def } from '../utils';
|
||||
import { clamp, def } from '../utils'
|
||||
|
||||
export default function currentTimeMix(art) {
|
||||
const { $video } = art.template;
|
||||
const { $video } = art.template
|
||||
|
||||
def(art, 'currentTime', {
|
||||
get: () => $video.currentTime || 0,
|
||||
set: (time) => {
|
||||
time = parseFloat(time);
|
||||
if (Number.isNaN(time)) return;
|
||||
$video.currentTime = clamp(time, 0, art.duration);
|
||||
},
|
||||
});
|
||||
def(art, 'currentTime', {
|
||||
get: () => $video.currentTime || 0,
|
||||
set: (time) => {
|
||||
time = Number.parseFloat(time)
|
||||
if (Number.isNaN(time))
|
||||
return
|
||||
$video.currentTime = clamp(time, 0, art.duration)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function durationMix(art) {
|
||||
def(art, 'duration', {
|
||||
get: () => {
|
||||
const { duration } = art.template.$video;
|
||||
if (duration === Infinity) return 0;
|
||||
return duration || 0;
|
||||
},
|
||||
});
|
||||
def(art, 'duration', {
|
||||
get: () => {
|
||||
const { duration } = art.template.$video
|
||||
if (duration === Infinity)
|
||||
return 0
|
||||
return duration || 0
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,153 +1,155 @@
|
||||
import config from '../config';
|
||||
import { sleep, addClass, setStyle, isMobile } from '../utils';
|
||||
import config from '../config'
|
||||
import { addClass, isMobile, setStyle, sleep } from '../utils'
|
||||
|
||||
export default function eventInit(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
option,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video, $poster },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
option,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video, $poster },
|
||||
} = art
|
||||
|
||||
let reconnectTime = 0;
|
||||
let reconnectTime = 0
|
||||
|
||||
for (let index = 0; index < config.events.length; index++) {
|
||||
proxy($video, config.events[index], (event) => {
|
||||
art.emit(`video:${event.type}`, event);
|
||||
});
|
||||
for (let index = 0; index < config.events.length; index++) {
|
||||
proxy($video, config.events[index], (event) => {
|
||||
art.emit(`video:${event.type}`, event)
|
||||
})
|
||||
}
|
||||
|
||||
// art.on('video:abort', () => {
|
||||
|
||||
// });
|
||||
|
||||
art.on('video:canplay', () => {
|
||||
reconnectTime = 0
|
||||
art.loading.show = false
|
||||
})
|
||||
|
||||
art.once('video:canplay', () => {
|
||||
art.loading.show = false
|
||||
art.controls.show = true
|
||||
art.mask.show = true
|
||||
art.isReady = true
|
||||
art.emit('ready')
|
||||
})
|
||||
|
||||
// art.on('video:canplaythrough', () => {
|
||||
|
||||
// });
|
||||
|
||||
// art.on('video:durationchange', () => {
|
||||
|
||||
// });
|
||||
|
||||
// art.on('video:emptied', () => {
|
||||
|
||||
// });
|
||||
|
||||
art.on('video:ended', () => {
|
||||
if (option.loop) {
|
||||
art.seek = 0
|
||||
art.play()
|
||||
art.controls.show = false
|
||||
art.mask.show = false
|
||||
}
|
||||
else {
|
||||
art.controls.show = true
|
||||
art.mask.show = true
|
||||
}
|
||||
})
|
||||
|
||||
// art.on('video:abort', () => {
|
||||
art.on('video:error', async (error) => {
|
||||
if (reconnectTime < constructor.RECONNECT_TIME_MAX) {
|
||||
await sleep(constructor.RECONNECT_SLEEP_TIME)
|
||||
reconnectTime += 1
|
||||
art.url = option.url
|
||||
notice.show = `${i18n.get('Reconnect')}: ${reconnectTime}`
|
||||
art.emit('error', error, reconnectTime)
|
||||
}
|
||||
else {
|
||||
art.mask.show = true
|
||||
art.loading.show = false
|
||||
art.controls.show = true
|
||||
addClass($player, 'art-error')
|
||||
await sleep(constructor.RECONNECT_SLEEP_TIME)
|
||||
notice.show = i18n.get('Video Load Failed')
|
||||
}
|
||||
})
|
||||
|
||||
// });
|
||||
// art.on('video:loadeddata', () => {
|
||||
|
||||
art.on('video:canplay', () => {
|
||||
reconnectTime = 0;
|
||||
art.loading.show = false;
|
||||
});
|
||||
// });
|
||||
|
||||
art.once('video:canplay', () => {
|
||||
art.loading.show = false;
|
||||
art.controls.show = true;
|
||||
art.mask.show = true;
|
||||
art.isReady = true;
|
||||
art.emit('ready');
|
||||
});
|
||||
art.on('video:loadedmetadata', () => {
|
||||
art.emit('resize')
|
||||
if (isMobile) {
|
||||
art.loading.show = false
|
||||
art.controls.show = true
|
||||
art.mask.show = true
|
||||
}
|
||||
})
|
||||
|
||||
// art.on('video:canplaythrough', () => {
|
||||
art.on('video:loadstart', () => {
|
||||
art.loading.show = true
|
||||
art.mask.show = false
|
||||
art.controls.show = true
|
||||
})
|
||||
|
||||
// });
|
||||
art.on('video:pause', () => {
|
||||
art.controls.show = true
|
||||
art.mask.show = true
|
||||
})
|
||||
|
||||
// art.on('video:durationchange', () => {
|
||||
art.on('video:play', () => {
|
||||
art.mask.show = false
|
||||
setStyle($poster, 'display', 'none')
|
||||
})
|
||||
|
||||
// });
|
||||
art.on('video:playing', () => {
|
||||
art.mask.show = false
|
||||
})
|
||||
|
||||
// art.on('video:emptied', () => {
|
||||
art.on('video:progress', () => {
|
||||
if (art.playing) {
|
||||
art.loading.show = false
|
||||
}
|
||||
})
|
||||
|
||||
// });
|
||||
// art.on('video:ratechange', () => {
|
||||
|
||||
art.on('video:ended', () => {
|
||||
if (option.loop) {
|
||||
art.seek = 0;
|
||||
art.play();
|
||||
art.controls.show = false;
|
||||
art.mask.show = false;
|
||||
} else {
|
||||
art.controls.show = true;
|
||||
art.mask.show = true;
|
||||
}
|
||||
});
|
||||
// });
|
||||
|
||||
art.on('video:error', async (error) => {
|
||||
if (reconnectTime < constructor.RECONNECT_TIME_MAX) {
|
||||
await sleep(constructor.RECONNECT_SLEEP_TIME);
|
||||
reconnectTime += 1;
|
||||
art.url = option.url;
|
||||
notice.show = `${i18n.get('Reconnect')}: ${reconnectTime}`;
|
||||
art.emit('error', error, reconnectTime);
|
||||
} else {
|
||||
art.mask.show = true;
|
||||
art.loading.show = false;
|
||||
art.controls.show = true;
|
||||
addClass($player, 'art-error');
|
||||
await sleep(constructor.RECONNECT_SLEEP_TIME);
|
||||
notice.show = i18n.get('Video Load Failed');
|
||||
}
|
||||
});
|
||||
art.on('video:seeked', () => {
|
||||
art.loading.show = false
|
||||
art.mask.show = true
|
||||
})
|
||||
|
||||
// art.on('video:loadeddata', () => {
|
||||
art.on('video:seeking', () => {
|
||||
art.loading.show = true
|
||||
art.mask.show = false
|
||||
})
|
||||
|
||||
// });
|
||||
// art.on('video:stalled', () => {
|
||||
|
||||
art.on('video:loadedmetadata', () => {
|
||||
art.emit('resize');
|
||||
if (isMobile) {
|
||||
art.loading.show = false;
|
||||
art.controls.show = true;
|
||||
art.mask.show = true;
|
||||
}
|
||||
});
|
||||
// });
|
||||
|
||||
art.on('video:loadstart', () => {
|
||||
art.loading.show = true;
|
||||
art.mask.show = false;
|
||||
art.controls.show = true;
|
||||
});
|
||||
// art.on('video:suspend', () => {
|
||||
|
||||
art.on('video:pause', () => {
|
||||
art.controls.show = true;
|
||||
art.mask.show = true;
|
||||
});
|
||||
// });
|
||||
|
||||
art.on('video:play', () => {
|
||||
art.mask.show = false;
|
||||
setStyle($poster, 'display', 'none');
|
||||
});
|
||||
art.on('video:timeupdate', () => {
|
||||
art.mask.show = false
|
||||
})
|
||||
|
||||
art.on('video:playing', () => {
|
||||
art.mask.show = false;
|
||||
});
|
||||
// art.on('video:volumechange', () => {
|
||||
|
||||
art.on('video:progress', () => {
|
||||
if (art.playing) {
|
||||
art.loading.show = false;
|
||||
}
|
||||
});
|
||||
// });
|
||||
|
||||
// art.on('video:ratechange', () => {
|
||||
|
||||
// });
|
||||
|
||||
art.on('video:seeked', () => {
|
||||
art.loading.show = false;
|
||||
art.mask.show = true;
|
||||
});
|
||||
|
||||
art.on('video:seeking', () => {
|
||||
art.loading.show = true;
|
||||
art.mask.show = false;
|
||||
});
|
||||
|
||||
// art.on('video:stalled', () => {
|
||||
|
||||
// });
|
||||
|
||||
// art.on('video:suspend', () => {
|
||||
|
||||
// });
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
art.mask.show = false;
|
||||
});
|
||||
|
||||
// art.on('video:volumechange', () => {
|
||||
|
||||
// });
|
||||
|
||||
art.on('video:waiting', () => {
|
||||
art.loading.show = true;
|
||||
art.mask.show = false;
|
||||
});
|
||||
art.on('video:waiting', () => {
|
||||
art.loading.show = true
|
||||
art.mask.show = false
|
||||
})
|
||||
}
|
||||
@@ -1,26 +1,28 @@
|
||||
import { def, capitalize } from '../utils';
|
||||
import { capitalize, def } from '../utils'
|
||||
|
||||
export default function flipMix(art) {
|
||||
const {
|
||||
template: { $player },
|
||||
i18n,
|
||||
notice,
|
||||
} = art;
|
||||
const {
|
||||
template: { $player },
|
||||
i18n,
|
||||
notice,
|
||||
} = art
|
||||
|
||||
def(art, 'flip', {
|
||||
get() {
|
||||
return $player.dataset.flip || 'normal';
|
||||
},
|
||||
set(flip) {
|
||||
if (!flip) flip = 'normal';
|
||||
if (flip === 'normal') {
|
||||
delete $player.dataset.flip;
|
||||
} else {
|
||||
$player.dataset.flip = flip;
|
||||
}
|
||||
def(art, 'flip', {
|
||||
get() {
|
||||
return $player.dataset.flip || 'normal'
|
||||
},
|
||||
set(flip) {
|
||||
if (!flip)
|
||||
flip = 'normal'
|
||||
if (flip === 'normal') {
|
||||
delete $player.dataset.flip
|
||||
}
|
||||
else {
|
||||
$player.dataset.flip = flip
|
||||
}
|
||||
|
||||
notice.show = `${i18n.get('Video Flip')}: ${i18n.get(capitalize(flip))}`;
|
||||
art.emit('flip', flip);
|
||||
},
|
||||
});
|
||||
notice.show = `${i18n.get('Video Flip')}: ${i18n.get(capitalize(flip))}`
|
||||
art.emit('flip', flip)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,83 +1,88 @@
|
||||
import screenfull from '../libs/screenfull';
|
||||
import { addClass, removeClass, def, get } from '../utils';
|
||||
import screenfull from '../libs/screenfull'
|
||||
import { addClass, def, get, removeClass } from '../utils'
|
||||
|
||||
export default function fullscreenMix(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video, $player },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video, $player },
|
||||
} = art
|
||||
|
||||
const nativeScreenfull = (art) => {
|
||||
screenfull.on('change', () => {
|
||||
art.emit('fullscreen', screenfull.isFullscreen);
|
||||
const nativeScreenfull = (art) => {
|
||||
screenfull.on('change', () => {
|
||||
art.emit('fullscreen', screenfull.isFullscreen)
|
||||
|
||||
if (screenfull.isFullscreen) {
|
||||
art.state = 'fullscreen';
|
||||
addClass($player, 'art-fullscreen');
|
||||
} else {
|
||||
removeClass($player, 'art-fullscreen');
|
||||
}
|
||||
if (screenfull.isFullscreen) {
|
||||
art.state = 'fullscreen'
|
||||
addClass($player, 'art-fullscreen')
|
||||
}
|
||||
else {
|
||||
removeClass($player, 'art-fullscreen')
|
||||
}
|
||||
|
||||
art.emit('resize');
|
||||
});
|
||||
art.emit('resize')
|
||||
})
|
||||
|
||||
screenfull.on('error', (event) => {
|
||||
art.emit('fullscreenError', event);
|
||||
});
|
||||
screenfull.on('error', (event) => {
|
||||
art.emit('fullscreenError', event)
|
||||
})
|
||||
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return screenfull.isFullscreen;
|
||||
},
|
||||
async set(value) {
|
||||
if (value) {
|
||||
await screenfull.request($player);
|
||||
} else {
|
||||
await screenfull.exit();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const webkitScreenfull = (art) => {
|
||||
art.proxy(document, 'webkitfullscreenchange', () => {
|
||||
art.emit('fullscreen', art.fullscreen);
|
||||
art.emit('resize');
|
||||
});
|
||||
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return document.fullscreenElement === $video;
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'fullscreen';
|
||||
$video.webkitEnterFullscreen();
|
||||
} else {
|
||||
$video.webkitExitFullscreen();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
art.once('video:loadedmetadata', () => {
|
||||
if (screenfull.isEnabled) {
|
||||
nativeScreenfull(art);
|
||||
} else if ($video.webkitSupportsFullscreen) {
|
||||
webkitScreenfull(art);
|
||||
} else {
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return false;
|
||||
},
|
||||
set() {
|
||||
notice.show = i18n.get('Fullscreen Not Supported');
|
||||
},
|
||||
});
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return screenfull.isFullscreen
|
||||
},
|
||||
async set(value) {
|
||||
if (value) {
|
||||
await screenfull.request($player)
|
||||
}
|
||||
else {
|
||||
await screenfull.exit()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Asynchronous setting
|
||||
def(art, 'fullscreen', get(art, 'fullscreen'));
|
||||
});
|
||||
const webkitScreenfull = (art) => {
|
||||
art.proxy(document, 'webkitfullscreenchange', () => {
|
||||
art.emit('fullscreen', art.fullscreen)
|
||||
art.emit('resize')
|
||||
})
|
||||
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return document.fullscreenElement === $video
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'fullscreen'
|
||||
$video.webkitEnterFullscreen()
|
||||
}
|
||||
else {
|
||||
$video.webkitExitFullscreen()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
art.once('video:loadedmetadata', () => {
|
||||
if (screenfull.isEnabled) {
|
||||
nativeScreenfull(art)
|
||||
}
|
||||
else if ($video.webkitSupportsFullscreen) {
|
||||
webkitScreenfull(art)
|
||||
}
|
||||
else {
|
||||
def(art, 'fullscreen', {
|
||||
get() {
|
||||
return false
|
||||
},
|
||||
set() {
|
||||
notice.show = i18n.get('Fullscreen Not Supported')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Asynchronous setting
|
||||
def(art, 'fullscreen', get(art, 'fullscreen'))
|
||||
})
|
||||
}
|
||||
@@ -1,40 +1,41 @@
|
||||
import { addClass, removeClass, hasClass, def, append, setStyle } from '../utils';
|
||||
import { addClass, append, def, hasClass, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function fullscreenWebMix(art) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $container, $player },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
template: { $container, $player },
|
||||
} = art
|
||||
|
||||
let cssText = '';
|
||||
def(art, 'fullscreenWeb', {
|
||||
get() {
|
||||
return hasClass($player, 'art-fullscreen-web');
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
cssText = $player.style.cssText;
|
||||
if (constructor.FULLSCREEN_WEB_IN_BODY) {
|
||||
append(document.body, $player);
|
||||
}
|
||||
art.state = 'fullscreenWeb';
|
||||
setStyle($player, 'width', '100%');
|
||||
setStyle($player, 'height', '100%');
|
||||
addClass($player, 'art-fullscreen-web');
|
||||
art.emit('fullscreenWeb', true);
|
||||
} else {
|
||||
if (constructor.FULLSCREEN_WEB_IN_BODY) {
|
||||
append($container, $player);
|
||||
}
|
||||
if (cssText) {
|
||||
$player.style.cssText = cssText;
|
||||
cssText = '';
|
||||
}
|
||||
removeClass($player, 'art-fullscreen-web');
|
||||
art.emit('fullscreenWeb', false);
|
||||
}
|
||||
let cssText = ''
|
||||
def(art, 'fullscreenWeb', {
|
||||
get() {
|
||||
return hasClass($player, 'art-fullscreen-web')
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
cssText = $player.style.cssText
|
||||
if (constructor.FULLSCREEN_WEB_IN_BODY) {
|
||||
append(document.body, $player)
|
||||
}
|
||||
art.state = 'fullscreenWeb'
|
||||
setStyle($player, 'width', '100%')
|
||||
setStyle($player, 'height', '100%')
|
||||
addClass($player, 'art-fullscreen-web')
|
||||
art.emit('fullscreenWeb', true)
|
||||
}
|
||||
else {
|
||||
if (constructor.FULLSCREEN_WEB_IN_BODY) {
|
||||
append($container, $player)
|
||||
}
|
||||
if (cssText) {
|
||||
$player.style.cssText = cssText
|
||||
cssText = ''
|
||||
}
|
||||
removeClass($player, 'art-fullscreen-web')
|
||||
art.emit('fullscreenWeb', false)
|
||||
}
|
||||
|
||||
art.emit('resize');
|
||||
},
|
||||
});
|
||||
art.emit('resize')
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,75 +1,75 @@
|
||||
import urlMix from './urlMix';
|
||||
import attrMix from './attrMix';
|
||||
import playMix from './playMix';
|
||||
import pauseMix from './pauseMix';
|
||||
import toggleMix from './toggleMix';
|
||||
import seekMix from './seekMix';
|
||||
import volumeMix from './volumeMix';
|
||||
import currentTimeMix from './currentTimeMix';
|
||||
import durationMix from './durationMix';
|
||||
import switchMix from './switchMix';
|
||||
import playbackRateMix from './playbackRateMix';
|
||||
import aspectRatioMix from './aspectRatioMix';
|
||||
import screenshotMix from './screenshotMix';
|
||||
import fullscreenMix from './fullscreenMix';
|
||||
import fullscreenWebMix from './fullscreenWebMix';
|
||||
import pipMix from './pipMix';
|
||||
import loadedMix from './loadedMix';
|
||||
import playedMix from './playedMix';
|
||||
import playingMix from './playingMix';
|
||||
import autoSizeMix from './autoSizeMix';
|
||||
import rectMix from './rectMix';
|
||||
import flipMix from './flipMix';
|
||||
import miniMix from './miniMix';
|
||||
import posterMix from './posterMix';
|
||||
import autoHeightMix from './autoHeightMix';
|
||||
import cssVarMix from './cssVarMix';
|
||||
import themeMix from './themeMix';
|
||||
import typeMix from './typeMix';
|
||||
import stateMix from './stateMix';
|
||||
import subtitleOffsetMix from './subtitleOffsetMix';
|
||||
import airplayMix from './airplayMix';
|
||||
import qualityMix from './qualityMix';
|
||||
import thumbnailsMix from './thumbnailsMix';
|
||||
import optionInit from './optionInit';
|
||||
import eventInit from './eventInit';
|
||||
import airplayMix from './airplayMix'
|
||||
import aspectRatioMix from './aspectRatioMix'
|
||||
import attrMix from './attrMix'
|
||||
import autoHeightMix from './autoHeightMix'
|
||||
import autoSizeMix from './autoSizeMix'
|
||||
import cssVarMix from './cssVarMix'
|
||||
import currentTimeMix from './currentTimeMix'
|
||||
import durationMix from './durationMix'
|
||||
import eventInit from './eventInit'
|
||||
import flipMix from './flipMix'
|
||||
import fullscreenMix from './fullscreenMix'
|
||||
import fullscreenWebMix from './fullscreenWebMix'
|
||||
import loadedMix from './loadedMix'
|
||||
import miniMix from './miniMix'
|
||||
import optionInit from './optionInit'
|
||||
import pauseMix from './pauseMix'
|
||||
import pipMix from './pipMix'
|
||||
import playbackRateMix from './playbackRateMix'
|
||||
import playedMix from './playedMix'
|
||||
import playingMix from './playingMix'
|
||||
import playMix from './playMix'
|
||||
import posterMix from './posterMix'
|
||||
import qualityMix from './qualityMix'
|
||||
import rectMix from './rectMix'
|
||||
import screenshotMix from './screenshotMix'
|
||||
import seekMix from './seekMix'
|
||||
import stateMix from './stateMix'
|
||||
import subtitleOffsetMix from './subtitleOffsetMix'
|
||||
import switchMix from './switchMix'
|
||||
import themeMix from './themeMix'
|
||||
import thumbnailsMix from './thumbnailsMix'
|
||||
import toggleMix from './toggleMix'
|
||||
import typeMix from './typeMix'
|
||||
import urlMix from './urlMix'
|
||||
import volumeMix from './volumeMix'
|
||||
|
||||
export default class Player {
|
||||
constructor(art) {
|
||||
urlMix(art);
|
||||
attrMix(art);
|
||||
playMix(art);
|
||||
pauseMix(art);
|
||||
toggleMix(art);
|
||||
seekMix(art);
|
||||
volumeMix(art);
|
||||
currentTimeMix(art);
|
||||
durationMix(art);
|
||||
switchMix(art);
|
||||
playbackRateMix(art);
|
||||
aspectRatioMix(art);
|
||||
screenshotMix(art);
|
||||
fullscreenMix(art);
|
||||
fullscreenWebMix(art);
|
||||
pipMix(art);
|
||||
loadedMix(art);
|
||||
playedMix(art);
|
||||
playingMix(art);
|
||||
autoSizeMix(art);
|
||||
rectMix(art);
|
||||
flipMix(art);
|
||||
miniMix(art);
|
||||
posterMix(art);
|
||||
autoHeightMix(art);
|
||||
cssVarMix(art);
|
||||
themeMix(art);
|
||||
typeMix(art);
|
||||
stateMix(art);
|
||||
subtitleOffsetMix(art);
|
||||
airplayMix(art);
|
||||
qualityMix(art);
|
||||
thumbnailsMix(art);
|
||||
eventInit(art);
|
||||
optionInit(art);
|
||||
}
|
||||
constructor(art) {
|
||||
urlMix(art)
|
||||
attrMix(art)
|
||||
playMix(art)
|
||||
pauseMix(art)
|
||||
toggleMix(art)
|
||||
seekMix(art)
|
||||
volumeMix(art)
|
||||
currentTimeMix(art)
|
||||
durationMix(art)
|
||||
switchMix(art)
|
||||
playbackRateMix(art)
|
||||
aspectRatioMix(art)
|
||||
screenshotMix(art)
|
||||
fullscreenMix(art)
|
||||
fullscreenWebMix(art)
|
||||
pipMix(art)
|
||||
loadedMix(art)
|
||||
playedMix(art)
|
||||
playingMix(art)
|
||||
autoSizeMix(art)
|
||||
rectMix(art)
|
||||
flipMix(art)
|
||||
miniMix(art)
|
||||
posterMix(art)
|
||||
autoHeightMix(art)
|
||||
cssVarMix(art)
|
||||
themeMix(art)
|
||||
typeMix(art)
|
||||
stateMix(art)
|
||||
subtitleOffsetMix(art)
|
||||
airplayMix(art)
|
||||
qualityMix(art)
|
||||
thumbnailsMix(art)
|
||||
eventInit(art)
|
||||
optionInit(art)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function loadedMix(art) {
|
||||
const { $video } = art.template;
|
||||
const { $video } = art.template
|
||||
|
||||
def(art, 'loaded', {
|
||||
get: () => art.loadedTime / $video.duration,
|
||||
});
|
||||
def(art, 'loaded', {
|
||||
get: () => art.loadedTime / $video.duration,
|
||||
})
|
||||
|
||||
def(art, 'loadedTime', {
|
||||
get: () => {
|
||||
return $video.buffered.length ? $video.buffered.end($video.buffered.length - 1) : 0;
|
||||
},
|
||||
});
|
||||
def(art, 'loadedTime', {
|
||||
get: () => {
|
||||
return $video.buffered.length ? $video.buffered.end($video.buffered.length - 1) : 0
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,130 +1,134 @@
|
||||
import { append, setStyle, addClass, removeClass, hasClass, def, isInViewport, createElement, getRect } from '../utils';
|
||||
import { addClass, append, createElement, def, getRect, hasClass, isInViewport, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function miniMix(art) {
|
||||
const {
|
||||
icons,
|
||||
proxy,
|
||||
storage,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
icons,
|
||||
proxy,
|
||||
storage,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
let isDragging = false;
|
||||
let lastPageX = 0;
|
||||
let lastPageY = 0;
|
||||
let isDragging = false
|
||||
let lastPageX = 0
|
||||
let lastPageY = 0
|
||||
|
||||
function hideMini() {
|
||||
const { $mini } = art.template;
|
||||
if ($mini) {
|
||||
removeClass($player, 'art-mini');
|
||||
setStyle($mini, 'display', 'none');
|
||||
$player.prepend($video);
|
||||
art.emit('mini', false);
|
||||
function hideMini() {
|
||||
const { $mini } = art.template
|
||||
if ($mini) {
|
||||
removeClass($player, 'art-mini')
|
||||
setStyle($mini, 'display', 'none')
|
||||
$player.prepend($video)
|
||||
art.emit('mini', false)
|
||||
}
|
||||
}
|
||||
|
||||
function initState($play, $pause) {
|
||||
if (art.playing) {
|
||||
setStyle($play, 'display', `none`)
|
||||
setStyle($pause, 'display', `flex`)
|
||||
}
|
||||
else {
|
||||
setStyle($play, 'display', `flex`)
|
||||
setStyle($pause, 'display', `none`)
|
||||
}
|
||||
}
|
||||
|
||||
function createMini() {
|
||||
const { $mini } = art.template
|
||||
if ($mini) {
|
||||
append($mini, $video)
|
||||
return setStyle($mini, 'display', 'flex')
|
||||
}
|
||||
else {
|
||||
const $mini = createElement('div')
|
||||
addClass($mini, 'art-mini-popup')
|
||||
append(document.body, $mini)
|
||||
art.template.$mini = $mini
|
||||
append($mini, $video)
|
||||
|
||||
const $close = append($mini, `<div class="art-mini-close"></div>`)
|
||||
append($close, icons.close)
|
||||
proxy($close, 'click', hideMini)
|
||||
|
||||
const $state = append($mini, `<div class="art-mini-state"></div>`)
|
||||
const $play = append($state, icons.play)
|
||||
const $pause = append($state, icons.pause)
|
||||
proxy($play, 'click', () => art.play())
|
||||
proxy($pause, 'click', () => art.pause())
|
||||
initState($play, $pause)
|
||||
art.on('video:playing', () => initState($play, $pause))
|
||||
art.on('video:pause', () => initState($play, $pause))
|
||||
art.on('video:timeupdate', () => initState($play, $pause))
|
||||
|
||||
proxy($mini, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0
|
||||
lastPageX = event.pageX
|
||||
lastPageY = event.pageY
|
||||
})
|
||||
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
addClass($mini, 'art-mini-dragging')
|
||||
const x = event.pageX - lastPageX
|
||||
const y = event.pageY - lastPageY
|
||||
setStyle($mini, 'transform', `translate(${x}px, ${y}px)`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function initState($play, $pause) {
|
||||
if (art.playing) {
|
||||
setStyle($play, 'display', `none`);
|
||||
setStyle($pause, 'display', `flex`);
|
||||
} else {
|
||||
setStyle($play, 'display', `flex`);
|
||||
setStyle($pause, 'display', `none`);
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false
|
||||
removeClass($mini, 'art-mini-dragging')
|
||||
const rect = getRect($mini)
|
||||
storage.set('left', rect.left)
|
||||
storage.set('top', rect.top)
|
||||
setStyle($mini, 'left', `${rect.left}px`)
|
||||
setStyle($mini, 'top', `${rect.top}px`)
|
||||
setStyle($mini, 'transform', null)
|
||||
}
|
||||
})
|
||||
|
||||
return $mini
|
||||
}
|
||||
}
|
||||
|
||||
function createMini() {
|
||||
const { $mini } = art.template;
|
||||
if ($mini) {
|
||||
append($mini, $video);
|
||||
return setStyle($mini, 'display', 'flex');
|
||||
} else {
|
||||
const $mini = createElement('div');
|
||||
addClass($mini, 'art-mini-popup');
|
||||
append(document.body, $mini);
|
||||
art.template.$mini = $mini;
|
||||
append($mini, $video);
|
||||
function initMini() {
|
||||
const { $mini } = art.template
|
||||
const rect = getRect($mini)
|
||||
const top = window.innerHeight - rect.height - 50
|
||||
const left = window.innerWidth - rect.width - 50
|
||||
storage.set('top', top)
|
||||
storage.set('left', left)
|
||||
setStyle($mini, 'top', `${top}px`)
|
||||
setStyle($mini, 'left', `${left}px`)
|
||||
}
|
||||
|
||||
const $close = append($mini, `<div class="art-mini-close"></div>`);
|
||||
append($close, icons.close);
|
||||
proxy($close, 'click', hideMini);
|
||||
|
||||
const $state = append($mini, `<div class="art-mini-state"></div>`);
|
||||
const $play = append($state, icons.play);
|
||||
const $pause = append($state, icons.pause);
|
||||
proxy($play, 'click', () => art.play());
|
||||
proxy($pause, 'click', () => art.pause());
|
||||
initState($play, $pause);
|
||||
art.on('video:playing', () => initState($play, $pause));
|
||||
art.on('video:pause', () => initState($play, $pause));
|
||||
art.on('video:timeupdate', () => initState($play, $pause));
|
||||
|
||||
proxy($mini, 'mousedown', (event) => {
|
||||
isDragging = event.button === 0;
|
||||
lastPageX = event.pageX;
|
||||
lastPageY = event.pageY;
|
||||
});
|
||||
|
||||
art.on('document:mousemove', (event) => {
|
||||
if (isDragging) {
|
||||
addClass($mini, 'art-mini-dragging');
|
||||
const x = event.pageX - lastPageX;
|
||||
const y = event.pageY - lastPageY;
|
||||
setStyle($mini, 'transform', `translate(${x}px, ${y}px)`);
|
||||
}
|
||||
});
|
||||
|
||||
art.on('document:mouseup', () => {
|
||||
if (isDragging) {
|
||||
isDragging = false;
|
||||
removeClass($mini, 'art-mini-dragging');
|
||||
const rect = getRect($mini);
|
||||
storage.set('left', rect.left);
|
||||
storage.set('top', rect.top);
|
||||
setStyle($mini, 'left', `${rect.left}px`);
|
||||
setStyle($mini, 'top', `${rect.top}px`);
|
||||
setStyle($mini, 'transform', null);
|
||||
}
|
||||
});
|
||||
|
||||
return $mini;
|
||||
def(art, 'mini', {
|
||||
get() {
|
||||
return hasClass($player, 'art-mini')
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'mini'
|
||||
addClass($player, 'art-mini')
|
||||
const $mini = createMini()
|
||||
const top = storage.get('top')
|
||||
const left = storage.get('left')
|
||||
if (typeof top === 'number' && typeof left === 'number') {
|
||||
setStyle($mini, 'top', `${top}px`)
|
||||
setStyle($mini, 'left', `${left}px`)
|
||||
if (!isInViewport($mini)) {
|
||||
initMini()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initMini() {
|
||||
const { $mini } = art.template;
|
||||
const rect = getRect($mini);
|
||||
const top = window.innerHeight - rect.height - 50;
|
||||
const left = window.innerWidth - rect.width - 50;
|
||||
storage.set('top', top);
|
||||
storage.set('left', left);
|
||||
setStyle($mini, 'top', `${top}px`);
|
||||
setStyle($mini, 'left', `${left}px`);
|
||||
}
|
||||
|
||||
def(art, 'mini', {
|
||||
get() {
|
||||
return hasClass($player, 'art-mini');
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'mini';
|
||||
addClass($player, 'art-mini');
|
||||
const $mini = createMini();
|
||||
const top = storage.get('top');
|
||||
const left = storage.get('left');
|
||||
if (typeof top === 'number' && typeof left === 'number') {
|
||||
setStyle($mini, 'top', `${top}px`);
|
||||
setStyle($mini, 'left', `${left}px`);
|
||||
if (!isInViewport($mini)) {
|
||||
initMini();
|
||||
}
|
||||
} else {
|
||||
initMini();
|
||||
}
|
||||
art.emit('mini', true);
|
||||
} else {
|
||||
hideMini();
|
||||
}
|
||||
},
|
||||
});
|
||||
else {
|
||||
initMini()
|
||||
}
|
||||
art.emit('mini', true)
|
||||
}
|
||||
else {
|
||||
hideMini()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,49 +1,49 @@
|
||||
import { clamp, setStyle } from '../utils';
|
||||
import { clamp, setStyle } from '../utils'
|
||||
|
||||
export default function optionInit(art) {
|
||||
const {
|
||||
option,
|
||||
storage,
|
||||
template: { $video, $poster },
|
||||
} = art;
|
||||
const {
|
||||
option,
|
||||
storage,
|
||||
template: { $video, $poster },
|
||||
} = art
|
||||
|
||||
for (const key in option.moreVideoAttr) {
|
||||
art.attr(key, option.moreVideoAttr[key]);
|
||||
}
|
||||
for (const key in option.moreVideoAttr) {
|
||||
art.attr(key, option.moreVideoAttr[key])
|
||||
}
|
||||
|
||||
if (option.muted) {
|
||||
art.muted = option.muted;
|
||||
}
|
||||
if (option.muted) {
|
||||
art.muted = option.muted
|
||||
}
|
||||
|
||||
if (option.volume) {
|
||||
$video.volume = clamp(option.volume, 0, 1);
|
||||
}
|
||||
if (option.volume) {
|
||||
$video.volume = clamp(option.volume, 0, 1)
|
||||
}
|
||||
|
||||
const volumeStorage = storage.get('volume');
|
||||
if (typeof volumeStorage === 'number') {
|
||||
$video.volume = clamp(volumeStorage, 0, 1);
|
||||
}
|
||||
const volumeStorage = storage.get('volume')
|
||||
if (typeof volumeStorage === 'number') {
|
||||
$video.volume = clamp(volumeStorage, 0, 1)
|
||||
}
|
||||
|
||||
if (option.poster) {
|
||||
setStyle($poster, 'backgroundImage', `url(${option.poster})`);
|
||||
}
|
||||
if (option.poster) {
|
||||
setStyle($poster, 'backgroundImage', `url(${option.poster})`)
|
||||
}
|
||||
|
||||
if (option.autoplay) {
|
||||
$video.autoplay = option.autoplay;
|
||||
}
|
||||
if (option.autoplay) {
|
||||
$video.autoplay = option.autoplay
|
||||
}
|
||||
|
||||
if (option.playsInline) {
|
||||
$video.playsInline = true;
|
||||
$video['webkit-playsinline'] = true;
|
||||
}
|
||||
if (option.playsInline) {
|
||||
$video.playsInline = true
|
||||
$video['webkit-playsinline'] = true
|
||||
}
|
||||
|
||||
if (option.theme) {
|
||||
option.cssVar['--art-theme'] = option.theme;
|
||||
}
|
||||
if (option.theme) {
|
||||
option.cssVar['--art-theme'] = option.theme
|
||||
}
|
||||
|
||||
for (const key in option.cssVar) {
|
||||
art.cssVar(key, option.cssVar[key]);
|
||||
}
|
||||
for (const key in option.cssVar) {
|
||||
art.cssVar(key, option.cssVar[key])
|
||||
}
|
||||
|
||||
art.url = option.url;
|
||||
art.url = option.url
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function pauseMix(art) {
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
} = art;
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
} = art
|
||||
|
||||
def(art, 'pause', {
|
||||
value() {
|
||||
const result = $video.pause();
|
||||
notice.show = i18n.get('Pause');
|
||||
art.emit('pause');
|
||||
return result;
|
||||
},
|
||||
});
|
||||
def(art, 'pause', {
|
||||
value() {
|
||||
const result = $video.pause()
|
||||
notice.show = i18n.get('Pause')
|
||||
art.emit('pause')
|
||||
return result
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,83 +1,87 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
function nativePip(art) {
|
||||
const {
|
||||
template: { $video },
|
||||
proxy,
|
||||
notice,
|
||||
} = art;
|
||||
const {
|
||||
template: { $video },
|
||||
proxy,
|
||||
notice,
|
||||
} = art
|
||||
|
||||
$video.disablePictureInPicture = false;
|
||||
$video.disablePictureInPicture = false
|
||||
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return document.pictureInPictureElement;
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'pip';
|
||||
$video.requestPictureInPicture().catch((err) => {
|
||||
notice.show = err;
|
||||
throw err;
|
||||
});
|
||||
} else {
|
||||
document.exitPictureInPicture().catch((err) => {
|
||||
notice.show = err;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return document.pictureInPictureElement
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'pip'
|
||||
$video.requestPictureInPicture().catch((err) => {
|
||||
notice.show = err
|
||||
throw err
|
||||
})
|
||||
}
|
||||
else {
|
||||
document.exitPictureInPicture().catch((err) => {
|
||||
notice.show = err
|
||||
throw err
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
proxy($video, 'enterpictureinpicture', () => {
|
||||
art.emit('pip', true);
|
||||
});
|
||||
proxy($video, 'enterpictureinpicture', () => {
|
||||
art.emit('pip', true)
|
||||
})
|
||||
|
||||
proxy($video, 'leavepictureinpicture', () => {
|
||||
art.emit('pip', false);
|
||||
});
|
||||
proxy($video, 'leavepictureinpicture', () => {
|
||||
art.emit('pip', false)
|
||||
})
|
||||
}
|
||||
|
||||
function webkitPip(art) {
|
||||
const { $video } = art.template;
|
||||
const { $video } = art.template
|
||||
|
||||
$video.webkitSetPresentationMode('inline');
|
||||
$video.webkitSetPresentationMode('inline')
|
||||
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return $video.webkitPresentationMode === 'picture-in-picture';
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'pip';
|
||||
$video.webkitSetPresentationMode('picture-in-picture');
|
||||
art.emit('pip', true);
|
||||
} else {
|
||||
$video.webkitSetPresentationMode('inline');
|
||||
art.emit('pip', false);
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return $video.webkitPresentationMode === 'picture-in-picture'
|
||||
},
|
||||
set(value) {
|
||||
if (value) {
|
||||
art.state = 'pip'
|
||||
$video.webkitSetPresentationMode('picture-in-picture')
|
||||
art.emit('pip', true)
|
||||
}
|
||||
else {
|
||||
$video.webkitSetPresentationMode('inline')
|
||||
art.emit('pip', false)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default function pipMix(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video },
|
||||
} = art;
|
||||
if (document.pictureInPictureEnabled) {
|
||||
nativePip(art);
|
||||
} else if ($video.webkitSupportsPresentationMode) {
|
||||
webkitPip(art);
|
||||
} else {
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return false;
|
||||
},
|
||||
set() {
|
||||
notice.show = i18n.get('PIP Not Supported');
|
||||
},
|
||||
});
|
||||
}
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
template: { $video },
|
||||
} = art
|
||||
if (document.pictureInPictureEnabled) {
|
||||
nativePip(art)
|
||||
}
|
||||
else if ($video.webkitSupportsPresentationMode) {
|
||||
webkitPip(art)
|
||||
}
|
||||
else {
|
||||
def(art, 'pip', {
|
||||
get() {
|
||||
return false
|
||||
},
|
||||
set() {
|
||||
notice.show = i18n.get('PIP Not Supported')
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,30 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function playMix(art) {
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
option,
|
||||
constructor: { instances },
|
||||
template: { $video },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
notice,
|
||||
option,
|
||||
constructor: { instances },
|
||||
template: { $video },
|
||||
} = art
|
||||
|
||||
def(art, 'play', {
|
||||
value: async function () {
|
||||
const result = await $video.play();
|
||||
notice.show = i18n.get('Play');
|
||||
art.emit('play');
|
||||
def(art, 'play', {
|
||||
async value() {
|
||||
const result = await $video.play()
|
||||
notice.show = i18n.get('Play')
|
||||
art.emit('play')
|
||||
|
||||
if (option.mutex) {
|
||||
for (let index = 0; index < instances.length; index++) {
|
||||
const instance = instances[index];
|
||||
if (instance !== art) {
|
||||
instance.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (option.mutex) {
|
||||
for (let index = 0; index < instances.length; index++) {
|
||||
const instance = instances[index]
|
||||
if (instance !== art) {
|
||||
instance.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
});
|
||||
return result
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,24 +1,26 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function playbackRateMix(art) {
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
} = art;
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
} = art
|
||||
|
||||
def(art, 'playbackRate', {
|
||||
get() {
|
||||
return $video.playbackRate;
|
||||
},
|
||||
set(rate) {
|
||||
if (rate) {
|
||||
if (rate === $video.playbackRate) return;
|
||||
$video.playbackRate = rate;
|
||||
notice.show = `${i18n.get('Rate')}: ${rate === 1.0 ? i18n.get('Normal') : `${rate}x`}`;
|
||||
} else {
|
||||
art.playbackRate = 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'playbackRate', {
|
||||
get() {
|
||||
return $video.playbackRate
|
||||
},
|
||||
set(rate) {
|
||||
if (rate) {
|
||||
if (rate === $video.playbackRate)
|
||||
return
|
||||
$video.playbackRate = rate
|
||||
notice.show = `${i18n.get('Rate')}: ${rate === 1.0 ? i18n.get('Normal') : `${rate}x`}`
|
||||
}
|
||||
else {
|
||||
art.playbackRate = 1
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function playedMix(art) {
|
||||
def(art, 'played', {
|
||||
get: () => art.currentTime / art.duration,
|
||||
});
|
||||
def(art, 'played', {
|
||||
get: () => art.currentTime / art.duration,
|
||||
})
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function playingMix(art) {
|
||||
const { $video } = art.template;
|
||||
def(art, 'playing', {
|
||||
get: () => {
|
||||
if (typeof $video.playing === 'boolean') return $video.playing;
|
||||
return !!($video.currentTime > 0 && !$video.paused && !$video.ended && $video.readyState > 2);
|
||||
},
|
||||
});
|
||||
const { $video } = art.template
|
||||
def(art, 'playing', {
|
||||
get: () => {
|
||||
if (typeof $video.playing === 'boolean')
|
||||
return $video.playing
|
||||
return !!($video.currentTime > 0 && !$video.paused && !$video.ended && $video.readyState > 2)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
import { def, setStyle } from '../utils';
|
||||
import { def, setStyle } from '../utils'
|
||||
|
||||
export default function posterMix(art) {
|
||||
const {
|
||||
template: { $poster },
|
||||
} = art;
|
||||
const {
|
||||
template: { $poster },
|
||||
} = art
|
||||
|
||||
def(art, 'poster', {
|
||||
get: () => {
|
||||
try {
|
||||
return $poster.style['backgroundImage'].match(/"(.*)"/)[1];
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
set(url) {
|
||||
setStyle($poster, 'backgroundImage', `url(${url})`);
|
||||
},
|
||||
});
|
||||
def(art, 'poster', {
|
||||
get: () => {
|
||||
try {
|
||||
return $poster.style.backgroundImage.match(/"(.*)"/)[1]
|
||||
}
|
||||
catch {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
set(url) {
|
||||
setStyle($poster, 'backgroundImage', `url(${url})`)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function qualityMix(art) {
|
||||
def(art, 'quality', {
|
||||
set(quality) {
|
||||
const { controls, notice, i18n } = art;
|
||||
const qualityDefault = quality.find((item) => item.default) || quality[0];
|
||||
controls.update({
|
||||
name: 'quality',
|
||||
position: 'right',
|
||||
index: 10,
|
||||
style: {
|
||||
marginRight: '10px',
|
||||
},
|
||||
html: qualityDefault?.html || '',
|
||||
selector: quality,
|
||||
async onSelect(item) {
|
||||
await art.switchQuality(item.url);
|
||||
notice.show = `${i18n.get('Switch Video')}: ${item.html}`;
|
||||
return item.html;
|
||||
},
|
||||
});
|
||||
def(art, 'quality', {
|
||||
set(quality) {
|
||||
const { controls, notice, i18n } = art
|
||||
const qualityDefault = quality.find(item => item.default) || quality[0]
|
||||
controls.update({
|
||||
name: 'quality',
|
||||
position: 'right',
|
||||
index: 10,
|
||||
style: {
|
||||
marginRight: '10px',
|
||||
},
|
||||
});
|
||||
html: qualityDefault?.html || '',
|
||||
selector: quality,
|
||||
async onSelect(item) {
|
||||
await art.switchQuality(item.url)
|
||||
notice.show = `${i18n.get('Switch Video')}: ${item.html}`
|
||||
return item.html
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
import { def, getRect } from '../utils';
|
||||
import { def, getRect } from '../utils'
|
||||
|
||||
export default function rectMix(art) {
|
||||
def(art, 'rect', {
|
||||
get: () => {
|
||||
return getRect(art.template.$player);
|
||||
},
|
||||
});
|
||||
def(art, 'rect', {
|
||||
get: () => {
|
||||
return getRect(art.template.$player)
|
||||
},
|
||||
})
|
||||
|
||||
const keys = ['bottom', 'height', 'left', 'right', 'top', 'width'];
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const key = keys[index];
|
||||
def(art, key, {
|
||||
get: () => {
|
||||
return art.rect[key];
|
||||
},
|
||||
});
|
||||
}
|
||||
const keys = ['bottom', 'height', 'left', 'right', 'top', 'width']
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const key = keys[index]
|
||||
def(art, key, {
|
||||
get: () => {
|
||||
return art.rect[key]
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
def(art, 'x', {
|
||||
get: () => {
|
||||
return art.left + window.pageXOffset;
|
||||
},
|
||||
});
|
||||
def(art, 'x', {
|
||||
get: () => {
|
||||
return art.left + window.pageXOffset
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'y', {
|
||||
get: () => {
|
||||
return art.top + window.pageYOffset;
|
||||
},
|
||||
});
|
||||
def(art, 'y', {
|
||||
get: () => {
|
||||
return art.top + window.pageYOffset
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,52 +1,54 @@
|
||||
import { secondToTime, download, def, createElement } from '../utils';
|
||||
import { createElement, def, download, secondToTime } from '../utils'
|
||||
|
||||
export default function screenshotMix(art) {
|
||||
const {
|
||||
notice,
|
||||
template: { $video },
|
||||
} = art;
|
||||
const {
|
||||
notice,
|
||||
template: { $video },
|
||||
} = art
|
||||
|
||||
const $canvas = createElement('canvas');
|
||||
const $canvas = createElement('canvas')
|
||||
|
||||
def(art, 'getDataURL', {
|
||||
value: () =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
$canvas.width = $video.videoWidth;
|
||||
$canvas.height = $video.videoHeight;
|
||||
$canvas.getContext('2d').drawImage($video, 0, 0);
|
||||
resolve($canvas.toDataURL('image/png'));
|
||||
} catch (err) {
|
||||
notice.show = err;
|
||||
reject(err);
|
||||
}
|
||||
}),
|
||||
});
|
||||
def(art, 'getDataURL', {
|
||||
value: () =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
$canvas.width = $video.videoWidth
|
||||
$canvas.height = $video.videoHeight
|
||||
$canvas.getContext('2d').drawImage($video, 0, 0)
|
||||
resolve($canvas.toDataURL('image/png'))
|
||||
}
|
||||
catch (err) {
|
||||
notice.show = err
|
||||
reject(err)
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
def(art, 'getBlobUrl', {
|
||||
value: () =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
$canvas.width = $video.videoWidth;
|
||||
$canvas.height = $video.videoHeight;
|
||||
$canvas.getContext('2d').drawImage($video, 0, 0);
|
||||
$canvas.toBlob((blob) => {
|
||||
resolve(URL.createObjectURL(blob));
|
||||
});
|
||||
} catch (err) {
|
||||
notice.show = err;
|
||||
reject(err);
|
||||
}
|
||||
}),
|
||||
});
|
||||
def(art, 'getBlobUrl', {
|
||||
value: () =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
$canvas.width = $video.videoWidth
|
||||
$canvas.height = $video.videoHeight
|
||||
$canvas.getContext('2d').drawImage($video, 0, 0)
|
||||
$canvas.toBlob((blob) => {
|
||||
resolve(URL.createObjectURL(blob))
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
notice.show = err
|
||||
reject(err)
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
def(art, 'screenshot', {
|
||||
value: async (name) => {
|
||||
const dataUri = await art.getDataURL();
|
||||
const fileName = name || `artplayer_${secondToTime($video.currentTime)}`;
|
||||
download(dataUri, `${fileName}.png`);
|
||||
art.emit('screenshot', dataUri);
|
||||
return dataUri;
|
||||
},
|
||||
});
|
||||
def(art, 'screenshot', {
|
||||
value: async (name) => {
|
||||
const dataUri = await art.getDataURL()
|
||||
const fileName = name || `artplayer_${secondToTime($video.currentTime)}`
|
||||
download(dataUri, `${fileName}.png`)
|
||||
art.emit('screenshot', dataUri)
|
||||
return dataUri
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
import { secondToTime, def } from '../utils';
|
||||
import { def, secondToTime } from '../utils'
|
||||
|
||||
export default function seekMix(art) {
|
||||
const { notice } = art;
|
||||
const { notice } = art
|
||||
|
||||
def(art, 'seek', {
|
||||
set(time) {
|
||||
art.currentTime = time;
|
||||
if (art.duration) {
|
||||
notice.show = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`;
|
||||
}
|
||||
art.emit('seek', art.currentTime);
|
||||
},
|
||||
});
|
||||
def(art, 'seek', {
|
||||
set(time) {
|
||||
art.currentTime = time
|
||||
if (art.duration) {
|
||||
notice.show = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`
|
||||
}
|
||||
art.emit('seek', art.currentTime)
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'forward', {
|
||||
set(time) {
|
||||
art.seek = art.currentTime + time;
|
||||
},
|
||||
});
|
||||
def(art, 'forward', {
|
||||
set(time) {
|
||||
art.seek = art.currentTime + time
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'backward', {
|
||||
set(time) {
|
||||
art.seek = art.currentTime - time;
|
||||
},
|
||||
});
|
||||
def(art, 'backward', {
|
||||
set(time) {
|
||||
art.seek = art.currentTime - time
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function stateMix(art) {
|
||||
const states = ['mini', 'pip', 'fullscreen', 'fullscreenWeb'];
|
||||
def(art, 'state', {
|
||||
get: () => states.find((name) => art[name]) || 'standard',
|
||||
set(name) {
|
||||
for (let index = 0; index < states.length; index++) {
|
||||
const prop = states[index];
|
||||
if (prop !== name && art[prop]) {
|
||||
art[prop] = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
const states = ['mini', 'pip', 'fullscreen', 'fullscreenWeb']
|
||||
def(art, 'state', {
|
||||
get: () => states.find(name => art[name]) || 'standard',
|
||||
set(name) {
|
||||
for (let index = 0; index < states.length; index++) {
|
||||
const prop = states[index]
|
||||
if (prop !== name && art[prop]) {
|
||||
art[prop] = false
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,27 +1,28 @@
|
||||
import { def, clamp } from '../utils';
|
||||
import { clamp, def } from '../utils'
|
||||
|
||||
export default function subtitleOffsetMix(art) {
|
||||
const { notice, i18n, template } = art;
|
||||
const { notice, i18n, template } = art
|
||||
|
||||
def(art, 'subtitleOffset', {
|
||||
get() {
|
||||
return template.$track?.offset || 0;
|
||||
},
|
||||
set(value) {
|
||||
const { cues } = art.subtitle;
|
||||
if (!template.$track || cues.length === 0) return;
|
||||
const offset = clamp(value, -10, 10);
|
||||
template.$track.offset = offset;
|
||||
for (let index = 0; index < cues.length; index++) {
|
||||
const cue = cues[index];
|
||||
cue.originalStartTime = cue.originalStartTime ?? cue.startTime;
|
||||
cue.originalEndTime = cue.originalEndTime ?? cue.endTime;
|
||||
cue.startTime = clamp(cue.originalStartTime + offset, 0, art.duration);
|
||||
cue.endTime = clamp(cue.originalEndTime + offset, 0, art.duration);
|
||||
}
|
||||
art.subtitle.update();
|
||||
notice.show = `${i18n.get('Subtitle Offset')}: ${value}s`;
|
||||
art.emit('subtitleOffset', value);
|
||||
},
|
||||
});
|
||||
def(art, 'subtitleOffset', {
|
||||
get() {
|
||||
return template.$track?.offset || 0
|
||||
},
|
||||
set(value) {
|
||||
const { cues } = art.subtitle
|
||||
if (!template.$track || cues.length === 0)
|
||||
return
|
||||
const offset = clamp(value, -10, 10)
|
||||
template.$track.offset = offset
|
||||
for (let index = 0; index < cues.length; index++) {
|
||||
const cue = cues[index]
|
||||
cue.originalStartTime = cue.originalStartTime ?? cue.startTime
|
||||
cue.originalEndTime = cue.originalEndTime ?? cue.endTime
|
||||
cue.startTime = clamp(cue.originalStartTime + offset, 0, art.duration)
|
||||
cue.endTime = clamp(cue.originalEndTime + offset, 0, art.duration)
|
||||
}
|
||||
art.subtitle.update()
|
||||
notice.show = `${i18n.get('Subtitle Offset')}: ${value}s`
|
||||
art.emit('subtitleOffset', value)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,49 +1,50 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function switchMix(art) {
|
||||
function switchUrl(url, currentTime) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (url === art.url) return;
|
||||
const { playing, aspectRatio, playbackRate } = art;
|
||||
function switchUrl(url, currentTime) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (url === art.url)
|
||||
return
|
||||
const { playing, aspectRatio, playbackRate } = art
|
||||
|
||||
art.pause();
|
||||
art.url = url;
|
||||
art.notice.show = '';
|
||||
art.pause()
|
||||
art.url = url
|
||||
art.notice.show = ''
|
||||
|
||||
art.once('video:error', reject);
|
||||
art.once('video:error', reject)
|
||||
|
||||
art.once('video:loadedmetadata', () => {
|
||||
art.currentTime = currentTime;
|
||||
});
|
||||
art.once('video:loadedmetadata', () => {
|
||||
art.currentTime = currentTime
|
||||
})
|
||||
|
||||
art.once('video:canplay', async () => {
|
||||
art.playbackRate = playbackRate;
|
||||
art.aspectRatio = aspectRatio;
|
||||
art.once('video:canplay', async () => {
|
||||
art.playbackRate = playbackRate
|
||||
art.aspectRatio = aspectRatio
|
||||
|
||||
if (playing) {
|
||||
await art.play();
|
||||
}
|
||||
if (playing) {
|
||||
await art.play()
|
||||
}
|
||||
|
||||
art.notice.show = '';
|
||||
art.notice.show = ''
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
def(art, 'switchQuality', {
|
||||
value: (url) => {
|
||||
return switchUrl(url, art.currentTime);
|
||||
},
|
||||
});
|
||||
def(art, 'switchQuality', {
|
||||
value: (url) => {
|
||||
return switchUrl(url, art.currentTime)
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'switchUrl', {
|
||||
value: (url) => {
|
||||
return switchUrl(url, 0);
|
||||
},
|
||||
});
|
||||
def(art, 'switchUrl', {
|
||||
value: (url) => {
|
||||
return switchUrl(url, 0)
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'switch', {
|
||||
set: art.switchUrl,
|
||||
});
|
||||
def(art, 'switch', {
|
||||
set: art.switchUrl,
|
||||
})
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function themeMix(art) {
|
||||
def(art, 'theme', {
|
||||
get() {
|
||||
return art.cssVar('--art-theme');
|
||||
},
|
||||
set(theme) {
|
||||
art.cssVar('--art-theme', theme);
|
||||
},
|
||||
});
|
||||
def(art, 'theme', {
|
||||
get() {
|
||||
return art.cssVar('--art-theme')
|
||||
},
|
||||
set(theme) {
|
||||
art.cssVar('--art-theme', theme)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,105 +1,111 @@
|
||||
import { def, setStyle, isMobile, loadImg } from '../utils';
|
||||
import { def, isMobile, loadImg, setStyle } from '../utils'
|
||||
|
||||
export default function thumbnailsMix(art) {
|
||||
const {
|
||||
events,
|
||||
option,
|
||||
template: { $progress, $video },
|
||||
} = art;
|
||||
const {
|
||||
events,
|
||||
option,
|
||||
template: { $progress, $video },
|
||||
} = art
|
||||
|
||||
let timer = null;
|
||||
let image = null;
|
||||
let loading = false;
|
||||
let isLoad = false;
|
||||
let isHover = false;
|
||||
let timer = null
|
||||
let image = null
|
||||
let loading = false
|
||||
let isLoad = false
|
||||
let isHover = false
|
||||
|
||||
function reset() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
image = null;
|
||||
loading = false;
|
||||
isLoad = false;
|
||||
function reset() {
|
||||
clearTimeout(timer)
|
||||
timer = null
|
||||
image = null
|
||||
loading = false
|
||||
isLoad = false
|
||||
}
|
||||
|
||||
function showThumbnails(posWidth) {
|
||||
const $thumbnails = art.controls?.thumbnails
|
||||
if (!$thumbnails)
|
||||
return
|
||||
|
||||
const { number, column, width, height, scale } = option.thumbnails
|
||||
const width2 = width * scale || image.naturalWidth / column
|
||||
const height2 = height * scale || width2 / ($video.videoWidth / $video.videoHeight)
|
||||
const perWidth = $progress.clientWidth / number
|
||||
const perIndex = Math.floor(posWidth / perWidth)
|
||||
const yIndex = Math.ceil(perIndex / column) - 1
|
||||
const xIndex = perIndex % column || column - 1
|
||||
setStyle($thumbnails, 'backgroundImage', `url(${image.src})`)
|
||||
setStyle($thumbnails, 'height', `${height2}px`)
|
||||
setStyle($thumbnails, 'width', `${width2}px`)
|
||||
setStyle($thumbnails, 'backgroundPosition', `-${xIndex * width2}px -${yIndex * height2}px`)
|
||||
if (posWidth <= width2 / 2) {
|
||||
setStyle($thumbnails, 'left', 0)
|
||||
}
|
||||
|
||||
function showThumbnails(posWidth) {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
if (!$thumbnails) return;
|
||||
|
||||
const { number, column, width, height, scale } = option.thumbnails;
|
||||
const width2 = width * scale || image.naturalWidth / column;
|
||||
const height2 = height * scale || width2 / ($video.videoWidth / $video.videoHeight);
|
||||
const perWidth = $progress.clientWidth / number;
|
||||
const perIndex = Math.floor(posWidth / perWidth);
|
||||
const yIndex = Math.ceil(perIndex / column) - 1;
|
||||
const xIndex = perIndex % column || column - 1;
|
||||
setStyle($thumbnails, 'backgroundImage', `url(${image.src})`);
|
||||
setStyle($thumbnails, 'height', `${height2}px`);
|
||||
setStyle($thumbnails, 'width', `${width2}px`);
|
||||
setStyle($thumbnails, 'backgroundPosition', `-${xIndex * width2}px -${yIndex * height2}px`);
|
||||
if (posWidth <= width2 / 2) {
|
||||
setStyle($thumbnails, 'left', 0);
|
||||
} else if (posWidth > $progress.clientWidth - width2 / 2) {
|
||||
setStyle($thumbnails, 'left', `${$progress.clientWidth - width2}px`);
|
||||
} else {
|
||||
setStyle($thumbnails, 'left', `${posWidth - width2 / 2}px`);
|
||||
}
|
||||
else if (posWidth > $progress.clientWidth - width2 / 2) {
|
||||
setStyle($thumbnails, 'left', `${$progress.clientWidth - width2}px`)
|
||||
}
|
||||
else {
|
||||
setStyle($thumbnails, 'left', `${posWidth - width2 / 2}px`)
|
||||
}
|
||||
}
|
||||
|
||||
events.hover(
|
||||
$progress,
|
||||
() => {
|
||||
isHover = true;
|
||||
},
|
||||
() => {
|
||||
isHover = false;
|
||||
},
|
||||
);
|
||||
events.hover(
|
||||
$progress,
|
||||
() => {
|
||||
isHover = true
|
||||
},
|
||||
() => {
|
||||
isHover = false
|
||||
},
|
||||
)
|
||||
|
||||
art.on('setBar', async (type, percentage, event) => {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
const { url, scale } = option.thumbnails;
|
||||
if (!$thumbnails || !url) return;
|
||||
art.on('setBar', async (type, percentage, event) => {
|
||||
const $thumbnails = art.controls?.thumbnails
|
||||
const { url, scale } = option.thumbnails
|
||||
if (!$thumbnails || !url)
|
||||
return
|
||||
|
||||
const isMobileDragging = type === 'played' && event && isMobile;
|
||||
const isMobileDragging = type === 'played' && event && isMobile
|
||||
|
||||
if (type === 'hover' || isMobileDragging) {
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
image = await loadImg(url, scale);
|
||||
isLoad = true;
|
||||
}
|
||||
if (type === 'hover' || isMobileDragging) {
|
||||
if (!loading) {
|
||||
loading = true
|
||||
image = await loadImg(url, scale)
|
||||
isLoad = true
|
||||
}
|
||||
|
||||
if (!isLoad || !isHover) return;
|
||||
if (!isLoad || !isHover)
|
||||
return
|
||||
|
||||
const width = $progress.clientWidth * percentage;
|
||||
setStyle($thumbnails, 'display', 'flex');
|
||||
const width = $progress.clientWidth * percentage
|
||||
setStyle($thumbnails, 'display', 'flex')
|
||||
|
||||
if (width > 0 && width < $progress.clientWidth) {
|
||||
showThumbnails(width);
|
||||
} else {
|
||||
if (!isMobile) {
|
||||
setStyle($thumbnails, 'display', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
if (isMobileDragging) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
setStyle($thumbnails, 'display', 'none');
|
||||
}, 500);
|
||||
}
|
||||
if (width > 0 && width < $progress.clientWidth) {
|
||||
showThumbnails(width)
|
||||
}
|
||||
else {
|
||||
if (!isMobile) {
|
||||
setStyle($thumbnails, 'display', 'none')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
def(art, 'thumbnails', {
|
||||
get() {
|
||||
return art.option.thumbnails;
|
||||
},
|
||||
set(thumbnails) {
|
||||
if (thumbnails.url && !art.option.isLive) {
|
||||
art.option.thumbnails = thumbnails;
|
||||
reset();
|
||||
}
|
||||
},
|
||||
});
|
||||
if (isMobileDragging) {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
setStyle($thumbnails, 'display', 'none')
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
def(art, 'thumbnails', {
|
||||
get() {
|
||||
return art.option.thumbnails
|
||||
},
|
||||
set(thumbnails) {
|
||||
if (thumbnails.url && !art.option.isLive) {
|
||||
art.option.thumbnails = thumbnails
|
||||
reset()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function toggleMix(art) {
|
||||
def(art, 'toggle', {
|
||||
value() {
|
||||
if (art.playing) {
|
||||
return art.pause();
|
||||
} else {
|
||||
return art.play();
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'toggle', {
|
||||
value() {
|
||||
if (art.playing) {
|
||||
return art.pause()
|
||||
}
|
||||
else {
|
||||
return art.play()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { def } from '../utils';
|
||||
import { def } from '../utils'
|
||||
|
||||
export default function typeMix(art) {
|
||||
def(art, 'type', {
|
||||
get() {
|
||||
return art.option.type;
|
||||
},
|
||||
set(type) {
|
||||
art.option.type = type;
|
||||
},
|
||||
});
|
||||
def(art, 'type', {
|
||||
get() {
|
||||
return art.option.type
|
||||
},
|
||||
set(type) {
|
||||
art.option.type = type
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,42 +1,44 @@
|
||||
import { getExt, def, sleep } from '../utils';
|
||||
import { def, getExt, sleep } from '../utils'
|
||||
|
||||
export default function urlMix(art) {
|
||||
const {
|
||||
option,
|
||||
template: { $video },
|
||||
} = art;
|
||||
const {
|
||||
option,
|
||||
template: { $video },
|
||||
} = art
|
||||
|
||||
def(art, 'url', {
|
||||
get() {
|
||||
return $video.src;
|
||||
},
|
||||
async set(newUrl) {
|
||||
if (newUrl) {
|
||||
const oldUrl = art.url;
|
||||
const typeName = option.type || getExt(newUrl);
|
||||
const typeCallback = option.customType[typeName];
|
||||
def(art, 'url', {
|
||||
get() {
|
||||
return $video.src
|
||||
},
|
||||
async set(newUrl) {
|
||||
if (newUrl) {
|
||||
const oldUrl = art.url
|
||||
const typeName = option.type || getExt(newUrl)
|
||||
const typeCallback = option.customType[typeName]
|
||||
|
||||
if (typeName && typeCallback) {
|
||||
await sleep();
|
||||
art.loading.show = true;
|
||||
typeCallback.call(art, $video, newUrl, art);
|
||||
} else {
|
||||
URL.revokeObjectURL(oldUrl);
|
||||
$video.src = newUrl;
|
||||
}
|
||||
if (typeName && typeCallback) {
|
||||
await sleep()
|
||||
art.loading.show = true
|
||||
typeCallback.call(art, $video, newUrl, art)
|
||||
}
|
||||
else {
|
||||
URL.revokeObjectURL(oldUrl)
|
||||
$video.src = newUrl
|
||||
}
|
||||
|
||||
if (oldUrl !== art.url) {
|
||||
art.option.url = newUrl;
|
||||
if (art.isReady && oldUrl) {
|
||||
art.once('video:canplay', () => {
|
||||
art.emit('restart', newUrl);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await sleep();
|
||||
art.loading.show = true;
|
||||
}
|
||||
},
|
||||
});
|
||||
if (oldUrl !== art.url) {
|
||||
art.option.url = newUrl
|
||||
if (art.isReady && oldUrl) {
|
||||
art.once('video:canplay', () => {
|
||||
art.emit('restart', newUrl)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
await sleep()
|
||||
art.loading.show = true
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
import { clamp, def } from '../utils';
|
||||
import { clamp, def } from '../utils'
|
||||
|
||||
export default function volumeMix(art) {
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
storage,
|
||||
} = art;
|
||||
const {
|
||||
template: { $video },
|
||||
i18n,
|
||||
notice,
|
||||
storage,
|
||||
} = art
|
||||
|
||||
def(art, 'volume', {
|
||||
get: () => $video.volume || 0,
|
||||
set: (percentage) => {
|
||||
$video.volume = clamp(percentage, 0, 1);
|
||||
notice.show = `${i18n.get('Volume')}: ${parseInt($video.volume * 100, 10)}`;
|
||||
if ($video.volume !== 0) {
|
||||
storage.set('volume', $video.volume);
|
||||
}
|
||||
},
|
||||
});
|
||||
def(art, 'volume', {
|
||||
get: () => $video.volume || 0,
|
||||
set: (percentage) => {
|
||||
$video.volume = clamp(percentage, 0, 1)
|
||||
notice.show = `${i18n.get('Volume')}: ${Number.parseInt($video.volume * 100, 10)}`
|
||||
if ($video.volume !== 0) {
|
||||
storage.set('volume', $video.volume)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
def(art, 'muted', {
|
||||
get: () => $video.muted,
|
||||
set: (muted) => {
|
||||
$video.muted = muted;
|
||||
art.emit('muted', muted);
|
||||
},
|
||||
});
|
||||
def(art, 'muted', {
|
||||
get: () => $video.muted,
|
||||
set: (muted) => {
|
||||
$video.muted = muted
|
||||
art.emit('muted', muted)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,66 +1,69 @@
|
||||
import { setStyle, addClass, removeClass, hasClass } from '../utils';
|
||||
import { addClass, hasClass, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function autoOrientation(art) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video;
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement;
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight) ||
|
||||
(videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
// There is a conflict with the fullscreen event, and it is changed to asynchronous execution
|
||||
setTimeout(() => {
|
||||
setStyle($player, 'width', `${viewHeight}px`);
|
||||
setStyle($player, 'height', `${viewWidth}px`);
|
||||
setStyle($player, 'transform-origin', '0 0');
|
||||
setStyle($player, 'transform', `rotate(90deg) translate(0, -${viewWidth}px)`);
|
||||
addClass($player, 'art-auto-orientation');
|
||||
art.isRotate = true;
|
||||
art.emit('resize');
|
||||
}, constructor.AUTO_ORIENTATION_TIME);
|
||||
}
|
||||
} else {
|
||||
if (hasClass($player, 'art-auto-orientation')) {
|
||||
removeClass($player, 'art-auto-orientation');
|
||||
art.isRotate = false;
|
||||
art.emit('resize');
|
||||
}
|
||||
}
|
||||
});
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight)
|
||||
|| (videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
// There is a conflict with the fullscreen event, and it is changed to asynchronous execution
|
||||
setTimeout(() => {
|
||||
setStyle($player, 'width', `${viewHeight}px`)
|
||||
setStyle($player, 'height', `${viewWidth}px`)
|
||||
setStyle($player, 'transform-origin', '0 0')
|
||||
setStyle($player, 'transform', `rotate(90deg) translate(0, -${viewWidth}px)`)
|
||||
addClass($player, 'art-auto-orientation')
|
||||
art.isRotate = true
|
||||
art.emit('resize')
|
||||
}, constructor.AUTO_ORIENTATION_TIME)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasClass($player, 'art-auto-orientation')) {
|
||||
removeClass($player, 'art-auto-orientation')
|
||||
art.isRotate = false
|
||||
art.emit('resize')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
art.on('fullscreen', async (state) => {
|
||||
if (!screen?.orientation?.lock) return;
|
||||
art.on('fullscreen', async (state) => {
|
||||
if (!screen?.orientation?.lock)
|
||||
return
|
||||
|
||||
const lastOrientation = screen.orientation.type;
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video;
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement;
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight) ||
|
||||
(videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
const oppositeOrientation = lastOrientation.startsWith('portrait') ? 'landscape' : 'portrait';
|
||||
await screen.orientation.lock(oppositeOrientation);
|
||||
addClass($player, 'art-auto-orientation-fullscreen');
|
||||
}
|
||||
} else {
|
||||
if (hasClass($player, 'art-auto-orientation-fullscreen')) {
|
||||
await screen.orientation.lock(lastOrientation);
|
||||
removeClass($player, 'art-auto-orientation-fullscreen');
|
||||
}
|
||||
}
|
||||
});
|
||||
const lastOrientation = screen.orientation.type
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight)
|
||||
|| (videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
const oppositeOrientation = lastOrientation.startsWith('portrait') ? 'landscape' : 'portrait'
|
||||
await screen.orientation.lock(oppositeOrientation)
|
||||
addClass($player, 'art-auto-orientation-fullscreen')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasClass($player, 'art-auto-orientation-fullscreen')) {
|
||||
await screen.orientation.lock(lastOrientation)
|
||||
removeClass($player, 'art-auto-orientation-fullscreen')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
name: 'autoOrientation',
|
||||
get state() {
|
||||
return hasClass($player, 'art-auto-orientation');
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'autoOrientation',
|
||||
get state() {
|
||||
return hasClass($player, 'art-auto-orientation')
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,91 @@
|
||||
import { secondToTime, setStyle, query, append } from '../utils';
|
||||
import { append, query, secondToTime, setStyle } from '../utils'
|
||||
|
||||
export default function autoPlayback(art) {
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
storage,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $poster },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
storage,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $poster },
|
||||
} = art
|
||||
|
||||
const $autoPlayback = art.layers.add({
|
||||
name: 'auto-playback',
|
||||
html: `
|
||||
const $autoPlayback = art.layers.add({
|
||||
name: 'auto-playback',
|
||||
html: `
|
||||
<div class="art-auto-playback-close"></div>
|
||||
<div class="art-auto-playback-last"></div>
|
||||
<div class="art-auto-playback-jump"></div>
|
||||
`,
|
||||
});
|
||||
})
|
||||
|
||||
const $last = query('.art-auto-playback-last', $autoPlayback);
|
||||
const $jump = query('.art-auto-playback-jump', $autoPlayback);
|
||||
const $close = query('.art-auto-playback-close', $autoPlayback);
|
||||
append($close, icons.close);
|
||||
const $last = query('.art-auto-playback-last', $autoPlayback)
|
||||
const $jump = query('.art-auto-playback-jump', $autoPlayback)
|
||||
const $close = query('.art-auto-playback-close', $autoPlayback)
|
||||
append($close, icons.close)
|
||||
|
||||
let timer = null;
|
||||
let timer = null
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
if (art.playing) {
|
||||
const times = storage.get('times') || {};
|
||||
const keys = Object.keys(times);
|
||||
if (keys.length > constructor.AUTO_PLAYBACK_MAX) {
|
||||
delete times[keys[0]];
|
||||
}
|
||||
times[art.option.id || art.option.url] = art.currentTime;
|
||||
storage.set('times', times);
|
||||
}
|
||||
});
|
||||
|
||||
function init() {
|
||||
const times = storage.get('times') || {};
|
||||
const currentTime = times[art.option.id || art.option.url];
|
||||
|
||||
clearTimeout(timer);
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
|
||||
if (currentTime && currentTime >= constructor.AUTO_PLAYBACK_MIN) {
|
||||
setStyle($autoPlayback, 'display', 'flex');
|
||||
|
||||
$last.innerText = `${i18n.get('Last Seen')} ${secondToTime(currentTime)}`;
|
||||
$jump.innerText = i18n.get('Jump Play');
|
||||
|
||||
proxy($close, 'click', () => {
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
});
|
||||
|
||||
proxy($jump, 'click', () => {
|
||||
art.seek = currentTime;
|
||||
art.play();
|
||||
setStyle($poster, 'display', 'none');
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
});
|
||||
|
||||
art.once('video:timeupdate', () => {
|
||||
timer = setTimeout(() => {
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
}, constructor.AUTO_PLAYBACK_TIMEOUT);
|
||||
});
|
||||
}
|
||||
art.on('video:timeupdate', () => {
|
||||
if (art.playing) {
|
||||
const times = storage.get('times') || {}
|
||||
const keys = Object.keys(times)
|
||||
if (keys.length > constructor.AUTO_PLAYBACK_MAX) {
|
||||
delete times[keys[0]]
|
||||
}
|
||||
times[art.option.id || art.option.url] = art.currentTime
|
||||
storage.set('times', times)
|
||||
}
|
||||
})
|
||||
|
||||
art.on('ready', init);
|
||||
art.on('restart', init);
|
||||
function init() {
|
||||
const times = storage.get('times') || {}
|
||||
const currentTime = times[art.option.id || art.option.url]
|
||||
|
||||
return {
|
||||
name: 'auto-playback',
|
||||
get times() {
|
||||
return storage.get('times') || {};
|
||||
},
|
||||
clear() {
|
||||
return storage.del('times');
|
||||
},
|
||||
delete(id) {
|
||||
const times = storage.get('times') || {};
|
||||
delete times[id];
|
||||
storage.set('times', times);
|
||||
return times;
|
||||
},
|
||||
};
|
||||
clearTimeout(timer)
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
|
||||
if (currentTime && currentTime >= constructor.AUTO_PLAYBACK_MIN) {
|
||||
setStyle($autoPlayback, 'display', 'flex')
|
||||
|
||||
$last.textContent = `${i18n.get('Last Seen')} ${secondToTime(currentTime)}`
|
||||
$jump.textContent = i18n.get('Jump Play')
|
||||
|
||||
proxy($close, 'click', () => {
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
})
|
||||
|
||||
proxy($jump, 'click', () => {
|
||||
art.seek = currentTime
|
||||
art.play()
|
||||
setStyle($poster, 'display', 'none')
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
})
|
||||
|
||||
art.once('video:timeupdate', () => {
|
||||
timer = setTimeout(() => {
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
}, constructor.AUTO_PLAYBACK_TIMEOUT)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
art.on('ready', init)
|
||||
art.on('restart', init)
|
||||
|
||||
return {
|
||||
name: 'auto-playback',
|
||||
get times() {
|
||||
return storage.get('times') || {}
|
||||
},
|
||||
clear() {
|
||||
return storage.del('times')
|
||||
},
|
||||
delete(id) {
|
||||
const times = storage.get('times') || {}
|
||||
delete times[id]
|
||||
storage.set('times', times)
|
||||
return times
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
import { hasClass, addClass, removeClass } from '../utils';
|
||||
import { addClass, hasClass, removeClass } from '../utils'
|
||||
|
||||
export default function fastForward(art) {
|
||||
const {
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
let timer = null;
|
||||
let isPress = false;
|
||||
let lastPlaybackRate = 1;
|
||||
let timer = null
|
||||
let isPress = false
|
||||
let lastPlaybackRate = 1
|
||||
|
||||
const onStart = (event) => {
|
||||
if (event.touches.length === 1 && art.playing && !art.isLock) {
|
||||
timer = setTimeout(() => {
|
||||
isPress = true;
|
||||
lastPlaybackRate = art.playbackRate;
|
||||
art.playbackRate = constructor.FAST_FORWARD_VALUE;
|
||||
addClass($player, 'art-fast-forward');
|
||||
}, constructor.FAST_FORWARD_TIME);
|
||||
}
|
||||
};
|
||||
const onStart = (event) => {
|
||||
if (event.touches.length === 1 && art.playing && !art.isLock) {
|
||||
timer = setTimeout(() => {
|
||||
isPress = true
|
||||
lastPlaybackRate = art.playbackRate
|
||||
art.playbackRate = constructor.FAST_FORWARD_VALUE
|
||||
addClass($player, 'art-fast-forward')
|
||||
}, constructor.FAST_FORWARD_TIME)
|
||||
}
|
||||
}
|
||||
|
||||
const onStop = () => {
|
||||
clearTimeout(timer);
|
||||
if (isPress) {
|
||||
isPress = false;
|
||||
art.playbackRate = lastPlaybackRate;
|
||||
removeClass($player, 'art-fast-forward');
|
||||
}
|
||||
};
|
||||
const onStop = () => {
|
||||
clearTimeout(timer)
|
||||
if (isPress) {
|
||||
isPress = false
|
||||
art.playbackRate = lastPlaybackRate
|
||||
removeClass($player, 'art-fast-forward')
|
||||
}
|
||||
}
|
||||
|
||||
proxy($video, 'touchstart', onStart);
|
||||
proxy(document, 'touchmove', onStop);
|
||||
proxy(document, 'touchend', onStop);
|
||||
proxy($video, 'touchstart', onStart)
|
||||
proxy(document, 'touchmove', onStop)
|
||||
proxy(document, 'touchend', onStop)
|
||||
|
||||
return {
|
||||
name: 'fastForward',
|
||||
get state() {
|
||||
return hasClass($player, 'art-fast-forward');
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'fastForward',
|
||||
get state() {
|
||||
return hasClass($player, 'art-fast-forward')
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,59 @@
|
||||
import { errorHandle, isMobile, has, def } from '../utils';
|
||||
import miniProgressBar from './miniProgressBar';
|
||||
import autoOrientation from './autoOrientation';
|
||||
import autoPlayback from './autoPlayback';
|
||||
import fastForward from './fastForward';
|
||||
import lock from './lock';
|
||||
import { def, errorHandle, has, isMobile } from '../utils'
|
||||
import autoOrientation from './autoOrientation'
|
||||
import autoPlayback from './autoPlayback'
|
||||
import fastForward from './fastForward'
|
||||
import lock from './lock'
|
||||
import miniProgressBar from './miniProgressBar'
|
||||
|
||||
export default class Plugins {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.id = 0;
|
||||
constructor(art) {
|
||||
this.art = art
|
||||
this.id = 0
|
||||
|
||||
const { option } = art;
|
||||
const { option } = art
|
||||
|
||||
if (option.miniProgressBar && !option.isLive) {
|
||||
this.add(miniProgressBar);
|
||||
}
|
||||
|
||||
if (option.lock && isMobile) {
|
||||
this.add(lock);
|
||||
}
|
||||
|
||||
if (option.autoPlayback && !option.isLive) {
|
||||
this.add(autoPlayback);
|
||||
}
|
||||
|
||||
if (option.autoOrientation && isMobile) {
|
||||
this.add(autoOrientation);
|
||||
}
|
||||
|
||||
if (option.fastForward && isMobile && !option.isLive) {
|
||||
this.add(fastForward);
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.plugins.length; index++) {
|
||||
this.add(option.plugins[index]);
|
||||
}
|
||||
if (option.miniProgressBar && !option.isLive) {
|
||||
this.add(miniProgressBar)
|
||||
}
|
||||
|
||||
add(plugin) {
|
||||
this.id += 1;
|
||||
const result = plugin.call(this.art, this.art);
|
||||
if (result instanceof Promise) {
|
||||
return result.then((res) => this.next(plugin, res));
|
||||
} else {
|
||||
return this.next(plugin, result);
|
||||
}
|
||||
if (option.lock && isMobile) {
|
||||
this.add(lock)
|
||||
}
|
||||
|
||||
next(plugin, result) {
|
||||
const pluginName = (result && result.name) || plugin.name || `plugin${this.id}`;
|
||||
errorHandle(!has(this, pluginName), `Cannot add a plugin that already has the same name: ${pluginName}`);
|
||||
def(this, pluginName, {
|
||||
value: result,
|
||||
});
|
||||
return this;
|
||||
if (option.autoPlayback && !option.isLive) {
|
||||
this.add(autoPlayback)
|
||||
}
|
||||
|
||||
if (option.autoOrientation && isMobile) {
|
||||
this.add(autoOrientation)
|
||||
}
|
||||
|
||||
if (option.fastForward && isMobile && !option.isLive) {
|
||||
this.add(fastForward)
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.plugins.length; index++) {
|
||||
this.add(option.plugins[index])
|
||||
}
|
||||
}
|
||||
|
||||
add(plugin) {
|
||||
this.id += 1
|
||||
const result = plugin.call(this.art, this.art)
|
||||
if (result instanceof Promise) {
|
||||
return result.then(res => this.next(plugin, res))
|
||||
}
|
||||
else {
|
||||
return this.next(plugin, result)
|
||||
}
|
||||
}
|
||||
|
||||
next(plugin, result) {
|
||||
const pluginName = (result && result.name) || plugin.name || `plugin${this.id}`
|
||||
errorHandle(!has(this, pluginName), `Cannot add a plugin that already has the same name: ${pluginName}`)
|
||||
def(this, pluginName, {
|
||||
value: result,
|
||||
})
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,68 @@
|
||||
import { append, setStyle, hasClass, addClass, removeClass } from '../utils';
|
||||
import { addClass, append, hasClass, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function lock(art) {
|
||||
const {
|
||||
layers,
|
||||
icons,
|
||||
template: { $player },
|
||||
} = art;
|
||||
const {
|
||||
layers,
|
||||
icons,
|
||||
template: { $player },
|
||||
} = art
|
||||
|
||||
function getState() {
|
||||
return hasClass($player, 'art-lock');
|
||||
}
|
||||
function getState() {
|
||||
return hasClass($player, 'art-lock')
|
||||
}
|
||||
|
||||
function setLock() {
|
||||
addClass($player, 'art-lock');
|
||||
art.isLock = true;
|
||||
art.emit('lock', true);
|
||||
}
|
||||
function setLock() {
|
||||
addClass($player, 'art-lock')
|
||||
art.isLock = true
|
||||
art.emit('lock', true)
|
||||
}
|
||||
|
||||
function setUnlock() {
|
||||
removeClass($player, 'art-lock');
|
||||
art.isLock = false;
|
||||
art.emit('lock', false);
|
||||
}
|
||||
function setUnlock() {
|
||||
removeClass($player, 'art-lock')
|
||||
art.isLock = false
|
||||
art.emit('lock', false)
|
||||
}
|
||||
|
||||
layers.add({
|
||||
name: 'lock',
|
||||
mounted($el) {
|
||||
const $lock = append($el, icons.lock);
|
||||
const $unlock = append($el, icons.unlock);
|
||||
setStyle($lock, 'display', 'none');
|
||||
layers.add({
|
||||
name: 'lock',
|
||||
mounted($el) {
|
||||
const $lock = append($el, icons.lock)
|
||||
const $unlock = append($el, icons.unlock)
|
||||
setStyle($lock, 'display', 'none')
|
||||
|
||||
art.on('lock', (state) => {
|
||||
if (state) {
|
||||
setStyle($lock, 'display', 'inline-flex');
|
||||
setStyle($unlock, 'display', 'none');
|
||||
} else {
|
||||
setStyle($lock, 'display', 'none');
|
||||
setStyle($unlock, 'display', 'inline-flex');
|
||||
}
|
||||
});
|
||||
},
|
||||
click() {
|
||||
if (getState()) {
|
||||
setUnlock();
|
||||
} else {
|
||||
setLock();
|
||||
}
|
||||
},
|
||||
});
|
||||
art.on('lock', (state) => {
|
||||
if (state) {
|
||||
setStyle($lock, 'display', 'inline-flex')
|
||||
setStyle($unlock, 'display', 'none')
|
||||
}
|
||||
else {
|
||||
setStyle($lock, 'display', 'none')
|
||||
setStyle($unlock, 'display', 'inline-flex')
|
||||
}
|
||||
})
|
||||
},
|
||||
click() {
|
||||
if (getState()) {
|
||||
setUnlock()
|
||||
}
|
||||
else {
|
||||
setLock()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
name: 'lock',
|
||||
get state() {
|
||||
return getState();
|
||||
},
|
||||
set state(value) {
|
||||
if (value) {
|
||||
setLock();
|
||||
} else {
|
||||
setUnlock();
|
||||
}
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'lock',
|
||||
get state() {
|
||||
return getState()
|
||||
},
|
||||
set state(value) {
|
||||
if (value) {
|
||||
setLock()
|
||||
}
|
||||
else {
|
||||
setUnlock()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import { addClass, removeClass } from '../utils';
|
||||
import { addClass, removeClass } from '../utils'
|
||||
|
||||
export default function miniProgressBar(art) {
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass(art.template.$player, 'art-mini-progress-bar');
|
||||
} else {
|
||||
addClass(art.template.$player, 'art-mini-progress-bar');
|
||||
}
|
||||
});
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass(art.template.$player, 'art-mini-progress-bar')
|
||||
}
|
||||
else {
|
||||
addClass(art.template.$player, 'art-mini-progress-bar')
|
||||
}
|
||||
})
|
||||
|
||||
return { name: 'mini-progress-bar' };
|
||||
return { name: 'mini-progress-bar' }
|
||||
}
|
||||
@@ -1,124 +1,124 @@
|
||||
import { errorHandle } from '../utils';
|
||||
import { errorHandle } from '../utils'
|
||||
|
||||
const a = 'array';
|
||||
const b = 'boolean';
|
||||
const s = 'string';
|
||||
const n = 'number';
|
||||
const o = 'object';
|
||||
const f = 'function';
|
||||
const a = 'array'
|
||||
const b = 'boolean'
|
||||
const s = 'string'
|
||||
const n = 'number'
|
||||
const o = 'object'
|
||||
const f = 'function'
|
||||
|
||||
function validElement(value, type, paths) {
|
||||
return errorHandle(
|
||||
type === s || type === n || value instanceof Element,
|
||||
`${paths.join('.')} require '${s}' or 'Element' type`,
|
||||
);
|
||||
return errorHandle(
|
||||
type === s || type === n || value instanceof Element,
|
||||
`${paths.join('.')} require '${s}' or 'Element' type`,
|
||||
)
|
||||
}
|
||||
|
||||
export const ComponentOption = {
|
||||
html: validElement,
|
||||
disable: `?${b}`,
|
||||
name: `?${s}`,
|
||||
index: `?${n}`,
|
||||
style: `?${o}`,
|
||||
click: `?${f}`,
|
||||
mounted: `?${f}`,
|
||||
tooltip: `?${s}|${n}`,
|
||||
width: `?${n}`,
|
||||
selector: `?${a}`,
|
||||
onSelect: `?${f}`,
|
||||
switch: `?${b}`,
|
||||
onSwitch: `?${f}`,
|
||||
range: `?${a}`,
|
||||
onRange: `?${f}`,
|
||||
onChange: `?${f}`,
|
||||
};
|
||||
html: validElement,
|
||||
disable: `?${b}`,
|
||||
name: `?${s}`,
|
||||
index: `?${n}`,
|
||||
style: `?${o}`,
|
||||
click: `?${f}`,
|
||||
mounted: `?${f}`,
|
||||
tooltip: `?${s}|${n}`,
|
||||
width: `?${n}`,
|
||||
selector: `?${a}`,
|
||||
onSelect: `?${f}`,
|
||||
switch: `?${b}`,
|
||||
onSwitch: `?${f}`,
|
||||
range: `?${a}`,
|
||||
onRange: `?${f}`,
|
||||
onChange: `?${f}`,
|
||||
}
|
||||
|
||||
export default {
|
||||
id: s,
|
||||
container: validElement,
|
||||
id: s,
|
||||
container: validElement,
|
||||
url: s,
|
||||
poster: s,
|
||||
type: s,
|
||||
theme: s,
|
||||
lang: s,
|
||||
volume: n,
|
||||
isLive: b,
|
||||
muted: b,
|
||||
autoplay: b,
|
||||
autoSize: b,
|
||||
autoMini: b,
|
||||
loop: b,
|
||||
flip: b,
|
||||
playbackRate: b,
|
||||
aspectRatio: b,
|
||||
screenshot: b,
|
||||
setting: b,
|
||||
hotkey: b,
|
||||
pip: b,
|
||||
mutex: b,
|
||||
backdrop: b,
|
||||
fullscreen: b,
|
||||
fullscreenWeb: b,
|
||||
subtitleOffset: b,
|
||||
miniProgressBar: b,
|
||||
useSSR: b,
|
||||
playsInline: b,
|
||||
lock: b,
|
||||
gesture: b,
|
||||
fastForward: b,
|
||||
autoPlayback: b,
|
||||
autoOrientation: b,
|
||||
airplay: b,
|
||||
proxy: `?${f}`,
|
||||
plugins: [f],
|
||||
layers: [ComponentOption],
|
||||
contextmenu: [ComponentOption],
|
||||
settings: [ComponentOption],
|
||||
controls: [
|
||||
{
|
||||
...ComponentOption,
|
||||
position: (value, _, paths) => {
|
||||
const position = ['top', 'left', 'right']
|
||||
return errorHandle(
|
||||
position.includes(value),
|
||||
`${paths.join('.')} only accept ${position.toString()} as parameters`,
|
||||
)
|
||||
},
|
||||
},
|
||||
],
|
||||
quality: [
|
||||
{
|
||||
default: `?${b}`,
|
||||
html: s,
|
||||
url: s,
|
||||
},
|
||||
],
|
||||
highlight: [
|
||||
{
|
||||
time: n,
|
||||
text: s,
|
||||
},
|
||||
],
|
||||
thumbnails: {
|
||||
url: s,
|
||||
poster: s,
|
||||
number: n,
|
||||
column: n,
|
||||
width: n,
|
||||
height: n,
|
||||
scale: n,
|
||||
},
|
||||
subtitle: {
|
||||
url: s,
|
||||
name: s,
|
||||
type: s,
|
||||
theme: s,
|
||||
lang: s,
|
||||
volume: n,
|
||||
isLive: b,
|
||||
muted: b,
|
||||
autoplay: b,
|
||||
autoSize: b,
|
||||
autoMini: b,
|
||||
loop: b,
|
||||
flip: b,
|
||||
playbackRate: b,
|
||||
aspectRatio: b,
|
||||
screenshot: b,
|
||||
setting: b,
|
||||
hotkey: b,
|
||||
pip: b,
|
||||
mutex: b,
|
||||
backdrop: b,
|
||||
fullscreen: b,
|
||||
fullscreenWeb: b,
|
||||
subtitleOffset: b,
|
||||
miniProgressBar: b,
|
||||
useSSR: b,
|
||||
playsInline: b,
|
||||
lock: b,
|
||||
gesture: b,
|
||||
fastForward: b,
|
||||
autoPlayback: b,
|
||||
autoOrientation: b,
|
||||
airplay: b,
|
||||
proxy: `?${f}`,
|
||||
plugins: [f],
|
||||
layers: [ComponentOption],
|
||||
contextmenu: [ComponentOption],
|
||||
settings: [ComponentOption],
|
||||
controls: [
|
||||
{
|
||||
...ComponentOption,
|
||||
position: (value, _, paths) => {
|
||||
const position = ['top', 'left', 'right'];
|
||||
return errorHandle(
|
||||
position.includes(value),
|
||||
`${paths.join('.')} only accept ${position.toString()} as parameters`,
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
quality: [
|
||||
{
|
||||
default: `?${b}`,
|
||||
html: s,
|
||||
url: s,
|
||||
},
|
||||
],
|
||||
highlight: [
|
||||
{
|
||||
time: n,
|
||||
text: s,
|
||||
},
|
||||
],
|
||||
thumbnails: {
|
||||
url: s,
|
||||
number: n,
|
||||
column: n,
|
||||
width: n,
|
||||
height: n,
|
||||
scale: n,
|
||||
},
|
||||
subtitle: {
|
||||
url: s,
|
||||
name: s,
|
||||
type: s,
|
||||
style: o,
|
||||
escape: b,
|
||||
encoding: s,
|
||||
onVttLoad: f,
|
||||
},
|
||||
moreVideoAttr: o,
|
||||
i18n: o,
|
||||
icons: o,
|
||||
cssVar: o,
|
||||
customType: o,
|
||||
};
|
||||
style: o,
|
||||
escape: b,
|
||||
encoding: s,
|
||||
onVttLoad: f,
|
||||
},
|
||||
moreVideoAttr: o,
|
||||
i18n: o,
|
||||
icons: o,
|
||||
cssVar: o,
|
||||
customType: o,
|
||||
}
|
||||
@@ -1,40 +1,40 @@
|
||||
export default function aspectRatio(art) {
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, ASPECT_RATIO },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, ASPECT_RATIO },
|
||||
} = art
|
||||
|
||||
function getI18n(value) {
|
||||
return value === 'default' ? i18n.get('Default') : value;
|
||||
}
|
||||
function getI18n(value) {
|
||||
return value === 'default' ? i18n.get('Default') : value
|
||||
}
|
||||
|
||||
function update() {
|
||||
const target = art.setting.find(`aspect-ratio-${art.aspectRatio}`);
|
||||
art.setting.check(target);
|
||||
}
|
||||
function update() {
|
||||
const target = art.setting.find(`aspect-ratio-${art.aspectRatio}`)
|
||||
art.setting.check(target)
|
||||
}
|
||||
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'aspect-ratio',
|
||||
html: i18n.get('Aspect Ratio'),
|
||||
icon: icons.aspectRatio,
|
||||
tooltip: getI18n(art.aspectRatio),
|
||||
selector: ASPECT_RATIO.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `aspect-ratio-${item}`,
|
||||
default: item === art.aspectRatio,
|
||||
html: getI18n(item),
|
||||
};
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.aspectRatio = item.value;
|
||||
return item.html;
|
||||
},
|
||||
mounted: () => {
|
||||
update();
|
||||
art.on('aspectRatio', () => update());
|
||||
},
|
||||
};
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'aspect-ratio',
|
||||
html: i18n.get('Aspect Ratio'),
|
||||
icon: icons.aspectRatio,
|
||||
tooltip: getI18n(art.aspectRatio),
|
||||
selector: ASPECT_RATIO.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `aspect-ratio-${item}`,
|
||||
default: item === art.aspectRatio,
|
||||
html: getI18n(item),
|
||||
}
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.aspectRatio = item.value
|
||||
return item.html
|
||||
},
|
||||
mounted: () => {
|
||||
update()
|
||||
art.on('aspectRatio', () => update())
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,42 @@
|
||||
import { capitalize } from '../utils';
|
||||
import { capitalize } from '../utils'
|
||||
|
||||
export default function flip(art) {
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, FLIP },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, FLIP },
|
||||
} = art
|
||||
|
||||
function getI18n(value) {
|
||||
return i18n.get(capitalize(value));
|
||||
}
|
||||
function getI18n(value) {
|
||||
return i18n.get(capitalize(value))
|
||||
}
|
||||
|
||||
function update() {
|
||||
const target = art.setting.find(`flip-${art.flip}`);
|
||||
art.setting.check(target);
|
||||
}
|
||||
function update() {
|
||||
const target = art.setting.find(`flip-${art.flip}`)
|
||||
art.setting.check(target)
|
||||
}
|
||||
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'flip',
|
||||
html: i18n.get('Video Flip'),
|
||||
tooltip: getI18n(art.flip),
|
||||
icon: icons.flip,
|
||||
selector: FLIP.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `flip-${item}`,
|
||||
default: item === art.flip,
|
||||
html: getI18n(item),
|
||||
};
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.flip = item.value;
|
||||
return item.html;
|
||||
},
|
||||
mounted: () => {
|
||||
update();
|
||||
art.on('flip', () => update());
|
||||
},
|
||||
};
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'flip',
|
||||
html: i18n.get('Video Flip'),
|
||||
tooltip: getI18n(art.flip),
|
||||
icon: icons.flip,
|
||||
selector: FLIP.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `flip-${item}`,
|
||||
default: item === art.flip,
|
||||
html: getI18n(item),
|
||||
}
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.flip = item.value
|
||||
return item.html
|
||||
},
|
||||
mounted: () => {
|
||||
update()
|
||||
art.on('flip', () => update())
|
||||
},
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,40 +1,40 @@
|
||||
export default function playbackRate(art) {
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, PLAYBACK_RATE },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
constructor: { SETTING_ITEM_WIDTH, PLAYBACK_RATE },
|
||||
} = art
|
||||
|
||||
function getI18n(value) {
|
||||
return value === 1.0 ? i18n.get('Normal') : value.toFixed(1);
|
||||
}
|
||||
function getI18n(value) {
|
||||
return value === 1.0 ? i18n.get('Normal') : value.toFixed(1)
|
||||
}
|
||||
|
||||
function update() {
|
||||
const target = art.setting.find(`playback-rate-${art.playbackRate}`);
|
||||
art.setting.check(target);
|
||||
}
|
||||
function update() {
|
||||
const target = art.setting.find(`playback-rate-${art.playbackRate}`)
|
||||
art.setting.check(target)
|
||||
}
|
||||
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'playback-rate',
|
||||
html: i18n.get('Play Speed'),
|
||||
tooltip: getI18n(art.playbackRate),
|
||||
icon: icons.playbackRate,
|
||||
selector: PLAYBACK_RATE.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `playback-rate-${item}`,
|
||||
default: item === art.playbackRate,
|
||||
html: getI18n(item),
|
||||
};
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.playbackRate = item.value;
|
||||
return item.html;
|
||||
},
|
||||
mounted: () => {
|
||||
update();
|
||||
art.on('video:ratechange', () => update());
|
||||
},
|
||||
};
|
||||
return {
|
||||
width: SETTING_ITEM_WIDTH,
|
||||
name: 'playback-rate',
|
||||
html: i18n.get('Play Speed'),
|
||||
tooltip: getI18n(art.playbackRate),
|
||||
icon: icons.playbackRate,
|
||||
selector: PLAYBACK_RATE.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
name: `playback-rate-${item}`,
|
||||
default: item === art.playbackRate,
|
||||
html: getI18n(item),
|
||||
}
|
||||
}),
|
||||
onSelect(item) {
|
||||
art.playbackRate = item.value
|
||||
return item.html
|
||||
},
|
||||
mounted: () => {
|
||||
update()
|
||||
art.on('video:ratechange', () => update())
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
export default function subtitleOffset(art) {
|
||||
const { i18n, icons, constructor } = art;
|
||||
const { i18n, icons, constructor } = art
|
||||
|
||||
return {
|
||||
width: constructor.SETTING_ITEM_WIDTH,
|
||||
name: 'subtitle-offset',
|
||||
html: i18n.get('Subtitle Offset'),
|
||||
icon: icons.subtitle,
|
||||
tooltip: '0s',
|
||||
range: [0, -10, 10, 0.1],
|
||||
onChange(item) {
|
||||
art.subtitleOffset = item.range[0];
|
||||
return item.range[0] + 's';
|
||||
},
|
||||
mounted: (_, item) => {
|
||||
art.on('subtitleOffset', (value) => {
|
||||
item.$range.value = value;
|
||||
item.tooltip = value + 's';
|
||||
});
|
||||
},
|
||||
};
|
||||
return {
|
||||
width: constructor.SETTING_ITEM_WIDTH,
|
||||
name: 'subtitle-offset',
|
||||
html: i18n.get('Subtitle Offset'),
|
||||
icon: icons.subtitle,
|
||||
tooltip: '0s',
|
||||
range: [0, -10, 10, 0.1],
|
||||
onChange(item) {
|
||||
art.subtitleOffset = item.range[0]
|
||||
return `${item.range[0]}s`
|
||||
},
|
||||
mounted: (_, item) => {
|
||||
art.on('subtitleOffset', (value) => {
|
||||
item.$range.value = value
|
||||
item.tooltip = `${value}s`
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,48 @@
|
||||
export default class Storage {
|
||||
constructor() {
|
||||
this.name = 'artplayer_settings';
|
||||
this.settings = {};
|
||||
}
|
||||
constructor() {
|
||||
this.name = 'artplayer_settings'
|
||||
this.settings = {}
|
||||
}
|
||||
|
||||
get(key) {
|
||||
try {
|
||||
const storage = JSON.parse(window.localStorage.getItem(this.name)) || {};
|
||||
return key ? storage[key] : storage;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (error) {
|
||||
return key ? this.settings[key] : this.settings;
|
||||
}
|
||||
get(key) {
|
||||
try {
|
||||
const storage = JSON.parse(window.localStorage.getItem(this.name)) || {}
|
||||
return key ? storage[key] : storage
|
||||
}
|
||||
catch {
|
||||
return key ? this.settings[key] : this.settings
|
||||
}
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
try {
|
||||
const storage = Object.assign({}, this.get(), {
|
||||
[key]: value,
|
||||
});
|
||||
window.localStorage.setItem(this.name, JSON.stringify(storage));
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (error) {
|
||||
this.settings[key] = value;
|
||||
}
|
||||
set(key, value) {
|
||||
try {
|
||||
const storage = Object.assign({}, this.get(), {
|
||||
[key]: value,
|
||||
})
|
||||
window.localStorage.setItem(this.name, JSON.stringify(storage))
|
||||
}
|
||||
catch {
|
||||
this.settings[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
del(key) {
|
||||
try {
|
||||
const storage = this.get();
|
||||
delete storage[key];
|
||||
window.localStorage.setItem(this.name, JSON.stringify(storage));
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (error) {
|
||||
delete this.settings[key];
|
||||
}
|
||||
del(key) {
|
||||
try {
|
||||
const storage = this.get()
|
||||
delete storage[key]
|
||||
window.localStorage.setItem(this.name, JSON.stringify(storage))
|
||||
}
|
||||
catch {
|
||||
delete this.settings[key]
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
try {
|
||||
window.localStorage.removeItem(this.name);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (error) {
|
||||
this.settings = {};
|
||||
}
|
||||
clear() {
|
||||
try {
|
||||
window.localStorage.removeItem(this.name)
|
||||
}
|
||||
catch {
|
||||
this.settings = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 447 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user