From 0a9aadf543d924ad75b6c9d4d192336a921d49c0 Mon Sep 17 00:00:00 2001
From: Harvey Zhao
diff --git a/docs/assets/example/ads.js b/docs/assets/example/ads.js
index e1d2a983a..75897f065 100644
--- a/docs/assets/example/ads.js
+++ b/docs/assets/example/ads.js
@@ -1,48 +1,48 @@
// npm i artplayer-plugin-ads
// import artplayerPluginAds from 'artplayer-plugin-ads';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- autoSize: true,
- fullscreen: true,
- fullscreenWeb: true,
- plugins: [
- artplayerPluginAds({
- // html广告,假如是视频广告则忽略该值
- html: '
',
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ plugins: [
+ artplayerPluginAds({
+ // html广告,假如是视频广告则忽略该值
+ html: '
',
- // 视频广告的地址
- video: '/assets/sample/test1.mp4',
+ // 视频广告的地址
+ video: '/assets/sample/test1.mp4',
- // 广告跳转网址,为空则不跳转
- url: 'http://artplayer.org',
+ // 广告跳转网址,为空则不跳转
+ url: 'http://artplayer.org',
- // 必须观看的时长,期间不能被跳过,单位为秒
- // 当该值大于或等于totalDuration时,不能提前关闭广告
- // 当该值等于或小于0时,则随时都可以关闭广告
- playDuration: 5,
+ // 必须观看的时长,期间不能被跳过,单位为秒
+ // 当该值大于或等于totalDuration时,不能提前关闭广告
+ // 当该值等于或小于0时,则随时都可以关闭广告
+ playDuration: 5,
- // 广告总时长,单位为秒
- totalDuration: 10,
+ // 广告总时长,单位为秒
+ totalDuration: 10,
- // 多语言支持
- i18n: {
- close: '关闭广告',
- countdown: '%s秒',
- detail: '查看详情',
- canBeClosed: '%s秒后可关闭广告',
- },
- }),
- ],
-});
+ // 多语言支持
+ i18n: {
+ close: '关闭广告',
+ countdown: '%s秒',
+ detail: '查看详情',
+ canBeClosed: '%s秒后可关闭广告',
+ },
+ }),
+ ],
+})
// 广告被点击
art.on('artplayerPluginAds:click', (ads) => {
- console.info('广告被点击', ads);
-});
+ console.info('广告被点击', ads)
+})
// 广告被跳过
art.on('artplayerPluginAds:skip', (ads) => {
- console.info('广告被跳过', ads);
-});
+ console.info('广告被跳过', ads)
+})
diff --git a/docs/assets/example/ambilight.js b/docs/assets/example/ambilight.js
index 4d97c14f1..a1a3e6c63 100644
--- a/docs/assets/example/ambilight.js
+++ b/docs/assets/example/ambilight.js
@@ -1,16 +1,16 @@
// npm i artplayer-plugin-ambilight
// import artplayerPluginAmbilight from 'artplayer-plugin-ambilight';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- autoSize: true,
- plugins: [
- artplayerPluginAmbilight({
- blur: '50px',
- opacity: 1,
- frequency: 10,
- duration: 0.3,
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ plugins: [
+ artplayerPluginAmbilight({
+ blur: '50px',
+ opacity: 1,
+ frequency: 10,
+ duration: 0.3,
+ }),
+ ],
+})
diff --git a/docs/assets/example/asr.js b/docs/assets/example/asr.js
index 513d8a4c6..d7bc60b0b 100644
--- a/docs/assets/example/asr.js
+++ b/docs/assets/example/asr.js
@@ -1,58 +1,61 @@
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/steve-jobs.mp4',
- autoSize: true,
- fullscreen: true,
- fullscreenWeb: true,
- moreVideoAttr: {
- // crossOrigin: 'anonymous',
- },
- plugins: [
- artplayerPluginAsr({
- length: 2,
- interval: 40,
- sampleRate: 16000,
- autoHideTimeout: 10000,
- // Use your AI tool to convert pcm into subtitles
- onAudioChunk: ({ pcm }) => startAsr(pcm),
- }),
- ]
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/steve-jobs.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ moreVideoAttr: {
+ // crossOrigin: 'anonymous',
+ },
+ plugins: [
+ artplayerPluginAsr({
+ length: 2,
+ interval: 40,
+ sampleRate: 16000,
+ autoHideTimeout: 10000,
+ // Use your AI tool to convert pcm into subtitles
+ onAudioChunk: ({ pcm }) => startAsr(pcm),
+ }),
+ ],
+})
-var ws = null;
-var loading = false;
+let ws = null
+let loading = false
function stopAsr() {
- try {
- ws.send(JSON.stringify({ type: 'end' }));
- ws.close();
- } catch {}
- ws = null;
- loading = false;
+ try {
+ ws.send(JSON.stringify({ type: 'end' }))
+ ws.close()
+ }
+ catch {}
+ ws = null
+ loading = false
}
async function startAsr(buffer) {
- if (loading) return;
- if (!ws) {
- loading = true;
- const api = 'https://api.aimu.app/asr/tencent?engine_model_type=16k_en';
- const { url } = await (await fetch(api)).json();
- ws = new WebSocket(url);
- ws.binaryType = 'arraybuffer';
- ws.onmessage = (event) => {
- const { code, result, message } = JSON.parse(event.data);
- if (code === 0) {
- art.plugins.artplayerPluginAsr.append(result?.voice_text_str);
- } else {
- console.error(code, message);
- stopAsr();
- }
- };
- loading = false;
- }
- if (ws?.readyState === WebSocket.OPEN) {
- ws.send(buffer);
+ if (loading)
+ return
+ if (!ws) {
+ loading = true
+ const api = 'https://api.aimu.app/asr/tencent?engine_model_type=16k_en'
+ const { url } = await (await fetch(api)).json()
+ ws = new WebSocket(url)
+ ws.binaryType = 'arraybuffer'
+ ws.onmessage = (event) => {
+ const { code, result, message } = JSON.parse(event.data)
+ if (code === 0) {
+ art.plugins.artplayerPluginAsr.append(result?.voice_text_str)
+ }
+ else {
+ console.error(code, message)
+ stopAsr()
+ }
}
+ loading = false
+ }
+ if (ws?.readyState === WebSocket.OPEN) {
+ ws.send(buffer)
+ }
}
-art.on('destroy', stopAsr);
+art.on('destroy', stopAsr)
diff --git a/docs/assets/example/auto.thumbnail.js b/docs/assets/example/auto.thumbnail.js
index e04385fd5..bffe1c7e9 100644
--- a/docs/assets/example/auto.thumbnail.js
+++ b/docs/assets/example/auto.thumbnail.js
@@ -1,12 +1,12 @@
// npm i artplayer-plugin-auto-thumbnail
// import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- plugins: [
- artplayerPluginAutoThumbnail({
- //
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginAutoThumbnail({
+ //
+ }),
+ ],
+})
diff --git a/docs/assets/example/canvas.js b/docs/assets/example/canvas.js
index 2887ed712..dd32f6cf7 100644
--- a/docs/assets/example/canvas.js
+++ b/docs/assets/example/canvas.js
@@ -1,30 +1,30 @@
// npm i artplayer-proxy-canvas
// import artplayerProxyCanvas from 'artplayer-proxy-canvas';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- poster: '/assets/sample/poster.jpg',
- volume: 0.5,
- autoplay: false,
- autoSize: false,
- screenshot: true,
- setting: true,
- loop: true,
- flip: true,
- pip: true,
- playbackRate: true,
- aspectRatio: true,
- fullscreen: true,
- fullscreenWeb: true,
- miniProgressBar: true,
- autoPlayback: true,
- autoOrientation: true,
- thumbnails: {
- url: '/assets/sample/thumbnails.png',
- number: 60,
- column: 10,
- scale: 0.85,
- },
- proxy: artplayerProxyCanvas(),
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ volume: 0.5,
+ autoplay: false,
+ autoSize: false,
+ screenshot: true,
+ setting: true,
+ loop: true,
+ flip: true,
+ pip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoPlayback: true,
+ autoOrientation: true,
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.85,
+ },
+ proxy: artplayerProxyCanvas(),
+})
diff --git a/docs/assets/example/chapter.js b/docs/assets/example/chapter.js
index 47971ed73..4dba39272 100644
--- a/docs/assets/example/chapter.js
+++ b/docs/assets/example/chapter.js
@@ -1,28 +1,28 @@
// npm i artplayer-plugin-chapter
// import artplayerPluginChapter from 'artplayer-plugin-chapter';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- autoSize: true,
- fullscreen: true,
- fullscreenWeb: true,
- miniProgressBar: true,
- autoOrientation: true,
- thumbnails: {
- url: '/assets/sample/thumbnails.png',
- number: 60,
- column: 10,
- },
- plugins: [
- artplayerPluginChapter({
- chapters: [
- { start: 0, end: 18, title: 'One more chance' },
- { start: 18, end: 36, title: '谁でもいいはずなのに' },
- { start: 36, end: 54, title: '夏の想い出がまわる' },
- { start: 54, end: 72, title: 'こんなとこにあるはずもないのに' },
- { start: 72, end: Infinity, title: '终わり' },
- ]
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoOrientation: true,
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ },
+ plugins: [
+ artplayerPluginChapter({
+ chapters: [
+ { start: 0, end: 18, title: 'One more chance' },
+ { start: 18, end: 36, title: '谁でもいいはずなのに' },
+ { start: 36, end: 54, title: '夏の想い出がまわる' },
+ { start: 54, end: 72, title: 'こんなとこにあるはずもないのに' },
+ { start: 72, end: Infinity, title: '终わり' },
+ ],
+ }),
+ ],
+})
diff --git a/docs/assets/example/chromecast.js b/docs/assets/example/chromecast.js
index a855a5658..416a9cf2c 100644
--- a/docs/assets/example/chromecast.js
+++ b/docs/assets/example/chromecast.js
@@ -1,15 +1,15 @@
// npm i artplayer-plugin-chromecast
// import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- fullscreen: true,
- fullscreenWeb: true,
- plugins: [
- artplayerPluginChromecast({
- // sdk: '', // The URL of the Cast SDK
- // mimeType: '', // The MIME type of the media
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ plugins: [
+ artplayerPluginChromecast({
+ // sdk: '', // The URL of the Cast SDK
+ // mimeType: '', // The MIME type of the media
+ }),
+ ],
+})
diff --git a/docs/assets/example/danmuku.js b/docs/assets/example/danmuku.js
index 821384986..934816cb1 100644
--- a/docs/assets/example/danmuku.js
+++ b/docs/assets/example/danmuku.js
@@ -2,53 +2,53 @@
// import artplayerPluginDanmuku from 'artplayer-plugin-danmuku';
// 使用文档 https://artplayer.org/document/plugin/danmuku.html
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- autoSize: true,
- fullscreen: true,
- fullscreenWeb: true,
- autoOrientation: true,
- plugins: [
- artplayerPluginDanmuku({
- danmuku: '/assets/sample/danmuku.xml',
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ autoOrientation: true,
+ plugins: [
+ artplayerPluginDanmuku({
+ danmuku: '/assets/sample/danmuku.xml',
- // 以下为非必填
- speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
- margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
- opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
- color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
- mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
- modes: [0, 1, 2], // 弹幕可见的模式
- fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
- antiOverlap: true, // 弹幕是否防重叠
- synchronousPlayback: false, // 是否同步播放速度
- mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
- heatmap: true, // 是否开启热力图
- width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
- points: [], // 热力图数据
- filter: (danmu) => danmu.text.length <= 100, // 弹幕载入前的过滤器
- beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
- visible: true, // 弹幕层是否可见
- emitter: true, // 是否开启弹幕发射器
- maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
- lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
- theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
- OPACITY: {}, // 不透明度配置项
- FONT_SIZE: {}, // 弹幕字号配置项
- MARGIN: {}, // 显示区域配置项
- SPEED: {}, // 弹幕速度配置项
- COLOR: [], // 颜色列表配置项
+ // 以下为非必填
+ speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
+ margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
+ opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
+ color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
+ mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
+ modes: [0, 1, 2], // 弹幕可见的模式
+ fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
+ antiOverlap: true, // 弹幕是否防重叠
+ synchronousPlayback: false, // 是否同步播放速度
+ mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
+ heatmap: true, // 是否开启热力图
+ width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
+ points: [], // 热力图数据
+ filter: danmu => danmu.text.length <= 100, // 弹幕载入前的过滤器
+ beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
+ visible: true, // 弹幕层是否可见
+ emitter: true, // 是否开启弹幕发射器
+ maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
+ lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
+ theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
+ OPACITY: {}, // 不透明度配置项
+ FONT_SIZE: {}, // 弹幕字号配置项
+ MARGIN: {}, // 显示区域配置项
+ SPEED: {}, // 弹幕速度配置项
+ COLOR: [], // 颜色列表配置项
- // 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
- beforeEmit(danmu) {
- return new Promise((resolve) => {
- console.log(danmu);
- setTimeout(() => {
- resolve(true);
- }, 1000);
- });
- },
- }),
- ],
-});
\ No newline at end of file
+ // 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
+ beforeEmit(danmu) {
+ return new Promise((resolve) => {
+ console.log(danmu)
+ setTimeout(() => {
+ resolve(true)
+ }, 1000)
+ })
+ },
+ }),
+ ],
+})
diff --git a/docs/assets/example/danmuku.mask.js b/docs/assets/example/danmuku.mask.js
index 20114a080..224ad5036 100644
--- a/docs/assets/example/danmuku.mask.js
+++ b/docs/assets/example/danmuku.mask.js
@@ -4,19 +4,19 @@
// npm i @mediapipe/selfie_segmentation
// 把 node_modules/@mediapipe/selfie_segmentation 目录复制到你的项目下
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- autoSize: true,
- fullscreen: true,
- fullscreenWeb: true,
- autoOrientation: true,
- plugins: [
- artplayerPluginDanmuku({
- danmuku: '/assets/sample/danmuku.xml'
- }),
- artplayerPluginDanmukuMask({
- solutionPath: '/assets/@mediapipe/selfie_segmentation',
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ autoOrientation: true,
+ plugins: [
+ artplayerPluginDanmuku({
+ danmuku: '/assets/sample/danmuku.xml',
+ }),
+ artplayerPluginDanmukuMask({
+ solutionPath: '/assets/@mediapipe/selfie_segmentation',
+ }),
+ ],
+})
diff --git a/docs/assets/example/dash.control.js b/docs/assets/example/dash.control.js
index f339a89c7..6b32a02c2 100644
--- a/docs/assets/example/dash.control.js
+++ b/docs/assets/example/dash.control.js
@@ -4,47 +4,49 @@
// import dashjs from 'dashjs';
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
- setting: true,
- plugins: [
- artplayerPluginDashControl({
- quality: {
- // Show qualitys in control
- control: true,
- // Show qualitys in setting
- setting: true,
- // Get the quality name from level
- getName: (level) => level.height + 'P',
- // I18n
- title: 'Quality',
- auto: 'Auto',
- },
- audio: {
- // Show audios in control
- control: true,
- // Show audios in setting
- setting: true,
- // Get the audio name from track
- getName: (track) => track.lang.toUpperCase(),
- // I18n
- title: 'Audio',
- auto: 'Auto',
- }
- }),
- ],
- customType: {
- mpd: function playMpd(video, url, art) {
- if (dashjs.supportsMediaSource()) {
- if (art.dash) art.dash.destroy();
- const dash = dashjs.MediaPlayer().create();
- dash.initialize(video, url, art.option.autoplay);
- art.dash = dash;
- art.on('destroy', () => dash.destroy());
- } else {
- art.notice.show = 'Unsupported playback format: mpd';
- }
- }
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
+ setting: true,
+ plugins: [
+ artplayerPluginDashControl({
+ quality: {
+ // Show qualitys in control
+ control: true,
+ // Show qualitys in setting
+ setting: true,
+ // Get the quality name from level
+ getName: level => `${level.height}P`,
+ // I18n
+ title: 'Quality',
+ auto: 'Auto',
+ },
+ audio: {
+ // Show audios in control
+ control: true,
+ // Show audios in setting
+ setting: true,
+ // Get the audio name from track
+ getName: track => track.lang.toUpperCase(),
+ // I18n
+ title: 'Audio',
+ auto: 'Auto',
+ },
+ }),
+ ],
+ customType: {
+ mpd: function playMpd(video, url, art) {
+ if (dashjs.supportsMediaSource()) {
+ if (art.dash)
+ art.dash.destroy()
+ const dash = dashjs.MediaPlayer().create()
+ dash.initialize(video, url, art.option.autoplay)
+ art.dash = dash
+ art.on('destroy', () => dash.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: mpd'
+ }
},
-});
+ },
+})
diff --git a/docs/assets/example/dash.js b/docs/assets/example/dash.js
index b55a9ebd2..e007a9b22 100644
--- a/docs/assets/example/dash.js
+++ b/docs/assets/example/dash.js
@@ -2,26 +2,28 @@
// import dashjs from 'dashjs';
function playMpd(video, url, art) {
- if (dashjs.supportsMediaSource()) {
- if (art.dash) art.dash.destroy();
- const dash = dashjs.MediaPlayer().create();
- dash.initialize(video, url, art.option.autoplay);
- art.dash = dash;
- art.on('destroy', () => dash.destroy());
- } else {
- art.notice.show = 'Unsupported playback format: mpd';
- }
+ if (dashjs.supportsMediaSource()) {
+ if (art.dash)
+ art.dash.destroy()
+ const dash = dashjs.MediaPlayer().create()
+ dash.initialize(video, url, art.option.autoplay)
+ art.dash = dash
+ art.on('destroy', () => dash.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: mpd'
+ }
}
-var art = new Artplayer({
- container: '.artplayer-app',
- url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
- type: 'mpd',
- customType: {
- mpd: playMpd
- },
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
+ type: 'mpd',
+ customType: {
+ mpd: playMpd,
+ },
+})
art.on('ready', () => {
- console.info(art.dash);
-});
\ No newline at end of file
+ console.info(art.dash)
+})
diff --git a/docs/assets/example/document.pip.js b/docs/assets/example/document.pip.js
index 437403d2f..a9d7ac177 100644
--- a/docs/assets/example/document.pip.js
+++ b/docs/assets/example/document.pip.js
@@ -1,7 +1,7 @@
// npm i artplayer-plugin-document-pip
// import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
-let art = new Artplayer({
+const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
diff --git a/docs/assets/example/flv.js b/docs/assets/example/flv.js
index 93ed114ff..e88b076dd 100644
--- a/docs/assets/example/flv.js
+++ b/docs/assets/example/flv.js
@@ -2,27 +2,29 @@
// import flvjs from 'flv.js';
function playFlv(video, url, art) {
- if (flvjs.isSupported()) {
- if (art.flv) art.flv.destroy();
- const flv = flvjs.createPlayer({ type: 'flv', url });
- flv.attachMediaElement(video);
- flv.load();
- art.flv = flv;
- art.on('destroy', () => flv.destroy());
- } else {
- art.notice.show = 'Unsupported playback format: flv';
- }
+ if (flvjs.isSupported()) {
+ if (art.flv)
+ art.flv.destroy()
+ const flv = flvjs.createPlayer({ type: 'flv', url })
+ flv.attachMediaElement(video)
+ flv.load()
+ art.flv = flv
+ art.on('destroy', () => flv.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: flv'
+ }
}
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.flv',
- type: 'flv',
- customType: {
- flv: playFlv,
- },
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.flv',
+ type: 'flv',
+ customType: {
+ flv: playFlv,
+ },
+})
art.on('ready', () => {
- console.info(art.flv);
-});
\ No newline at end of file
+ console.info(art.flv)
+})
diff --git a/docs/assets/example/hls.control.js b/docs/assets/example/hls.control.js
index bd00744d1..f20742174 100644
--- a/docs/assets/example/hls.control.js
+++ b/docs/assets/example/hls.control.js
@@ -4,50 +4,53 @@
// import Hls from 'hls.js';
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
- setting: true,
- plugins: [
- artplayerPluginHlsControl({
- quality: {
- // Show qualitys in control
- control: true,
- // Show qualitys in setting
- setting: true,
- // Get the quality name from level
- getName: (level) => level.height + 'P',
- // I18n
- title: 'Quality',
- auto: 'Auto',
- },
- audio: {
- // Show audios in control
- control: true,
- // Show audios in setting
- setting: true,
- // Get the audio name from track
- getName: (track) => track.name,
- // I18n
- title: 'Audio',
- auto: 'Auto',
- }
- }),
- ],
- customType: {
- m3u8: function playM3u8(video, url, art) {
- if (Hls.isSupported()) {
- if (art.hls) art.hls.destroy();
- const hls = new Hls();
- hls.loadSource(url);
- hls.attachMedia(video);
- art.hls = hls;
- art.on('destroy', () => hls.destroy());
- } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
- video.src = url;
- } else {
- art.notice.show = 'Unsupported playback format: m3u8';
- }
- }
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
+ setting: true,
+ plugins: [
+ artplayerPluginHlsControl({
+ quality: {
+ // Show qualitys in control
+ control: true,
+ // Show qualitys in setting
+ setting: true,
+ // Get the quality name from level
+ getName: level => `${level.height}P`,
+ // I18n
+ title: 'Quality',
+ auto: 'Auto',
+ },
+ audio: {
+ // Show audios in control
+ control: true,
+ // Show audios in setting
+ setting: true,
+ // Get the audio name from track
+ getName: track => track.name,
+ // I18n
+ title: 'Audio',
+ auto: 'Auto',
+ },
+ }),
+ ],
+ customType: {
+ m3u8: function playM3u8(video, url, art) {
+ if (Hls.isSupported()) {
+ if (art.hls)
+ art.hls.destroy()
+ const hls = new Hls()
+ hls.loadSource(url)
+ hls.attachMedia(video)
+ art.hls = hls
+ art.on('destroy', () => hls.destroy())
+ }
+ else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = url
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: m3u8'
+ }
},
-});
+ },
+})
diff --git a/docs/assets/example/hls.js b/docs/assets/example/hls.js
index 930e21f38..31bf14d30 100644
--- a/docs/assets/example/hls.js
+++ b/docs/assets/example/hls.js
@@ -2,29 +2,32 @@
// import Hls from 'hls.js';
function playM3u8(video, url, art) {
- if (Hls.isSupported()) {
- if (art.hls) art.hls.destroy();
- const hls = new Hls();
- hls.loadSource(url);
- hls.attachMedia(video);
- art.hls = hls;
- art.on('destroy', () => hls.destroy());
- } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
- video.src = url;
- } else {
- art.notice.show = 'Unsupported playback format: m3u8';
- }
+ if (Hls.isSupported()) {
+ if (art.hls)
+ art.hls.destroy()
+ const hls = new Hls()
+ hls.loadSource(url)
+ hls.attachMedia(video)
+ art.hls = hls
+ art.on('destroy', () => hls.destroy())
+ }
+ else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = url
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: m3u8'
+ }
}
-var art = new Artplayer({
- container: '.artplayer-app',
- url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
- type: 'm3u8',
- customType: {
- m3u8: playM3u8,
- },
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
+ type: 'm3u8',
+ customType: {
+ m3u8: playM3u8,
+ },
+})
art.on('ready', () => {
- console.info(art.hls);
-});
\ No newline at end of file
+ console.info(art.hls)
+})
diff --git a/docs/assets/example/iframe.js b/docs/assets/example/iframe.js
index f91bf9e78..165369436 100644
--- a/docs/assets/example/iframe.js
+++ b/docs/assets/example/iframe.js
@@ -1,46 +1,47 @@
// npm i artplayer-plugin-iframe
// import ArtplayerPluginIframe from 'artplayer-plugin-iframe';
-const $iframe = document.createElement('iframe');
-$iframe.allowFullscreen = true;
-$iframe.width = '100%';
-$iframe.height = '100%';
+const $iframe = document.createElement('iframe')
+$iframe.allowFullscreen = true
+$iframe.width = '100%'
+$iframe.height = '100%'
-const $container = document.querySelector('.artplayer-app');
-$container.innerHTML = '';
-$container.appendChild($iframe);
+const $container = document.querySelector('.artplayer-app')
+$container.innerHTML = ''
+$container.appendChild($iframe)
const iframe = new ArtplayerPluginIframe({
- iframe: $iframe,
- url: '/iframe.html',
-});
+ iframe: $iframe,
+ url: '/iframe.html',
+})
iframe.message(({ type, data }) => {
- switch (type) {
- case 'fullscreenWeb':
- if (data) {
- $iframe.classList.add('fullscreenWeb');
- } else {
- $iframe.classList.remove('fullscreenWeb');
- }
- break;
- default:
- break;
- }
-});
+ switch (type) {
+ case 'fullscreenWeb':
+ if (data) {
+ $iframe.classList.add('fullscreenWeb')
+ }
+ else {
+ $iframe.classList.remove('fullscreenWeb')
+ }
+ break
+ default:
+ break
+ }
+})
iframe.commit(() => {
- var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- fullscreen: true,
- fullscreenWeb: true,
- });
+ const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ })
- art.on('fullscreenWeb', (state) => {
- ArtplayerPluginIframe.postMessage({
- type: 'fullscreenWeb',
- data: state,
- });
- });
-});
+ art.on('fullscreenWeb', (state) => {
+ ArtplayerPluginIframe.postMessage({
+ type: 'fullscreenWeb',
+ data: state,
+ })
+ })
+})
diff --git a/docs/assets/example/index.js b/docs/assets/example/index.js
index 953e035b1..b359a1983 100644
--- a/docs/assets/example/index.js
+++ b/docs/assets/example/index.js
@@ -1,190 +1,190 @@
var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- poster: '/assets/sample/poster.jpg',
- volume: 0.5,
- isLive: false,
- muted: false,
- autoplay: false,
- pip: true,
- autoSize: true,
- autoMini: true,
- screenshot: true,
- setting: true,
- loop: true,
- flip: true,
- playbackRate: true,
- aspectRatio: true,
- fullscreen: true,
- fullscreenWeb: true,
- subtitleOffset: true,
- miniProgressBar: true,
- mutex: true,
- backdrop: true,
- playsInline: true,
- autoPlayback: true,
- airplay: true,
- theme: '#23ade5',
- lang: navigator.language.toLowerCase(),
- moreVideoAttr: {
- crossOrigin: 'anonymous',
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ volume: 0.5,
+ isLive: false,
+ muted: false,
+ autoplay: false,
+ pip: true,
+ autoSize: true,
+ autoMini: true,
+ screenshot: true,
+ setting: true,
+ loop: true,
+ flip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ subtitleOffset: true,
+ miniProgressBar: true,
+ mutex: true,
+ backdrop: true,
+ playsInline: true,
+ autoPlayback: true,
+ airplay: true,
+ theme: '#23ade5',
+ lang: navigator.language.toLowerCase(),
+ moreVideoAttr: {
+ crossOrigin: 'anonymous',
+ },
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ tooltip: 'Bilingual',
+ icon: '',
+ selector: [
+ {
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: 'Bilingual',
+ url: '/assets/sample/subtitle.srt',
+ },
+ {
+ html: 'Chinese',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ html: 'Japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
},
- settings: [
- {
- width: 200,
- html: 'Subtitle',
- tooltip: 'Bilingual',
- icon: '
',
- selector: [
- {
- html: 'Display',
- tooltip: 'Show',
- switch: true,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'Hide' : 'Show';
- art.subtitle.show = !item.switch;
- return !item.switch;
- },
- },
- {
- default: true,
- html: 'Bilingual',
- url: '/assets/sample/subtitle.srt',
- },
- {
- html: 'Chinese',
- url: '/assets/sample/subtitle.cn.srt',
- },
- {
- html: 'Japanese',
- url: '/assets/sample/subtitle.jp.srt',
- },
- ],
- onSelect: function (item) {
- art.subtitle.switch(item.url, {
- name: item.html,
- });
- return item.html;
- },
- },
- {
- html: 'Switcher',
- icon: '
',
- tooltip: 'OFF',
- switch: false,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'OFF' : 'ON';
- console.info('You clicked on the custom switch', item.switch);
- return !item.switch;
- },
- },
- {
- html: 'Slider',
- icon: '
',
- tooltip: '5x',
- range: [5, 1, 10, 0.1],
- onRange: function (item) {
- return item.range[0] + 'x';
- },
- },
- {
- html: 'Button',
- icon: '
',
- tooltip: 'tooltip',
- onClick() {
- return 'Button clicked';
- }
- },
- ],
- contextmenu: [
- {
- html: 'Custom menu',
- click: function (contextmenu) {
- console.info('You clicked on the custom menu');
- contextmenu.show = false;
- },
- },
- ],
- layers: [
- {
- html: '
',
- click: function () {
- window.open('https://aimu.app');
- console.info('You clicked on the custom layer');
- },
- style: {
- position: 'absolute',
- top: '20px',
- right: '20px',
- opacity: '.9',
- },
- },
- ],
- quality: [
- {
- default: true,
- html: 'SD 480P',
- url: '/assets/sample/video.mp4?q=480',
- },
- {
- html: 'HD 720P',
- url: '/assets/sample/video.mp4?q=720',
- },
- ],
- thumbnails: {
- url: '/assets/sample/thumbnails.png',
- number: 60,
- column: 10,
- scale: 0.85,
+ {
+ html: 'Switcher',
+ icon: '',
+ tooltip: 'OFF',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'OFF' : 'ON'
+ console.info('You clicked on the custom switch', item.switch)
+ return !item.switch
+ },
},
- subtitle: {
- url: '/assets/sample/subtitle.srt',
- type: 'srt',
- style: {
- color: '#fe9200',
- fontSize: '20px',
- },
- encoding: 'utf-8',
+ {
+ html: 'Slider',
+ icon: '
',
+ tooltip: '5x',
+ range: [5, 1, 10, 0.1],
+ onRange(item) {
+ return `${item.range[0]}x`
+ },
},
- highlight: [
- {
- time: 15,
- text: 'One more chance',
- },
- {
- time: 30,
- text: '谁でもいいはずなのに',
- },
- {
- time: 45,
- text: '夏の想い出がまわる',
- },
- {
- time: 60,
- text: 'こんなとこにあるはずもないのに',
- },
- {
- time: 75,
- text: '终わり',
- },
- ],
- controls: [
- {
- position: 'right',
- html: 'Control',
- index: 1,
- tooltip: 'Control Tooltip',
- style: {
- marginRight: '20px',
- },
- click: function () {
- console.info('You clicked on the custom control');
- },
- },
- ],
- icons: {
- loading: '
',
- state: '',
- indicator: '
',
+ {
+ html: 'Button',
+ icon: '
',
+ tooltip: 'tooltip',
+ onClick() {
+ return 'Button clicked'
+ },
},
-});
+ ],
+ contextmenu: [
+ {
+ html: 'Custom menu',
+ click(contextmenu) {
+ console.info('You clicked on the custom menu')
+ contextmenu.show = false
+ },
+ },
+ ],
+ layers: [
+ {
+ html: '
',
+ click() {
+ window.open('https://aimu.app')
+ console.info('You clicked on the custom layer')
+ },
+ style: {
+ position: 'absolute',
+ top: '20px',
+ right: '20px',
+ opacity: '.9',
+ },
+ },
+ ],
+ quality: [
+ {
+ default: true,
+ html: 'SD 480P',
+ url: '/assets/sample/video.mp4?q=480',
+ },
+ {
+ html: 'HD 720P',
+ url: '/assets/sample/video.mp4?q=720',
+ },
+ ],
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.85,
+ },
+ subtitle: {
+ url: '/assets/sample/subtitle.srt',
+ type: 'srt',
+ style: {
+ color: '#fe9200',
+ fontSize: '20px',
+ },
+ encoding: 'utf-8',
+ },
+ highlight: [
+ {
+ time: 15,
+ text: 'One more chance',
+ },
+ {
+ time: 30,
+ text: '谁でもいいはずなのに',
+ },
+ {
+ time: 45,
+ text: '夏の想い出がまわる',
+ },
+ {
+ time: 60,
+ text: 'こんなとこにあるはずもないのに',
+ },
+ {
+ time: 75,
+ text: '终わり',
+ },
+ ],
+ controls: [
+ {
+ position: 'right',
+ html: 'Control',
+ index: 1,
+ tooltip: 'Control Tooltip',
+ style: {
+ marginRight: '20px',
+ },
+ click() {
+ console.info('You clicked on the custom control')
+ },
+ },
+ ],
+ icons: {
+ loading: '
',
+ state: '',
+ indicator: '
',
+ },
+})
diff --git a/docs/assets/example/libass.js b/docs/assets/example/libass.js
index 67e15141a..77aa1f981 100644
--- a/docs/assets/example/libass.js
+++ b/docs/assets/example/libass.js
@@ -1,44 +1,44 @@
// npm i artplayer-plugin-libass
// import artplayerPluginLibass from 'artplayer-plugin-libass';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- fullscreenWeb: true,
- subtitle: {
- url: '/assets/sample/style-test.ass',
- },
- plugins: [
- artplayerPluginLibass({
- // debug: true,
- workerUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.js',
- // wasmUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.wasm',
- fallbackFont: '/assets/misc/SourceHanSansCN-Bold.woff2'
- }),
- ],
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreenWeb: true,
+ subtitle: {
+ url: '/assets/sample/style-test.ass',
+ },
+ plugins: [
+ artplayerPluginLibass({
+ // debug: true,
+ workerUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.js',
+ // wasmUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.wasm',
+ fallbackFont: '/assets/misc/SourceHanSansCN-Bold.woff2',
+ }),
+ ],
+})
// init
art.on('artplayerPluginLibass:init', (adapter) => {
- console.info('artplayerPluginLibass:init', adapter);
-});
+ console.info('artplayerPluginLibass:init', adapter)
+})
// subtitle switch
art.on('artplayerPluginLibass:switch', (url) => {
- console.info('artplayerPluginLibass:switch', url);
+ console.info('artplayerPluginLibass:switch', url)
})
// subtitle visible
art.on('artplayerPluginLibass:visible', (visible) => {
- console.info('artplayerPluginLibass:visible', visible);
+ console.info('artplayerPluginLibass:visible', visible)
})
// subtitle timeOffset
art.on('artplayerPluginLibass:timeOffset', (timeOffset) => {
- console.info('artplayerPluginLibass:timeOffset', timeOffset);
+ console.info('artplayerPluginLibass:timeOffset', timeOffset)
})
// destroy
art.on('artplayerPluginLibass:destroy', () => {
- console.info('artplayerPluginLibass:destroy');
+ console.info('artplayerPluginLibass:destroy')
})
diff --git a/docs/assets/example/mobile.js b/docs/assets/example/mobile.js
index 0225e7732..3fda3a802 100644
--- a/docs/assets/example/mobile.js
+++ b/docs/assets/example/mobile.js
@@ -1,98 +1,98 @@
var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- poster: '/assets/sample/poster.jpg',
- autoSize: true,
- loop: true,
- mutex: true,
- setting: true,
- flip: true,
- lock: true,
- fastForward: true,
- playbackRate: true,
- aspectRatio: true,
- theme: '#ff0057',
- fullscreen: true,
- fullscreenWeb: true,
- miniProgressBar: true,
- autoOrientation: true,
- airplay: true,
- moreVideoAttr: {
- 'x5-video-player-type': 'h5',
- 'x5-video-player-fullscreen': false,
- 'x5-video-orientation': 'portraint',
- preload: "metadata"
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ autoSize: true,
+ loop: true,
+ mutex: true,
+ setting: true,
+ flip: true,
+ lock: true,
+ fastForward: true,
+ playbackRate: true,
+ aspectRatio: true,
+ theme: '#ff0057',
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoOrientation: true,
+ airplay: true,
+ moreVideoAttr: {
+ 'x5-video-player-type': 'h5',
+ 'x5-video-player-fullscreen': false,
+ 'x5-video-orientation': 'portraint',
+ 'preload': 'metadata',
+ },
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.6,
+ },
+ subtitle: {
+ name: '中日双语',
+ url: '/assets/sample/subtitle.srt',
+ style: {
+ color: '#48aff0',
+ fontSize: '16px',
},
- thumbnails: {
- url: '/assets/sample/thumbnails.png',
- number: 60,
- column: 10,
- scale: 0.6
+ },
+ layers: [
+ {
+ html: `
`,
+ click() {
+ art.notice.show = '你点击了自定义层'
+ },
+ style: {
+ position: 'absolute',
+ top: '10px',
+ right: '10px',
+ opacity: '.9',
+ },
},
- subtitle: {
- name: '中日双语',
- url: '/assets/sample/subtitle.srt',
- style: {
- color: '#48aff0',
- fontSize: '16px',
- },
- },
- layers: [
+ ],
+ icons: {
+ loading: '
',
+ state: '',
+ indicator: '
',
+ },
+ settings: [
+ {
+ width: 200,
+ html: '切换字幕',
+ tooltip: '双语',
+ icon: '
',
+ selector: [
{
- html: `
`,
- click: function () {
- art.notice.show = "你点击了自定义层";
- },
- style: {
- position: 'absolute',
- top: '10px',
- right: '10px',
- opacity: '.9',
- },
+ html: '开关',
+ switch: true,
+ tooltip: '显示',
+ onSwitch(item) {
+ item.tooltip = item.switch ? '隐藏' : '显示'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
},
- ],
- icons: {
- loading: '
',
- state: '',
- indicator: '
',
- },
- settings: [
{
- width: 200,
- html: '切换字幕',
- tooltip: '双语',
- icon: '
',
- selector: [
- {
- html: '开关',
- switch: true,
- tooltip: '显示',
- onSwitch: function (item) {
- item.tooltip = item.switch ? '隐藏' : '显示';
- art.subtitle.show = !item.switch;
- return !item.switch;
- },
- },
- {
- default: true,
- html: '双语',
- url: '/assets/sample/subtitle.srt'
- },
- {
- html: '中文',
- url: '/assets/sample/subtitle.cn.srt'
- },
- {
- html: '日文',
- url: '/assets/sample/subtitle.jp.srt'
- },
- ],
- onSelect: function (item) {
- art.subtitle.switch(item.url, {
- name: item.html
- });
- return item.html;
- },
+ default: true,
+ html: '双语',
+ url: '/assets/sample/subtitle.srt',
},
- ],
-});
\ No newline at end of file
+ {
+ html: '中文',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ html: '日文',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
+ },
+ ],
+})
diff --git a/docs/assets/example/mpegts.js b/docs/assets/example/mpegts.js
index 8f2b71f23..b35b17a07 100644
--- a/docs/assets/example/mpegts.js
+++ b/docs/assets/example/mpegts.js
@@ -2,33 +2,35 @@
// import mpegts from 'mpegts';
function playFlv(video, url, art) {
- if (mpegts.isSupported()) {
- if (art.flv) art.flv.destroy();
+ if (mpegts.isSupported()) {
+ if (art.flv)
+ art.flv.destroy()
- const flv = mpegts.createPlayer({
- type: 'flv',
- url: url
- });
- flv.attachMediaElement(video);
- flv.load();
- flv.play();
+ const flv = mpegts.createPlayer({
+ type: 'flv',
+ url,
+ })
+ flv.attachMediaElement(video)
+ flv.load()
+ flv.play()
- art.flv = flv;
- art.on('destroy', () => flv.destroy());
- } else {
- art.notice.show = 'Unsupported playback format: flv';
- }
+ art.flv = flv
+ art.on('destroy', () => flv.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: flv'
+ }
}
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.flv',
- type: 'flv',
- customType: {
- flv: playFlv,
- },
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.flv',
+ type: 'flv',
+ customType: {
+ flv: playFlv,
+ },
+})
art.on('ready', () => {
- console.info(art.flv);
-});
\ No newline at end of file
+ console.info(art.flv)
+})
diff --git a/docs/assets/example/multiple.subtitles.js b/docs/assets/example/multiple.subtitles.js
index d3b1a53a2..82af8ec98 100644
--- a/docs/assets/example/multiple.subtitles.js
+++ b/docs/assets/example/multiple.subtitles.js
@@ -2,88 +2,89 @@
// import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- setting: true,
- plugins: [
- artplayerPluginMultipleSubtitles({
- subtitles: [
- {
- name: 'chinese',
- url: '/assets/sample/subtitle.cn.srt',
- },
- {
- name: 'japanese',
- url: '/assets/sample/subtitle.jp.srt',
- }
- ],
- })
- ],
- settings: [
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ plugins: [
+ artplayerPluginMultipleSubtitles({
+ subtitles: [
{
- width: 200,
- html: 'Subtitle',
- tooltip: 'Double',
- icon: '
',
- selector: [
- {
- html: 'Display',
- tooltip: 'Show',
- switch: true,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'Hide' : 'Show';
- // 显示/隐藏字幕
- // Show/hide subtitles
- art.subtitle.show = !item.switch;
- return !item.switch;
- },
- },
- {
- html: 'Reverse',
- tooltip: 'Off',
- switch: false,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'Off' : 'On';
- // 修改字幕顺序
- // Change the order of subtitles
- if (item.switch) {
- art.plugins.multipleSubtitles.tracks(['chinese', 'japanese']);
- } else {
- art.plugins.multipleSubtitles.tracks(['japanese', 'chinese']);
-
- }
- return !item.switch;
- },
- },
- {
- default: true,
- html: 'Double',
- name: 'double',
- },
- {
- html: 'Chinese',
- name: 'chinese',
- },
- {
- html: 'Japanese',
- name: 'japanese',
- },
- ],
- onSelect: function (item) {
- if (item.name === 'double') {
- // 重置字幕
- // Reset subtitles
- art.plugins.multipleSubtitles.reset();
- } else {
- // 显示单个字幕
- // Show single subtitle
- art.plugins.multipleSubtitles.tracks([item.name]);
- }
- return item.html;
- },
+ name: 'chinese',
+ url: '/assets/sample/subtitle.cn.srt',
},
- ],
-});
+ {
+ name: 'japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ }),
+ ],
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ tooltip: 'Double',
+ icon: '
',
+ selector: [
+ {
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ // 显示/隐藏字幕
+ // Show/hide subtitles
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ html: 'Reverse',
+ tooltip: 'Off',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Off' : 'On'
+ // 修改字幕顺序
+ // Change the order of subtitles
+ if (item.switch) {
+ art.plugins.multipleSubtitles.tracks(['chinese', 'japanese'])
+ }
+ else {
+ art.plugins.multipleSubtitles.tracks(['japanese', 'chinese'])
+ }
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: 'Double',
+ name: 'double',
+ },
+ {
+ html: 'Chinese',
+ name: 'chinese',
+ },
+ {
+ html: 'Japanese',
+ name: 'japanese',
+ },
+ ],
+ onSelect(item) {
+ if (item.name === 'double') {
+ // 重置字幕
+ // Reset subtitles
+ art.plugins.multipleSubtitles.reset()
+ }
+ else {
+ // 显示单个字幕
+ // Show single subtitle
+ art.plugins.multipleSubtitles.tracks([item.name])
+ }
+ return item.html
+ },
+ },
+ ],
+})
// 自定义你自己的样式,请勿复制以下代码
// Customize your own style, please do not copy the following code
@@ -98,14 +99,15 @@ const style = `
color: yellow;
font-size: 12px;
}
-`;
+`
-const $style = document.getElementById('artplayer-subtitle-style');
+const $style = document.getElementById('artplayer-subtitle-style')
if ($style) {
- $style.textContent = style;
-} else {
- const $style = document.createElement('style');
- $style.id = 'artplayer-subtitle-style';
- $style.textContent = style;
- document.head.appendChild($style);
-}
\ No newline at end of file
+ $style.textContent = style
+}
+else {
+ const $style = document.createElement('style')
+ $style.id = 'artplayer-subtitle-style'
+ $style.textContent = style
+ document.head.appendChild($style)
+}
diff --git a/docs/assets/example/setting.test.js b/docs/assets/example/setting.test.js
index 1dab9085f..8ffcba30f 100644
--- a/docs/assets/example/setting.test.js
+++ b/docs/assets/example/setting.test.js
@@ -1,138 +1,140 @@
var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- setting: true,
- flip: true,
- playbackRate: true,
- aspectRatio: true,
- subtitleOffset: true,
- settings: [
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ flip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ subtitleOffset: true,
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ name: 'subtitle',
+ tooltip: 'Bilingual',
+ icon: '
',
+ selector: [
{
- width: 200,
- html: 'Subtitle',
- name: 'subtitle',
- tooltip: 'Bilingual',
- icon: '
',
- selector: [
- {
- html: 'Display',
- tooltip: 'Show',
- switch: true,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'Hide' : 'Show';
- art.subtitle.show = !item.switch;
- return !item.switch;
- },
- },
- {
- default: true,
- html: 'Bilingual',
- url: '/assets/sample/subtitle.srt',
- },
- {
- html: 'Chinese',
- url: '/assets/sample/subtitle.cn.srt',
- },
- {
- html: 'Japanese',
- url: '/assets/sample/subtitle.jp.srt',
- },
- ],
- onSelect: function (item) {
- art.subtitle.switch(item.url, {
- name: item.html,
- });
- return item.html;
- },
- mounted: function (...args) {
- console.info(args);
- },
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
},
{
- html: 'Switcher',
- icon: '
',
- tooltip: 'OFF',
- switch: false,
- onSwitch: function (item) {
- item.tooltip = item.switch ? 'OFF' : 'ON';
- console.info('You clicked on the custom switch', item.switch);
- return !item.switch;
- },
- mounted: function (...args) {
- console.info(args);
- },
+ default: true,
+ html: 'Bilingual',
+ url: '/assets/sample/subtitle.srt',
},
{
- html: 'Slider',
- icon: '
',
- tooltip: '5x',
- range: [5, 1, 10, 0.1],
- onRange: function (item) {
- return item.range[0] + 'x';
- },
- mounted: function (...args) {
- console.info(args);
- },
+ html: 'Chinese',
+ url: '/assets/sample/subtitle.cn.srt',
},
- ],
+ {
+ html: 'Japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ {
+ html: 'Switcher',
+ icon: '
',
+ tooltip: 'OFF',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'OFF' : 'ON'
+ console.info('You clicked on the custom switch', item.switch)
+ return !item.switch
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ {
+ html: 'Slider',
+ icon: '
',
+ tooltip: '5x',
+ range: [5, 1, 10, 0.1],
+ onRange(item) {
+ return `${item.range[0]}x`
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ ],
}, async () => {
- const { sleep } = Artplayer.utils;
- art.setting.show = true;
- console.log(art.setting.builtin);
- console.log(art.setting.find('aspect-ratio'));
- console.log(art.setting.find('aspect-ratio2'));
- await sleep(1000);
- art.setting.resize();
- await sleep(1000);
- art.setting.inactivate(art.setting.find('subtitle'));
- art.setting.remove('aspect-ratio');
- try {
- art.setting.remove('aspect-ratio2');
- } catch (error) {
- console.log(error.message);
- }
- await sleep(1000);
- art.setting.update({
- name: 'subtitle-offset',
- html: 'new offset',
- range: [5, -11, 11, 1],
- });
- await sleep(1000);
- art.setting.find('subtitle-offset').range = [0, -0, 10, 1];
- await sleep(1000);
- art.setting.update({
- name: 'subtitle-offset2',
- html: 'new offset 2',
- range: [5, -11, 11, 1],
- onChange(item) {
- return item.range[0] + 's';
- },
- });
- await sleep(1000);
- art.setting.update({
- name: 'flip',
- html: 'new flip',
- tooltip: 'OFF',
- switch: false,
- });
- await sleep(1000);
- art.setting.find('flip').switch = true;
- await sleep(1000);
- art.setting.update({
- name: 'flip2',
- html: 'new flip2',
- tooltip: 'OFF',
- switch: true,
- });
- await sleep(1000);
- try {
- art.setting.add({
- name: 'flip2',
- html: 'new flip2',
- tooltip: 'OFF',
- switch: true,
- });
- } catch (error) {
- console.log(error.message);
- }
-});
+ const { sleep } = Artplayer.utils
+ art.setting.show = true
+ console.log(art.setting.builtin)
+ console.log(art.setting.find('aspect-ratio'))
+ console.log(art.setting.find('aspect-ratio2'))
+ await sleep(1000)
+ art.setting.resize()
+ await sleep(1000)
+ art.setting.inactivate(art.setting.find('subtitle'))
+ art.setting.remove('aspect-ratio')
+ try {
+ art.setting.remove('aspect-ratio2')
+ }
+ catch (error) {
+ console.log(error.message)
+ }
+ await sleep(1000)
+ art.setting.update({
+ name: 'subtitle-offset',
+ html: 'new offset',
+ range: [5, -11, 11, 1],
+ })
+ await sleep(1000)
+ art.setting.find('subtitle-offset').range = [0, -0, 10, 1]
+ await sleep(1000)
+ art.setting.update({
+ name: 'subtitle-offset2',
+ html: 'new offset 2',
+ range: [5, -11, 11, 1],
+ onChange(item) {
+ return `${item.range[0]}s`
+ },
+ })
+ await sleep(1000)
+ art.setting.update({
+ name: 'flip',
+ html: 'new flip',
+ tooltip: 'OFF',
+ switch: false,
+ })
+ await sleep(1000)
+ art.setting.find('flip').switch = true
+ await sleep(1000)
+ art.setting.update({
+ name: 'flip2',
+ html: 'new flip2',
+ tooltip: 'OFF',
+ switch: true,
+ })
+ await sleep(1000)
+ try {
+ art.setting.add({
+ name: 'flip2',
+ html: 'new flip2',
+ tooltip: 'OFF',
+ switch: true,
+ })
+ }
+ catch (error) {
+ console.log(error.message)
+ }
+})
diff --git a/docs/assets/example/thumbnail.js b/docs/assets/example/thumbnail.js
index 2cb3b342c..ac28de015 100644
--- a/docs/assets/example/thumbnail.js
+++ b/docs/assets/example/thumbnail.js
@@ -1,14 +1,14 @@
// npm i artplayer-plugin-thumbnail
// import artplayerPluginThumbnail from 'artplayer-plugin-thumbnail';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- plugins: [
- artplayerPluginThumbnail({
- width: 160,
- number: 100,
- scale: 1,
- }),
- ],
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginThumbnail({
+ width: 160,
+ number: 100,
+ scale: 1,
+ }),
+ ],
+})
diff --git a/docs/assets/example/vast.js b/docs/assets/example/vast.js
index ab9e75099..b6457f5f9 100644
--- a/docs/assets/example/vast.js
+++ b/docs/assets/example/vast.js
@@ -1,4 +1,4 @@
-// Depends on:
+// Depends on:
// https://glomex.github.io/vast-ima-player/
// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side
@@ -9,16 +9,16 @@
// import artplayerPluginVast from 'artplayer-plugin-vast';
var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/video.mp4',
- fullscreen: true,
- fullscreenWeb: true,
- plugins: [
- artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
- // Play the ad when the video is played
- art.once('play', () => {
- playUrl('https://artplayer.org/assets/vast/linear-ad.xml');
- });
- }),
- ],
-});
\ No newline at end of file
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ plugins: [
+ artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
+ // Play the ad when the video is played
+ art.once('play', () => {
+ playUrl('https://artplayer.org/assets/vast/linear-ad.xml')
+ })
+ }),
+ ],
+})
diff --git a/docs/assets/example/vtt.thumbnail.js b/docs/assets/example/vtt.thumbnail.js
index b656729f9..451f60774 100644
--- a/docs/assets/example/vtt.thumbnail.js
+++ b/docs/assets/example/vtt.thumbnail.js
@@ -1,12 +1,12 @@
// npm i artplayer-plugin-vtt-thumbnail
// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
-var art = new Artplayer({
- container: '.artplayer-app',
- url: '/assets/sample/bbb-video.mp4',
- plugins: [
- artplayerPluginVttThumbnail({
- vtt: '/assets/sample/bbb-thumbnails.vtt',
- })
- ]
-});
\ No newline at end of file
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/bbb-video.mp4',
+ plugins: [
+ artplayerPluginVttThumbnail({
+ vtt: '/assets/sample/bbb-thumbnails.vtt',
+ }),
+ ],
+})
diff --git a/docs/assets/example/webtorrent.js b/docs/assets/example/webtorrent.js
index cd8ea3622..a25a6f762 100644
--- a/docs/assets/example/webtorrent.js
+++ b/docs/assets/example/webtorrent.js
@@ -2,35 +2,37 @@
// import WebTorrent from 'webtorrent';
async function playTorrent(video, url, art) {
- if (WebTorrent.WEBRTC_SUPPORT) {
- if (art.torrent) art.torrent.destroy();
- art.torrent = new WebTorrent();
+ if (WebTorrent.WEBRTC_SUPPORT) {
+ if (art.torrent)
+ art.torrent.destroy()
+ art.torrent = new WebTorrent()
- await navigator.serviceWorker.register('/webtorrent.sw.min.js');
- art.torrent.loadWorker(navigator.serviceWorker.controller);
+ await navigator.serviceWorker.register('/webtorrent.sw.min.js')
+ art.torrent.loadWorker(navigator.serviceWorker.controller)
- art.torrent.add(url, (torrent) => {
- const file = torrent.files.find((file) => {
- return file.name.endsWith('.mp4');
- });
- file.streamTo(video);
- });
+ art.torrent.add(url, (torrent) => {
+ const file = torrent.files.find((file) => {
+ return file.name.endsWith('.mp4')
+ })
+ file.streamTo(video)
+ })
- art.on('destroy', () => art.torrent.destroy());
- } else {
- art.notice.show = 'Unsupported playback format: torrent';
- }
+ art.on('destroy', () => art.torrent.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: torrent'
+ }
}
-var art = new Artplayer({
- container: '.artplayer-app',
- url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
- type: 'torrent',
- customType: {
- torrent: playTorrent,
- },
-});
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
+ type: 'torrent',
+ customType: {
+ torrent: playTorrent,
+ },
+})
art.on('ready', () => {
- console.info(art.torrent);
-});
+ console.info(art.torrent)
+})
diff --git a/docs/assets/ts/artplayer-plugin-ads.d.ts b/docs/assets/ts/artplayer-plugin-ads.d.ts
index dd3cde90e..618fdd6c1 100644
--- a/docs/assets/ts/artplayer-plugin-ads.d.ts
+++ b/docs/assets/ts/artplayer-plugin-ads.d.ts
@@ -48,5 +48,5 @@ declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
export default artplayerPluginAds
-export = artplayerPluginAds;
-export as namespace artplayerPluginAds;
\ No newline at end of file
+export = artplayerPluginAds
+export as namespace artplayerPluginAds;
diff --git a/docs/assets/ts/artplayer-plugin-ambilight.d.ts b/docs/assets/ts/artplayer-plugin-ambilight.d.ts
index 786b884f4..50abda15a 100644
--- a/docs/assets/ts/artplayer-plugin-ambilight.d.ts
+++ b/docs/assets/ts/artplayer-plugin-ambilight.d.ts
@@ -16,5 +16,5 @@ declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) =>
export default artplayerPluginAmbilight
-export = artplayerPluginAmbilight;
-export as namespace artplayerPluginAmbilight;
\ No newline at end of file
+export = artplayerPluginAmbilight
+export as namespace artplayerPluginAmbilight;
diff --git a/docs/assets/ts/artplayer-plugin-asr.d.ts b/docs/assets/ts/artplayer-plugin-asr.d.ts
index a134e7348..769e0b30f 100644
--- a/docs/assets/ts/artplayer-plugin-asr.d.ts
+++ b/docs/assets/ts/artplayer-plugin-asr.d.ts
@@ -22,5 +22,5 @@ declare function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer)
export default artplayerPluginAsr
-export = artplayerPluginAsr;
-export as namespace artplayerPluginAsr;
\ No newline at end of file
+export = artplayerPluginAsr
+export as namespace artplayerPluginAsr;
diff --git a/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts b/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts
index dff0302ce..e6f616aa0 100644
--- a/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts
+++ b/docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts
@@ -13,5 +13,5 @@ declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer)
export default artplayerPluginAutoThumbnail
-export = artplayerPluginAutoThumbnail;
-export as namespace artplayerPluginAutoThumbnail;
\ No newline at end of file
+export = artplayerPluginAutoThumbnail
+export as namespace artplayerPluginAutoThumbnail;
diff --git a/docs/assets/ts/artplayer-plugin-chapter.d.ts b/docs/assets/ts/artplayer-plugin-chapter.d.ts
index 0c16baa40..5d6f7b378 100644
--- a/docs/assets/ts/artplayer-plugin-chapter.d.ts
+++ b/docs/assets/ts/artplayer-plugin-chapter.d.ts
@@ -17,5 +17,5 @@ declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Re
export default artplayerPluginChapter
-export = artplayerPluginChapter;
-export as namespace artplayerPluginChapter;
\ No newline at end of file
+export = artplayerPluginChapter
+export as namespace artplayerPluginChapter;
diff --git a/docs/assets/ts/artplayer-plugin-chromecast.d.ts b/docs/assets/ts/artplayer-plugin-chromecast.d.ts
index 4d3aadd12..5069b042d 100644
--- a/docs/assets/ts/artplayer-plugin-chromecast.d.ts
+++ b/docs/assets/ts/artplayer-plugin-chromecast.d.ts
@@ -13,5 +13,5 @@ declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) =>
export default artplayerPluginChromecast
-export = artplayerPluginChromecast;
-export as namespace artplayerPluginChromecast;
\ No newline at end of file
+export = artplayerPluginChromecast
+export as namespace artplayerPluginChromecast;
diff --git a/docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts b/docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts
index b2c996b79..68515f8f8 100644
--- a/docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts
+++ b/docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts
@@ -21,5 +21,5 @@ declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer)
export default artplayerPluginDanmukuMask
-export = artplayerPluginDanmukuMask;
-export as namespace artplayerPluginDanmukuMask;
\ No newline at end of file
+export = artplayerPluginDanmukuMask
+export as namespace artplayerPluginDanmukuMask;
diff --git a/docs/assets/ts/artplayer-plugin-danmuku.d.ts b/docs/assets/ts/artplayer-plugin-danmuku.d.ts
index 6f6a5ec04..554ce0fe2 100644
--- a/docs/assets/ts/artplayer-plugin-danmuku.d.ts
+++ b/docs/assets/ts/artplayer-plugin-danmuku.d.ts
@@ -255,5 +255,5 @@ declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Re
export default artplayerPluginDanmuku
-export = artplayerPluginDanmuku;
-export as namespace artplayerPluginDanmuku;
\ No newline at end of file
+export = artplayerPluginDanmuku
+export as namespace artplayerPluginDanmuku;
diff --git a/docs/assets/ts/artplayer-plugin-dash-control.d.ts b/docs/assets/ts/artplayer-plugin-dash-control.d.ts
index 35057bb07..39a52d129 100644
--- a/docs/assets/ts/artplayer-plugin-dash-control.d.ts
+++ b/docs/assets/ts/artplayer-plugin-dash-control.d.ts
@@ -13,5 +13,5 @@ declare const artplayerPluginDashControl: (option: { quality?: Config, audio?: C
export default artplayerPluginDashControl
-export = artplayerPluginDashControl;
-export as namespace artplayerPluginDashControl;
\ No newline at end of file
+export = artplayerPluginDashControl
+export as namespace artplayerPluginDashControl;
diff --git a/docs/assets/ts/artplayer-plugin-document-pip.d.ts b/docs/assets/ts/artplayer-plugin-document-pip.d.ts
index dee9d2c41..df061d9f4 100644
--- a/docs/assets/ts/artplayer-plugin-document-pip.d.ts
+++ b/docs/assets/ts/artplayer-plugin-document-pip.d.ts
@@ -18,5 +18,5 @@ declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) =
export default artplayerPluginDocumentPip
-export = artplayerPluginDocumentPip;
-export as namespace artplayerPluginDocumentPip;
\ No newline at end of file
+export = artplayerPluginDocumentPip
+export as namespace artplayerPluginDocumentPip;
diff --git a/docs/assets/ts/artplayer-plugin-hls-control.d.ts b/docs/assets/ts/artplayer-plugin-hls-control.d.ts
index 01c881339..f047513e8 100644
--- a/docs/assets/ts/artplayer-plugin-hls-control.d.ts
+++ b/docs/assets/ts/artplayer-plugin-hls-control.d.ts
@@ -13,5 +13,5 @@ declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Co
export default artplayerPluginHlsControl
-export = artplayerPluginHlsControl;
-export as namespace artplayerPluginHlsControl;
\ No newline at end of file
+export = artplayerPluginHlsControl
+export as namespace artplayerPluginHlsControl;
diff --git a/docs/assets/ts/artplayer-plugin-iframe.d.ts b/docs/assets/ts/artplayer-plugin-iframe.d.ts
index f5ebf54f5..88cfd5bad 100644
--- a/docs/assets/ts/artplayer-plugin-iframe.d.ts
+++ b/docs/assets/ts/artplayer-plugin-iframe.d.ts
@@ -28,5 +28,5 @@ declare class ArtplayerPluginIframe {
export default ArtplayerPluginIframe
-export = artplayerPluginIframe;
-export as namespace artplayerPluginIframe;
\ No newline at end of file
+export = artplayerPluginIframe
+export as namespace artplayerPluginIframe;
diff --git a/docs/assets/ts/artplayer-plugin-libass.d.ts b/docs/assets/ts/artplayer-plugin-libass.d.ts
index ae373d1b6..ff0632692 100644
--- a/docs/assets/ts/artplayer-plugin-libass.d.ts
+++ b/docs/assets/ts/artplayer-plugin-libass.d.ts
@@ -11,5 +11,5 @@ declare const artplayerPluginAss: (options: Options) => (art: Artplayer) => {
export default artplayerPluginAss
-export = artplayerPluginLibass;
-export as namespace artplayerPluginLibass;
\ No newline at end of file
+export = artplayerPluginLibass
+export as namespace artplayerPluginLibass;
diff --git a/docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts b/docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts
index 4d6161dff..a6f710bc1 100644
--- a/docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts
+++ b/docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts
@@ -12,5 +12,5 @@ declare const artplayerPluginMultipleSubtitles: (option: {
export default artplayerPluginMultipleSubtitles
-export = artplayerPluginMultipleSubtitles;
-export as namespace artplayerPluginMultipleSubtitles;
\ No newline at end of file
+export = artplayerPluginMultipleSubtitles
+export as namespace artplayerPluginMultipleSubtitles;
diff --git a/docs/assets/ts/artplayer-plugin-vast.d.ts b/docs/assets/ts/artplayer-plugin-vast.d.ts
index b34e73c10..41d815667 100644
--- a/docs/assets/ts/artplayer-plugin-vast.d.ts
+++ b/docs/assets/ts/artplayer-plugin-vast.d.ts
@@ -29,5 +29,5 @@ declare function artplayerPluginVast(
export default artplayerPluginVast
-export = artplayerPluginVast;
-export as namespace artplayerPluginVast;
\ No newline at end of file
+export = artplayerPluginVast
+export as namespace artplayerPluginVast;
diff --git a/docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts b/docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts
index aaed1e528..4e8307e77 100644
--- a/docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts
+++ b/docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts
@@ -6,5 +6,5 @@ declare const artplayerPluginVttThumbnail: (option: { vtt?: string, style?: Part
export default artplayerPluginVttThumbnail
-export = artplayerPluginVttThumbnail;
-export as namespace artplayerPluginVttThumbnail;
\ No newline at end of file
+export = artplayerPluginVttThumbnail
+export as namespace artplayerPluginVttThumbnail;
diff --git a/docs/assets/ts/artplayer.d.ts b/docs/assets/ts/artplayer.d.ts
index a181ef13e..43827733c 100644
--- a/docs/assets/ts/artplayer.d.ts
+++ b/docs/assets/ts/artplayer.d.ts
@@ -124,8 +124,6 @@ export interface Subtitle {
onVttLoad?: (vtt: string) => string
}
-
-
type Props
`,
+ style: {
+ display: 'none',
+ position: 'absolute',
+ top: '20px',
+ right: '20px',
+ },
+ });
+
+ function show() {
+ art.layers.ads.style.display = 'block';
+ }
+
+ function hide() {
+ art.layers.ads.style.display = 'none';
+ }
+
+ art.controls.add({
+ name: 'hide-ads',
+ position: 'right',
+ html: 'Hide Ads',
+ tooltip: 'Hide Ads',
+ click: hide,
+ style: {
+ marginRight: '20px'
+ }
+ });
+
+ art.controls.add({
+ name: 'show-ads',
+ position: 'right',
+ html: 'Show Ads',
+ tooltip: 'Show Ads',
+ click: show,
+ });
+
+ art.on('play', hide);
+ art.on('pause', show);
+
+ return {
+ name: 'adsPlugin',
+ show,
+ hide
+ };
+ }
+}
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ adsPlugin({
+ url: '/assets/sample/layer.png'
+ })
+ ],
+});
+```
+
+Instance Properties
+
+Instance properties refer to the top-level properties mounted on the ArtPlayer instance that are commonly used.
+
+play
+Type: Function
+Play the video.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ muted: true,
+});
+
+art.on('ready', () => {
+ art.play();
+});
+
+pause
+Type: Function
+Pause the video.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ muted: true,
+});
+
+art.on('ready', () => {
+ art.play();
+
+ setTimeout(() => {
+ art.pause();
+ }, 3000);
+});
+
+toggle
+Type: Function
+Toggle between playing and pausing the video.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ muted: true,
+});
+
+art.on('ready', () => {
+ art.toggle();
+
+ setTimeout(() => {
+ art.toggle();
+ }, 3000);
+});
+
+destroy
+Type: Function
+Parameter: Boolean
+Destroy the player. Accepts a parameter indicating whether to also remove the player's html after destruction. Defaults to true.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.destroy();
+});
+
+seek
+Type: Setter
+Parameter: Number
+Seek to a specific time in the video, in seconds.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.seek = 5;
+});
+
+forward
+Type: Setter
+Parameter: Number
+Fast forward the video by a specified number of seconds.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.forward = 5;
+});
+
+backward
+Type: Setter
+Parameter: Number
+Rewind the video by a specified number of seconds.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.seek = 5;
+
+ setTimeout(() => {
+ art.backward = 2;
+ }, 3000);
+});
+
+volume
+Type: Setter/Getter
+Parameter: Number
+Set or get the video volume. Range: [0, 1].
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.volume);
+ art.volume = 0.5;
+ console.info(art.volume);
+});
+
+url
+Type: Setter/Getter
+Parameter: String
+Set or get the video URL.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.url = '/assets/sample/video.mp4?t=0';
+});
+
+switch
+Type: Setter
+Parameter: String
+Set the video URL. Similar to art.url when setting, but performs some optimization operations.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.seek = 10;
+ setTimeout(() => {
+ art.switch = '/assets/sample/video.mp4?t=0';
+ }, 3000);
+});
+
+switchUrl
+Type: Function
+Parameter: String
+Set the video URL. Similar to art.url when setting, but performs some optimization operations.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.seek = 10;
+ setTimeout(() => {
+ art.switchUrl('/assets/sample/video.mp4?t=0');
+ }, 3000);
+});
+
+Note: art.switch and art.switchUrl have the same functionality, but art.switchUrl returns a Promise. It resolves when the new URL is playable and rejects when the new URL fails to load.
+
+switchQuality
+Type: Function
+Parameter: String
+Sets the video quality URL. Similar to art.switchUrl, but preserves the previous playback progress.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.seek = 10;
+ setTimeout(() => {
+ art.switchQuality('/assets/sample/video.mp4?t=0');
+ }, 3000);
+});
+
+muted
+Type: Setter/Getter
+Parameter: Boolean
+Sets and gets whether the video is muted.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.muted);
+ art.muted = true;
+ console.info(art.muted);
+});
+
+currentTime
+Type: Setter/Getter
+Parameter: Number
+Sets and gets the current playback time of the video. Setting the time is similar to seek, but it does not trigger additional events.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.currentTime);
+ art.currentTime = 5;
+ console.info(art.currentTime);
+});
+
+duration
+Type: Getter
+Gets the duration of the video.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.duration);
+});
+
+Note: Some videos may not have a duration, such as live streams or videos that haven't finished decoding. In these cases, the obtained duration will be 0.
+
+screenshot
+Type: Function
+Downloads a screenshot of the current video frame. An optional parameter specifies the screenshot filename.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.screenshot('your-name');
+});
+
+getDataURL
+Type: Function
+Gets the base64 URL of the screenshot for the current video frame. Returns a Promise.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', async () => {
+ const url = await art.getDataURL();
+ console.info(url)
+});
+
+getBlobUrl
+Type: Function
+Gets the blob URL of the screenshot for the current video frame. Returns a Promise.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', async () => {
+ const url = await art.getBlobUrl();
+ console.info(url);
+});
+
+fullscreen
+Type: Setter/Getter
+Parameter: Boolean
+Sets and gets the fullscreen state of the player window.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ position: 'right',
+ html: 'Fullscreen Switch',
+ click: function () {
+ art.fullscreen = !art.fullscreen;
+ },
+ },
+ ],
+});
+
+Note: Due to browser security mechanisms, the page must have prior interaction (e.g., the user has clicked on the page) before triggering window fullscreen.
+
+fullscreenWeb
+Type: Setter/Getter
+Parameter: Boolean
+Sets and gets the web fullscreen state of the player.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreenWeb: true,
+});
+
+art.on('ready', () => {
+ art.fullscreenWeb = true;
+
+ setTimeout(() => {
+ art.fullscreenWeb = false;
+ }, 3000);
+});
+
+pip
+Type: Setter/Getter
+Parameter: Boolean
+Sets and gets the Picture-in-Picture mode of the player.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ position: 'right',
+ html: 'PIP',
+ click: function () {
+ art.pip = !art.pip;
+ },
+ },
+ ],
+});
+
+Note: Due to browser security mechanisms, the page must have prior user interaction (e.g., a user click) before Picture-in-Picture can be triggered.
+
+poster
+Type: Setter/Getter
+Parameter: String
+Sets and gets the video poster. The poster is only visible before video playback starts.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+});
+
+art.on('ready', () => {
+ console.info(art.poster);
+ art.poster = '/assets/sample/poster.jpg?t=0';
+ console.info(art.poster);
+});
+
+mini
+Type: Setter/Getter
+Parameter: Boolean
+Sets and gets the player's mini mode.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.mini = true;
+});
+
+playing
+Type: Getter
+Parameter: Boolean
+Gets whether the video is currently playing.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ muted: true,
+});
+
+art.on('ready', () => {
+ console.info(art.playing);
+});
+
+autoSize
+Type: Function
+Sets whether the video should automatically adjust its size.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.autoSize();
+});
+
+rect
+Type: Getter
+Gets the player's dimensions and coordinate information.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(JSON.stringify(art.rect));
+});
+
+Note: The dimension and coordinate information is obtained via getBoundingClientRect.
+
+flip
+Type: Setter/Getter
+Parameter: String
+Sets and gets the player flip mode. Supports normal, horizontal, vertical.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.flip);
+ art.flip = 'horizontal';
+ console.info(art.flip);
+});
+
+playbackRate
+Type: Setter/Getter
+Parameter: Number
+Sets and gets the player's playback speed.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.playbackRate);
+ art.playbackRate = 2;
+ console.info(art.playbackRate);
+});
+
+aspectRatio
+Type: Setter/Getter
+Parameter: String
+Sets and gets the player's aspect ratio.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.aspectRatio);
+ art.aspectRatio = '16:9';
+ console.info(art.aspectRatio);
+});
+
+autoHeight
+Type: Function
+When the container only has a defined width, this property can automatically calculate and set the video's height.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.autoHeight();
+});
+
+art.on('resize', () => {
+ art.autoHeight();
+});
+
+Note: This property is useful when your container has a defined width but an unknown height, as it automatically calculates the video's height. However, you need to determine the appropriate timing to set this property.
+
+attr
+Type: Function
+Parameter: String
+Dynamically gets and sets attributes of the video element.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.attr('playsInline'));
+ art.attr('playsInline', true);
+ console.info(art.attr('playsInline'));
+});
+
+type
+Type: Setter/Getter
+Parameter: String
+Dynamically gets and sets the video type.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.type);
+ art.type = 'm3u8';
+ console.info(art.type);
+});
+
+theme
+Type: Setter/Getter
+Parameter: String
+Dynamically gets and sets the player's theme color.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.info(art.theme);
+ art.theme = '#000';
+ console.info(art.theme);
+});
+
+airplay
+Type: Function
+Initiates AirPlay.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ position: 'right',
+ html: 'AirPlay',
+ click: function () {
+ art.airplay();
+ },
+ },
+ ],
+});
+
+loaded
+Type: Getter
+The proportion of the video that has been buffered, ranging from [0, 1]. Often used with the video:timeupdate event.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('video:timeupdate', () => {
+ console.info(art.loaded);
+});
+
+played
+Type: Getter
+The proportion of the video that has been played, ranging from [0, 1]. Often used with the video:timeupdate event.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('video:timeupdate', () => {
+ console.info(art.played);
+});
+
+proxy
+Type: Function
+A proxy function for DOM events, essentially proxying addEventListener and removeEventListener. When using proxy to handle events, the event will be automatically removed when the player is destroyed.
+
+Example usage:
+var container = document.querySelector('.artplayer-app');
+
+var art = new Artplayer({
+ container: container,
+ url: '/assets/sample/video.mp4',
+});
+
+art.proxy(container, 'click', event => {
+ console.info(event);
+});
+
+Note: If you need certain DOM events to exist only for the duration of the player's lifecycle, it is strongly recommended to use this function to avoid memory leaks.
+
+query
+Type: Function
+A DOM query function, similar to document.querySelector, but the search is scoped to within the current player, preventing errors from duplicate class names.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+console.info(art.query('.art-video'));
+
+video
+Type: Element
+Quickly returns the player's video element.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+console.info(art.video);
+
+cssVar
+Type: Function
+Dynamically gets or sets CSS variables.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ console.log(art.cssVar('--art-theme'));
+ art.cssVar('--art-theme', 'green');
+ console.log(art.cssVar('--art-theme'));
+});
+
+quality
+Type: Setter
+Parameter: Array
+Dynamically sets the list of available quality levels.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ quality: [
+ {
+ default: true,
+ html: 'SD 480P',
+ url: '/assets/sample/video.mp4',
+ },
+ {
+ html: 'HD 720P',
+ url: '/assets/sample/video.mp4',
+ },
+ ],
+});
+
+art.on('ready', () => {
+ setTimeout(() => {
+ art.quality = [
+ {
+ default: true,
+ html: '1080P',
+ url: '/assets/sample/video.mp4',
+ },
+ {
+ html: '4K',
+ url: '/assets/sample/video.mp4',
+ },
+ ];
+ }, 3000);
+})
+
+thumbnails
+Type: Setter/Getter
+Parameter: Object
+Dynamically sets the thumbnails.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.on('ready', () => {
+ art.thumbnails = {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ };
+});
+
+subtitleOffset
+Type: Setter/Getter
+Parameter: Number
+Dynamically set subtitle offset.
+
+Example usage:
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ subtitle: {
+ url: '/assets/sample/subtitle.srt',
+ },
+});
+
+art.on('ready', () => {
+ art.subtitleOffset = 1;
+});
+
+Context Menu
+
+Configuration
+
+Property: disable
+Type: Boolean
+Description: Whether to disable the component
+
+Property: name
+Type: String
+Description: Unique component name for CSS class
+
+Property: index
+Type: Number
+Description: Component index for display priority
+
+Property: html
+Type: String, Element
+Description: Component DOM element
+
+Property: style
+Type: Object
+Description: Component style object
+
+Property: click
+Type: Function
+Description: Component click event
+
+Property: mounted
+Type: Function
+Description: Triggered after component mount
+
+Property: tooltip
+Type: String
+Description: Component tooltip text
+
+Creation
+
+You can create context menu items during ArtPlayer initialization by including them in the contextmenu array.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ contextmenu: [
+ {
+ name: 'your-menu',
+ html: 'Your Menu',
+ click: function (...args) {
+ console.info(args);
+ art.contextmenu.show = false;
+ },
+ },
+ ],
+});
+
+art.contextmenu.show = true;
+
+// Get the Element of contextmenu by name
+console.info(art.contextmenu['your-menu']);
+
+Addition
+
+You can add context menu items after ArtPlayer initialization using the add method.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.contextmenu.add({
+ name: 'your-menu',
+ html: 'Your Menu',
+ click: function (...args) {
+ console.info(args);
+ art.contextmenu.show = false;
+ },
+});
+
+art.contextmenu.show = true;
+
+// Get the Element of contextmenu by name
+console.info(art.contextmenu['your-menu']);
+
+Removal
+
+You can remove context menu items by name using the remove method.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ contextmenu: [
+ {
+ name: 'your-menu',
+ html: 'Your Menu',
+ click: function (...args) {
+ console.info(args);
+ art.contextmenu.show = false;
+ },
+ },
+ ],
+});
+
+art.contextmenu.show = true;
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Delete the contextmenu by name
+ art.contextmenu.remove('your-menu')
+ }, 3000);
+});
+
+Update
+
+You can update existing context menu items by name using the update method.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ contextmenu: [
+ {
+ name: 'your-menu',
+ html: 'Your Menu',
+ click: function (...args) {
+ console.info(args);
+ art.contextmenu.show = false;
+ },
+ },
+ ],
+});
+
+art.contextmenu.show = true;
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Update the contextmenu by name
+ art.contextmenu.update({
+ name: 'your-menu',
+ html: 'Your New Menu',
+ })
+ }, 3000);
+});
+
+Controllers
+
+Configuration
+
+Property: disable
+Type: Boolean
+Description: Whether to disable the component
+
+Property: name
+Type: String
+Description: Unique component name for CSS class identification
+
+Property: index
+Type: Number
+Description: Component index for display priority
+
+Property: html
+Type: String, Element
+Description: Component DOM element
+
+Property: style
+Type: Object
+Description: Component style object
+
+Property: click
+Type: Function
+Description: Component click event
+
+Property: mounted
+Type: Function
+Description: Triggered after component mounting
+
+Property: tooltip
+Type: String
+Description: Component tooltip text
+
+Property: position
+Type: String
+Description: left and right control controller placement
+
+Property: selector
+Type: Array
+Description: Array of selector list objects
+
+Property: onSelect
+Type: Function
+Description: Function triggered when selector item is clicked
+
+Creation
+
+Here is an example of creating controllers during ArtPlayer initialization:
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ name: 'your-button',
+ index: 10,
+ position: 'left',
+ html: 'Your Button',
+ tooltip: 'Your Button',
+ style: {
+ color: 'red',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ },
+ mounted: function (...args) {
+ console.info('mounted', args);
+ },
+ },
+ {
+ name: 'subtitle',
+ position: 'right',
+ html: 'Subtitle',
+ selector: [
+ {
+ default: true,
+ html: 'subtitle 01',
+ },
+ {
+ html: 'subtitle 02',
+ },
+ ],
+ onSelect: function (item, $dom) {
+ console.info(item, $dom);
+ return 'Your ' + item.html;
+ },
+ },
+ ],
+});
+
+// Get the Element of control by name
+console.info(art.controls['your-button']);
+console.info(art.controls['subtitle']);
+
+Addition
+
+You can add controllers to an existing ArtPlayer instance using the add method:
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.controls.add({
+ name: 'button1',
+ index: 10,
+ position: 'left',
+ html: 'Your Button',
+ tooltip: 'Your Button',
+ style: {
+ color: 'red',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ },
+ mounted: function (...args) {
+ console.info('mounted', args);
+ },
+});
+
+// Get the Element of control by name
+console.info(art.controls['button1']);
+
+Removal
+
+Controllers can be removed by name using the remove method. This example removes a controller after a 3-second delay:
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ name: 'button1',
+ index: 10,
+ position: 'right',
+ html: 'Your Button',
+ tooltip: 'Your Button',
+ style: {
+ color: 'red',
+ },
+ }
+ ]
+});
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Delete the control by name
+ art.controls.remove('button1');
+ }, 3000);
+});
+
+Update
+
+Existing controllers can be updated with new properties. This example updates a controller after a 3-second delay:
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ name: 'button1',
+ index: 10,
+ position: 'right',
+ html: 'Subtitle',
+ selector: [
+ {
+ default: true,
+ html: 'subtitle 01',
+ },
+ {
+ html: 'subtitle 02',
+ },
+ ],
+ }
+ ]
+});
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Update the control by name
+ art.controls.update({
+ name: 'button1',
+ index: 10,
+ position: 'right',
+ html: 'New Subtitle',
+ selector: [
+ {
+ default: true,
+ html: 'new subtitle 01',
+ },
+ {
+ html: 'new subtitle 02',
+ },
+ ],
+ });
+ }, 3000);
+});
+
+Business Layer
+
+Configuration
+
+The following table describes the configuration properties available for layers in ArtPlayer.
+
+Property: disable
+Type: Boolean
+Description: Whether to disable the component
+
+Property: name
+Type: String
+Description: Unique component name for class marking
+
+Property: index
+Type: Number
+Description: Component index for display priority
+
+Property: html
+Type: String, Element
+Description: Component DOM element
+
+Property: style
+Type: Object
+Description: Component style object
+
+Property: click
+Type: Function
+Description: Component click event
+
+Property: mounted
+Type: Function
+Description: Triggered after component mounting
+
+Property: tooltip
+Type: String
+Description: Component tooltip text
+
+Creation
+
+You can create layers during ArtPlayer initialization by including them in the layers array. Here is an example:
+
+var img = '/assets/sample/layer.png';
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ layers: [
+ {
+ name: 'potser',
+ html: `
`,
+ tooltip: 'Potser Tip',
+ style: {
+ position: 'absolute',
+ top: '50px',
+ right: '50px',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ },
+ mounted: function (...args) {
+ console.info('mounted', args);
+ },
+ },
+ ],
+});
+
+// Get the Element of layer by name
+console.info(art.layers['potser']);
+
+Addition
+
+You can add layers to an existing ArtPlayer instance using the layers.add method. Here is an example:
+
+var img = '/assets/sample/layer.png';
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+});
+
+art.layers.add({
+ name: 'potser',
+ html: `
`,
+ tooltip: 'Potser Tip',
+ style: {
+ position: 'absolute',
+ top: '50px',
+ right: '50px',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ },
+ mounted: function (...args) {
+ console.info('mounted', args);
+ },
+});
+
+// Get the Element of layer by name
+console.info(art.layers['potser']);
+
+Removal
+
+You can remove layers by name using the layers.remove method. This example shows removing a layer after a delay:
+
+var img = '/assets/sample/layer.png';
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ layers: [
+ {
+ name: 'potser',
+ html: `
`,
+ style: {
+ position: 'absolute',
+ top: '50px',
+ right: '50px',
+ },
+ },
+ ],
+});
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Delete the layer by name
+ art.layers.remove('potser');
+ }, 3000);
+});
+
+Update
+
+You can update existing layers by name using the layers.update method. This example shows updating a layer's properties after a delay:
+
+var img = '/assets/sample/layer.png';
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ layers: [
+ {
+ name: 'potser',
+ html: `
`,
+ style: {
+ position: 'absolute',
+ top: '50px',
+ right: '50px',
+ },
+ },
+ ],
+});
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Update the layer by name
+ art.layers.update({
+ name: 'potser',
+ html: `
`,
+ style: {
+ position: 'absolute',
+ top: '50px',
+ left: '50px',
+ },
+ });
+ }, 3000);
+});
+
+Settings Panel
+
+Built-in Settings
+
+To use the settings panel, first enable it by setting 'setting: true'. The panel includes four built-in items: flip, playbackRate, aspectRatio, and subtitleOffset.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ flip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ subtitleOffset: true,
+});
+
+Creating a Button
+
+Properties for button creation:
+html: String or Element - The DOM element
+icon: String or Element - The icon element
+onClick: Function - Click event handler
+width: Number - List width
+tooltip: String - Tooltip text
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'Button',
+ icon: '
',
+ tooltip: 'tooltip',
+ onClick(item, $dom, event) {
+ console.info(item, $dom, event);
+ return 'new tooltip'
+ }
+ },
+ ],
+});
+
+Creating a Selector List
+
+Properties for selector list:
+html: String or Element - The DOM element
+icon: String or Element - The icon element
+selector: Array - List of options
+onSelect: Function - Selection event handler
+width: Number - List width
+tooltip: String - Tooltip text
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'Subtitle',
+ width: 250,
+ tooltip: 'Subtitle 01',
+ selector: [
+ {
+ default: true,
+ html: 'Subtitle 01',
+ url: '/assets/sample/subtitle.srt?id=1',
+ },
+ {
+ html: 'Subtitle 02',
+ url: '/assets/sample/subtitle.srt?id=2',
+ },
+ ],
+ onSelect: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ art.subtitle.url = item.url;
+ return item.html;
+ },
+ },
+ {
+ html: 'Quality',
+ width: 150,
+ tooltip: '1080P',
+ selector: [
+ {
+ default: true,
+ html: '1080P',
+ url: '/assets/sample/video.mp4?id=1080',
+ },
+ {
+ html: '720P',
+ url: '/assets/sample/video.mp4?id=720',
+ },
+ {
+ html: '360P',
+ url: '/assets/sample/video.mp4?id=360',
+ },
+ ],
+ onSelect: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ art.switchQuality(item.url, item.html);
+ return item.html;
+ },
+ },
+ ],
+});
+
+Creating a Nested List
+
+This example shows how to create multi-level nested settings.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'Multi-level',
+ selector: [
+ {
+ html: 'Setting 01',
+ width: 150,
+ selector: [
+ {
+ html: 'Setting 01 - 01',
+ },
+ {
+ html: 'Setting 01 - 02',
+ },
+ ],
+ onSelect: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ return item.html;
+ },
+ },
+ {
+ html: 'Setting 02',
+ width: 150,
+ selector: [
+ {
+ html: 'Setting 02 - 01',
+ },
+ {
+ html: 'Setting 02 - 02',
+ },
+ ],
+ onSelect: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ return item.html;
+ },
+ },
+ ],
+ },
+ ],
+});
+
+Creating a Toggle Button
+
+Properties for toggle button:
+html: String or Element - DOM element of the item
+icon: String or Element - Icon of the item
+switch: Boolean - Default state of the button
+onSwitch: Function - Button toggle event handler
+tooltip: String - Tooltip text
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'PIP Mode',
+ tooltip: 'Close',
+ icon: '
',
+ switch: false,
+ onSwitch: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ const nextState = !item.switch;
+ art.pip = nextState;
+ item.tooltip = nextState ? 'Open' : 'Close';
+ return nextState;
+ },
+ },
+ ],
+});
+
+Creating a Range Slider
+
+Properties for range slider:
+html: String or Element - DOM element of the item
+icon: String or Element - Icon of the item
+range: Array - Default state array [value, min, max, step]
+onRange: Function - Event triggered on completion
+onChange: Function - Event triggered on change
+tooltip: String - Tooltip text
+
+The range array format: [value, min, max, step]
+For example: [5, 1, 10, 1] means value=5, min=1, max=10, step=1
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'Slider',
+ tooltip: '5x',
+ icon: '
',
+ range: [5, 1, 10, 1],
+ onChange: function (item, $dom, event) {
+ console.info(item, $dom, event);
+ return item.range[0] + 'x';
+ },
+ },
+ ],
+});
+
+Adding Settings Dynamically
+
+You can add settings after initialization using the add method.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+});
+
+art.setting.show = true;
+
+art.setting.add({
+ html: 'Slider',
+ tooltip: '5x',
+ icon: '
',
+ range: [5, 1, 10, 1],
+});
+
+Removing Settings
+
+Settings can be removed by their name using the remove method.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ flip: true,
+ settings: [
+ {
+ name: 'slider',
+ html: 'Slider',
+ tooltip: '5x',
+ icon: '
',
+ range: [5, 1, 10, 1],
+ },
+ ],
+});
+
+art.setting.show = true;
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Delete the setting by name
+ art.setting.remove('slider');
+ }, 3000);
+});
+
+Updating Settings
+
+Existing settings can be updated using the update method with the setting name.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ name: 'slider',
+ html: 'Slider',
+ tooltip: '5x',
+ icon: '
',
+ range: [5, 1, 10, 1],
+ },
+ ],
+});
+
+art.setting.show = true;
+
+art.on('ready', () => {
+ setTimeout(() => {
+ // Update the setting by name
+ art.setting.update({
+ name: 'slider',
+ html: 'PIP Mode',
+ tooltip: 'Close',
+ icon: '
',
+ switch: false,
+ });
+ }, 3000);
+});
+
+To help an AI model learn ArtPlayer, here is the reorganized documentation in a clean, plain text format.
+
+ArtPlayer Documentation
+
+Introduction
+
+ArtPlayer is a modern, feature-rich HTML5 video player with a highly customizable UI. It supports a wide range of video formats and offers extensive configuration options for developers.
+
+Installation
+
+You can install ArtPlayer via npm or include it directly from a CDN.
+
+Using npm:
+npm install artplayer
+
+Using CDN:
+
+
+
+Basic Usage
+
+Here is a simple example to get started with ArtPlayer. Create a container element in your HTML and initialize the player with JavaScript.
+
+HTML:
+
+
+JavaScript:
+var art = new Artplayer({
+ container: '#art-player',
+ url: 'path/to/video.mp4',
+});
+
+Configuration Options
+
+ArtPlayer offers various configuration options to customize the player's behavior and appearance. Below are some commonly used options.
+
+Option: url
+Description: Specifies the video source URL.
+Example:
+url: 'https://example.com/sample-video.mp4'
+
+Option: volume
+Description: Sets the initial volume level, from 0 to 1.
+Example:
+volume: 0.8
+
+Option: autoplay
+Description: Enables or disables autoplay.
+Example:
+autoplay: true
+
+Option: pip
+Description: Enables or disables picture-in-picture mode.
+Example:
+pip: true
+
+Option: screenshot
+Description: Enables or disables screenshot functionality.
+Example:
+screenshot: true
+
+Option: theme
+Description: Sets the player's theme color.
+Example:
+theme: '#ffad00'
+
+Option: hotkey
+Description: Enables or disables keyboard shortcuts.
+Example:
+hotkey: true
+
+Option: fullscreen
+Description: Enables or disables fullscreen mode.
+Example:
+fullscreen: true
+
+Option: subtitle
+Description: Configures subtitle settings.
+Example:
+subtitle: {
+ url: 'path/to/subtitle.vtt',
+ style: {
+ color: '#fff',
+ },
+}
+
+Option: moreVideoAttr
+Description: Sets additional video attributes.
+Example:
+moreVideoAttr: {
+ crossOrigin: 'anonymous',
+}
+
+Events
+
+ArtPlayer provides events to handle various player interactions. You can use these to execute code in response to player actions.
+
+Example: Ready event
+Description: Triggered when the player is ready.
+Code:
+art.on('ready', () => {
+ console.log('Player is ready');
+});
+
+Example: Play event
+Description: Triggered when the video starts playing.
+Code:
+art.on('play', () => {
+ console.log('Video is playing');
+});
+
+Example: Pause event
+Description: Triggered when the video is paused.
+Code:
+art.on('pause', () => {
+ console.log('Video is paused');
+});
+
+Example: Destroy event
+Description: Triggered when the player is destroyed.
+Code:
+art.on('destroy', () => {
+ console.log('Player is destroyed');
+});
+
+Methods
+
+ArtPlayer includes methods to control the player programmatically. Here are some essential methods.
+
+Method: play
+Description: Starts video playback.
+Example:
+art.play();
+
+Method: pause
+Description: Pauses the video.
+Example:
+art.pause();
+
+Method: destroy
+Description: Destroys the player instance and cleans up resources.
+Example:
+art.destroy();
+
+Components
+
+You can customize the player by adding or modifying components. Below is an example of adding a custom control.
+
+Example: Adding a custom control
+Description: Adds a button to toggle playback speed.
+Code:
+art.controls.add({
+ name: 'speed',
+ position: 'right',
+ html: 'Speed',
+ click: function () {
+ const speeds = [1, 1.5, 2];
+ const current = art.playbackRate;
+ const index = speeds.indexOf(current);
+ const next = speeds[(index + 1) % speeds.length];
+ art.playbackRate = next;
+ },
+});
+
+This documentation covers the basics of ArtPlayer. For more advanced features and detailed API references, please refer to the official documentation.
+
+Installation
+
+You can install ArtPlayer using various package managers or include it directly via script tag.
+
+Using npm:
+npm install artplayer
+
+Using yarn:
+yarn add artplayer
+
+Using pnpm:
+pnpm add artplayer
+
+Using script tag:
+
+
+CDN
+
+You can also use CDN links for quick setup.
+
+From jsdelivr.net:
+https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
+
+From unpkg.com:
+https://unpkg.com/artplayer/dist/artplayer.js
+
+Usage
+
+Here is a basic HTML example to get started with ArtPlayer.
+
+
+
+
`,
+ style: {
+ position: 'absolute',
+ top: '20px',
+ right: '20px',
+ opacity: '.9',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ art.layers.show = false;
+ },
+ mounted: function (...args) {
+ console.info('mounted', args);
+ },
+ },
+ ],
+});
+
+For Component Configuration, please refer to: /component/layers.html
+
+settings
+Type: Array
+Default: []
+Initialize custom Settings Panel.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ settings: [
+ {
+ html: 'setting01',
+ selector: [
+ {
+ html: 'setting01-01',
+ },
+ {
+ html: 'setting01-02',
+ },
+ ],
+ onSelect: function (...args) {
+ console.info(args);
+ },
+ },
+ {
+ html: 'setting02',
+ selector: [
+ {
+ html: 'setting02-01',
+ },
+ {
+ html: 'setting02-02',
+ },
+ ],
+ onSelect: function (...args) {
+ console.info(args);
+ },
+ },
+ ],
+});
+
+For Settings Panel, please refer to: /component/setting.html
+
+contextmenu
+Type: Array
+Default: []
+Initialize custom Context Menu.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ contextmenu: [
+ {
+ html: 'your-menu',
+ click: function (...args) {
+ console.info('click', args);
+ art.contextmenu.show = false;
+ },
+ },
+ ],
+});
+
+For Component Configuration, please refer to: /component/contextmenu.html
+
+controls
+Type: Array
+Default: []
+Initialize custom bottom control bar.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ controls: [
+ {
+ position: 'left',
+ html: 'your-control',
+ tooltip: 'Your Control',
+ style: {
+ color: 'green',
+ },
+ click: function (...args) {
+ console.info('click', args);
+ },
+ },
+ ],
+});
+
+For component configuration, please refer to: /component/controls.html
+
+quality
+Type: Array
+Default: []
+Whether to display the quality selection list in the bottom control bar.
+
+Property Type Description
+default Boolean Default quality
+html String Quality name
+url String Quality URL
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ quality: [
+ {
+ default: true,
+ html: 'SD 480P',
+ url: '/assets/sample/video.mp4',
+ },
+ {
+ html: 'HD 720P',
+ url: '/assets/sample/video.mp4',
+ },
+ ],
+});
+
+highlight
+Type: Array
+Default: []
+Display highlight information on the progress bar.
+
+Property Type Description
+time Number Highlight time (in seconds)
+text String Highlight text
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ highlight: [
+ {
+ time: 60,
+ text: 'One more chance',
+ },
+ {
+ time: 120,
+ text: '谁でもいいはずなのに',
+ },
+ {
+ time: 180,
+ text: '夏の想い出がまわる',
+ },
+ {
+ time: 240,
+ text: 'こんなとこにあるはずもないのに',
+ },
+ {
+ time: 300,
+ text: '--终わり--',
+ },
+ ],
+});
+
+plugins
+Type: Array
+Default: []
+Initialize custom plugins.
+
+function myPlugin(art) {
+ console.info(art);
+ return {
+ name: 'myPlugin',
+ something: 'something',
+ doSomething: function () {
+ console.info('doSomething');
+ },
+ };
+}
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [myPlugin],
+});
+
+thumbnails
+Type: Object
+Default: {}
+Set thumbnails on the progress bar.
+
+Property Type Description
+url String Thumbnail URL
+number Number Number of thumbnails
+column Number Number of columns
+width Number Thumbnail width
+height Number Thumbnail height
+scale Number Thumbnail scale
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ },
+});
+
+Generate thumbnails online: artplayer-tool-thumbnail
+
+subtitle
+Type: Object
+Default: {}
+Set video subtitles, supported subtitle formats: vtt, srt, ass.
+
+Property Type Description
+name String Subtitle name
+url String Subtitle URL
+type String Subtitle type, options: vtt, srt, ass
+style Object Subtitle style
+encoding String Subtitle encoding, defaults to utf-8
+escape Boolean Whether to escape html tags, defaults to true
+onVttLoad Function Function used to modify vtt text
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ subtitle: {
+ url: '/assets/sample/subtitle.srt',
+ type: 'srt',
+ encoding: 'utf-8',
+ escape: true,
+ style: {
+ color: '#03A9F4',
+ 'font-size': '30px',
+ },
+ },
+});
+
+moreVideoAttr
+Type: Object
+Default: {'controls': false,'preload': 'metadata'}
+More video attributes, these attributes will be directly written into the video element.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ moreVideoAttr: {
+ 'webkit-playsinline': true,
+ playsInline: true,
+ },
+});
+
+icons
+Type: Object
+Default: {}
+Used to replace default icons, supports Html string and HTMLElement.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ icons: {
+ loading: '
',
+ state: '
',
+ },
+});
+
+All Icon Definitions: artplayer/types/icons.d.ts
+
+type
+Type: String
+Default: ''
+Used to specify the video format, needs to be used together with customType. The default video format is the suffix of the video URL (e.g., .m3u8, .mkv, .ts). However, sometimes the video URL does not have the correct suffix, so it needs to be explicitly specified.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.m3u8',
+ type: 'm3u8',
+});
+
+Suffix Recognition: The player can only parse suffixes like this: /assets/sample/video.m3u8. But cannot parse suffixes like this: /assets/sample/video?type=m3u8. Therefore, if you use customType, it is best to also specify type.
+
+customType
+Type: Object
+Default: {}
+Matches via the video's type and delegates video decoding to a third-party program for processing. The processing function can receive three parameters: video (Video DOM element), url (Video URL), art (Current instance).
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.m3u8',
+ customType: {
+ m3u8: function (video, url, art) {
+ //
+ },
+ },
+});
+
+lang
+Type: String
+Default: navigator.language.toLowerCase()
+Default display language, currently supports: en, zh-cn.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ lang: 'en',
+});
+
+More Language Settings: /start/i18n.html
+
+i18n
+Type: Object
+Default: {}
+Custom i18n configuration, this configuration will be deeply merged with the built-in i18n.
+
+Add your language:
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ lang: 'your-lang',
+ i18n: {
+ 'your-lang': {
+ Play: 'Your
+
+
+
+===== Type Definitions Overview =====
+
+artplayer-plugin-ads.d.ts
+
+This plugin provides advertising functionality for ArtPlayer, allowing insertion of video, image, or HTML ads with configurable timing and playback options.
+
+interface Option {
+ /**
+ * 广告源文本,支持视频链接、图片链接、HTML文本
+ */
+ source: string
+
+ /**
+ * 知名广告的类型:'video' | 'image' | 'html'
+ */
+ type: 'video' | 'image' | 'html'
+
+ /**
+ * 广告必看的时长,单位为秒
+ */
+ playDuration?: number
+
+ /**
+ * 广告总的时长,单位为秒
+ */
+ totalDuration?: number
+
+ /**
+ * 视频广告是否默认静音
+ */
+ muted?: boolean
+}
+
+interface Ads {
+ name: 'artplayerPluginAds'
+
+ /**
+ * 跳过广告
+ */
+ skip: () => void
+
+ /**
+ * 暂停广告
+ */
+ pause: () => void
+
+ /**
+ * 播放广告
+ */
+ play: () => void
+}
+
+declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
+
+export default artplayerPluginAds
+
+export = artplayerPluginAds
+export as namespace artplayerPluginAds;
+
+artplayer-plugin-ambilight.d.ts
+
+This plugin creates ambient lighting effects around the video player that match the video content.
+
+interface Option {
+ blur?: string
+ opacity?: number
+ frequency?: number
+ zIndex?: number
+ duration?: number
+}
+
+interface Result {
+ name: 'artplayerPluginAmbilight'
+ start: () => void
+ stop: () => void
+}
+
+declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
+
+export default artplayerPluginAmbilight
+
+export = artplayerPluginAmbilight
+export as namespace artplayerPluginAmbilight;
+
+artplayer-plugin-asr.d.ts
+
+This plugin provides automatic speech recognition (ASR) functionality for generating subtitles from audio.
+
+interface AudioChunk {
+ pcm: ArrayBuffer
+ wav: ArrayBuffer
+}
+
+interface AsrPluginOption {
+ length?: number
+ interval?: number
+ sampleRate?: number
+ autoHideTimeout?: number
+ onAudioChunk?: (chunk: AudioChunk) => void | Promise
',
+
+ // 视频广告的地址
+ video: '/assets/sample/test1.mp4',
+
+ // 广告跳转网址,为空则不跳转
+ url: 'http://artplayer.org',
+
+ // 必须观看的时长,期间不能被跳过,单位为秒
+ // 当该值大于或等于totalDuration时,不能提前关闭广告
+ // 当该值等于或小于0时,则随时都可以关闭广告
+ playDuration: 5,
+
+ // 广告总时长,单位为秒
+ totalDuration: 10,
+
+ // 多语言支持
+ i18n: {
+ close: '关闭广告',
+ countdown: '%s秒',
+ detail: '查看详情',
+ canBeClosed: '%s秒后可关闭广告',
+ },
+ }),
+ ],
+})
+
+// 广告被点击
+art.on('artplayerPluginAds:click', (ads) => {
+ console.info('广告被点击', ads)
+})
+
+// 广告被跳过
+art.on('artplayerPluginAds:skip', (ads) => {
+ console.info('广告被跳过', ads)
+})
+
+ambilight.js example:
+This example shows how to create ambient lighting effects around the video player using the artplayer-plugin-ambilight plugin with customizable blur, opacity, frequency, and duration settings.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ plugins: [
+ artplayerPluginAmbilight({
+ blur: '50px',
+ opacity: 1,
+ frequency: 10,
+ duration: 0.3,
+ }),
+ ],
+})
+
+asr.js example:
+This example demonstrates automatic speech recognition integration using WebSocket connections to convert audio chunks to subtitles in real-time during video playback.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/steve-jobs.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ moreVideoAttr: {
+ // crossOrigin: 'anonymous',
+ },
+ plugins: [
+ artplayerPluginAsr({
+ length: 2,
+ interval: 40,
+ sampleRate: 16000,
+ autoHideTimeout: 10000,
+ // Use your AI tool to convert pcm into subtitles
+ onAudioChunk: ({ pcm }) => startAsr(pcm),
+ }),
+ ],
+})
+
+let ws = null
+let loading = false
+
+function stopAsr() {
+ try {
+ ws.send(JSON.stringify({ type: 'end' }))
+ ws.close()
+ }
+ catch {}
+ ws = null
+ loading = false
+}
+
+async function startAsr(buffer) {
+ if (loading)
+ return
+ if (!ws) {
+ loading = true
+ const api = 'https://api.aimu.app/asr/tencent?engine_model_type=16k_en'
+ const { url } = await (await fetch(api)).json()
+ ws = new WebSocket(url)
+ ws.binaryType = 'arraybuffer'
+ ws.onmessage = (event) => {
+ const { code, result, message } = JSON.parse(event.data)
+ if (code === 0) {
+ art.plugins.artplayerPluginAsr.append(result?.voice_text_str)
+ }
+ else {
+ console.error(code, message)
+ stopAsr()
+ }
+ }
+ loading = false
+ }
+ if (ws?.readyState === WebSocket.OPEN) {
+ ws.send(buffer)
+ }
+}
+
+art.on('destroy', stopAsr)
+
+auto.thumbnail.js example:
+This example shows automatic thumbnail generation for video scrubbing using the artplayer-plugin-auto-thumbnail plugin with default configuration.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginAutoThumbnail({
+ //
+ }),
+ ],
+})
+
+canvas.js example:
+This example demonstrates advanced video manipulation using canvas proxy for features like screenshots, thumbnails, and various playback controls with artplayer-proxy-canvas integration.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ volume: 0.5,
+ autoplay: false,
+ autoSize: false,
+ screenshot: true,
+ setting: true,
+ loop: true,
+ flip: true,
+ pip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoPlayback: true,
+ autoOrientation: true,
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.85,
+ },
+ proxy: artplayerProxyCanvas(),
+})
+
+chapter.js example:
+This example shows video chapter segmentation with defined time ranges and titles using the artplayer-plugin-chapter plugin for enhanced navigation.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoOrientation: true,
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ },
+ plugins: [
+ artplayerPluginChapter({
+ chapters: [
+ { start: 0, end: 18, title: 'One more chance' },
+ { start: 18, end: 36, title: '谁でもいいはずなのに' },
+ { start: 36, end: 54, title: '夏の想い出がまわる' },
+ { start: 54, end: 72, title: 'こんなとこにあるはずもないのに' },
+ { start: 72, end: Infinity, title: '终わり' },
+ ],
+ }),
+ ],
+})
+
+chromecast.js example:
+This example demonstrates Google Chromecast integration for casting video content to external devices using the artplayer-plugin-chromecast plugin.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ plugins: [
+ artplayerPluginChromecast({
+ // sdk: '', // The URL of the Cast SDK
+ // mimeType: '', // The MIME type of the media
+ }),
+ ],
+})
+
+danmuku.js example:
+This example shows comprehensive danmaku (bullet chat) functionality with extensive configuration options for appearance, behavior, and filtering using artplayer-plugin-danmuku.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ autoOrientation: true,
+ plugins: [
+ artplayerPluginDanmuku({
+ danmuku: '/assets/sample/danmuku.xml',
+
+ // 以下为非必填
+ speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
+ margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
+ opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
+ color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
+ mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
+ modes: [0, 1, 2], // 弹幕可见的模式
+ fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
+ antiOverlap: true, // 弹幕是否防重叠
+ synchronousPlayback: false, // 是否同步播放速度
+ mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
+ heatmap: true, // 是否开启热力图
+ width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
+ points: [], // 热力图数据
+ filter: danmu => danmu.text.length <= 100, // 弹幕载入前的过滤器
+ beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
+ visible: true, // 弹幕层是否可见
+ emitter: true, // 是否开启弹幕发射器
+ maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
+ lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
+ theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
+ OPACITY: {}, // 不透明度配置项
+ FONT_SIZE: {}, // 弹幕字号配置项
+ MARGIN: {}, // 显示区域配置项
+ SPEED: {}, // 弹幕速度配置项
+ COLOR: [], // 颜色列表配置项
+
+ // 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
+ beforeEmit(danmu) {
+ return new Promise((resolve) => {
+ console.log(danmu)
+ setTimeout(() => {
+ resolve(true)
+ }, 1000)
+ })
+ },
+ }),
+ ],
+})
+
+danmuku.mask.js example:
+This example combines danmaku functionality with selfie segmentation masking using artplayer-plugin-danmuku-mask to create background-aware bullet chat displays.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ autoSize: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ autoOrientation: true,
+ plugins: [
+ artplayerPluginDanmuku({
+ danmuku: '/assets/sample/danmuku.xml',
+ }),
+ artplayerPluginDanmukuMask({
+ solutionPath: '/assets/@mediapipe/selfie_segmentation',
+ }),
+ ],
+})
+
+dash.control.js example:
+This example demonstrates DASH (Dynamic Adaptive Streaming over HTTP) video streaming integration using dashjs library with artplayer-plugin-dash-control for adaptive bitrate streaming.
+
+// npm i dashjs
+// npm i artplayer-plugin-dash-control
+
+// import dashjs from 'dashjs';
+// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
+
+Example 1: ArtPlayer with DASH.js and custom quality/audio controls
+This example shows how to integrate ArtPlayer with DASH.js for MPEG-DASH streaming and uses the artplayerPluginDashControl plugin to add quality selection and audio track controls.
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
+ setting: true,
+ plugins: [
+ artplayerPluginDashControl({
+ quality: {
+ // Show qualitys in control
+ control: true,
+ // Show qualitys in setting
+ setting: true,
+ // Get the quality name from level
+ getName: level => `${level.height}P`,
+ // I18n
+ title: 'Quality',
+ auto: 'Auto',
+ },
+ audio: {
+ // Show audios in control
+ control: true,
+ // Show audios in setting
+ setting: true,
+ // Get the audio name from track
+ getName: track => track.lang.toUpperCase(),
+ // I18n
+ title: 'Audio',
+ auto: 'Auto',
+ },
+ }),
+ ],
+ customType: {
+ mpd: function playMpd(video, url, art) {
+ if (dashjs.supportsMediaSource()) {
+ if (art.dash)
+ art.dash.destroy()
+ const dash = dashjs.MediaPlayer().create()
+ dash.initialize(video, url, art.option.autoplay)
+ art.dash = dash
+ art.on('destroy', () => dash.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: mpd'
+ }
+ },
+ },
+})
+
+===== dash.js =====
+
+Example 2: Basic DASH.js integration
+This example demonstrates a simpler DASH.js implementation with ArtPlayer, showing how to handle MPEG-DASH streams with custom type handlers and accessing the DASH player instance.
+
+// npm i dashjs
+// import dashjs from 'dashjs';
+
+function playMpd(video, url, art) {
+ if (dashjs.supportsMediaSource()) {
+ if (art.dash)
+ art.dash.destroy()
+ const dash = dashjs.MediaPlayer().create()
+ dash.initialize(video, url, art.option.autoplay)
+ art.dash = dash
+ art.on('destroy', () => dash.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: mpd'
+ }
+}
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
+ type: 'mpd',
+ customType: {
+ mpd: playMpd,
+ },
+})
+
+art.on('ready', () => {
+ console.info(art.dash)
+})
+
+===== document.pip.js =====
+
+Example 3: Document Picture-in-Picture plugin
+This example shows how to use the artplayerPluginDocumentPip plugin to enable Document Picture-in-Picture mode with custom dimensions and fallback options.
+
+// npm i artplayer-plugin-document-pip
+// import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginDocumentPip({
+ width: 480,
+ height: 270,
+ fallbackToVideoPiP: true,
+ placeholder: `Playing in Document Picture-in-Picture`,
+ }),
+ ],
+})
+
+art.on('document-pip', (state) => {
+ console.log('Document Picture-in-Picture', state)
+})
+
+===== flv.js =====
+
+Example 4: FLV.js integration
+This example demonstrates how to integrate FLV.js with ArtPlayer for FLV video playback, including proper cleanup on player destruction.
+
+// npm i flv.js
+// import flvjs from 'flv.js';
+
+function playFlv(video, url, art) {
+ if (flvjs.isSupported()) {
+ if (art.flv)
+ art.flv.destroy()
+ const flv = flvjs.createPlayer({ type: 'flv', url })
+ flv.attachMediaElement(video)
+ flv.load()
+ art.flv = flv
+ art.on('destroy', () => flv.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: flv'
+ }
+}
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.flv',
+ type: 'flv',
+ customType: {
+ flv: playFlv,
+ },
+})
+
+art.on('ready', () => {
+ console.info(art.flv)
+})
+
+===== hls.control.js =====
+
+Example 5: HLS.js with quality and audio controls
+This example shows HLS.js integration with the artplayerPluginHlsControl plugin, providing quality selection and audio track controls for HLS streams.
+
+// npm i hls.js
+// npm i artplayer-plugin-hls-control
+
+// import Hls from 'hls.js';
+// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
+ setting: true,
+ plugins: [
+ artplayerPluginHlsControl({
+ quality: {
+ // Show qualitys in control
+ control: true,
+ // Show qualitys in setting
+ setting: true,
+ // Get the quality name from level
+ getName: level => `${level.height}P`,
+ // I18n
+ title: 'Quality',
+ auto: 'Auto',
+ },
+ audio: {
+ // Show audios in control
+ control: true,
+ // Show audios in setting
+ setting: true,
+ // Get the audio name from track
+ getName: track => track.name,
+ // I18n
+ title: 'Audio',
+ auto: 'Auto',
+ },
+ }),
+ ],
+ customType: {
+ m3u8: function playM3u8(video, url, art) {
+ if (Hls.isSupported()) {
+ if (art.hls)
+ art.hls.destroy()
+ const hls = new Hls()
+ hls.loadSource(url)
+ hls.attachMedia(video)
+ art.hls = hls
+ art.on('destroy', () => hls.destroy())
+ }
+ else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = url
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: m3u8'
+ }
+ },
+ },
+})
+
+===== hls.js =====
+
+Example 6: Basic HLS.js integration
+This example shows a simpler HLS.js implementation with ArtPlayer, handling both native HLS support and HLS.js fallback for broader browser compatibility.
+
+// npm i hls.js
+// import Hls from 'hls.js';
+
+function playM3u8(video, url, art) {
+ if (Hls.isSupported()) {
+ if (art.hls)
+ art.hls.destroy()
+ const hls = new Hls()
+ hls.loadSource(url)
+ hls.attachMedia(video)
+ art.hls = hls
+ art.on('destroy', () => hls.destroy())
+ }
+ else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = url
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: m3u8'
+ }
+}
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
+ type: 'm3u8',
+ customType: {
+ m3u8: playM3u8,
+ },
+})
+
+art.on('ready', () => {
+ console.info(art.hls)
+})
+
+===== iframe.js =====
+
+Example 7: Iframe integration plugin
+This example demonstrates how to use the ArtplayerPluginIframe to embed ArtPlayer within an iframe and handle cross-frame communication for fullscreen functionality.
+
+// npm i artplayer-plugin-iframe
+// import ArtplayerPluginIframe from 'artplayer-plugin-iframe';
+
+const $iframe = document.createElement('iframe')
+$iframe.allowFullscreen = true
+$iframe.width = '100%'
+$iframe.height = '100%'
+
+const $container = document.querySelector('.artplayer-app')
+$container.innerHTML = ''
+$container.appendChild($iframe)
+
+const iframe = new ArtplayerPluginIframe({
+ iframe: $iframe,
+ url: '/iframe.html',
+})
+
+iframe.message(({ type, data }) => {
+ switch (type) {
+ case 'fullscreenWeb':
+ if (data) {
+ $iframe.classList.add('fullscreenWeb')
+ }
+ else {
+ $iframe.classList.remove('fullscreenWeb')
+ }
+ break
+ default:
+ break
+ }
+})
+
+iframe.commit(() => {
+ const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ })
+
+ art.on('fullscreenWeb', (state) => {
+ ArtplayerPluginIframe.postMessage({
+ type: 'fullscreenWeb',
+ data: state,
+ })
+ })
+})
+
+===== index.js =====
+
+Example 8: Basic ArtPlayer setup
+This appears to be a placeholder for a basic ArtPlayer configuration file, typically used as the main entry point for simple video player implementations.
+
+Example 1: Basic ArtPlayer Configuration
+This example shows a comprehensive ArtPlayer setup with multiple features enabled, including custom settings, context menu, layers, quality options, thumbnails, subtitles, highlights, and custom controls.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ volume: 0.5,
+ isLive: false,
+ muted: false,
+ autoplay: false,
+ pip: true,
+ autoSize: true,
+ autoMini: true,
+ screenshot: true,
+ setting: true,
+ loop: true,
+ flip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ subtitleOffset: true,
+ miniProgressBar: true,
+ mutex: true,
+ backdrop: true,
+ playsInline: true,
+ autoPlayback: true,
+ airplay: true,
+ theme: '#23ade5',
+ lang: navigator.language.toLowerCase(),
+ moreVideoAttr: {
+ crossOrigin: 'anonymous',
+ },
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ tooltip: 'Bilingual',
+ icon: '',
+ selector: [
+ {
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: 'Bilingual',
+ url: '/assets/sample/subtitle.srt',
+ },
+ {
+ html: 'Chinese',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ html: 'Japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
+ },
+ {
+ html: 'Switcher',
+ icon: '
',
+ tooltip: 'OFF',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'OFF' : 'ON'
+ console.info('You clicked on the custom switch', item.switch)
+ return !item.switch
+ },
+ },
+ {
+ html: 'Slider',
+ icon: '
',
+ tooltip: '5x',
+ range: [5, 1, 10, 0.1],
+ onRange(item) {
+ return `${item.range[0]}x`
+ },
+ },
+ {
+ html: 'Button',
+ icon: '
',
+ tooltip: 'tooltip',
+ onClick() {
+ return 'Button clicked'
+ },
+ },
+ ],
+ contextmenu: [
+ {
+ html: 'Custom menu',
+ click(contextmenu) {
+ console.info('You clicked on the custom menu')
+ contextmenu.show = false
+ },
+ },
+ ],
+ layers: [
+ {
+ html: '
',
+ click() {
+ window.open('https://aimu.app')
+ console.info('You clicked on the custom layer')
+ },
+ style: {
+ position: 'absolute',
+ top: '20px',
+ right: '20px',
+ opacity: '.9',
+ },
+ },
+ ],
+ quality: [
+ {
+ default: true,
+ html: 'SD 480P',
+ url: '/assets/sample/video.mp4?q=480',
+ },
+ {
+ html: 'HD 720P',
+ url: '/assets/sample/video.mp4?q=720',
+ },
+ ],
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.85,
+ },
+ subtitle: {
+ url: '/assets/sample/subtitle.srt',
+ type: 'srt',
+ style: {
+ color: '#fe9200',
+ fontSize: '20px',
+ },
+ encoding: 'utf-8',
+ },
+ highlight: [
+ {
+ time: 15,
+ text: 'One more chance',
+ },
+ {
+ time: 30,
+ text: '谁でもいいはずなのに',
+ },
+ {
+ time: 45,
+ text: '夏の想い出がまわる',
+ },
+ {
+ time: 60,
+ text: 'こんなとこにあるはずもないのに',
+ },
+ {
+ time: 75,
+ text: '终わり',
+ },
+ ],
+ controls: [
+ {
+ position: 'right',
+ html: 'Control',
+ index: 1,
+ tooltip: 'Control Tooltip',
+ style: {
+ marginRight: '20px',
+ },
+ click() {
+ console.info('You clicked on the custom control')
+ },
+ },
+ ],
+ icons: {
+ loading: '
',
+ state: '',
+ indicator: '
',
+ },
+})
+
+===== libass.js =====
+
+Example 2: Libass Plugin Integration
+This example demonstrates how to integrate the libass plugin for advanced ASS subtitle support, including event handling for subtitle operations.
+
+// npm i artplayer-plugin-libass
+// import artplayerPluginLibass from 'artplayer-plugin-libass';
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreenWeb: true,
+ subtitle: {
+ url: '/assets/sample/style-test.ass',
+ },
+ plugins: [
+ artplayerPluginLibass({
+ // debug: true,
+ workerUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.js',
+ // wasmUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.wasm',
+ fallbackFont: '/assets/misc/SourceHanSansCN-Bold.woff2',
+ }),
+ ],
+})
+
+// init
+art.on('artplayerPluginLibass:init', (adapter) => {
+ console.info('artplayerPluginLibass:init', adapter)
+})
+
+// subtitle switch
+art.on('artplayerPluginLibass:switch', (url) => {
+ console.info('artplayerPluginLibass:switch', url)
+})
+
+// subtitle visible
+art.on('artplayerPluginLibass:visible', (visible) => {
+ console.info('artplayerPluginLibass:visible', visible)
+})
+
+// subtitle timeOffset
+art.on('artplayerPluginLibass:timeOffset', (timeOffset) => {
+ console.info('artplayerPluginLibass:timeOffset', timeOffset)
+})
+
+// destroy
+art.on('artplayerPluginLibass:destroy', () => {
+ console.info('artplayerPluginLibass:destroy')
+})
+
+===== mobile.js =====
+
+Example 3: Mobile-Optimized Configuration
+This example shows a mobile-optimized ArtPlayer setup with mobile-specific attributes, auto-orientation, and Chinese language interface.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ poster: '/assets/sample/poster.jpg',
+ autoSize: true,
+ loop: true,
+ mutex: true,
+ setting: true,
+ flip: true,
+ lock: true,
+ fastForward: true,
+ playbackRate: true,
+ aspectRatio: true,
+ theme: '#ff0057',
+ fullscreen: true,
+ fullscreenWeb: true,
+ miniProgressBar: true,
+ autoOrientation: true,
+ airplay: true,
+ moreVideoAttr: {
+ 'x5-video-player-type': 'h5',
+ 'x5-video-player-fullscreen': false,
+ 'x5-video-orientation': 'portraint',
+ 'preload': 'metadata',
+ },
+ thumbnails: {
+ url: '/assets/sample/thumbnails.png',
+ number: 60,
+ column: 10,
+ scale: 0.6,
+ },
+ subtitle: {
+ name: '中日双语',
+ url: '/assets/sample/subtitle.srt',
+ style: {
+ color: '#48aff0',
+ fontSize: '16px',
+ },
+ },
+ layers: [
+ {
+ html: `
`,
+ click() {
+ art.notice.show = '你点击了自定义层'
+ },
+ style: {
+ position: 'absolute',
+ top: '10px',
+ right: '10px',
+ opacity: '.9',
+ },
+ },
+ ],
+ icons: {
+ loading: '
',
+ state: '',
+ indicator: '
',
+ },
+ settings: [
+ {
+ width: 200,
+ html: '切换字幕',
+ tooltip: '双语',
+ icon: '
',
+ selector: [
+ {
+ html: '开关',
+ switch: true,
+ tooltip: '显示',
+ onSwitch(item) {
+ item.tooltip = item.switch ? '隐藏' : '显示'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: '双语',
+ url: '/assets/sample/subtitle.srt',
+ },
+ {
+ html: '中文',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ html: '日文',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
+ },
+ ],
+})
+
+===== mpegts.js =====
+
+Example 4: FLV Playback with mpegts.js
+This example demonstrates how to integrate mpegts.js for FLV video playback support with proper cleanup and media element attachment.
+
+// npm i mpegts
+// import mpegts from 'mpegts';
+
+function playFlv(video, url, art) {
+ if (mpegts.isSupported()) {
+ if (art.flv)
+ art.flv.destroy()
+
+ const flv = mpegts.createPlayer({
+ type: 'flv',
+ url,
+ })
+ flv.attachMediaElement(video)
+ flv.load()
+ flv.play()
+
+Example: flv.js
+This example demonstrates how to play FLV format videos using a custom type handler with ArtPlayer. It shows integration with an external FLV library and proper cleanup on player destruction.
+
+function playFlv(video, url, art) {
+ if (flvjs.isSupported()) {
+ const flv = flvjs.createPlayer({ type: 'flv', url })
+ flv.attachMediaElement(video)
+ flv.load()
+ art.flv = flv
+ art.on('destroy', () => flv.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: flv'
+ }
+}
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.flv',
+ type: 'flv',
+ customType: {
+ flv: playFlv,
+ },
+})
+
+art.on('ready', () => {
+ console.info(art.flv)
+})
+
+===== multiple.subtitles.js =====
+
+Example: Multiple Subtitles Plugin
+This example shows how to use the multiple subtitles plugin with ArtPlayer, featuring bilingual subtitles, custom styling, and interactive settings for subtitle management.
+
+// npm i artplayer-plugin-multiple-subtitles
+// import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ plugins: [
+ artplayerPluginMultipleSubtitles({
+ subtitles: [
+ {
+ name: 'chinese',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ name: 'japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ }),
+ ],
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ tooltip: 'Double',
+ icon: '
',
+ selector: [
+ {
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ // 显示/隐藏字幕
+ // Show/hide subtitles
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ html: 'Reverse',
+ tooltip: 'Off',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Off' : 'On'
+ // 修改字幕顺序
+ // Change the order of subtitles
+ if (item.switch) {
+ art.plugins.multipleSubtitles.tracks(['chinese', 'japanese'])
+ }
+ else {
+ art.plugins.multipleSubtitles.tracks(['japanese', 'chinese'])
+ }
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: 'Double',
+ name: 'double',
+ },
+ {
+ html: 'Chinese',
+ name: 'chinese',
+ },
+ {
+ html: 'Japanese',
+ name: 'japanese',
+ },
+ ],
+ onSelect(item) {
+ if (item.name === 'double') {
+ // 重置字幕
+ // Reset subtitles
+ art.plugins.multipleSubtitles.reset()
+ }
+ else {
+ // 显示单个字幕
+ // Show single subtitle
+ art.plugins.multipleSubtitles.tracks([item.name])
+ }
+ return item.html
+ },
+ },
+ ],
+})
+
+// 自定义你自己的样式,请勿复制以下代码
+// Customize your own style, please do not copy the following code
+
+const style = `
+.art-subtitle-chinese {
+ color: red;
+ font-size: 18px;
+}
+
+.art-subtitle-japanese {
+ color: yellow;
+ font-size: 12px;
+}
+`
+
+const $style = document.getElementById('artplayer-subtitle-style')
+if ($style) {
+ $style.textContent = style
+}
+else {
+ const $style = document.createElement('style')
+ $style.id = 'artplayer-subtitle-style'
+ $style.textContent = style
+ document.head.appendChild($style)
+}
+
+===== setting.test.js =====
+
+Example: Settings API Testing
+This example demonstrates comprehensive testing of ArtPlayer's settings API, including custom settings, dynamic updates, and error handling for various setting types.
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ setting: true,
+ flip: true,
+ playbackRate: true,
+ aspectRatio: true,
+ subtitleOffset: true,
+ settings: [
+ {
+ width: 200,
+ html: 'Subtitle',
+ name: 'subtitle',
+ tooltip: 'Bilingual',
+ icon: '
',
+ selector: [
+ {
+ html: 'Display',
+ tooltip: 'Show',
+ switch: true,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'Hide' : 'Show'
+ art.subtitle.show = !item.switch
+ return !item.switch
+ },
+ },
+ {
+ default: true,
+ html: 'Bilingual',
+ url: '/assets/sample/subtitle.srt',
+ },
+ {
+ html: 'Chinese',
+ url: '/assets/sample/subtitle.cn.srt',
+ },
+ {
+ html: 'Japanese',
+ url: '/assets/sample/subtitle.jp.srt',
+ },
+ ],
+ onSelect(item) {
+ art.subtitle.switch(item.url, {
+ name: item.html,
+ })
+ return item.html
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ {
+ html: 'Switcher',
+ icon: '
',
+ tooltip: 'OFF',
+ switch: false,
+ onSwitch(item) {
+ item.tooltip = item.switch ? 'OFF' : 'ON'
+ console.info('You clicked on the custom switch', item.switch)
+ return !item.switch
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ {
+ html: 'Slider',
+ icon: '
',
+ tooltip: '5x',
+ range: [5, 1, 10, 0.1],
+ onRange(item) {
+ return `${item.range[0]}x`
+ },
+ mounted(...args) {
+ console.info(args)
+ },
+ },
+ ],
+}, async () => {
+ const { sleep } = Artplayer.utils
+ art.setting.show = true
+ console.log(art.setting.builtin)
+ console.log(art.setting.find('aspect-ratio'))
+ console.log(art.setting.find('aspect-ratio2'))
+ await sleep(1000)
+ art.setting.resize()
+ await sleep(1000)
+ art.setting.inactivate(art.setting.find('subtitle'))
+ art.setting.remove('aspect-ratio')
+ try {
+ art.setting.remove('aspect-ratio2')
+ }
+ catch (error) {
+ console.log(error.message)
+ }
+ await sleep(1000)
+ art.setting.update({
+ name: 'subtitle-offset',
+ html: 'new offset',
+ range: [5, -11, 11, 1],
+ })
+ await sleep(1000)
+ art.setting.find('subtitle-offset').range = [0, -0, 10, 1]
+ await sleep(1000)
+ art.setting.update({
+ name: 'subtitle-offset2',
+ html: 'new offset 2',
+ range: [5, -11, 11, 1],
+ onChange(item) {
+ return `${item.range[0]}s`
+ },
+ })
+ await sleep(1000)
+ art.setting.update({
+ name: 'flip',
+ html: 'new flip',
+ tooltip: 'OFF',
+ switch: false,
+ })
+ await sleep(1000)
+ art.setting.find('flip').switch = true
+ await sleep(1000)
+ art.setting.update({
+ name: 'flip2',
+ html: 'new flip2',
+ tooltip: 'OFF',
+ switch: true,
+ })
+ await sleep(1000)
+ try {
+ art.setting.add({
+ name: 'flip2',
+ html: 'new flip2',
+ tooltip: 'OFF',
+ switch: true,
+ })
+ }
+ catch (error) {
+ console.log(error.message)
+ }
+})
+
+===== thumbnail.js =====
+
+Example: Thumbnail Plugin
+This example demonstrates the thumbnail preview plugin for ArtPlayer, showing hover-based video thumbnails with customizable size and quantity.
+
+// npm i artplayer-plugin-thumbnail
+// import artplayerPluginThumbnail from 'artplayer-plugin-thumbnail';
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ plugins: [
+ artplayerPluginThumbnail({
+ width: 160,
+ number: 100,
+ scale: 1,
+ }),
+ ],
+})
+
+===== vast.js =====
+
+Example: VAST Advertising Plugin
+This example shows integration with VAST advertising using Google IMA SDK, demonstrating ad playback triggered by video play events.
+
+// Depends on:
+// https://glomex.github.io/vast-ima-player/
+// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side
+
+// Google's IMA SDK are blocked by your Ad blocker.
+// Please Turn Off Your Ad Blocker.
+
+// npm i artplayer-plugin-vast
+// import artplayerPluginVast from 'artplayer-plugin-vast';
+
+var art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/video.mp4',
+ fullscreen: true,
+ fullscreenWeb: true,
+ plugins: [
+ artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
+ // Play the ad when the video is played
+ art.once('play', () => {
+ playUrl('https://artplayer.org/assets/vast/linear-ad.xml')
+ })
+ }),
+ ],
+})
+
+===== vtt.thumbnail.js =====
+
+Example: VTT Thumbnail Plugin
+This example demonstrates using WebVTT files for thumbnail generation, showing how to display thumbnails from a VTT file during video playback.
+
+// npm i artplayer-plugin-vtt-thumbnail
+// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: '/assets/sample/bbb-video.mp4',
+ plugins: [
+ artplayerPluginVttThumbnail({
+ vtt: '/assets/sample/bbb-thumbnails.vtt',
+ }),
+ ],
+})
+
+===== webtorrent.js =====
+
+Example: WebTorrent Integration
+This example shows the setup for WebTorrent integration with ArtPlayer, enabling torrent-based video streaming (implementation details would follow).
+
+// npm i webtorrent
+// import WebTorrent from 'webtorrent';
+
+Full example code:
+
+async function playTorrent(video, url, art) {
+ if (WebTorrent.WEBRTC_SUPPORT) {
+ if (art.torrent)
+ art.torrent.destroy()
+ art.torrent = new WebTorrent()
+
+ await navigator.serviceWorker.register('/webtorrent.sw.min.js')
+ art.torrent.loadWorker(navigator.serviceWorker.controller)
+
+ art.torrent.add(url, (torrent) => {
+ const file = torrent.files.find((file) => {
+ return file.name.endsWith('.mp4')
+ })
+ file.streamTo(video)
+ })
+
+ art.on('destroy', () => art.torrent.destroy())
+ }
+ else {
+ art.notice.show = 'Unsupported playback format: torrent'
+ }
+}
+
+const art = new Artplayer({
+ container: '.artplayer-app',
+ url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
+ type: 'torrent',
+ customType: {
+ torrent: playTorrent,
+ },
+})
+
+art.on('ready', () => {
+ console.info(art.torrent)
+})
+
+This example demonstrates WebTorrent integration with ArtPlayer, showing how to stream torrent content directly in the video player. The playTorrent function checks for WebRTC support, initializes WebTorrent, registers a service worker, and streams MP4 files from torrents to the video element. The ArtPlayer configuration uses a magnet URI as the video source and defines a custom 'torrent' type that calls the playTorrent function. The ready event listener logs the torrent instance when the player is initialized. Key APIs used include WebTorrent for torrent streaming, ArtPlayer's customType for custom video handlers, and the player's event system for lifecycle management.
\ No newline at end of file
diff --git a/docs/uncompiled/artplayer/index.js b/docs/uncompiled/artplayer/index.js
index 7bf25be13..018cd12d3 100644
--- a/docs/uncompiled/artplayer/index.js
+++ b/docs/uncompiled/artplayer/index.js
@@ -428,7 +428,7 @@ if (_utils.isBrowser) {
}
},{"bundle-text:./style/index.less":"bFGMG","option-validator":"9hUEm","../package.json":"3r4tp","./config":"1dlGA","./contextmenu":"dx7Zz","./control":"cNVpy","./events":"dQzlM","./hotkey":"drylQ","./i18n":"3Jf1s","./icons":"avFu3","./info":"gvEup","./layer":"7Oas9","./loading":"glZdQ","./mask":"iGxU6","./notice":"jZEIz","./player":"iA4EC","./plugins":"6P64r","./scheme":"8YPbR","./setting":"7ATN8","./storage":"grHII","./subtitle":"hxr0l","./template":"5JwMQ","./utils":"gGxPm","./utils/emitter":"2qvfs","@parcel/transformer-js/src/esmodule-helpers.js":"8oCsH"}],"bFGMG":[function(require,module,exports,__globalThis) {
-module.exports = ".art-video-player {\n --art-theme: red;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: #00000080;\n --art-transition-duration: .2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: #ffffff40;\n --art-hover-color: #ffffff40;\n --art-loaded-color: #ffffff40;\n --art-state-size: 80px;\n --art-state-opacity: .8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: #ffffff80;\n --art-control-height: 46px;\n --art-control-opacity: .75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: #000000d9;\n --art-tip-background: #000000b3;\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: #ffffff40;\n --art-scrollbar-background-hover: #ffffff80;\n --art-mini-progress-height: 2px;\n}\n\n.art-bg-cover {\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, #0006, #0000);\n background-position: bottom;\n background-repeat: repeat-x;\n}\n\n.art-backdrop-filter {\n backdrop-filter: saturate(180%) blur(20px);\n background-color: #000000bf !important;\n}\n\n.art-truncate {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.art-video-player {\n zoom: 1;\n text-align: left;\n user-select: none;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n -webkit-tap-highlight-color: #0000;\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n direction: ltr;\n outline: 0;\n margin: 0 auto;\n padding: 0;\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.3;\n position: relative;\n}\n\n.art-video-player *, .art-video-player :before, .art-video-player :after {\n box-sizing: border-box;\n}\n\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n\n.art-video-player img {\n vertical-align: top;\n max-width: 100%;\n}\n\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n\n.art-icon {\n justify-content: center;\n align-items: center;\n line-height: 1;\n display: flex;\n}\n\n.art-video-player.art-backdrop .art-contextmenus, .art-video-player.art-backdrop .art-info, .art-video-player.art-backdrop .art-settings, .art-video-player.art-backdrop .art-layer-auto-playback, .art-video-player.art-backdrop .art-selector-list, .art-video-player.art-backdrop .art-volume-inner {\n backdrop-filter: saturate(180%) blur(20px);\n background-color: #000000bf !important;\n}\n\n.art-video {\n z-index: 10;\n cursor: pointer;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-poster {\n z-index: 11;\n pointer-events: none;\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-subtitle {\n z-index: 20;\n text-align: center;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n gap: var(--art-subtitle-gap);\n width: 100%;\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n flex-direction: column;\n padding: 0 5%;\n display: none;\n position: absolute;\n}\n\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n\n.art-danmuku {\n z-index: 30;\n pointer-events: none;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.art-video-player .art-layers {\n z-index: 40;\n pointer-events: none;\n width: 100%;\n height: 100%;\n display: none;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n\n.art-video-player .art-mask {\n z-index: 50;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n display: flex;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-mask .art-state {\n opacity: 0;\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n justify-content: center;\n align-items: center;\n display: flex;\n transform: scale(2);\n}\n\n.art-video-player.art-mask-show .art-state {\n cursor: pointer;\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n\n.art-video-player .art-loading {\n z-index: 70;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n display: none;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n\n.art-video-player .art-bottom {\n z-index: 60;\n opacity: 0;\n pointer-events: none;\n width: 100%;\n height: 100%;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, #0006, #0000);\n background-position: bottom;\n background-repeat: repeat-x;\n flex-direction: column;\n justify-content: flex-end;\n display: flex;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.art-video-player .art-bottom .art-controls, .art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n\n.art-video-player.art-control-show .art-bottom, .art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n\n.art-video-player.art-control-show .art-bottom .art-controls, .art-video-player.art-hover .art-bottom .art-controls, .art-video-player.art-control-show .art-bottom .art-progress, .art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n\n.art-bottom .art-progress {\n z-index: 0;\n pointer-events: auto;\n padding-bottom: var(--art-bottom-gap);\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress {\n cursor: pointer;\n height: var(--art-progress-height);\n justify-content: center;\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n width: 100%;\n height: 50%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n z-index: 0;\n background-color: var(--art-hover-color);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n z-index: 10;\n background-color: var(--art-loaded-color);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n z-index: 20;\n background-color: var(--art-theme);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n z-index: 30;\n pointer-events: none;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n z-index: 0;\n pointer-events: auto;\n width: 100%;\n height: 100%;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--art-highlight-width) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n z-index: 40;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n display: flex;\n position: absolute;\n left: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n pointer-events: none;\n width: 100%;\n height: 100%;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n z-index: 50;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n padding: 3px 5px;\n font-size: 12px;\n line-height: 1;\n display: none;\n position: absolute;\n top: -25px;\n left: 0;\n}\n\n.art-bottom .art-progress .art-control-progress:hover .art-control-progress-inner {\n height: 100%;\n}\n\n.art-bottom .art-progress .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 10px);\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n display: none;\n position: absolute;\n left: 0;\n box-shadow: 0 1px 3px #0003, 0 1px 2px -1px #0003;\n}\n\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n\n.art-controls {\n z-index: 10;\n pointer-events: auto;\n height: var(--art-control-height);\n justify-content: space-between;\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-controls .art-controls-left, .art-controls .art-controls-right {\n height: 100%;\n display: flex;\n}\n\n.art-controls .art-controls-center {\n flex: 1;\n justify-content: center;\n align-items: center;\n height: 100%;\n padding: 0 10px;\n display: none;\n}\n\n.art-controls .art-controls-right {\n justify-content: flex-end;\n}\n\n.art-controls .art-control {\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n\n.art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * .8));\n}\n\n.art-controls .art-control:hover {\n opacity: 1;\n}\n\n.art-control-volume {\n position: relative;\n}\n\n.art-control-volume .art-volume-panel {\n text-align: center;\n cursor: default;\n opacity: 0;\n pointer-events: none;\n left: 0;\n right: 0;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n justify-content: center;\n align-items: center;\n padding: 0 5px;\n font-size: 12px;\n display: flex;\n position: absolute;\n transform: translateY(10px);\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner {\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n flex-direction: column;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 100%;\n padding: 10px 0 12px;\n display: flex;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n cursor: pointer;\n flex: 1;\n justify-content: center;\n width: 100%;\n display: flex;\n position: relative;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n border-radius: var(--art-border-radius);\n background-color: #ffffff40;\n justify-content: center;\n width: 2px;\n display: flex;\n position: relative;\n overflow: hidden;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n z-index: 0;\n background-color: var(--art-theme);\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n border-radius: 100%;\n flex-shrink: 0;\n position: absolute;\n transform: scale(1);\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(.9);\n}\n\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n.art-video-player .art-notice {\n z-index: 80;\n width: 100%;\n height: auto;\n padding: var(--art-padding);\n pointer-events: none;\n display: none;\n position: absolute;\n inset: 0 0 auto;\n}\n\n.art-video-player .art-notice .art-notice-inner {\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n padding: 5px;\n line-height: 1;\n display: inline-flex;\n}\n\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n\n.art-video-player .art-contextmenus {\n z-index: 120;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n flex-direction: column;\n padding: 5px 0;\n font-size: 12px;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n border-bottom: 1px solid #ffffff1a;\n padding: 10px 15px;\n display: flex;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu span:hover, .art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: #ffffff1a;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n\n.art-video-player .art-settings {\n z-index: 90;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n left: auto;\n right: var(--art-padding);\n bottom: var(--art-control-height);\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n flex-direction: column;\n display: none;\n position: absolute;\n overflow: hidden auto;\n}\n\n.art-video-player .art-settings .art-setting-panel {\n flex-direction: column;\n display: none;\n}\n\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n cursor: pointer;\n transition: background-color var(--art-transition-duration) ease;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n display: flex;\n overflow: hidden;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: #ffffff1a;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: #ffffff80;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n appearance: none;\n background-color: #fff3;\n outline: none;\n width: 80px;\n height: 3px;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid #ffffff1a;\n}\n\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n\n.art-video-player .art-info {\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n padding: 10px;\n font-size: 12px;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-info .art-info-panel {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item {\n align-items: center;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n text-align: right;\n width: 100px;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n width: 250px;\n overflow: hidden;\n}\n\n.art-video-player .art-info .art-info-close {\n cursor: pointer;\n position: absolute;\n top: 5px;\n right: 5px;\n}\n\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n\n.art-hide-cursor * {\n cursor: none !important;\n}\n\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n position: fixed;\n inset: 0;\n}\n\n.art-mini-popup {\n z-index: 9999;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n background: #000;\n width: 320px;\n height: 180px;\n transition: opacity .2s;\n position: fixed;\n overflow: hidden;\n box-shadow: 0 0 5px #00000080;\n}\n\n.art-mini-popup svg {\n fill: #fff;\n}\n\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n\n.art-mini-popup .art-mini-close {\n z-index: 20;\n cursor: pointer;\n opacity: 0;\n transition: opacity .2s;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n\n.art-mini-popup .art-mini-state {\n z-index: 30;\n pointer-events: none;\n opacity: 0;\n background-color: #00000040;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n transition: opacity .2s;\n display: flex;\n position: absolute;\n inset: 0;\n}\n\n.art-mini-popup .art-mini-state .art-icon {\n opacity: .75;\n cursor: pointer;\n pointer-events: auto;\n transition: transform .2s;\n transform: scale(3);\n}\n\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n\n.art-mini-popup.art-mini-dragging {\n opacity: .9;\n}\n\n.art-mini-popup:hover .art-mini-close, .art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n\n.art-video-player[data-flip=\"horizontal\"] .art-video {\n transform: scaleX(-1);\n}\n\n.art-video-player[data-flip=\"vertical\"] .art-video {\n transform: scaleY(-1);\n}\n\n.art-video-player .art-layer-lock {\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n top: 50%;\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n display: none;\n position: absolute;\n transform: translateY(-50%);\n}\n\n.art-video-player .art-layer-auto-playback {\n border-radius: var(--art-border-radius);\n left: var(--art-padding);\n bottom: calc(var(--art-control-height) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n align-items: center;\n gap: 10px;\n padding: 10px;\n line-height: 1;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n cursor: pointer;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom, .art-video-player.art-lock .art-bottom {\n opacity: 1;\n background-image: none;\n padding: 0;\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls, .art-video-player.art-lock .art-bottom .art-controls, .art-video-player.art-mini-progress-bar .art-bottom .art-progress, .art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-control-height) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator, .art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n\n.art-control-selector {\n justify-content: center;\n display: flex;\n position: relative;\n}\n\n.art-control-selector .art-selector-list {\n text-align: center;\n border-radius: var(--art-border-radius);\n opacity: 0;\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n flex-direction: column;\n align-items: center;\n display: flex;\n position: absolute;\n overflow: hidden auto;\n transform: translateY(10px);\n}\n\n.art-control-selector .art-selector-list .art-selector-item {\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n line-height: 1;\n display: flex;\n}\n\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: #ffffff1a;\n}\n\n.art-control-selector .art-selector-list .art-selector-item:hover, .art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n[class*=\"hint--\"] {\n font-style: normal;\n display: inline-block;\n position: relative;\n}\n\n[class*=\"hint--\"]:before, [class*=\"hint--\"]:after {\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n transition: all .3s;\n position: absolute;\n transform: translate3d(0, 0, 0);\n}\n\n[class*=\"hint--\"]:hover:before, [class*=\"hint--\"]:hover:after {\n visibility: visible;\n opacity: 1;\n transition-delay: .1s;\n}\n\n[class*=\"hint--\"]:before {\n content: \"\";\n z-index: 1000001;\n background: none;\n border: 6px solid #0000;\n position: absolute;\n}\n\n[class*=\"hint--\"]:after {\n color: #fff;\n white-space: nowrap;\n background: #000;\n padding: 8px 10px;\n font-family: Helvetica Neue, Helvetica, Arial, sans-serif;\n font-size: 12px;\n line-height: 12px;\n}\n\n[class*=\"hint--\"][aria-label]:after {\n content: attr(aria-label);\n}\n\n[class*=\"hint--\"][data-hint]:after {\n content: attr(data-hint);\n}\n\n[aria-label=\"\"]:before, [aria-label=\"\"]:after, [data-hint=\"\"]:before, [data-hint=\"\"]:after {\n display: none !important;\n}\n\n.hint--top-left:before, .hint--top-right:before, .hint--top:before {\n border-top-color: #000;\n}\n\n.hint--bottom-left:before, .hint--bottom-right:before, .hint--bottom:before {\n border-bottom-color: #000;\n}\n\n.hint--left:before {\n border-left-color: #000;\n}\n\n.hint--right:before {\n border-right-color: #000;\n}\n\n.hint--top:before {\n margin-bottom: -11px;\n}\n\n.hint--top:before, .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top:before {\n left: calc(50% - 6px);\n}\n\n.hint--top:after {\n transform: translateX(-50%);\n}\n\n.hint--top:hover:before {\n transform: translateY(-8px);\n}\n\n.hint--top:hover:after {\n transform: translateX(-50%)translateY(-8px);\n}\n\n.hint--bottom:before {\n margin-top: -11px;\n}\n\n.hint--bottom:before, .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom:after {\n transform: translateX(-50%);\n}\n\n.hint--bottom:hover:before {\n transform: translateY(8px);\n}\n\n.hint--bottom:hover:after {\n transform: translateX(-50%)translateY(8px);\n}\n\n.hint--right:before {\n margin-bottom: -6px;\n margin-left: -11px;\n}\n\n.hint--right:after {\n margin-bottom: -14px;\n}\n\n.hint--right:before, .hint--right:after {\n bottom: 50%;\n left: 100%;\n}\n\n.hint--right:hover:before, .hint--right:hover:after {\n transform: translateX(8px);\n}\n\n.hint--left:before {\n margin-bottom: -6px;\n margin-right: -11px;\n}\n\n.hint--left:after {\n margin-bottom: -14px;\n}\n\n.hint--left:before, .hint--left:after {\n bottom: 50%;\n right: 100%;\n}\n\n.hint--left:hover:before, .hint--left:hover:after {\n transform: translateX(-8px);\n}\n\n.hint--top-left:before {\n margin-bottom: -11px;\n}\n\n.hint--top-left:before, .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top-left:before {\n left: calc(50% - 6px);\n}\n\n.hint--top-left:after {\n margin-left: 12px;\n transform: translateX(-100%);\n}\n\n.hint--top-left:hover:before {\n transform: translateY(-8px);\n}\n\n.hint--top-left:hover:after {\n transform: translateX(-100%)translateY(-8px);\n}\n\n.hint--top-right:before {\n margin-bottom: -11px;\n}\n\n.hint--top-right:before, .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top-right:before {\n left: calc(50% - 6px);\n}\n\n.hint--top-right:after {\n margin-left: -12px;\n transform: translateX(0);\n}\n\n.hint--top-right:hover:before, .hint--top-right:hover:after {\n transform: translateY(-8px);\n}\n\n.hint--bottom-left:before {\n margin-top: -11px;\n}\n\n.hint--bottom-left:before, .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom-left:after {\n margin-left: 12px;\n transform: translateX(-100%);\n}\n\n.hint--bottom-left:hover:before {\n transform: translateY(8px);\n}\n\n.hint--bottom-left:hover:after {\n transform: translateX(-100%)translateY(8px);\n}\n\n.hint--bottom-right:before {\n margin-top: -11px;\n}\n\n.hint--bottom-right:before, .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom-right:after {\n margin-left: -12px;\n transform: translateX(0);\n}\n\n.hint--bottom-right:hover:before, .hint--bottom-right:hover:after {\n transform: translateY(8px);\n}\n\n.hint--small:after, .hint--medium:after, .hint--large:after {\n white-space: normal;\n word-wrap: break-word;\n line-height: 1.4em;\n}\n\n.hint--small:after {\n width: 80px;\n}\n\n.hint--medium:after {\n width: 150px;\n}\n\n.hint--large:after {\n width: 300px;\n}\n\n[class*=\"hint--\"]:after {\n text-shadow: 0 -1px #000;\n box-shadow: 4px 4px 8px #0000004d;\n}\n\n.hint--error:after {\n text-shadow: 0 -1px #592726;\n background-color: #b34e4d;\n}\n\n.hint--error.hint--top-left:before, .hint--error.hint--top-right:before, .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n\n.hint--error.hint--bottom-left:before, .hint--error.hint--bottom-right:before, .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n\n.hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n\n.hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n\n.hint--warning:after {\n text-shadow: 0 -1px #6c5328;\n background-color: #c09854;\n}\n\n.hint--warning.hint--top-left:before, .hint--warning.hint--top-right:before, .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n\n.hint--warning.hint--bottom-left:before, .hint--warning.hint--bottom-right:before, .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n\n.hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n\n.hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n\n.hint--info:after {\n text-shadow: 0 -1px #1a3c4d;\n background-color: #3986ac;\n}\n\n.hint--info.hint--top-left:before, .hint--info.hint--top-right:before, .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n\n.hint--info.hint--bottom-left:before, .hint--info.hint--bottom-right:before, .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n\n.hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n\n.hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n\n.hint--success:after {\n text-shadow: 0 -1px #1a321a;\n background-color: #458746;\n}\n\n.hint--success.hint--top-left:before, .hint--success.hint--top-right:before, .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n\n.hint--success.hint--bottom-left:before, .hint--success.hint--bottom-right:before, .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n\n.hint--success.hint--left:before {\n border-left-color: #458746;\n}\n\n.hint--success.hint--right:before {\n border-right-color: #458746;\n}\n\n.hint--always:after, .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n\n.hint--always.hint--top:before {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--top:after {\n transform: translateX(-50%)translateY(-8px);\n}\n\n.hint--always.hint--top-left:before {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--top-left:after {\n transform: translateX(-100%)translateY(-8px);\n}\n\n.hint--always.hint--top-right:before, .hint--always.hint--top-right:after {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--bottom:before {\n transform: translateY(8px);\n}\n\n.hint--always.hint--bottom:after {\n transform: translateX(-50%)translateY(8px);\n}\n\n.hint--always.hint--bottom-left:before {\n transform: translateY(8px);\n}\n\n.hint--always.hint--bottom-left:after {\n transform: translateX(-100%)translateY(8px);\n}\n\n.hint--always.hint--bottom-right:before, .hint--always.hint--bottom-right:after {\n transform: translateY(8px);\n}\n\n.hint--always.hint--left:before, .hint--always.hint--left:after {\n transform: translateX(-8px);\n}\n\n.hint--always.hint--right:before, .hint--always.hint--right:after {\n transform: translateX(8px);\n}\n\n.hint--rounded:after {\n border-radius: 4px;\n}\n\n.hint--no-animate:before, .hint--no-animate:after {\n transition-duration: 0s;\n}\n\n.hint--bounce:before, .hint--bounce:after {\n -webkit-transition: opacity .3s, visibility .3s, -webkit-transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n -moz-transition: opacity .3s, visibility .3s, -moz-transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n transition: opacity .3s, visibility .3s, transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n}\n\n.hint--no-shadow:before, .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n\n.hint--no-arrow:before {\n display: none;\n}\n\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n";
+module.exports = ".art-video-player {\n --art-theme: red;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: #00000080;\n --art-transition-duration: .2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: #ffffff40;\n --art-progress-top-gap: 8px;\n --art-hover-color: #ffffff40;\n --art-loaded-color: #ffffff40;\n --art-state-size: 80px;\n --art-state-opacity: .8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: #ffffff80;\n --art-control-height: 46px;\n --art-control-opacity: .75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: #000000d9;\n --art-tip-background: #000000b3;\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: #ffffff40;\n --art-scrollbar-background-hover: #ffffff80;\n --art-mini-progress-height: 2px;\n}\n\n.art-bg-cover {\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, #0006, #0000);\n background-position: bottom;\n background-repeat: repeat-x;\n}\n\n.art-backdrop-filter {\n backdrop-filter: saturate(180%) blur(20px);\n background-color: #000000bf !important;\n}\n\n.art-truncate {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.art-video-player {\n zoom: 1;\n text-align: left;\n user-select: none;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n -webkit-tap-highlight-color: #0000;\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n direction: ltr;\n outline: 0;\n margin: 0 auto;\n padding: 0;\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.3;\n position: relative;\n}\n\n.art-video-player *, .art-video-player :before, .art-video-player :after {\n box-sizing: border-box;\n}\n\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n\n.art-video-player img {\n vertical-align: top;\n max-width: 100%;\n}\n\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n\n.art-icon {\n justify-content: center;\n align-items: center;\n line-height: 1;\n display: flex;\n}\n\n.art-video-player.art-backdrop .art-contextmenus, .art-video-player.art-backdrop .art-info, .art-video-player.art-backdrop .art-settings, .art-video-player.art-backdrop .art-layer-auto-playback, .art-video-player.art-backdrop .art-selector-list, .art-video-player.art-backdrop .art-volume-inner {\n backdrop-filter: saturate(180%) blur(20px);\n background-color: #000000bf !important;\n}\n\n.art-video {\n z-index: 10;\n cursor: pointer;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-poster {\n z-index: 11;\n pointer-events: none;\n background-position: center;\n background-repeat: no-repeat;\n background-size: cover;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-subtitle {\n z-index: 20;\n text-align: center;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n gap: var(--art-subtitle-gap);\n width: 100%;\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n flex-direction: column;\n padding: 0 5%;\n display: none;\n position: absolute;\n}\n\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n\n.art-danmuku {\n z-index: 30;\n pointer-events: none;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.art-video-player .art-layers {\n z-index: 40;\n pointer-events: none;\n width: 100%;\n height: 100%;\n display: none;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n\n.art-video-player .art-mask {\n z-index: 50;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n display: flex;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player .art-mask .art-state {\n opacity: 0;\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n justify-content: center;\n align-items: center;\n display: flex;\n transform: scale(2);\n}\n\n.art-video-player.art-mask-show .art-state {\n cursor: pointer;\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n\n.art-video-player .art-loading {\n z-index: 70;\n pointer-events: none;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n display: none;\n position: absolute;\n inset: 0;\n}\n\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n\n.art-video-player .art-bottom {\n z-index: 60;\n opacity: 0;\n pointer-events: none;\n width: 100%;\n height: 100%;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, #0006, #0000);\n background-position: bottom;\n background-repeat: repeat-x;\n flex-direction: column;\n justify-content: flex-end;\n display: flex;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.art-video-player .art-bottom .art-controls, .art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n\n.art-video-player.art-control-show .art-bottom, .art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n\n.art-video-player.art-control-show .art-bottom .art-controls, .art-video-player.art-hover .art-bottom .art-controls, .art-video-player.art-control-show .art-bottom .art-progress, .art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n\n.art-bottom .art-progress {\n z-index: 0;\n pointer-events: auto;\n padding-top: var(--art-progress-top-gap);\n padding-bottom: var(--art-bottom-gap);\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress {\n cursor: pointer;\n height: var(--art-progress-height);\n justify-content: center;\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n width: 100%;\n height: 50%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n z-index: 0;\n background-color: var(--art-hover-color);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n z-index: 10;\n background-color: var(--art-loaded-color);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n z-index: 20;\n background-color: var(--art-theme);\n width: 0%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n z-index: 30;\n pointer-events: none;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n z-index: 0;\n pointer-events: auto;\n width: 100%;\n height: 100%;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n position: absolute;\n inset: 0 auto 0 0;\n width: var(--art-highlight-width) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n z-index: 40;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n display: flex;\n position: absolute;\n left: 0;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n pointer-events: none;\n width: 100%;\n height: 100%;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n z-index: 50;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n padding: 3px 5px;\n font-size: 12px;\n line-height: 1;\n display: none;\n position: absolute;\n top: -25px;\n left: 0;\n}\n\n.art-bottom .art-progress .art-control-progress:hover .art-control-progress-inner {\n height: 100%;\n}\n\n.art-bottom .art-progress .art-control-thumbnails {\n bottom: calc(var(--art-bottom-gap) + 10px);\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n display: none;\n position: absolute;\n left: 0;\n box-shadow: 0 1px 3px #0003, 0 1px 2px -1px #0003;\n}\n\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n\n.art-controls {\n z-index: 10;\n pointer-events: auto;\n height: var(--art-control-height);\n justify-content: space-between;\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.art-controls .art-controls-left, .art-controls .art-controls-right {\n height: 100%;\n display: flex;\n}\n\n.art-controls .art-controls-center {\n flex: 1;\n justify-content: center;\n align-items: center;\n height: 100%;\n padding: 0 10px;\n display: none;\n}\n\n.art-controls .art-controls-right {\n justify-content: flex-end;\n}\n\n.art-controls .art-control {\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n\n.art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * .8));\n}\n\n.art-controls .art-control:hover {\n opacity: 1;\n}\n\n.art-control-volume {\n position: relative;\n}\n\n.art-control-volume .art-volume-panel {\n text-align: center;\n cursor: default;\n opacity: 0;\n pointer-events: none;\n left: 0;\n right: 0;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n justify-content: center;\n align-items: center;\n padding: 0 5px;\n font-size: 12px;\n display: flex;\n position: absolute;\n transform: translateY(10px);\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner {\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n flex-direction: column;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 100%;\n padding: 10px 0 12px;\n display: flex;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n cursor: pointer;\n flex: 1;\n justify-content: center;\n width: 100%;\n display: flex;\n position: relative;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n border-radius: var(--art-border-radius);\n background-color: #ffffff40;\n justify-content: center;\n width: 2px;\n display: flex;\n position: relative;\n overflow: hidden;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n z-index: 0;\n background-color: var(--art-theme);\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n border-radius: 100%;\n flex-shrink: 0;\n position: absolute;\n transform: scale(1);\n}\n\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(.9);\n}\n\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n.art-video-player .art-notice {\n z-index: 80;\n width: 100%;\n height: auto;\n padding: var(--art-padding);\n pointer-events: none;\n display: none;\n position: absolute;\n inset: 0 0 auto;\n}\n\n.art-video-player .art-notice .art-notice-inner {\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n padding: 5px;\n line-height: 1;\n display: inline-flex;\n}\n\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n\n.art-video-player .art-contextmenus {\n z-index: 120;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n flex-direction: column;\n padding: 5px 0;\n font-size: 12px;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n border-bottom: 1px solid #ffffff1a;\n padding: 10px 15px;\n display: flex;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu span:hover, .art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: #ffffff1a;\n}\n\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n\n.art-video-player .art-settings {\n z-index: 90;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n left: auto;\n right: var(--art-padding);\n bottom: var(--art-control-height);\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n flex-direction: column;\n display: none;\n position: absolute;\n overflow: hidden auto;\n}\n\n.art-video-player .art-settings .art-setting-panel {\n flex-direction: column;\n display: none;\n}\n\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n cursor: pointer;\n transition: background-color var(--art-transition-duration) ease;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n display: flex;\n overflow: hidden;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: #ffffff1a;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: #ffffff80;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n display: flex;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n appearance: none;\n background-color: #fff3;\n outline: none;\n width: 80px;\n height: 3px;\n}\n\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid #ffffff1a;\n}\n\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n\n.art-video-player .art-info {\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n padding: 10px;\n font-size: 12px;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-info .art-info-panel {\n flex-direction: column;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item {\n align-items: center;\n gap: 5px;\n display: flex;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n text-align: right;\n width: 100px;\n}\n\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n width: 250px;\n overflow: hidden;\n}\n\n.art-video-player .art-info .art-info-close {\n cursor: pointer;\n position: absolute;\n top: 5px;\n right: 5px;\n}\n\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n\n.art-hide-cursor * {\n cursor: none !important;\n}\n\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n position: fixed;\n inset: 0;\n}\n\n.art-mini-popup {\n z-index: 9999;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n background: #000;\n width: 320px;\n height: 180px;\n transition: opacity .2s;\n position: fixed;\n overflow: hidden;\n box-shadow: 0 0 5px #00000080;\n}\n\n.art-mini-popup svg {\n fill: #fff;\n}\n\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n\n.art-mini-popup .art-mini-close {\n z-index: 20;\n cursor: pointer;\n opacity: 0;\n transition: opacity .2s;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n\n.art-mini-popup .art-mini-state {\n z-index: 30;\n pointer-events: none;\n opacity: 0;\n background-color: #00000040;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n transition: opacity .2s;\n display: flex;\n position: absolute;\n inset: 0;\n}\n\n.art-mini-popup .art-mini-state .art-icon {\n opacity: .75;\n cursor: pointer;\n pointer-events: auto;\n transition: transform .2s;\n transform: scale(3);\n}\n\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n\n.art-mini-popup.art-mini-dragging {\n opacity: .9;\n}\n\n.art-mini-popup:hover .art-mini-close, .art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n\n.art-video-player[data-flip=\"horizontal\"] .art-video {\n transform: scaleX(-1);\n}\n\n.art-video-player[data-flip=\"vertical\"] .art-video {\n transform: scaleY(-1);\n}\n\n.art-video-player .art-layer-lock {\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n top: 50%;\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n display: none;\n position: absolute;\n transform: translateY(-50%);\n}\n\n.art-video-player .art-layer-auto-playback {\n border-radius: var(--art-border-radius);\n left: var(--art-padding);\n bottom: calc(var(--art-control-height) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n align-items: center;\n gap: 10px;\n padding: 10px;\n line-height: 1;\n display: none;\n position: absolute;\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n cursor: pointer;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom, .art-video-player.art-lock .art-bottom {\n opacity: 1;\n background-image: none;\n padding: 0;\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls, .art-video-player.art-lock .art-bottom .art-controls, .art-video-player.art-mini-progress-bar .art-bottom .art-progress, .art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-control-height) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator, .art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n\n.art-control-selector {\n justify-content: center;\n display: flex;\n position: relative;\n}\n\n.art-control-selector .art-selector-list {\n text-align: center;\n border-radius: var(--art-border-radius);\n opacity: 0;\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n flex-direction: column;\n align-items: center;\n display: flex;\n position: absolute;\n overflow: hidden auto;\n transform: translateY(10px);\n}\n\n.art-control-selector .art-selector-list .art-selector-item {\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n line-height: 1;\n display: flex;\n}\n\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: #ffffff1a;\n}\n\n.art-control-selector .art-selector-list .art-selector-item:hover, .art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n[class*=\"hint--\"] {\n font-style: normal;\n display: inline-block;\n position: relative;\n}\n\n[class*=\"hint--\"]:before, [class*=\"hint--\"]:after {\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n transition: all .3s;\n position: absolute;\n transform: translate3d(0, 0, 0);\n}\n\n[class*=\"hint--\"]:hover:before, [class*=\"hint--\"]:hover:after {\n visibility: visible;\n opacity: 1;\n transition-delay: .1s;\n}\n\n[class*=\"hint--\"]:before {\n content: \"\";\n z-index: 1000001;\n background: none;\n border: 6px solid #0000;\n position: absolute;\n}\n\n[class*=\"hint--\"]:after {\n color: #fff;\n white-space: nowrap;\n background: #000;\n padding: 8px 10px;\n font-family: Helvetica Neue, Helvetica, Arial, sans-serif;\n font-size: 12px;\n line-height: 12px;\n}\n\n[class*=\"hint--\"][aria-label]:after {\n content: attr(aria-label);\n}\n\n[class*=\"hint--\"][data-hint]:after {\n content: attr(data-hint);\n}\n\n[aria-label=\"\"]:before, [aria-label=\"\"]:after, [data-hint=\"\"]:before, [data-hint=\"\"]:after {\n display: none !important;\n}\n\n.hint--top-left:before, .hint--top-right:before, .hint--top:before {\n border-top-color: #000;\n}\n\n.hint--bottom-left:before, .hint--bottom-right:before, .hint--bottom:before {\n border-bottom-color: #000;\n}\n\n.hint--left:before {\n border-left-color: #000;\n}\n\n.hint--right:before {\n border-right-color: #000;\n}\n\n.hint--top:before {\n margin-bottom: -11px;\n}\n\n.hint--top:before, .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top:before {\n left: calc(50% - 6px);\n}\n\n.hint--top:after {\n transform: translateX(-50%);\n}\n\n.hint--top:hover:before {\n transform: translateY(-8px);\n}\n\n.hint--top:hover:after {\n transform: translateX(-50%)translateY(-8px);\n}\n\n.hint--bottom:before {\n margin-top: -11px;\n}\n\n.hint--bottom:before, .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom:after {\n transform: translateX(-50%);\n}\n\n.hint--bottom:hover:before {\n transform: translateY(8px);\n}\n\n.hint--bottom:hover:after {\n transform: translateX(-50%)translateY(8px);\n}\n\n.hint--right:before {\n margin-bottom: -6px;\n margin-left: -11px;\n}\n\n.hint--right:after {\n margin-bottom: -14px;\n}\n\n.hint--right:before, .hint--right:after {\n bottom: 50%;\n left: 100%;\n}\n\n.hint--right:hover:before, .hint--right:hover:after {\n transform: translateX(8px);\n}\n\n.hint--left:before {\n margin-bottom: -6px;\n margin-right: -11px;\n}\n\n.hint--left:after {\n margin-bottom: -14px;\n}\n\n.hint--left:before, .hint--left:after {\n bottom: 50%;\n right: 100%;\n}\n\n.hint--left:hover:before, .hint--left:hover:after {\n transform: translateX(-8px);\n}\n\n.hint--top-left:before {\n margin-bottom: -11px;\n}\n\n.hint--top-left:before, .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top-left:before {\n left: calc(50% - 6px);\n}\n\n.hint--top-left:after {\n margin-left: 12px;\n transform: translateX(-100%);\n}\n\n.hint--top-left:hover:before {\n transform: translateY(-8px);\n}\n\n.hint--top-left:hover:after {\n transform: translateX(-100%)translateY(-8px);\n}\n\n.hint--top-right:before {\n margin-bottom: -11px;\n}\n\n.hint--top-right:before, .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n\n.hint--top-right:before {\n left: calc(50% - 6px);\n}\n\n.hint--top-right:after {\n margin-left: -12px;\n transform: translateX(0);\n}\n\n.hint--top-right:hover:before, .hint--top-right:hover:after {\n transform: translateY(-8px);\n}\n\n.hint--bottom-left:before {\n margin-top: -11px;\n}\n\n.hint--bottom-left:before, .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom-left:after {\n margin-left: 12px;\n transform: translateX(-100%);\n}\n\n.hint--bottom-left:hover:before {\n transform: translateY(8px);\n}\n\n.hint--bottom-left:hover:after {\n transform: translateX(-100%)translateY(8px);\n}\n\n.hint--bottom-right:before {\n margin-top: -11px;\n}\n\n.hint--bottom-right:before, .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n\n.hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n\n.hint--bottom-right:after {\n margin-left: -12px;\n transform: translateX(0);\n}\n\n.hint--bottom-right:hover:before, .hint--bottom-right:hover:after {\n transform: translateY(8px);\n}\n\n.hint--small:after, .hint--medium:after, .hint--large:after {\n white-space: normal;\n word-wrap: break-word;\n line-height: 1.4em;\n}\n\n.hint--small:after {\n width: 80px;\n}\n\n.hint--medium:after {\n width: 150px;\n}\n\n.hint--large:after {\n width: 300px;\n}\n\n[class*=\"hint--\"]:after {\n text-shadow: 0 -1px #000;\n box-shadow: 4px 4px 8px #0000004d;\n}\n\n.hint--error:after {\n text-shadow: 0 -1px #592726;\n background-color: #b34e4d;\n}\n\n.hint--error.hint--top-left:before, .hint--error.hint--top-right:before, .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n\n.hint--error.hint--bottom-left:before, .hint--error.hint--bottom-right:before, .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n\n.hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n\n.hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n\n.hint--warning:after {\n text-shadow: 0 -1px #6c5328;\n background-color: #c09854;\n}\n\n.hint--warning.hint--top-left:before, .hint--warning.hint--top-right:before, .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n\n.hint--warning.hint--bottom-left:before, .hint--warning.hint--bottom-right:before, .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n\n.hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n\n.hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n\n.hint--info:after {\n text-shadow: 0 -1px #1a3c4d;\n background-color: #3986ac;\n}\n\n.hint--info.hint--top-left:before, .hint--info.hint--top-right:before, .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n\n.hint--info.hint--bottom-left:before, .hint--info.hint--bottom-right:before, .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n\n.hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n\n.hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n\n.hint--success:after {\n text-shadow: 0 -1px #1a321a;\n background-color: #458746;\n}\n\n.hint--success.hint--top-left:before, .hint--success.hint--top-right:before, .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n\n.hint--success.hint--bottom-left:before, .hint--success.hint--bottom-right:before, .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n\n.hint--success.hint--left:before {\n border-left-color: #458746;\n}\n\n.hint--success.hint--right:before {\n border-right-color: #458746;\n}\n\n.hint--always:after, .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n\n.hint--always.hint--top:before {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--top:after {\n transform: translateX(-50%)translateY(-8px);\n}\n\n.hint--always.hint--top-left:before {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--top-left:after {\n transform: translateX(-100%)translateY(-8px);\n}\n\n.hint--always.hint--top-right:before, .hint--always.hint--top-right:after {\n transform: translateY(-8px);\n}\n\n.hint--always.hint--bottom:before {\n transform: translateY(8px);\n}\n\n.hint--always.hint--bottom:after {\n transform: translateX(-50%)translateY(8px);\n}\n\n.hint--always.hint--bottom-left:before {\n transform: translateY(8px);\n}\n\n.hint--always.hint--bottom-left:after {\n transform: translateX(-100%)translateY(8px);\n}\n\n.hint--always.hint--bottom-right:before, .hint--always.hint--bottom-right:after {\n transform: translateY(8px);\n}\n\n.hint--always.hint--left:before, .hint--always.hint--left:after {\n transform: translateX(-8px);\n}\n\n.hint--always.hint--right:before, .hint--always.hint--right:after {\n transform: translateX(8px);\n}\n\n.hint--rounded:after {\n border-radius: 4px;\n}\n\n.hint--no-animate:before, .hint--no-animate:after {\n transition-duration: 0s;\n}\n\n.hint--bounce:before, .hint--bounce:after {\n -webkit-transition: opacity .3s, visibility .3s, -webkit-transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n -moz-transition: opacity .3s, visibility .3s, -moz-transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n transition: opacity .3s, visibility .3s, transform .3s cubic-bezier(.71, 1.7, .77, 1.24);\n}\n\n.hint--no-shadow:before, .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n\n.hint--no-arrow:before {\n display: none;\n}\n\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n";
},{}],"9hUEm":[function(require,module,exports,__globalThis) {
!function(r, t) {
diff --git a/package.json b/package.json
index ba172b423..5dfdd1dbb 100644
--- a/package.json
+++ b/package.json
@@ -28,13 +28,14 @@
"bootstrap": "npx lerna link",
"postinstall": "npx lerna run prepare",
"build:ts": "node ./scripts/build-ts.js",
+ "build:llm": "node ./scripts/build-llm.js",
"build:docs": "node ./scripts/build-docs.js",
"build:i18n": "node ./scripts/build-i18n.js",
"trans:docs": "node ./scripts/trans-docs.js",
"create:plugin": "node ./scripts/plugin/create.js",
- "lint": "npx eslint packages/*/{src,types,package.json} --fix",
"dev": "npx cross-env NODE_ENV=development node ./scripts/dev.js",
"build": "npx cross-env NODE_ENV=production node ./scripts/build.js",
+ "lint": "npx eslint packages/*/{src,types,package.json} scripts/*.js test/* docs/assets/ts/* --fix",
"build:all": "npm run build all && npm run build:i18n && npm run build:ts && npm run build:docs"
},
"browserslist": "last 1 Chrome version",
@@ -57,4 +58,4 @@
"servor": "^4.0.2",
"svgo": "^4.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/packages/artplayer-vitepress/docs/.vitepress/cache/deps/@theme_index.js b/packages/artplayer-vitepress/docs/.vitepress/cache/deps/@theme_index.js
index aea9608fb..ec6a94270 100644
--- a/packages/artplayer-vitepress/docs/.vitepress/cache/deps/@theme_index.js
+++ b/packages/artplayer-vitepress/docs/.vitepress/cache/deps/@theme_index.js
@@ -9,38 +9,38 @@ import {
} from "./chunk-PYKB7VCN.js";
// ../../node_modules/vitepress/dist/client/theme-default/index.js
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// ../../node_modules/vitepress/dist/client/theme-default/without-fonts.js
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/base.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
-import "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
-import VPBadge from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
-import Layout from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/Layout.vue";
-import { default as default2 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
-import { default as default3 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
-import { default as default4 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
-import { default as default5 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
-import { default as default6 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
-import { default as default7 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
-import { default as default8 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
-import { default as default9 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
-import { default as default10 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
-import { default as default11 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
-import { default as default12 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
-import { default as default13 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
-import { default as default14 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
-import { default as default15 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
-import { default as default16 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
-import { default as default17 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
-import { default as default18 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
-import { default as default19 } from "/Users/zhaohaiwei/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/base.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
+import "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
+import VPBadge from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
+import Layout from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/Layout.vue";
+import { default as default2 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
+import { default as default3 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
+import { default as default4 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
+import { default as default5 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
+import { default as default6 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
+import { default as default7 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
+import { default as default8 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
+import { default as default9 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
+import { default as default10 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
+import { default as default11 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
+import { default as default12 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
+import { default as default13 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
+import { default as default14 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
+import { default as default15 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
+import { default as default16 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
+import { default as default17 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
+import { default as default18 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
+import { default as default19 } from "C:/Users/laozh/Desktop/github/ArtPlayer/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
// ../../node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
import { onContentUpdated } from "vitepress";
diff --git a/packages/artplayer-vitepress/docs/.vitepress/cache/deps/_metadata.json b/packages/artplayer-vitepress/docs/.vitepress/cache/deps/_metadata.json
index 4feb5a0c0..3f084b69e 100644
--- a/packages/artplayer-vitepress/docs/.vitepress/cache/deps/_metadata.json
+++ b/packages/artplayer-vitepress/docs/.vitepress/cache/deps/_metadata.json
@@ -1,31 +1,31 @@
{
- "hash": "f505e736",
- "configHash": "b7d2330b",
- "lockfileHash": "b7b1f3f6",
- "browserHash": "45c5fb1b",
+ "hash": "b82527ba",
+ "configHash": "ab6bce56",
+ "lockfileHash": "13bd46c6",
+ "browserHash": "7fe2a1dd",
"optimized": {
"vue": {
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
- "fileHash": "69d6db4c",
+ "fileHash": "9dd397e2",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
- "fileHash": "8a53d1df",
+ "fileHash": "04d89fe7",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
- "fileHash": "ca279ebd",
+ "fileHash": "a580052a",
"needsInterop": false
},
"@theme/index": {
"src": "../../../../../../node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
- "fileHash": "c611f6d4",
+ "fileHash": "553740c4",
"needsInterop": false
}
},
diff --git a/packages/artplayer-vitepress/docs/en/advanced/built-in.md b/packages/artplayer-vitepress/docs/en/advanced/built-in.md
index 25baf7cfa..8a657deab 100644
--- a/packages/artplayer-vitepress/docs/en/advanced/built-in.md
+++ b/packages/artplayer-vitepress/docs/en/advanced/built-in.md
@@ -1,10 +1,10 @@
# Advanced Properties
-The `advanced properties` here refer to the `secondary attributes` mounted on the `instance`, which are less commonly used
+The `Advanced Properties` here refer to the `secondary properties` attached to the `instance`, which are less commonly used.
## `option`
-Options for the player
+The player's options.
`,
- tooltip: 'Poster Tip',
+ tooltip: 'Potser Tip',
style: {
position: 'absolute',
top: '50px',
@@ -43,9 +43,10 @@ var art = new Artplayer({
});
// Get the Element of layer by name
-console.info(art.layers['poster']);
+console.info(art.layers['potser']);
```
-## Add
+
+## Addition
`,
- tooltip: 'Poster Tip',
+ tooltip: 'Potser Tip',
style: {
position: 'absolute',
top: '50px',
@@ -74,9 +75,10 @@ art.layers.add({
});
// Get the Element of layer by name
-console.info(art.layers['poster']);
+console.info(art.layers['potser']);
```
-## Delete
+
+## Removal
`,
style: {
position: 'absolute',
@@ -101,10 +103,11 @@ var art = new Artplayer({
art.on('ready', () => {
setTimeout(() => {
// Delete the layer by name
- art.layers.remove('poster');
+ art.layers.remove('potser');
}, 3000);
});
```
+
## Update
`,
style: {
position: 'absolute',
@@ -131,7 +134,7 @@ art.on('ready', () => {
setTimeout(() => {
// Update the layer by name
art.layers.update({
- name: 'poster',
+ name: 'potser',
html: `
`,
style: {
position: 'absolute',
@@ -140,5 +143,4 @@ art.on('ready', () => {
},
});
}, 3000);
-});
-```
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/packages/artplayer-vitepress/docs/en/component/setting.md b/packages/artplayer-vitepress/docs/en/component/setting.md
index 45aed67c0..383d66418 100644
--- a/packages/artplayer-vitepress/docs/en/component/setting.md
+++ b/packages/artplayer-vitepress/docs/en/component/setting.md
@@ -2,7 +2,7 @@
## Built-in
-First, open the settings panel, and then it comes with four built-in items: `flip`, `playbackRate`, `aspectRatio`, `subtitleOffset`
+First, you need to open the settings panel. It comes with four built-in items: `flip`, `playbackRate`, `aspectRatio`, `subtitleOffset`
`,
style: {
position: 'absolute',
@@ -605,7 +607,8 @@ var art = new Artplayer({
],
});
```
-:::warning `Component Configuration` Please refer to the following address:
+
+:::warning For `Component Configuration`, please refer to:
[/component/layers.html](/component/layers.html)
@@ -616,7 +619,7 @@ var art = new Artplayer({
- Type: `Array`
- Default: `[]`
-Initializes custom `settings panel`
+Initialize custom `Settings Panel`
',
+ loading: '
',
state: '
',
},
});
```
-:::warning Definition of all icons
+
+:::warning All Icon Definitions
[artplayer/types/icons.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/icons.d.ts)
@@ -949,7 +961,7 @@ var art = new Artplayer({
- Type: `String`
- Default: `''`
-Used to specify the format of the video, which is used in conjunction with `customType`. By default, the video format is the same as the file extension of the video URL (such as `.m3u8`, `.mkv`, `.ts`). However, sometimes the video URL does not have the correct file extension, so it needs to be specifically stated.
+Used to specify the video format, needs to be used together with `customType`. The default video format is the suffix of the video URL (e.g., `.m3u8`, `.mkv`, `.ts`). However, sometimes the video URL does not have the correct suffix, so it needs to be explicitly specified.