feat: add link to LLMs resource in README

Implement code changes to enhance functionality and improve performance

chore: add initial empty files for artplayer.d.ts, llm.txt, and build-llm.js

Refactor Artplayer examples for improved readability and consistency

- Updated mobile.js to enhance code formatting and structure.
- Refined mpegts.js for better readability and consistency in function usage.
- Improved multiple.subtitles.js with clearer structure and modern syntax.
- Enhanced setting.test.js for better organization and clarity in settings management.
- Streamlined thumbnail.js for consistent formatting.
- Updated vast.js for improved readability and consistency in plugin usage.
- Refined vtt.thumbnail.js for better code organization.
- Enhanced webtorrent.js for improved readability and consistency in async handling.
- Updated TypeScript definitions for various plugins to maintain consistency in export statements.
- Adjusted package.json linting script to include TypeScript files in the docs/assets/ts directory.
- Removed outdated types.test.js file to clean up the test suite.

refactor: remove outdated documentation files and update translation script

- Deleted i18n.md and option.md documentation files as they are no longer needed.
- Updated trans-docs.js to streamline the translation process and improve error handling.
- Adjusted plugin template package.json for consistency.
- Changed console.log to console.warn in various test files for better logging practices.

feat: add danmaku plugin documentation and i18n support

- Introduced comprehensive documentation for the Danmaku library, including installation, usage examples, and configuration options.
- Added language settings documentation, highlighting the need for manual language imports starting from version 5.1.0.
- Updated basic options documentation with detailed descriptions and examples for player configuration options.

Refactor documentation for clarity and consistency; update translation script to handle large Markdown chunks

refactor: improve documentation clarity and consistency across various components

- Updated property descriptions in layers.md and setting.md for better readability.
- Enhanced language and structure in index.md, danmuku.md, i18n.md, and option.md to ensure uniformity.
- Corrected minor grammatical errors and improved phrasing throughout the documentation.
- Ensured consistent formatting in tables and code snippets for better user experience.

feat: add build script for generating llm.txt and update translation source directories

Refactor build-llm.js to improve concurrency and enhance prompt clarity

- Introduced a MAX_CONCURRENT_REQUESTS constant to manage concurrent API requests.
- Added a runConcurrent function to handle task execution with a limit on concurrent requests.
- Updated the askDeepSeek function to include more informative logging.
- Enhanced prompts for summarizing documentation, TypeScript definitions, and JavaScript examples to improve clarity and maintain formatting.
- Modified the main function to fetch files concurrently and streamline the summarization process.

Increase text chunk size from 5000 to 8000 in summarizeSection function for improved processing of larger files.

fix: update lint script to include .js files in the scripts directory
This commit is contained in:
Harvey Zhao committed 2025-10-08 12:20:12 +08:00
1 parent 987795503b
commit 0a9aadf543
71 files changed
+10851 -1945

No files matched your search

+2
View File
@@ -27,6 +27,8 @@
<span>・</span>
<a href="./CHANGELOG.md">Changelog</a>
<span>・</span>
<a href="https://artplayer.org/llms.txt">🤖LLMs</a>
<span>・</span>
</p>
<p align="center">
+34 -34
View File
@@ -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: '<img src="/assets/sample/poster.jpg">',
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
autoSize: true,
fullscreen: true,
fullscreenWeb: true,
plugins: [
artplayerPluginAds({
// html广告,假如是视频广告则忽略该值
html: '<img src="/assets/sample/poster.jpg">',
// 视频广告的地址
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)
})
+13 -13
View File
@@ -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,
}),
],
});
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,
}),
],
})
+52 -49
View File
@@ -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)
+9 -9
View File
@@ -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({
//
}),
],
});
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginAutoThumbnail({
//
}),
],
})
+27 -27
View File
@@ -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(),
});
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(),
})
+25 -25
View File
@@ -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: '终わり' },
]
}),
],
});
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: '终わり' },
],
}),
],
})
+12 -12
View File
@@ -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
}),
],
});
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
}),
],
})
+48 -48
View File
@@ -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);
});
},
}),
],
});
// 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
beforeEmit(danmu) {
return new Promise((resolve) => {
console.log(danmu)
setTimeout(() => {
resolve(true)
}, 1000)
})
},
}),
],
})
+16 -16
View File
@@ -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',
}),
],
});
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',
}),
],
})
+45 -43
View File
@@ -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'
}
},
});
},
})
+21 -19
View File
@@ -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);
});
console.info(art.dash)
})
+1 -1
View File
@@ -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: [
+22 -20
View File
@@ -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);
});
console.info(art.flv)
})
+49 -46
View File
@@ -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'
}
},
});
},
})
+25 -22
View File
@@ -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);
});
console.info(art.hls)
})
+36 -35
View File
@@ -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,
})
})
})
+185 -185
View File
@@ -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: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
tooltip: '5x',
range: [5, 1, 10, 0.1],
onRange: function (item) {
return item.range[0] + 'x';
},
},
{
html: 'Button',
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="100" src="/assets/sample/layer.png">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img src="/assets/img/ploading.gif">',
state: '<img width="150" height="150" src="/assets/img/state.svg">',
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
{
html: 'Button',
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="100" src="/assets/sample/layer.png">',
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: '<img src="/assets/img/ploading.gif">',
state: '<img width="150" height="150" src="/assets/img/state.svg">',
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
},
})
+22 -22
View File
@@ -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')
})
+91 -91
View File
@@ -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: `<img width="50" src="/assets/sample/layer.png">`,
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: '<img src="/assets/img/ploading.gif">',
state: '<img width="150" height="150" src="/assets/img/state.svg">',
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
},
settings: [
{
width: 200,
html: '切换字幕',
tooltip: '双语',
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
selector: [
{
html: `<img width="50" src="/assets/sample/layer.png">`,
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: '<img src="/assets/img/ploading.gif">',
state: '<img width="150" height="150" src="/assets/img/state.svg">',
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
},
settings: [
{
width: 200,
html: '切换字幕',
tooltip: '双语',
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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',
},
],
});
{
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
},
},
],
})
+26 -24
View File
@@ -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);
});
console.info(art.flv)
})
+91 -89
View File
@@ -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: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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);
}
$style.textContent = style
}
else {
const $style = document.createElement('style')
$style.id = 'artplayer-subtitle-style'
$style.textContent = style
document.head.appendChild($style)
}
+132 -130
View File
@@ -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: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
selector: [
{
width: 200,
html: 'Subtitle',
name: 'subtitle',
tooltip: 'Bilingual',
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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: '<img width="22" height="22" src="/assets/img/state.svg">',
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)
}
})
+11 -11
View File
@@ -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,
}),
],
});
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginThumbnail({
width: 160,
number: 100,
scale: 1,
}),
],
})
+14 -14
View File
@@ -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');
});
}),
],
});
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')
})
}),
],
})
+9 -9
View File
@@ -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',
})
]
});
const art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/bbb-video.mp4',
plugins: [
artplayerPluginVttThumbnail({
vtt: '/assets/sample/bbb-thumbnails.vtt',
}),
],
})
+27 -25
View File
@@ -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)
})
+2 -2
View File
@@ -48,5 +48,5 @@ declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
export default artplayerPluginAds
export = artplayerPluginAds;
export as namespace artplayerPluginAds;
export = artplayerPluginAds
export as namespace artplayerPluginAds;
+2 -2
View File
@@ -16,5 +16,5 @@ declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) =>
export default artplayerPluginAmbilight
export = artplayerPluginAmbilight;
export as namespace artplayerPluginAmbilight;
export = artplayerPluginAmbilight
export as namespace artplayerPluginAmbilight;
+2 -2
View File
@@ -22,5 +22,5 @@ declare function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer)
export default artplayerPluginAsr
export = artplayerPluginAsr;
export as namespace artplayerPluginAsr;
export = artplayerPluginAsr
export as namespace artplayerPluginAsr;
+2 -2
View File
@@ -13,5 +13,5 @@ declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer)
export default artplayerPluginAutoThumbnail
export = artplayerPluginAutoThumbnail;
export as namespace artplayerPluginAutoThumbnail;
export = artplayerPluginAutoThumbnail
export as namespace artplayerPluginAutoThumbnail;
+2 -2
View File
@@ -17,5 +17,5 @@ declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Re
export default artplayerPluginChapter
export = artplayerPluginChapter;
export as namespace artplayerPluginChapter;
export = artplayerPluginChapter
export as namespace artplayerPluginChapter;
+2 -2
View File
@@ -13,5 +13,5 @@ declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) =>
export default artplayerPluginChromecast
export = artplayerPluginChromecast;
export as namespace artplayerPluginChromecast;
export = artplayerPluginChromecast
export as namespace artplayerPluginChromecast;
+2 -2
View File
@@ -21,5 +21,5 @@ declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer)
export default artplayerPluginDanmukuMask
export = artplayerPluginDanmukuMask;
export as namespace artplayerPluginDanmukuMask;
export = artplayerPluginDanmukuMask
export as namespace artplayerPluginDanmukuMask;
+2 -2
View File
@@ -255,5 +255,5 @@ declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Re
export default artplayerPluginDanmuku
export = artplayerPluginDanmuku;
export as namespace artplayerPluginDanmuku;
export = artplayerPluginDanmuku
export as namespace artplayerPluginDanmuku;
+2 -2
View File
@@ -13,5 +13,5 @@ declare const artplayerPluginDashControl: (option: { quality?: Config, audio?: C
export default artplayerPluginDashControl
export = artplayerPluginDashControl;
export as namespace artplayerPluginDashControl;
export = artplayerPluginDashControl
export as namespace artplayerPluginDashControl;
+2 -2
View File
@@ -18,5 +18,5 @@ declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) =
export default artplayerPluginDocumentPip
export = artplayerPluginDocumentPip;
export as namespace artplayerPluginDocumentPip;
export = artplayerPluginDocumentPip
export as namespace artplayerPluginDocumentPip;
+2 -2
View File
@@ -13,5 +13,5 @@ declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Co
export default artplayerPluginHlsControl
export = artplayerPluginHlsControl;
export as namespace artplayerPluginHlsControl;
export = artplayerPluginHlsControl
export as namespace artplayerPluginHlsControl;
+2 -2
View File
@@ -28,5 +28,5 @@ declare class ArtplayerPluginIframe {
export default ArtplayerPluginIframe
export = artplayerPluginIframe;
export as namespace artplayerPluginIframe;
export = artplayerPluginIframe
export as namespace artplayerPluginIframe;
+2 -2
View File
@@ -11,5 +11,5 @@ declare const artplayerPluginAss: (options: Options) => (art: Artplayer) => {
export default artplayerPluginAss
export = artplayerPluginLibass;
export as namespace artplayerPluginLibass;
export = artplayerPluginLibass
export as namespace artplayerPluginLibass;
+2 -2
View File
@@ -12,5 +12,5 @@ declare const artplayerPluginMultipleSubtitles: (option: {
export default artplayerPluginMultipleSubtitles
export = artplayerPluginMultipleSubtitles;
export as namespace artplayerPluginMultipleSubtitles;
export = artplayerPluginMultipleSubtitles
export as namespace artplayerPluginMultipleSubtitles;
+2 -2
View File
@@ -29,5 +29,5 @@ declare function artplayerPluginVast(
export default artplayerPluginVast
export = artplayerPluginVast;
export as namespace artplayerPluginVast;
export = artplayerPluginVast
export as namespace artplayerPluginVast;
+2 -2
View File
@@ -6,5 +6,5 @@ declare const artplayerPluginVttThumbnail: (option: { vtt?: string, style?: Part
export default artplayerPluginVttThumbnail
export = artplayerPluginVttThumbnail;
export as namespace artplayerPluginVttThumbnail;
export = artplayerPluginVttThumbnail
export as namespace artplayerPluginVttThumbnail;
+2 -34
View File
@@ -124,8 +124,6 @@ export interface Subtitle {
onVttLoad?: (vtt: string) => string
}
type Props<T> = {
html: string
icon: string
@@ -239,10 +237,6 @@ export interface Quality {
url: string
}
export type AspectRatio = 'default' | '4:3' | '16:9' | (`${number}:${number}` & Record<never, never>)
export type PlaybackRate = 0.5 | 0.75 | 1.0 | 1.25 | 1.5 | 1.75 | 2.0 | (number & Record<never, never>)
export type Flip = 'normal' | 'horizontal' | 'vertical' | (string & Record<never, never>)
@@ -354,15 +348,6 @@ export declare class Player {
autoHeight(): void
}
export type CustomType
= | 'flv'
| 'm3u8'
@@ -771,9 +756,6 @@ declare module 'artplayer/i18n/*' {
export default lang
}
export type Bar = 'loaded' | 'played' | 'hover'
export interface Events {
@@ -992,8 +974,6 @@ export interface Config {
]
}
export interface Selector {
/**
* Whether the default is selected
@@ -1120,18 +1100,6 @@ export interface ComponentOption {
onSelect?: (this: Artplayer, selector: Selector, element: HTMLElement, event: Event) => void
}
export type {
Config,
Events,
@@ -1313,5 +1281,5 @@ export default class Artplayer extends Player {
} & Record<string, unknown>
}
export = Artplayer;
export as namespace Artplayer;
export = Artplayer
export as namespace Artplayer;
+1
View File
@@ -135,6 +135,7 @@
</div>
<a class="item" href="./document/">Document</a>
<a class="item" href="https://github.com/zhw2590582/ArtPlayer">Github</a>
<a class="item" href="./llms.txt">🤖LLMs</a>
<span class="item" href="#">Q群: 320881312</span>
</div>
<div class="tool">
+8265
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -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-Line truncated
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 Line truncated
},{}],"9hUEm":[function(require,module,exports,__globalThis) {
!function(r, t) {
+3 -2
View File
@@ -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"
}
}
}
@@ -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";
@@ -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
}
},
@@ -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.
<div className="run-code">▶ Run Code</div>
@@ -17,7 +17,7 @@ var art = new Artplayer({
console.info(art.option);
```
:::warning Reminder
:::warning Note
If you directly modify this `option` object, the player will not respond immediately.
@@ -25,7 +25,7 @@ If you directly modify this `option` object, the player will not respond immedia
## `template`
Manages all of the `DOM` elements of the player
Manages all `DOM` elements of the player.
<div className="run-code">▶ Run Code</div>
@@ -38,20 +38,21 @@ var art = new Artplayer({
console.info(art.template);
console.info(art.template.$video);
```
:::warning Warning
To easily distinguish between `DOM` elements and plain objects, all `DOM` elements in the player are named starting with a `$`
:::warning Note
Here is the definition of all `DOM` elements: [artplayer/types/template.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/template.d.ts)
To easily distinguish between `DOM` elements and regular objects, all `DOM` elements within the player are prefixed with `$`.
This is the definition of all `DOM` elements: [artplayer/types/template.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/template.d.ts)
:::
## `events`
Manages all `DOM` events in the player, which is essentially a proxy for `addEventListener` and `removeEventListener`. When using the following methods to handle events, the event will also be automatically destroyed when the player is destroyed.
Manages all `DOM` events for the player. It essentially proxies `addEventListener` and `removeEventListener`. When using the following methods to handle events, the event will be automatically destroyed when the player is destroyed.
- The `proxy` method is used to proxy `DOM` events
- The `hover` method is used to proxy custom `hover` events
- The `proxy` method is used to proxy `DOM` events.
- The `hover` method is used to proxy custom `hover` events.
<div className="run-code">▶ Run Code</div>
@@ -64,7 +65,7 @@ var art = new Artplayer({
});
art.events.proxy(container, 'click', event => {
console.info('click', event);
console.info('click', event);
});
art.events.hover(container, (event) => {
@@ -73,21 +74,22 @@ art.events.hover(container, (event) => {
console.info('mouseleave', event);
});
```
:::warning Warning
If you need some `DOM` events to only exist during the lifecycle of the player, it is strongly recommended to use these functions to avoid causing memory leaks
:::warning Note
If you need `DOM` events that only exist for the duration of the player's lifecycle, it is highly recommended to use these functions to avoid memory leaks.
:::
## `storage`
Manages the local storage of the player
Manages the player's local storage.
- The `name` attribute is used to set the cache `key`
- The `set` method is used to set the cache
- The `get` method is used to get the cache
- The `del` method is used to delete the cache
- The `clear` method is used to clear the cache
- The `name` property is used to set the cache `key`.
- The `set` method is used to set the cache.
- The `get` method is used to get the cache.
- The `del` method is used to delete the cache.
- The `clear` method is used to clear the cache.
<div className="run-code">▶ Run Code</div>
@@ -104,11 +106,11 @@ art.storage.del('test');
art.storage.clear();
```
:::warning Warning
:::warning Note
By default, all player instances share the same `localStorage`, and the default `key` is `artplayer_settings`
By default, all player instances share the same `localStorage`, and the default `key` is `artplayer_settings`.
If you want different players to use different `localStorage`, you can modify `art.storage.name` accordingly
If you want different players to use different `localStorage`, you can modify `art.storage.name`.
:::
@@ -126,7 +128,7 @@ art.storage.set('test', { foo: 'bar' });
## `icons`
Manage all the `svg` icons of the player
Manages all `svg` icons for the player.
<div className="run-code">▶ Run Code</div>
@@ -147,10 +149,10 @@ console.info(art.icons.loading);
## `i18n`
Manage the player's `i18n`
Manages the player's `i18n`.
- The `get` method is used to retrieve the value of `i18n`
- The `update` method is used to update the `i18n` object
- The `get` method is used to get the `i18n` value.
- The `update` method is used to update the `i18n` object.
<div className="run-code">▶ Run Code</div>
@@ -171,14 +173,13 @@ art.i18n.update({
:::warning
Using `art.i18n.update` can only update `i18n` after instantiation. If you want to update `i18n` before instantiation, please use the `i18n` from the basic options for the update.
Using `art.i18n.update` can only update the `i18n` after instantiation. If you want to update `i18n` before instantiation, please use the basic option `i18n` to update.
:::
## `notice`
Manage the player's notices, there's only one `show` property used to display notices.
Manages the player's notifications. It only has a `show` property for displaying notifications.
<div className="run-code">▶ Run Code</div>
@@ -195,19 +196,19 @@ art.on('ready', () => {
:::warning
To immediately hide the display of `notice`: `art.notice.show = '';`
If you want to hide the `notice` immediately: `art.notice.show = '';`
:::
## `layers`
Manage the layers of the player
Manages the player's layers.
- The `add` method is used for dynamically adding layers
- The `remove` method is used for dynamically removing layers
- The `update` method is used for dynamically updating layers
- The `show` property is used to set whether to display all layers or not
- The `toggle` method is used to toggle the display of all layers
- The `add` method is used to dynamically add a layer.
- The `remove` method is used to dynamically remove a layer.
- The `update` method is used to dynamically update a layer.
- The `show` property is used to set whether all layers are visible.
- The `toggle` method is used to toggle the visibility of all layers.
<div className="run-code">▶ Run Code</div>
@@ -226,8 +227,8 @@ art.on('ready', () => {
art.layers.show = false;
}, 1000);
});
```
:::warning `Component configuration` Please refer to the following address:
:::warning For `Component Configuration`, please refer to:
[/component/layers.html](/component/layers.html)
@@ -235,13 +236,13 @@ art.on('ready', () => {
## `controls`
Manage the player's controllers
Manages the player's controls
- `add` method is used to dynamically add controllers
- `remove` method is used to dynamically remove controllers
- `update` method is used to dynamically update controllers
- `show` property is used to set whether to display all controllers
- `toggle` method is used to toggle the display of all controllers
- The `add` method dynamically adds controls
- The `remove` method dynamically removes controls
- The `update` method dynamically updates controls
- The `show` property sets whether to display all controls
- The `toggle` method toggles the visibility of all controls
<div className="run-code">▶ Run Code</div>
@@ -263,7 +264,7 @@ art.on('ready', () => {
});
```
:::warning `Component Configuration` Please refer to the following address:
:::warning For `Component Configuration`, please refer to:
[/component/controls.html](/component/controls.html)
@@ -271,13 +272,13 @@ art.on('ready', () => {
## `contextmenu`
Manage the right-click context menu of the player
Manages the player's context menu
- The `add` method is used to dynamically add menu items
- The `remove` method is used to dynamically remove menu items
- The `update` method is used to dynamically update menu items
- The `show` attribute is used to set whether to show all menu items
- The `toggle` method is used to switch the visibility of all menu items
- The `add` method dynamically adds menu items
- The `remove` method dynamically removes menu items
- The `update` method dynamically updates menu items
- The `show` property sets whether to display all menu items
- The `toggle` method toggles the visibility of all menu items
<div className="run-code">▶ Run Code</div>
@@ -293,13 +294,13 @@ art.on('ready', () => {
});
art.contextmenu.show = true;
setTimeout(() => {
art.contextmenu.show = false;
}, 1000);
setTimeout(() => {
art.contextmenu.show = false;
}, 1000);
});
```
:::warning `Component Configuration` Please refer to the following address:
:::warning For `Component Configuration`, please refer to:
[/component/contextmenu.html](/component/contextmenu.html)
@@ -307,14 +308,14 @@ art.on('ready', () => {
## `subtitle`
Manage the subtitle features of the player
Manages the player's subtitle functionality
- `url` property sets and returns the current subtitle address
- `style` method sets the style of the current subtitle
- `switch` method sets the current subtitle address and options
- `textTrack` Get the current subtitle track
- `activeCues` Get the currently active subtitle list
- `cues` Get the subtitle list
- The `url` property sets and returns the current subtitle URL
- The `style` method sets the current subtitle's style
- The `switch` method sets the current subtitle URL and options
- `textTrack` gets the current text track
- `activeCues` gets the list of currently active cues
- `cues` gets the complete list of cues
<div className="run-code">▶ Run Code</div>
@@ -334,10 +335,10 @@ art.on('ready', () => {
## `loading`
Manage the loading layer of the player
Manages the player's loading layer
- `show` property is used to set whether to display the loading layer
- The `toggle` attribute is used to toggle the display of the loading layer
- The `show` property sets whether to display the loading layer
- The `toggle` property toggles the visibility of the loading layer
<div className="run-code">▶ Run Code</div>
@@ -357,10 +358,10 @@ art.on('ready', () => {
## `hotkey`
Manage the hotkey functionality of the player
Manages the player's hotkey functionality
- The `add` method is used to add a hotkey
- The `remove` method is used to remove a hotkey
- The `add` method adds hotkeys
- The `remove` method removes hotkeys
<div className="run-code">▶ Run Code</div>
@@ -381,18 +382,19 @@ art.on('ready', () => {
}, 5000);
});
```
:::warning Warning
Shortcut keys will only work after the player has gained focus (e.g., after clicking on the player).
:::warning Note
These hotkeys only take effect when the player has focus (e.g., after clicking on the player)
:::
## `mask`
Manage the player's mask layer
Manages the player's mask layer
- `show` property is used to set whether to display the mask layer
- `toggle` property is used to toggle the display of the mask layer
- The `show` property sets whether to display the mask layer
- The `toggle` property toggles the visibility of the mask layer
<div className="run-code">▶ Run Code</div>
@@ -404,22 +406,21 @@ var art = new Artplayer({
art.on('ready', () => {
art.mask.show = false;
setTimeout(() => {
art.mask.show = true;
}, 1000);
setTimeout(() => {
art.mask.show = true;
}, 1000);
});
```
## `setting`
Manage the player's settings panel
- `add` method is used to dynamically add a setting item
- `remove` method is used to dynamically remove a setting item
- `update` method is used to dynamically update a setting item
- `show` property is used to set whether to display all the setting items
- `toggle` method is used to toggle whether to display all the setting items
Manages the player's settings panel
- The `add` method dynamically adds settings items
- The `remove` method dynamically removes settings items
- The `update` method dynamically updates settings items
- The `show` property sets whether to display all settings items
- The `toggle` method toggles the visibility of all settings items
<div className="run-code">▶ Run Code</div>
@@ -442,7 +443,7 @@ art.on('ready', () => {
});
```
:::warning `Settings Panel` Please refer to the following link
:::warning For `Settings Panel`, please refer to:
[/component/setting.html](/component/setting.html)
@@ -450,7 +451,7 @@ art.on('ready', () => {
## `plugins`
Manage the player's plugin features, with only one method `add` to dynamically add plugins
Manages the player's plugin functionality, with only one method `add` for dynamically adding plugins
<div className="run-code">▶ Run Code</div>
@@ -473,5 +474,4 @@ function myPlugin(art) {
art.on('ready', () => {
art.plugins.add(myPlugin);
});
```
});
@@ -1,10 +1,10 @@
# Static Properties
Here, `Static Properties` refer to the `first-level properties` mounted on the `constructor`, which are very rarely used.
Static properties here refer to first-level properties mounted on the constructor, which are rarely used.
## `instances`
Returns an array of all player instances. You can use this property when you want to manage multiple players at the same time.
Returns an array of all player instances. This property can be useful when you need to manage multiple player instances simultaneously.
<div className="run-code">▶ Run Code</div>
@@ -41,7 +41,7 @@ console.info(Artplayer.env);
## `build`
Returns the build time of the player
Returns the build timestamp of the player.
<div className="run-code">▶ Run Code</div>
@@ -51,7 +51,7 @@ console.info(Artplayer.build);
## `config`
Returns the default configuration of the video
Returns the default configuration for videos.
<div className="run-code">▶ Run Code</div>
@@ -61,7 +61,7 @@ console.info(Artplayer.config);
## `utils`
Returns a collection of utility functions for the player
Returns the collection of utility functions for the player.
<div className="run-code">▶ Run Code</div>
@@ -69,7 +69,7 @@ Returns a collection of utility functions for the player
console.info(Artplayer.utils);
```
:::warning For the full list of utility functions, please refer to the following address:
:::warning For all utility functions, please refer to:
[artplayer/types/utils.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/utils.d.ts)
@@ -77,7 +77,7 @@ console.info(Artplayer.utils);
## `scheme`
Returns the validation scheme for the player options
Returns the validation schema for player options.
<div className="run-code">▶ Run Code</div>
@@ -87,7 +87,7 @@ console.info(Artplayer.scheme);
## `Emitter`
Returns the constructor for the event dispatcher
Returns the constructor for the event emitter.
<div className="run-code">▶ Run Code</div>
@@ -97,7 +97,7 @@ console.info(Artplayer.Emitter);
## `validator`
Returns the validation function for options
Returns the validation function for options.
<div className="run-code">▶ Run Code</div>
@@ -107,7 +107,7 @@ console.info(Artplayer.validator);
## `kindOf`
Returns the function tool for type checking
Returns the type detection utility function.
<div className="run-code">▶ Run Code</div>
@@ -117,7 +117,7 @@ console.info(Artplayer.kindOf);
## `html`
Returns the `html` string required for the player
Returns the HTML string required by the player.
<div className="run-code">▶ Run Code</div>
@@ -127,10 +127,9 @@ console.info(Artplayer.html);
## `option`
Returns the player's default options
Returns the default options for the player.
<div className="run-code">▶ Run Code</div>
```js
console.info(Artplayer.option);
```
console.info(Artplayer.option);
@@ -1,8 +1,8 @@
# Example Events
# Instance Events
Player events are divided into two types, one is the video's `native events` (prefix `video:`), the other is `custom events`
Player events are divided into two types: `native events` from the video (prefixed with `video:`) and `custom events`.
Listening to events:
Listen for events:
<div className="run-code">▶ Run Code</div>
@@ -17,7 +17,7 @@ art.on('video:canplay', () => {
});
```
Listen to an event only once:
Listen for an event only once:
<div className="run-code">▶ Run Code</div>
@@ -63,14 +63,15 @@ const onReady = () => {
art.on('ready', onReady);
```
:::warning For a full list of events, please refer to the following address:
:::warning For all events, please refer to the following address:
[artplayer/types/events.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/events.d.ts)
:::
## `ready`
Triggered when the player is able to play for the first time
Triggered when the player is ready for the first time
<div className="run-code">▶ Run Code</div>
@@ -87,7 +88,7 @@ art.on('ready', () => {
## `restart`
Triggered when the player switches the address and is able to play
Triggered when the player switches URL and is ready to play
<div className="run-code">▶ Run Code</div>
@@ -105,6 +106,7 @@ art.on('restart', (url) => {
console.info('restart', url);
});
```
## `pause`
Triggered when the player is paused
@@ -141,7 +143,7 @@ art.on('play', () => {
## `hotkey`
Triggered when a hotkey on the player is pressed
Triggered when a player hotkey is pressed
<div className="run-code">▶ Run Code</div>
@@ -227,6 +229,7 @@ art.on('dblclick', (event) => {
console.info('dblclick', event);
});
```
## `click`
Triggered when the player is clicked
@@ -242,11 +245,10 @@ var art = new Artplayer({
art.on('click', (event) => {
console.info('click', event);
});
```
## `error`
Triggered when an error occurs while the player is loading the video
Triggered when an error occurs while the player is loading a video
<div className="run-code">▶ Run Code</div>
@@ -260,9 +262,10 @@ art.on('error', (error, reconnectTime) => {
console.info(error, reconnectTime);
});
```
## `hover`
Triggered when the player is hovered or unhovered by the mouse
Triggered when the mouse pointer enters or leaves the player
<div className="run-code">▶ Run Code</div>
@@ -279,7 +282,7 @@ art.on('hover', (state, event) => {
## `mousemove`
Triggered when the mouse moves over the player
Triggered when the mouse pointer moves over the player
<div className="run-code">▶ Run Code</div>
@@ -293,9 +296,10 @@ art.on('mousemove', (event) => {
console.info('mousemove', event);
});
```
## `resize`
Triggered when the player size changes
Triggered when the player's dimensions change
<div className="run-code">▶ Run Code</div>
@@ -312,7 +316,7 @@ art.on('resize', () => {
## `view`
Triggered when the player appears in the viewport
Triggered when the player enters or leaves the viewport
<div className="run-code">▶ Run Code</div>
@@ -329,7 +333,7 @@ art.on('view', (state) => {
## `lock`
On mobile, triggered when the locked state changes
Triggered when the lock state changes on mobile devices
<div className="run-code">▶ Run Code</div>
@@ -347,7 +351,7 @@ art.on('lock', (state) => {
## `aspectRatio`
Triggered when the aspect ratio of the player changes
Triggered when the player's aspect ratio changes
<div className="run-code">▶ Run Code</div>
@@ -366,7 +370,7 @@ art.on('aspectRatio', (aspectRatio) => {
## `autoHeight`
Triggered when the player automatically sets the height
Triggered when the player automatically sets its height
<div className="run-code">▶ Run Code</div>
@@ -387,7 +391,7 @@ art.on('autoHeight', (height) => {
## `autoSize`
Triggered when the player automatically sets the size
Triggered when the player automatically adjusts its size
<div className="run-code">▶ Run Code</div>
@@ -402,9 +406,10 @@ art.on('autoSize', () => {
console.info('autoSize');
});
```
## `flip`
Triggered when the player flips
Triggered when the player's video is flipped
<div className="run-code">▶ Run Code</div>
@@ -423,7 +428,7 @@ art.on('flip', (flip) => {
## `fullscreen`
Triggered when the player goes into full screen
Triggered when the player enters or exits fullscreen mode
<div className="run-code">▶ Run Code</div>
@@ -441,7 +446,7 @@ art.on('fullscreen', (state) => {
## `fullscreenError`
Triggered when the player goes into full screen error
Triggered when an error occurs during fullscreen mode transition
<div className="run-code">▶ Run Code</div>
@@ -462,7 +467,7 @@ art.on('fullscreenError', (event) => {
## `fullscreenWeb`
Triggered when the player enters web fullscreen
Triggered when the player enters or exits web page fullscreen mode
<div className="run-code">▶ Run Code</div>
@@ -480,7 +485,7 @@ art.on('fullscreenWeb', (state) => {
## `mini`
Triggered when the player enters mini mode
Triggered when the player enters or exits mini mode
<div className="run-code">▶ Run Code</div>
@@ -498,9 +503,10 @@ art.on('mini', (state) => {
console.info('mini', state);
});
```
## `pip`
Triggered when the player enters Picture-in-Picture mode
Triggered when the player enters or exits picture-in-picture mode
<div className="run-code">▶ Run Code</div>
@@ -518,7 +524,7 @@ art.on('pip', (state) => {
## `screenshot`
Triggered when the player takes a screenshot
Triggered when the player captures a screenshot
<div className="run-code">▶ Run Code</div>
@@ -533,9 +539,10 @@ art.on('screenshot', (dataUri) => {
console.info('screenshot', dataUri);
});
```
## `seek`
Triggered when the player jumps in time
Triggered when the player performs a time jump
<div className="run-code">▶ Run Code</div>
@@ -552,7 +559,7 @@ art.on('seek', (currentTime) => {
## `subtitleOffset`
Triggered when the subtitle offset occurs in the player
Triggered when subtitle offset changes
<div className="run-code">▶ Run Code</div>
@@ -594,7 +601,7 @@ art.on('subtitleBeforeUpdate', (cues) => {
## `subtitleAfterUpdate`
Triggered when the subtitles are updated
Triggered after subtitles are updated
<div className="run-code">▶ Run Code</div>
@@ -614,7 +621,7 @@ art.on('subtitleAfterUpdate', (cues) => {
## `subtitleLoad`
Triggered when the subtitle loads
Triggered when subtitles are loaded
<div className="run-code">▶ Run Code</div>
@@ -634,7 +641,7 @@ art.on('subtitleLoad', (option, cues) => {
## `info`
Triggered when the information panel is shown or hidden
Triggered when the info panel is shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -648,9 +655,10 @@ art.on('info', (state) => {
console.log(state);
});
```
## `layer`
Triggered when a custom layer is shown or hidden
Triggered when custom layers are shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -667,7 +675,7 @@ art.on('layer', (state) => {
## `loading`
Triggered when a loader is shown or hidden
Triggered when the loading indicator is shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -684,7 +692,7 @@ art.on('loading', (state) => {
## `mask`
Triggered when a mask layer is shown or hidden
Triggered when the mask layer is shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -714,11 +722,10 @@ var art = new Artplayer({
art.on('subtitle', (state) => {
console.log(state);
});
```
## `contextmenu`
Triggered when the right-click menu is shown or hidden
Triggered when the context menu is shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -735,7 +742,7 @@ art.on('contextmenu', (state) => {
## `control`
Triggered when the controller is shown or hidden
Triggered when the controls are shown or hidden
<div className="run-code">▶ Run Code</div>
@@ -787,7 +794,7 @@ art.on('muted', (state) => {
## `keydown`
Listen to the `keydown` event from `document`
Listens for the `keydown` event from `document`
<div className="run-code">▶ Run Code</div>
@@ -804,11 +811,11 @@ art.on('keydown', (event) => {
## `video:canplay`
The browser can play the media file, but estimates there is not enough data to play through to the end without having to stop for further buffering
The browser can start playing the media, but estimates that there isn't enough data to play through to the end without having to stop for further buffering
## `video:canplaythrough`
The browser estimates it can play the media through to the end without stopping for content buffering
The browser estimates it can play the media through to the end without having to stop for buffering
## `video:complete`
@@ -820,15 +827,15 @@ Triggered when the value of the duration property changes
## `video:emptied`
The media content becomes empty; for example, when this media has been completely loaded (or partially loaded), this event is sent and the load() method is called to reload it
The media has become empty; for example, this event is sent when the media has already been loaded (or partially loaded), and the load() method is called to reload it
## `video:ended`
The video has stopped because the media reached the end point
Playback has stopped because the media has reached its end point
## `video:error`
An error occurred while fetching media data, or the resource type is not a supported media format
An error occurred while fetching the media data, or the resource type is not a supported media format
## `video:loadeddata`
@@ -844,15 +851,15 @@ Playback has been paused
## `video:play`
Playback has started
Playback has begun
## `video:playing`
Playback is ready to start following a pause or delay due to lack of data
Playback is ready to start after having been paused or delayed due to lack of data
## `video:progress`
Periodically triggered while the browser is loading resources
Fired periodically as the browser loads the resource
## `video:ratechange`
@@ -860,15 +867,15 @@ The playback rate has changed
## `video:seeked`
A seek (frame skipping) operation has completed
A seek operation has completed
## `video:seeking`
A seek (frame skipping) operation has started
A seek operation has begun
## `video:stalled`
The user agent is trying to fetch media data, but the data unexpectedly has not appeared
The user agent is trying to fetch media data, but data is unexpectedly not forthcoming
## `video:suspend`
@@ -876,11 +883,12 @@ Media data loading has been suspended
## `video:timeupdate`
The time specified by the currentTime attribute has changed
The time indicated by the currentTime attribute has been updated
## `video:volumechange`
Volume changed
The volume has changed
## `video:waiting`
Playback has stopped due to temporarily missing data
Playback has stopped because of a temporary lack of data
@@ -1,10 +1,10 @@
# Global Attributes
# Global Properties
Here, `Global Attributes` refer to the `first-level properties` mounted on the `constructor`. Property names are all in uppercase, subject to change in the future and basically not needed.
These `global properties` refer to the top-level properties mounted on the `constructor`. All property names are in uppercase. These are subject to change in the future and are generally not used.
## DEBUG
Whether to start `debug` mode, which can print out all built-in events of the video by default is turned off.
Whether to enable `debug` mode, which can print all built-in video events. Default is off.
<div className="run-code">▶ Run Code</div>
@@ -19,7 +19,7 @@ var art = new Artplayer({
## STYLE
Returns the player style text
Returns the player's style text.
<div className="run-code">▶ Run Code</div>
@@ -29,7 +29,7 @@ console.log(Artplayer.STYLE);
## CONTEXTMENU
Whether to enable the right-click context menu, enabled by default.
Whether to enable the context menu. Default is on.
<div className="run-code">▶ Run Code</div>
@@ -41,9 +41,10 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
});
```
## NOTICE_TIME
The display duration of the notification message, in milliseconds, defaults to `2000`
The display duration for notification messages, in milliseconds. Default is `2000`.
<div className="run-code">▶ Run Code</div>
@@ -58,7 +59,7 @@ var art = new Artplayer({
## SETTING_WIDTH
The default width of the settings panel, in pixels, defaults to `250`
The default width of the settings panel, in pixels. Default is `250`.
<div className="run-code">▶ Run Code</div>
@@ -75,9 +76,10 @@ var art = new Artplayer({
aspectRatio: true,
});
```
## SETTING_ITEM_WIDTH
Set the default width of the settings items in the panel, in pixels, the default is `200`.
The default width of settings items in the settings panel, in pixels. Default is `200`.
<div className="run-code">▶ Run Code</div>
@@ -97,7 +99,7 @@ var art = new Artplayer({
## SETTING_ITEM_HEIGHT
Set the default height of the settings items in the panel, in pixels, the default is `35`.
The default height of settings items in the settings panel, in pixels. Default is `35`.
<div className="run-code">▶ Run Code</div>
@@ -117,7 +119,7 @@ var art = new Artplayer({
## RESIZE_TIME
Throttle time for the `resize` event, in milliseconds, defaults to `200`
The throttle time for `resize` events, in milliseconds. Default is `200`.
<div className="run-code">▶ Run Code</div>
@@ -136,7 +138,7 @@ art.on('resize', () => {
## SCROLL_TIME
Throttle time for the `scroll` event, in milliseconds, defaults to `200`
The throttle time for `scroll` events, in milliseconds. Default is `200`.
<div className="run-code">▶ Run Code</div>
@@ -152,9 +154,10 @@ art.on('scroll', () => {
console.log('scroll');
});
```
## SCROLL_GAP
The boundary tolerance distance for the `view` event, in pixels, default is `50`
The boundary tolerance distance for `view` events, in pixels. Default is `50`.
<div className="run-code">▶ Run Code</div>
@@ -173,7 +176,7 @@ art.on('scroll', () => {
## AUTO_PLAYBACK_MAX
The maximum number of records for the automatic playback feature, default is `10`
The maximum number of records for the auto-playback feature. Default is `10`.
<div className="run-code">▶ Run Code</div>
@@ -189,7 +192,7 @@ var art = new Artplayer({
## AUTO_PLAYBACK_MIN
The minimum duration for the auto playback feature, in seconds, with a default of `5`.
The minimum record duration for the auto-playback feature, in seconds. Default is `5`.
<div className="run-code">▶ Run Code</div>
@@ -205,7 +208,7 @@ var art = new Artplayer({
## AUTO_PLAYBACK_TIMEOUT
The delay duration for hiding the auto playback feature, in milliseconds, with a default of `3000`.
The hide delay duration for the auto-playback feature, in milliseconds. Default is `3000`.
<div className="run-code">▶ Run Code</div>
@@ -221,7 +224,7 @@ var art = new Artplayer({
## RECONNECT_TIME_MAX
The maximum number of automatic reconnection attempts when a connection error occurs, default is `5`
The maximum number of automatic reconnection attempts when a connection error occurs. Default is `5`.
<div className="run-code">▶ Run Code</div>
@@ -232,11 +235,10 @@ var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/404.mp4',
});
```
## RECONNECT_SLEEP_TIME
The delay time for the automatic reconnection attempt when a connection error occurs, in milliseconds, default is `1000`
The delay time for automatic reconnection when a connection error occurs, in milliseconds. Default is `1000`
<div className="run-code">▶ Run Code</div>
@@ -251,9 +253,7 @@ var art = new Artplayer({
## CONTROL_HIDE_TIME
...
Auto-hide delay time for the bottom control bar, measured in milliseconds, default is `3000`
The delay time for auto-hiding the bottom control bar, in milliseconds. Default is `3000`
<div className="run-code">▶ Run Code</div>
@@ -268,7 +268,7 @@ var art = new Artplayer({
## DBCLICK_TIME
Double-click event delay time, measured in milliseconds, default is `300`
The delay time for double-click events, in milliseconds. Default is `300`
<div className="run-code">▶ Run Code</div>
@@ -287,7 +287,7 @@ art.on('dblclick', () => {
## DBCLICK_FULLSCREEN
On desktop, whether to switch to fullscreen on double click, default is `true`
On desktop, whether to toggle fullscreen on double-click. Default is `true`
<div className="run-code">▶ Run Code</div>
@@ -302,7 +302,7 @@ var art = new Artplayer({
## MOBILE_DBCLICK_PLAY
On mobile, whether to toggle play/pause on double click, default is `true`
On mobile, whether to toggle play/pause on double-click. Default is `true`
<div className="run-code">▶ Run Code</div>
@@ -317,19 +317,7 @@ var art = new Artplayer({
## MOBILE_CLICK_PLAY
On mobile, whether to play/pause on single click, default is `false`
<div className="run-code">▶ Run Code</div>
```js
Artplayer.MOBILE_CLICK_PLAY = true;
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
});
```
On mobile devices, whether a tap toggles play/pause, defaults to `false`
On mobile, whether to toggle play/pause on single click. Default is `false`
<div className="run-code">▶ Run Code</div>
@@ -344,7 +332,7 @@ var art = new Artplayer({
## AUTO_ORIENTATION_TIME
On mobile devices, the delay time for auto-rotation, in milliseconds, defaults to `200`
On mobile, the delay time for automatic screen rotation, in milliseconds. Default is `200`
<div className="run-code">▶ Run Code</div>
@@ -359,7 +347,8 @@ var art = new Artplayer({
```
## INFO_LOOP_TIME
Info panel refresh time, unit in milliseconds, default is `1000`
The refresh interval for the information panel, in milliseconds. Default is `1000`
<div className="run-code">▶ Run Code</div>
@@ -376,7 +365,7 @@ art.info.show = true;
## FAST_FORWARD_VALUE
On mobile, the multiplier rate of the speed when long-pressing for fast-forward, default is `3`
On mobile, the speed multiplier for fast-forward during long press. Default is `3`
<div className="run-code">▶ Run Code</div>
@@ -392,8 +381,7 @@ var art = new Artplayer({
## FAST_FORWARD_TIME
The time, in milliseconds, to fast-forward when double-tapped, default is `10`
On mobile, the delay time of the long-press acceleration, in milliseconds, default is `1000`
On mobile, the delay time for fast-forward during long press, in milliseconds. Default is `1000`
<div className="run-code">▶ Run Code</div>
@@ -409,7 +397,7 @@ var art = new Artplayer({
## TOUCH_MOVE_RATIO
On mobile, the ratio of the speed of sliding left and right to seek, default is `0.5`
On mobile, the speed multiplier for progress seeking during left/right swipe. Default is `0.5`
<div className="run-code">▶ Run Code</div>
@@ -424,7 +412,7 @@ var art = new Artplayer({
## VOLUME_STEP
The step ratio of adjusting volume with shortcuts, default is `0.1`
The volume adjustment step for keyboard shortcuts. Default is `0.1`
<div className="run-code">▶ Run Code</div>
@@ -439,7 +427,7 @@ var art = new Artplayer({
## SEEK_STEP
The increment by which the playback progress is adjusted via keyboard shortcuts, in seconds, the default is `5`
The seek adjustment step for keyboard shortcuts, in seconds. Default is `5`
<div className="run-code">▶ Run Code</div>
@@ -454,7 +442,7 @@ var art = new Artplayer({
## PLAYBACK_RATE
The list of built-in playback speeds, by default `[0.5, 0.75, 1, 1.25, 1.5, 2]`
The built-in playback rate options list. Default is `[0.5, 0.75, 1, 1.25, 1.5, 2]`
<div className="run-code">▶ Run Code</div>
@@ -474,7 +462,7 @@ art.setting.show = true;
## ASPECT_RATIO
Built-in list of video aspect ratios, default is `['default', '4:3', '16:9']`
The built-in video aspect ratio options list. Default is `['default', '4:3', '16:9']`
<div className="run-code">▶ Run Code</div>
@@ -490,10 +478,10 @@ var art = new Artplayer({
art.contextmenu.show = true;
art.setting.show = true;
```
## FLIP
Built-in list of video flips, defaults to `['normal', 'horizontal', 'vertical']`
List of built-in video flip options, defaults to `['normal', 'horizontal', 'vertical']`
<div className="run-code">▶ Run Code</div>
@@ -513,7 +501,7 @@ art.setting.show = true;
## FULLSCREEN_WEB_IN_BODY
When in web fullscreen, whether to mount the player under the `body` element, defaults to `true`
Whether to mount the player under the `body` element during web fullscreen mode, defaults to `true`
<div className="run-code">▶ Run Code</div>
@@ -526,9 +514,10 @@ var art = new Artplayer({
fullscreenWeb: true,
});
```
## LOG_VERSION
Setting whether to print the player version, the default is `true`
Sets whether to print the player version, defaults to `true`
<div className="run-code">▶ Run Code</div>
@@ -543,7 +532,7 @@ var art = new Artplayer({
## USE_RAF
Setting whether to use `requestAnimationFrame`, the default is `false`, currently mainly used for smooth progress bar effects
Sets whether to use `requestAnimationFrame`, defaults to `false`. Currently mainly used for smooth progress bar effects
<div className="run-code">▶ Run Code</div>
@@ -554,5 +543,4 @@ var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
miniProgressBar: true,
});
```
});
@@ -1,8 +1,8 @@
# Writing Plugins
Once you know the player's `properties`, `methods`, and `events`, writing plugins is very simple.
Once you're familiar with the player's `properties`, `methods`, and `events`, writing plugins becomes very straightforward.
You can load plugin functions during instantiation.
You can load plugin functions during instantiation:
<div className="run-code">▶ Run Code</div>
@@ -28,7 +28,8 @@ art.on('ready', () => {
console.info(art.plugins.myPlugin);
});
```
You can also load plugins after instantiation:
You can also load plugin functions after instantiation:
<div className="run-code">▶ Run Code</div>
@@ -56,7 +57,10 @@ art.on('ready', () => {
});
```
For example, I want to write a plugin that displays an image advertisement after the video is paused.
For example, let's say I want to write a plugin that displays an image ad when the video is paused:
<div className="run-code">▶ Run Code</div>
```js
function adsPlugin(option) {
return (art) => {
@@ -117,5 +121,4 @@ var art = new Artplayer({
url: '/assets/sample/layer.png'
})
],
});
```
});
@@ -1,17 +1,16 @@
# Instance Properties
Here, `instance properties` refer to the `primary properties` mounted on the `instance`, which are quite commonly used.
Here, `instance properties` refer to the `top-level properties` mounted on the `instance`, which are commonly used.
## `play`
- Type: `Function`
Play video
Play the video.
<div className="run-code">▶ Run Code</div>
```js{8}
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
@@ -27,7 +26,7 @@ art.on('ready', () => {
- Type: `Function`
Pause video
Pause the video.
<div className="run-code">▶ Run Code</div>
@@ -46,11 +45,12 @@ art.on('ready', () => {
}, 3000);
});
```
## `toggle`
- Type: `Function`
Toggle the play and pause state of the video
Toggle between playing and pausing the video.
<div className="run-code">▶ Run Code</div>
@@ -75,7 +75,7 @@ art.on('ready', () => {
- Type: `Function`
- Parameter: `Boolean`
Destroy the player. Accepts a parameter indicating whether to remove the player's `html` after destruction, which defaults to `true`
Destroy the player. Accepts a parameter indicating whether to also remove the player's `html` after destruction. Defaults to `true`.
<div className="run-code">▶ Run Code</div>
@@ -89,12 +89,13 @@ art.on('ready', () => {
art.destroy();
});
```
## `seek`
- Type: `Setter`
- Parameter: `Number`
Jump to a specific time in the video, in seconds.
Seek to a specific time in the video, in seconds.
<div className="run-code">▶ Run Code</div>
@@ -114,7 +115,7 @@ art.on('ready', () => {
- Type: `Setter`
- Parameter: `Number`
Fast forward the video time, in seconds.
Fast forward the video by a specified number of seconds.
<div className="run-code">▶ Run Code</div>
@@ -128,12 +129,13 @@ art.on('ready', () => {
art.forward = 5;
});
```
## `backward`
- Type: `Setter`
- Parameter: `Number`
Video rewind time in seconds
Rewind the video by a specified number of seconds.
<div className="run-code">▶ Run Code</div>
@@ -157,7 +159,7 @@ art.on('ready', () => {
- Type: `Setter/Getter`
- Parameter: `Number`
Sets and gets the video volume, which ranges from `[0, 1]`
Set or get the video volume. Range: `[0, 1]`.
<div className="run-code">▶ Run Code</div>
@@ -173,12 +175,13 @@ art.on('ready', () => {
console.info(art.volume);
});
```
## `url`
- Type: `Setter/Getter`
- Parameter: `String`
- Type: `Setter/Getter`
- Parameter: `String`
Set and retrieve the video address
Set or get the video URL.
<div className="run-code">▶ Run Code</div>
@@ -195,10 +198,10 @@ art.on('ready', () => {
## `switch`
- Type: `Setter`
- Parameter: `String`
- Type: `Setter`
- Parameter: `String`
Set the video address, which is similar to `art.url`, but performs some optimization operations
Set the video URL. Similar to `art.url` when setting, but performs some optimization operations.
<div className="run-code">▶ Run Code</div>
@@ -215,12 +218,13 @@ art.on('ready', () => {
}, 3000);
});
```
## `switchUrl`
- Type: `Function`
- Parameter: `String`
- Type: `Function`
- Parameter: `String`
Set the video address, similar to setting `art.url`, but some optimization operations will be executed.
Set the video URL. Similar to `art.url` when setting, but performs some optimization operations.
<div className="run-code">▶ Run Code</div>
@@ -238,17 +242,18 @@ art.on('ready', () => {
});
```
:::warning Warning
:::warning Note
`art.switch` and `art.switchUrl` have the same functionality. However, the `art.switchUrl` method will return a `Promise`. When it resolves, it indicates that the new address can be played; when it rejects, it indicates there was an error loading the new address.
`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`
- Type: `Function`
- Parameter: `String`
Set video quality address, similar to `art.switchUrl`, but it will carry over the previous playback progress.
Sets the video quality URL. Similar to `art.switchUrl`, but preserves the previous playback progress.
<div className="run-code">▶ Run Code</div>
@@ -268,10 +273,10 @@ art.on('ready', () => {
## `muted`
- Type: `Setter/Getter`
- Parameter: `Boolean`
- Type: `Setter/Getter`
- Parameter: `Boolean`
Set and get whether the video is muted.
Sets and gets whether the video is muted.
<div className="run-code">▶ Run Code</div>
@@ -293,7 +298,7 @@ art.on('ready', () => {
- Type: `Setter/Getter`
- Parameter: `Number`
Set and get the current time of the video. Setting the time is similar to `seek`, but it does not trigger additional events.
Sets and gets the current playback time of the video. Setting the time is similar to `seek`, but it does not trigger additional events.
<div className="run-code">▶ Run Code</div>
@@ -309,11 +314,12 @@ art.on('ready', () => {
console.info(art.currentTime);
});
```
## `duration`
- Type: `Getter`
Get the video duration
Gets the duration of the video.
<div className="run-code">▶ Run Code</div>
@@ -330,7 +336,7 @@ art.on('ready', () => {
:::warning Note
Some videos do not have a duration, such as videos that are being live streamed or videos that have not been fully decoded, in which case the obtained duration will be `0`
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`.
:::
@@ -338,7 +344,7 @@ Some videos do not have a duration, such as videos that are being live streamed
- Type: `Function`
Download a screenshot of the current video frame, optional parameter is the screenshot name
Downloads a screenshot of the current video frame. An optional parameter specifies the screenshot filename.
<div className="run-code">▶ Run Code</div>
@@ -355,9 +361,9 @@ art.on('ready', () => {
## `getDataURL`
- Type: `Function`
- Type: `Function`
Gets the `base64` address of the screenshot of the current video frame, which returns a `Promise`.
Gets the `base64` URL of the screenshot for the current video frame. Returns a `Promise`.
<div className="run-code">▶ Run Code</div>
@@ -375,9 +381,9 @@ art.on('ready', async () => {
## `getBlobUrl`
- Type: `Function`
- Type: `Function`
Gets the `blob` address of the screenshot of the current video frame, which returns a `Promise`.
Gets the `blob` URL of the screenshot for the current video frame. Returns a `Promise`.
<div className="run-code">▶ Run Code</div>
@@ -392,12 +398,13 @@ art.on('ready', async () => {
console.info(url);
});
```
## `fullscreen`
- Type: `Setter/Getter`
- Parameter: `Boolean`
Set and get the player window fullscreen
Sets and gets the fullscreen state of the player window.
<div className="run-code">▶ Run Code</div>
@@ -419,15 +426,16 @@ var art = new Artplayer({
:::warning Note
Due to browser security mechanisms, before triggering the window to fullscreen, the page must have had an interaction (e.g. user clicked on the page).
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`
- Type: `Setter/Getter`
- Parameter: `Boolean`
Set and get the player web page full screen
Sets and gets the web fullscreen state of the player.
<div className="run-code">▶ Run Code</div>
@@ -449,10 +457,10 @@ art.on('ready', () => {
## `pip`
- Type: `Setter/Getter`
- Parameter: `Boolean`
- Type: `Setter/Getter`
- Parameter: `Boolean`
Set and get the player picture-in-picture mode
Sets and gets the Picture-in-Picture mode of the player.
<div className="run-code">▶ Run Code</div>
@@ -470,11 +478,10 @@ var art = new Artplayer({
},
],
});
```
:::warning Warning
:::warning Note
Due to browser security mechanisms, user interaction (e.g., a user click on the page) must occur before triggering picture-in-picture.
Due to browser security mechanisms, the page must have prior user interaction (e.g., a user click) before Picture-in-Picture can be triggered.
:::
@@ -483,7 +490,7 @@ Due to browser security mechanisms, user interaction (e.g., a user click on the
- Type: `Setter/Getter`
- Parameter: `String`
Set and get the video poster, the poster effect is visible only before the video starts playing.
Sets and gets the video poster. The poster is only visible before video playback starts.
<div className="run-code">▶ Run Code</div>
@@ -500,12 +507,13 @@ art.on('ready', () => {
console.info(art.poster);
});
```
## `mini`
- Type: `Setter/Getter`
- Parameter: `Boolean`
- Type: `Setter/Getter`
- Parameter: `Boolean`
Set and get the player's mini mode
Sets and gets the player's mini mode.
<div className="run-code">▶ Run Code</div>
@@ -522,10 +530,10 @@ art.on('ready', () => {
## `playing`
- Type: `Getter`
- Parameter: `Boolean`
- Type: `Getter`
- Parameter: `Boolean`
Get whether the video is currently playing
Gets whether the video is currently playing.
<div className="run-code">▶ Run Code</div>
@@ -540,11 +548,12 @@ art.on('ready', () => {
console.info(art.playing);
});
```
## `autoSize`
- Type: `Function`
Sets whether the video should auto adjust its size
Sets whether the video should automatically adjust its size.
<div className="run-code">▶ Run Code</div>
@@ -563,7 +572,7 @@ art.on('ready', () => {
- Type: `Getter`
Gets the size and position information of the player
Gets the player's dimensions and coordinate information.
<div className="run-code">▶ Run Code</div>
@@ -577,9 +586,10 @@ art.on('ready', () => {
console.info(JSON.stringify(art.rect));
});
```
:::warning Warning
The size and coordinates are obtained via `getBoundingClientRect`
:::warning Note
The dimension and coordinate information is obtained via `getBoundingClientRect`.
:::
@@ -588,7 +598,7 @@ The size and coordinates are obtained via `getBoundingClientRect`
- Type: `Setter/Getter`
- Parameter: `String`
Set and get the player flip, supports `normal`, `horizontal`, `vertical`
Sets and gets the player flip mode. Supports `normal`, `horizontal`, `vertical`.
<div className="run-code">▶ Run Code</div>
@@ -609,7 +619,8 @@ art.on('ready', () => {
- Type: `Setter/Getter`
- Parameter: `Number`
Set and get the playback speed of the player
Sets and gets the player's playback speed.
<div className="run-code">▶ Run Code</div>
@@ -631,7 +642,7 @@ art.on('ready', () => {
- Type: `Setter/Getter`
- Parameter: `String`
Set and get the aspect ratio of the player
Sets and gets the player's aspect ratio.
<div className="run-code">▶ Run Code</div>
@@ -647,11 +658,12 @@ art.on('ready', () => {
console.info(art.aspectRatio);
});
```
## `autoHeight`
- Type: `Function`
When the container has only width, this attribute can automatically calculate and set the height of the video
When the container only has a defined width, this property can automatically calculate and set the video's height.
<div className="run-code">▶ Run Code</div>
@@ -670,9 +682,9 @@ art.on('resize', () => {
});
```
:::warning Warning
:::warning Note
When your container has only width but you do not know the exact height, this property is very useful as it can automatically calculate the video's height, but you need to make sure when to set this property.
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.
:::
@@ -681,7 +693,7 @@ When your container has only width but you do not know the exact height, this pr
- Type: `Function`
- Parameter: `String`
Dynamically get and set the attributes of the video element
Dynamically gets and sets attributes of the video element.
<div className="run-code">▶ Run Code</div>
@@ -700,10 +712,10 @@ art.on('ready', () => {
## `type`
- Type: `Setter/Getter`
- Parameter: `String`
- Type: `Setter/Getter`
- Parameter: `String`
Dynamically get and set the video type
Dynamically gets and sets the video type.
<div className="run-code">▶ Run Code</div>
@@ -718,13 +730,13 @@ art.on('ready', () => {
art.type = 'm3u8';
console.info(art.type);
});
```
## `theme`
- Type: `Setter/Getter`
- Parameter: `String`
Dynamically get and set the player's theme color
Dynamically gets and sets the player's theme color.
<div className="run-code">▶ Run Code</div>
@@ -745,7 +757,7 @@ art.on('ready', () => {
- Type: `Function`
Activate airplay
Initiates AirPlay.
<div className="run-code">▶ Run Code</div>
@@ -764,11 +776,12 @@ var art = new Artplayer({
],
});
```
## `loaded`
- Type: `Getter`
- Type: `Getter`
The proportion of the video that is cached, ranging from `[0, 1]`, commonly used with the `video:timeupdate` event.
The proportion of the video that has been buffered, ranging from `[0, 1]`. Often used with the `video:timeupdate` event.
<div className="run-code">▶ Run Code</div>
@@ -785,9 +798,9 @@ art.on('video:timeupdate', () => {
## `played`
- Type: `Getter`
- Type: `Getter`
The proportion of the video that has been played, ranging from `[0, 1]`, commonly used with the `video:timeupdate` event.
The proportion of the video that has been played, ranging from `[0, 1]`. Often used with the `video:timeupdate` event.
<div className="run-code">▶ Run Code</div>
@@ -801,11 +814,12 @@ art.on('video:timeupdate', () => {
console.info(art.played);
});
```
## `proxy`
- Type: `Function`
- Type: `Function`
A proxy function for `DOM` events, which essentially proxies `addEventListener` and `removeEventListener`. When using `proxy` to handle events, the event will automatically be destroyed when the player is destroyed.
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.
<div className="run-code">▶ Run Code</div>
@@ -822,9 +836,9 @@ art.proxy(container, 'click', event => {
});
```
:::warning Tip
:::warning Note
If you need some `DOM` events to exist only during the lifespan of the player, it is highly recommended to use this function to avoid causing memory leaks.
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.
:::
@@ -832,7 +846,7 @@ If you need some `DOM` events to exist only during the lifespan of the player, i
- Type: `Function`
DOM query function, similar to `document.querySelector`, but the object being queried is limited within the current player, which can prevent errors due to having the same class name.
A DOM query function, similar to `document.querySelector`, but the search is scoped to within the current player, preventing errors from duplicate class names.
<div className="run-code">▶ Run Code</div>
@@ -849,7 +863,7 @@ console.info(art.query('.art-video'));
- Type: `Element`
A shortcut to return the `video` element of the player.
Quickly returns the player's `video` element.
<div className="run-code">▶ Run Code</div>
@@ -866,7 +880,7 @@ console.info(art.video);
- Type: `Function`
Dynamically getting or setting `css` variables
Dynamically gets or sets CSS variables.
<div className="run-code">▶ Run Code</div>
@@ -888,7 +902,7 @@ art.on('ready', () => {
- Type: `Setter`
- Parameter: `Array`
Dynamically setting the list of qualities
Dynamically sets the list of available quality levels.
<div className="run-code">▶ Run Code</div>
@@ -931,7 +945,7 @@ art.on('ready', () => {
- Type: `Setter/Getter`
- Parameter: `Object`
Dynamically set thumbnails
Dynamically sets the thumbnails.
<div className="run-code">▶ Run Code</div>
@@ -970,5 +984,4 @@ var art = new Artplayer({
art.on('ready', () => {
art.subtitleOffset = 1;
});
```
});
@@ -2,16 +2,16 @@
## Configuration
| Property | Type | Description |
| --------- | ------------------- | ----------------------------|
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | Unique name of the component, used for marking the class name |
| `index` | `Number` | Component index, used for display priority |
| `html` | `String`, `Element` | The DOM element of the component |
| `style` | `Object` | Style object for the component |
| `click` | `Function` | Click event for the component |
| `mounted` | `Function` | Triggered after the component is mounted |
| `tooltip` | `String` | Tooltip text for the component |
| Property | Type | Description |
| --------- | ------------------- | ------------------------------------ |
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | Unique component name for CSS class |
| `index` | `Number` | Component index for display priority |
| `html` | `String`, `Element` | Component DOM element |
| `style` | `Object` | Component style object |
| `click` | `Function` | Component click event |
| `mounted` | `Function` | Triggered after component mount |
| `tooltip` | `String` | Component tooltip text |
## Creation
@@ -38,7 +38,8 @@ art.contextmenu.show = true;
// Get the Element of contextmenu by name
console.info(art.contextmenu['your-menu']);
```
## Add
## Addition
<div className="run-code">▶ Run Code</div>
@@ -63,7 +64,7 @@ art.contextmenu.show = true;
console.info(art.contextmenu['your-menu']);
```
## Delete
## Removal
<div className="run-code">▶ Run Code</div>
@@ -87,13 +88,13 @@ art.contextmenu.show = true;
art.on('ready', () => {
setTimeout(() => {
// Delete the context menu by name
// Delete the contextmenu by name
art.contextmenu.remove('your-menu')
}, 3000);
});
```
## Updates
## Update
<div className="run-code">▶ Run Code</div>
@@ -123,5 +124,4 @@ art.on('ready', () => {
html: 'Your New Menu',
})
}, 3000);
});
```
});
@@ -1,20 +1,20 @@
# Controller
# Controllers
## Configuration
| Property | Type | Description |
| ---------- | ------------------- | ------------------------------------------ |
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | The unique name of the component for class identification |
| `index` | `Number` | The index of the component, used for display priority |
| `html` | `String`, `Element` | The component's DOM element |
| `style` | `Object` | The style object for the component |
| `click` | `Function` | Component click event |
| `mounted` | `Function` | Triggered after the component is mounted |
| `tooltip` | `String` | Tooltip text for the component |
| `position` | `String` | `left` and `right` control the position of the controller |
| `selector` | `Array` | An array of objects for the selection list |
| `onSelect` | `Function` | Function triggered when an item from the selection list is clicked |
| Property | Type | Description |
| ----------- | ------------------- | ------------------------------------------------ |
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | Unique component name for CSS class identification |
| `index` | `Number` | Component index for display priority |
| `html` | `String`, `Element` | Component DOM element |
| `style` | `Object` | Component style object |
| `click` | `Function` | Component click event |
| `mounted` | `Function` | Triggered after component mounting |
| `tooltip` | `String` | Component tooltip text |
| `position` | `String` | `left` and `right` control controller placement |
| `selector` | `Array` | Array of selector list objects |
| `onSelect` | `Function` | Function triggered when selector item is clicked |
## Creation
@@ -66,7 +66,8 @@ var art = new Artplayer({
console.info(art.controls['your-button']);
console.info(art.controls['subtitle']);
```
## Adding
## Addition
<div className="run-code">▶ Run Code</div>
@@ -96,7 +97,8 @@ art.controls.add({
// Get the Element of control by name
console.info(art.controls['button1']);
```
## Delete
## Removal
<div className="run-code">▶ Run Code</div>
@@ -125,6 +127,7 @@ art.on('ready', () => {
}, 3000);
});
```
## Update
<div className="run-code">▶ Run Code</div>
@@ -171,5 +174,4 @@ art.on('ready', () => {
],
});
}, 3000);
});
```
});
@@ -1,17 +1,17 @@
# Layer
# Business Layer
## Configuration
| Property | Type | Description |
| --------- | --------------------- | ---------------------------- |
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | Unique name of the component, used for marking class name |
| `index` | `Number` | Component index, used for display priority |
| `html` | `String`, `Element` | The DOM element of the component |
| `style` | `Object` | Style object for the component |
| `click` | `Function` | Click event for the component |
| `mounted` | `Function` | Triggered after the component is mounted |
| `tooltip` | `String` | Tooltip text for the component |
| Property | Type | Description |
| --------- | ------------------- | ------------------------------------ |
| `disable` | `Boolean` | Whether to disable the component |
| `name` | `String` | Unique component name for class marking |
| `index` | `Number` | Component index for display priority |
| `html` | `String`, `Element` | Component DOM element |
| `style` | `Object` | Component style object |
| `click` | `Function` | Component click event |
| `mounted` | `Function` | Triggered after component mounting |
| `tooltip` | `String` | Component tooltip text |
## Creation
@@ -24,9 +24,9 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
layers: [
{
name: 'poster',
name: 'potser',
html: `<img style="width: 100px" src="${img}">`,
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
<div className="run-code">▶ Run Code</div>
@@ -57,9 +58,9 @@ var art = new Artplayer({
});
art.layers.add({
name: 'poster',
name: 'potser',
html: `<img style="width: 100px" src="${img}">`,
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
<div className="run-code">▶ Run Code</div>
@@ -87,7 +89,7 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
layers: [
{
name: 'poster',
name: 'potser',
html: `<img style="width: 100px" src="${img}">`,
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
<div className="run-code">▶ Run Code</div>
@@ -116,7 +119,7 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
layers: [
{
name: 'poster',
name: 'potser',
html: `<img style="width: 100px" src="${img}">`,
style: {
position: 'absolute',
@@ -131,7 +134,7 @@ art.on('ready', () => {
setTimeout(() => {
// Update the layer by name
art.layers.update({
name: 'poster',
name: 'potser',
html: `<img style="width: 200px" src="${img}">`,
style: {
position: 'absolute',
@@ -140,5 +143,4 @@ art.on('ready', () => {
},
});
}, 3000);
});
```
});
@@ -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`
<div className="run-code">▶ Run Code</div>
@@ -10,7 +10,7 @@ First, open the settings panel, and then it comes with four built-in items: `fli
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
setting: true,
setting: true,
flip: true,
playbackRate: true,
aspectRatio: true,
@@ -20,13 +20,13 @@ var art = new Artplayer({
## Create - Button
| Property | Type | Description |
| ---------- | ------------------- | ------------- |
| `html` | `String`, `Element` | Item DOM |
| `icon` | `String`, `Element` | Item Icon |
| `onClick` | `Function` | Click event |
| `width` | `Number` | List Width |
| `tooltip` | `String` | Tooltip text |
| Property | Type | Description |
| ---------- | ------------------- | -------------------- |
| `html` | `String`, `Element` | Element DOM |
| `icon` | `String`, `Element` | Element icon |
| `onClick` | `Function` | Element click event |
| `width` | `Number` | List width |
| `tooltip` | `String` | Tooltip text |
<div className="run-code">▶ Run Code</div>
@@ -49,16 +49,16 @@ var art = new Artplayer({
});
```
## Create - Selection List
## Create - Selector List
| Property | Type | Description |
| ---------- | ------------------- | ------------- |
| `html` | `String`, `Element` | Item DOM |
| `icon` | `String`, `Element` | Item Icon |
| `selector` | `Array` | Item selector |
| `onSelect` | `Function` | Click event |
| `width` | `Number` | List Width |
| `tooltip` | `String` | Tooltip text |
| Property | Type | Description |
| ---------- | ------------------- | -------------------- |
| `html` | `String`, `Element` | Element DOM |
| `icon` | `String`, `Element` | Element icon |
| `selector` | `Array` | Element list |
| `onSelect` | `Function` | Element click event |
| `width` | `Number` | List width |
| `tooltip` | `String` | Tooltip text |
<div className="run-code">▶ Run Code</div>
@@ -118,7 +118,7 @@ var art = new Artplayer({
});
```
## Creating - Nested Lists
## Create - Nested List
<div className="run-code">▶ Run Code</div>
@@ -167,16 +167,16 @@ var art = new Artplayer({
},
],
});
```
## Create - Toggle Button
| Property | Type | Description |
| ---------- | ------------------- | ---------------------- |
| `html` | `String`, `Element` | Element's DOM element |
| `icon` | `String`, `Element` | Element's icon |
| `switch` | `Boolean` | Button's default state |
| `onSwitch` | `Function` | Button toggle event |
| `tooltip` | `String` | Tooltip text |
| Property | Type | Description |
| ---------- | ------------------- | ------------------------- |
| `html` | `String`, `Element` | DOM element of the item |
| `icon` | `String`, `Element` | Icon of the item |
| `switch` | `Boolean` | Default state of the button |
| `onSwitch` | `Function` | Button toggle event |
| `tooltip` | `String` | Tooltip text |
<div className="run-code">▶ Run Code</div>
@@ -202,16 +202,17 @@ var art = new Artplayer({
],
});
```
## Create - Range Slider
| Attribute | Type | Description |
| ---------- | ------------------- | ------------------------------- |
| `html` | `String`, `Element` | The element's DOM element |
| `icon` | `String`, `Element` | The element's icon |
| `range` | `Array` | Default state array |
| `onRange` | `Function` | Event triggered upon completion |
| `onChange` | `Function` | Event triggered on change |
| `tooltip` | `String` | Tooltip text |
| Property | Type | Description |
| ---------- | ------------------- | ------------------------- |
| `html` | `String`, `Element` | DOM element of the item |
| `icon` | `String`, `Element` | Icon of the item |
| `range` | `Array` | Default state array |
| `onRange` | `Function` | Event triggered on completion |
| `onChange` | `Function` | Event triggered on change |
| `tooltip` | `String` | Tooltip text |
```js
const range = [5, 1, 10, 1];
@@ -220,6 +221,7 @@ const min = range[1];
const max = range[2];
const step = range[3];
```
<div className="run-code">▶ Run Code</div>
```js
@@ -241,6 +243,7 @@ var art = new Artplayer({
],
});
```
## Add
<div className="run-code">▶ Run Code</div>
@@ -262,7 +265,7 @@ art.setting.add({
});
```
## Delete
## Remove
<div className="run-code">▶ Run Code</div>
@@ -292,7 +295,8 @@ art.on('ready', () => {
}, 3000);
});
```
## Updates
## Update
<div className="run-code">▶ Run Code</div>
@@ -325,5 +329,4 @@ art.on('ready', () => {
switch: false,
});
}, 3000);
});
```
});
+33 -31
View File
@@ -1,4 +1,4 @@
# Installation and Usage
# Installation & Usage
## Installation
@@ -22,7 +22,7 @@ pnpm add artplayer
:::
## `CDN`
## CDN
::: code-group
@@ -66,19 +66,20 @@ https://unpkg.com/artplayer/dist/artplayer.js
```
:::
::: warning Warning
The player's size depends on the size of the container `container`, so your container `container` must have a size.
::: warning Note
The player's dimensions depend on the size of its `container`, so your container must have defined dimensions
:::
::: tip You can find more usage examples at the link below
::: tip See more usage examples at the following link
[/packages/artplayer-template](https://github.com/zhw2590582/ArtPlayer/tree/master/packages/artplayer-template)
:::
## `Vue.js`
## Vue.js
::: code-group
@@ -144,14 +145,13 @@ function getInstance(art) {
:::
::: warning Artplayer is not reactive:
::: warning Artplayer Not Responsive:
Modifying `option` directly in `Vue.js` will not change the player
Directly modifying `option` in `Vue.js` will not update the player
:::
## `React.js`
## React.js
::: code-group
@@ -205,15 +205,15 @@ export default App
:::
::: warning Non-responsive Artplayer
::: warning Artplayer is not reactive:
In `React.js`, directly modifying the `option` will not change the player
Directly modifying `option` in `React.js` will not update the player
:::
## TypeScript
Importing `Artplayer` will automatically import `artplayer.d.ts`
The `artplayer.d.ts` file is automatically imported when importing `Artplayer`
### Vue.js
@@ -250,16 +250,17 @@ option.volume = 0.5;
const art = new Artplayer(option);
```
::: tip Complete TypeScript Definitions
::: tip All TypeScript Definitions
[packages/artplayer/types](https://github.com/zhw2590582/ArtPlayer/tree/master/packages/artplayer/types)
:::
## JavaScript
Sometimes your `js` file may lose the `TypeScript` type hints, in this case, you can manually import the types
Sometimes your `js` files may lose `TypeScript` type hints. In such cases, you can manually import the types.
Variables:
Variable:
```js{1-3}
/**
@@ -268,7 +269,7 @@ Variables:
let art = null;
```
Parameters:
Parameter:
```js{1-3}
/**
@@ -279,7 +280,7 @@ function getInstance(art) {
}
```
Properties:
Property:
```js{4-6}
export default {
@@ -294,7 +295,7 @@ export default {
}
```
Options:
Option:
```js{1-3}
/**
@@ -310,11 +311,12 @@ option.volume = 0.5;
const art8 = new Artplayer(option);
```
## Ancient Browsers
The production build of `artplayer.js` is only compatible with the latest major version of `Chrome`: `last 1 Chrome version`
## Legacy Browsers
For ancient browsers, you can use the `artplayer.legacy.js` file, which is compatible up to: `IE 11`
The production build `artplayer.js` only supports the latest major version of `Chrome`: `last 1 Chrome version`.
For legacy browsers, you can use the `artplayer.legacy.js` file, which supports compatibility down to: `IE 11`.
```js
import Artplayer from 'artplayer/legacy'
@@ -332,11 +334,11 @@ https://unpkg.com/artplayer/dist/artplayer.legacy.js
:::
::: tip If you need to support even older browsers, please modify the following configuration and then build it yourself:
::: tip If you need to support even older browsers, modify the following configuration and build it yourself:
Build configuration: [scripts/build.js](https://github.com/zhw2590582/ArtPlayer/blob/master/scripts/build.js#L29)
Build Configuration: [scripts/build.js](https://github.com/zhw2590582/ArtPlayer/blob/master/scripts/build.js#L29)
Refer to documentation: [browserslist](https://github.com/browserslist/browserslist#full-list)
Reference Documentation: [browserslist](https://github.com/browserslist/browserslist#full-list)
:::
@@ -348,7 +350,7 @@ Refer to documentation: [browserslist](https://github.com/browserslist/browsersl
:::
Starting from `5.2.6`, `artplayer` and all plugins will also provide an `ESM` version of `mjs`, such as:
Starting from `5.2.6`, `artplayer` and all plugins also provide an `ESM` version `mjs`, such as:
- `artplayer/dist/artplayer.mjs`
- `artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs`
@@ -371,7 +373,7 @@ Starting from `5.2.6`, `artplayer` and all plugins will also provide an `ESM` ve
<script type="importmap">
{
"imports": {
"artplayer": "https://unpkg.com/artplayer/dist/artplayer.mjs"
"artplayer": "https://unpkg.com/artplayer/dist/artplayer.esm.js"
}
}
</script>
@@ -394,7 +396,7 @@ Starting from `5.2.6`, `artplayer` and all plugins will also provide an `ESM` ve
## Custom userAgent
Currently, the determination of mobile devices is not accurate. Sometimes, you may want to adjust the player UI by changing the `userAgent`. Therefore, starting in version `5.2.4`, we added a new `globalThis.CUSTOM_USER_AGENT` global variable.
Currently, the detection for whether a device is mobile is not entirely accurate. Sometimes you may want to adjust the player's UI by changing the `userAgent`. Therefore, starting from `5.2.4`, a `globalThis.CUSTOM_USER_AGENT` global variable has been added.
```html
<html>
@@ -422,8 +424,8 @@ Currently, the determination of mobile devices is not accurate. Sometimes, you m
</html>
```
::: warning Warning
::: warning Note
You need to modify it before import the `Artplayer` for it to take effect
You need to modify it before importing the `Artplayer` dependency for it to take effect.
:::
:::
@@ -0,0 +1,555 @@
# Danmaku Library
## Demo
👉 [View Full Demo](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku)
## Installation
::: code-group
```bash [npm]
npm install artplayer-plugin-danmuku
```
```bash [yarn]
yarn add artplayer-plugin-danmuku
```
```bash [pnpm]
pnpm add artplayer-plugin-danmuku
```
```html [script]
<script src="path/to/artplayer-plugin-danmuku.js"></script>
```
:::
## CDN
::: code-group
```bash [jsdelivr.net]
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
```
```bash [unpkg.com]
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
```
:::
## Danmaku Structure
Each danmaku is an object, and an array of multiple danmaku objects forms the danmaku library. Typically, only `text` is required to send a danmaku, while the rest are optional parameters.
```js
{
text: '', // Danmaku text
time: 10, // Danmaku timestamp, defaults to current player time
mode: 0, // Danmaku mode: 0: scroll (default), 1: top, 2: bottom
color: '#FFFFFF', // Danmaku color, defaults to white
border: false, // Whether the danmaku has a border, defaults to false
style: {}, // Custom danmaku styles, defaults to an empty object
}
```
## All Options
Only `danmuku` is a required parameter; all others are optional.
```js
{
danmuku: [], // Danmaku data
speed: 5, // Danmaku duration, range [1 ~ 10]
margin: [10, '25%'], // Danmaku top and bottom margins, supports pixel values and percentages
opacity: 1, // Danmaku opacity, range [0 ~ 1]
color: '#FFFFFF', // Default danmaku color, can be overridden by individual danmaku items
mode: 0, // Default danmaku mode: 0: scroll, 1: top, 2: bottom
modes: [0, 1, 2], // Visible danmaku modes
fontSize: 25, // Danmaku font size, supports pixel values and percentages
antiOverlap: true, // Whether to prevent danmaku overlap
synchronousPlayback: false, // Whether to synchronize playback speed
mount: undefined, // Danmaku emitter mount point, defaults to the middle of the player control bar
heatmap: false, // Whether to enable the heatmap
width: 512, // When the player width is less than this value, the danmaku emitter is placed at the bottom of the player
points: [], // Heatmap data
filter: () => true, // Filter before danmaku loading, only supports boolean return values
beforeEmit: () => true, // Filter before danmaku emission, supports Promise return
beforeVisible: () => true, // Filter before danmaku display, supports Promise return
visible: true, // Whether the danmaku layer is visible
emitter: true, // Whether to enable the danmaku emitter
maxLength: 200, // Maximum input length for the danmaku input box, range [1 ~ 1000]
lockTime: 5, // Input box lock time, range [1 ~ 60]
theme: 'dark', // Danmaku theme, supports 'dark' and 'light', only effective when custom mounted
OPACITY: {}, // Opacity configuration
FONT_SIZE: {}, // Font size configuration
MARGIN: {}, // Display area configuration
SPEED: {}, // Danmaku speed configuration
COLOR: [], // Color list configuration
}
```
## Lifecycle
For user-input danmaku:
`beforeEmit -> filter -> beforeVisible -> artplayerPluginDanmuku:visible`
For server-side danmaku:
`filter -> beforeVisible -> artplayerPluginDanmuku:visible`
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
// Save to database
function saveDanmu(danmu) {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 1000);
})
}
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
// This function is triggered when the user enters danmaku text in the input box and clicks the send button
// You can perform validation on the danmaku or save it to the database
// The danmaku is added to the queue only when true is returned
async beforeEmit(danmu) {
const isDirty = (/fuck/i).test(danmu.text);
if (isDirty) return false;
const state = await saveDanmu(danmu);
return state;
},
// This is a filter for all danmaku, including those from the server and user input
// You can perform validation on the danmaku
// The danmaku is added to the queue only when true is returned
filter(danmu) {
return danmu.text.length <= 200;
},
// This function is triggered when the danmaku is about to be displayed
// You can perform validation on the danmaku
// The danmaku is sent to the player only when true is returned
async beforeVisible(danmu) {
return true;
},
}),
],
});
// The danmaku has appeared in the player, and you can access its DOM element
art.on('artplayerPluginDanmuku:visible', danmu => {
danmu.$ref.innerHTML = 'ଘ(੭ˊᵕˋ)੭: ' + danmu.$ref.innerHTML;
})
```
## Using Danmaku Array
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: [
{
text: 'Using array',
time: 1
},
],
}),
],
});
## Using Danmaku XML
The danmaku XML file follows the same format as Bilibili's danmaku system
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
```
## Using Asynchronous Returns
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: function () {
return new Promise((resovle) => {
return resovle([
{
text: 'Using Promise for asynchronous return',
time: 1
},
]);
});
},
}),
],
});
```
## `hide/show`
Use the `hide` and `show` methods to hide or display danmaku
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
controls: [
{
position: 'right',
html: 'Hide Danmaku',
click: function () {
art.plugins.artplayerPluginDanmuku.hide();
},
},
{
position: 'right',
html: 'Show Danmaku',
click: function () {
art.plugins.artplayerPluginDanmuku.show();
},
},
],
});
```
## `isHide`
Use the `isHide` property to determine if danmaku is currently hidden or displayed
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
controls: [
{
position: 'right',
html: 'Hide Danmaku',
click: function (_, event) {
if (art.plugins.artplayerPluginDanmuku.isHide) {
art.plugins.artplayerPluginDanmuku.show();
event.target.innerText = 'Hide Danmaku';
} else {
art.plugins.artplayerPluginDanmuku.hide();
event.target.innerText = 'Show Danmaku';
}
},
},
],
});
```
## `emit`
Use the `emit` method to send a real-time danmaku
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
controls: [
{
position: 'right',
html: 'Send Danmaku',
click: function () {
var text = prompt('Please enter danmaku text', 'Danmaku test text');
if (!text || !text.trim()) return;
var color = '#' + Math.floor(Math.random() * 0xffffff).toString(16);
art.plugins.artplayerPluginDanmuku.emit({
text: text,
color: color,
border: true,
});
},
},
],
});
```
## `config`
Use the `config` method to dynamically change danmaku settings
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
controls: [
{
position: 'right',
html: 'Danmaku Size:<input type="range" min="12" max="50" step="1" value="25">',
style: {
display: 'flex',
alignItems: 'center',
},
mounted: function ($setting) {
const $range = $setting.querySelector('input[type=range]');
$range.addEventListener('change', () => {
art.plugins.artplayerPluginDanmuku.config({
fontSize: Number($range.value),
});
});
},
},
],
});
## `load`
The `load` method can be used to reload the current danmaku library, switch to a new danmaku library, or append a new danmaku library.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
emitter: false,
}),
],
controls: [
{
position: 'right',
html: 'Reload',
click: function () {
// Reload the current danmaku library
art.plugins.artplayerPluginDanmuku.load();
},
},
{
position: 'right',
html: 'Switch',
click: function () {
// Switch to a new danmaku library
art.plugins.artplayerPluginDanmuku.config({
danmuku: '/assets/sample/danmuku-v2.xml',
});
art.plugins.artplayerPluginDanmuku.load();
},
},
{
position: 'right',
html: 'Append',
click: function () {
// Append a new danmaku library (parameter type is the same as option.danmuku)
const target = '/assets/sample/danmuku.xml'
art.plugins.artplayerPluginDanmuku.load(target);
},
},
],
});
```
## `reset`
Used to clear the currently displayed danmaku.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
art.on('resize', () => {
art.plugins.artplayerPluginDanmuku.reset();
});
```
## `mount`
When initializing the danmaku plugin, you can specify the mount position for the danmaku emitter. By default, it is mounted in the center of the control bar. You can also mount it outside the player.
When the player enters fullscreen mode, the emitter will automatically return to the center of the control bar. If the mounted location has a light background, it is recommended to set `theme` to `light` to ensure visibility.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var $danmu = document.querySelector('.artplayer-app');
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
fullscreenWeb: true,
plugins: [
artplayerPluginDanmuku({
mount: $danmu,
theme: 'dark',
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
// Can also be mounted manually
// art.plugins.artplayerPluginDanmuku.mount($danmu);
```
## `option`
Used to get the current danmaku configuration.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
art.on('ready', () => {
console.info(art.plugins.artplayerPluginDanmuku.option);
});
```
## Events
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
art.on('artplayerPluginDanmuku:visible', (danmu) => {
console.info('Danmaku visible', danmu);
});
art.on('artplayerPluginDanmuku:loaded', (danmus) => {
console.info('Danmaku loaded', danmus.length);
});
art.on('artplayerPluginDanmuku:error', (error) => {
console.info('Load error', error);
});
art.on('artplayerPluginDanmuku:config', (option) => {
console.info('Configuration changed', option);
});
art.on('artplayerPluginDanmuku:stop', () => {
console.info('Danmaku stopped');
});
art.on('artplayerPluginDanmuku:start', () => {
console.info('Danmaku started');
});
art.on('artplayerPluginDanmuku:hide', () => {
console.info('Danmaku hidden');
});
art.on('artplayerPluginDanmuku:show', () => {
console.info('Danmaku shown');
});
art.on('artplayerPluginDanmuku:reset', () => {
console.info('Danmaku reset');
});
art.on('artplayerPluginDanmuku:destroy', () => {
console.info('Danmaku destroyed');
});
@@ -2,19 +2,19 @@
::: danger
Given the increasing number of bundled multilingual packs, starting from version `5.1.0`, the core code of `artplayer.js` will no longer include other languages besides `Simplified Chinese` and `English`. You need to import the required languages on your own.
Due to the increasing number of bundled multi-language packs, starting from version `5.1.0`, the `artplayer.js` core code only includes `Simplified Chinese` and `English` by default. Other languages are no longer bundled and must be manually imported as needed.
:::
:::warning
When a language cannot be matched, English will be displayed by default. For i18n usage, refer to: [artplayer/types/i18n.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/i18n.d.ts)
When a language cannot be matched, English will be displayed by default. For i18n syntax reference, see: [artplayer/types/i18n.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/i18n.d.ts)
:::
## Default Languages
The default languages are: `en`, `zh-cn`, which do not require manual import.
The default languages are: `en`, `zh-cn`, no manual import required
```js{4}
var art = new Artplayer({
@@ -26,9 +26,9 @@ var art = new Artplayer({
## Importing Languages
Language files before packaging are located in: `artplayer/src/i18n/*.js`.
Language files before bundling are located at: `artplayer/src/i18n/*.js`. Contributions to add your language are welcome.
Packaged language files are located at: `artplayer/dist/i18n/*.js`.
Language files after bundling are located at: `artplayer/dist/i18n/*.js`
::: code-group
@@ -63,7 +63,8 @@ var art = new Artplayer({
```
:::
## Add Language
## Adding a New Language
```js{4-9}
var art = new Artplayer({
@@ -78,7 +79,7 @@ var art = new Artplayer({
});
```
## Modify Language
## Modifying Languages
```js
import zhTw from 'artplayer/i18n/zh-tw';
@@ -97,5 +98,4 @@ var art = new Artplayer({
Play: 'Your Play'
},
},
});
```
});
@@ -2,22 +2,22 @@
## `container`
- Type: `String, Element`
- Default: `#artplayer`
- Type: `String, Element`
- Default: `#artplayer`
The `DOM` container where the player mounts
The `DOM` container where the player is mounted.
<div className="run-code">▶ Run Code</div>
```js{2}
var art = new Artplayer({
container: '.artplayer-app',
container: '.artplayer-app',
// container: document.querySelector('.artplayer-app'),
url: '/assets/sample/video.mp4',
});
```
You may need to initialize the size of the container element, like:
You may need to initialize the size of the container element, for example:
```css{2-3}
.artplayer-app {
@@ -34,17 +34,18 @@ Or use `aspect-ratio`:
}
```
:::warning Tip
:::warning Note
Among all options, only `container` is mandatory.
Among all options, only `container` is required.
:::
## `url`
- Type: `String`
- Default: `''`
- Type: `String`
- Default: `''`
The video source address
The video source URL.
<div className="run-code">▶ Run Code</div>
@@ -55,7 +56,7 @@ var art = new Artplayer({
});
```
Sometimes the `url` is not known so quickly, in which case you can set the `url` asynchronously.
Sometimes the `url` is not known immediately; in such cases, you can set the `url` asynchronously.
<div className="run-code">▶ Run Code</div>
@@ -71,17 +72,18 @@ setTimeout(() => {
:::warning Note
The default support is for three video file formats: `.mp4`, `.ogg`, `.webm`.
By default, three video file formats are supported: `.mp4`, `.ogg`, `.webm`.
If you need to play other formats such as `.m3u8` or `.flv`, please refer to the `Third-party Libraries` on the left side.
To play other formats like `.m3u8` or `.flv`, please refer to the `Third-party Libraries` section on the left.
:::
## `id`
- Type: `String`
- Default: `''`
- Type: `String`
- Default: `''`
The unique identifier of the player, currently used only for remembering playback with `autoplayback`
The unique identifier for the player, currently only used for playback resumption (`autoplayback`).
<div className="run-code">▶ Run Code</div>
@@ -95,10 +97,10 @@ var art = new Artplayer({
## `onReady`
- Type: `Function`
- Default: `undefined`
- Type: `Function`
- Default: `undefined`
The constructor accepts a function as the second argument, which is triggered when the player is successfully initialized and the video is ready to play, similar to the `ready` event
The constructor accepts a function as the second argument, which is triggered when the player is successfully initialized and the video is ready to play, similar to the `ready` event.
<div className="run-code">▶ Run Code</div>
@@ -114,6 +116,7 @@ var art = new Artplayer(
},
);
```
Equivalent to:
```js{7-9}
@@ -128,9 +131,9 @@ art.on('ready', () => {
});
```
:::warning Warning
:::warning Note
The `this` inside the callback function refers to the player instance, but if an arrow function is used for the callback, `this` will not point to the player instance.
Inside the callback function, `this` refers to the player instance. However, if an arrow function is used for the callback, `this` will not point to the player instance.
:::
@@ -139,7 +142,7 @@ The `this` inside the callback function refers to the player instance, but if an
- Type: `String`
- Default: `''`
The poster of the video, which only appears when the player is initialized and before it starts playing.
The video poster image, which only appears when the player is initialized and not yet playing.
<div className="run-code">▶ Run Code</div>
@@ -150,12 +153,13 @@ var art = new Artplayer({
poster: '/assets/sample/poster.jpg',
});
```
## `theme`
- Type: `String`
- Default: `#f00`
- Type: `String`
- Default: `#f00`
Player theme color, currently used for `progress bar` and `highlight elements`
The player's theme color, currently used for the `progress bar` and `highlighted elements`.
<div className="run-code">▶ Run Code</div>
@@ -169,10 +173,10 @@ var art = new Artplayer({
## `volume`
- Type: `Number`
- Default: `0.7`
- Type: `Number`
- Default: `0.7`
The default volume of the player
The default volume of the player.
<div className="run-code">▶ Run Code</div>
@@ -184,17 +188,18 @@ var art = new Artplayer({
});
```
:::warning Warning
:::warning Note
The player will cache the size of the last volume. When the player is initialized next time (such as refreshing the page), it will read this cached value.
The player caches the last volume level; upon next initialization (e.g., page refresh), the player will read this cached value.
:::
## `isLive`
- Type: `Boolean`
- Default: `false`
Use live mode, which will hide the progress bar and playback time
Enable live streaming mode, which hides the progress bar and playback time.
<div className="run-code">▶ Run Code</div>
@@ -211,7 +216,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to mute by default
Whether to default to muted.
<div className="run-code">▶ Run Code</div>
@@ -228,10 +233,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to play automatically
- Default: `false`
Autoplay
Whether to autoplay.
<div className="run-code">▶ Run Code</div>
@@ -244,18 +246,18 @@ var art = new Artplayer({
});
```
:::warning Warning
:::warning Note
If you want the video to autoplay by default upon entering the page, `muted` must be set to `true`. For more information, please read [Autoplay Policy Changes](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes)
If you want the video to autoplay when entering the page by default, `muted` must be set to `true`. For more information, please read [Autoplay Policy Changes](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes).
:::
## `autoSize`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
The size of the player will by default fill the entire `container`, which often results in black bars. This value can automatically adjust the player size to hide the black bars, similar to `css`'s `object-fit: cover;`
By default, the player's dimensions fill the entire `container`, which often results in black bars. This option automatically adjusts the player size to hide black bars, similar to `object-fit: cover;` in CSS.
<div className="run-code">▶ Run Code</div>
@@ -272,7 +274,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Automatically enter `mini mode` when the player scrolls out of the browser viewport
Automatically switches to `mini player` mode when the player scrolls outside the browser viewport.
<div className="run-code">▶ Run Code</div>
@@ -289,7 +291,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to loop the video
Whether to enable video looping.
<div className="run-code">▶ Run Code</div>
@@ -303,10 +305,10 @@ var art = new Artplayer({
## `flip`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to show the video flip feature, currently only available in `Settings Panel` and `Context Menu`
Whether to display the video flip functionality. Currently appears in the `Settings Panel` and `Context Menu`.
<div className="run-code">▶ Run Code</div>
@@ -321,10 +323,10 @@ var art = new Artplayer({
## `playbackRate`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to show the playback speed feature of the video, it will appear in `Settings Panel` and `Context Menu`
Whether to display the playback rate functionality. Appears in the `Settings Panel` and `Context Menu`.
<div className="run-code">▶ Run Code</div>
@@ -342,7 +344,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Displays the video aspect ratio feature, it will appear in the `Settings Panel` and `Context Menu`
Whether to display the aspect ratio functionality. Appears in the `Settings Panel` and `Context Menu`.
<div className="run-code">▶ Run Code</div>
@@ -360,8 +362,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to show the screenshot button, it will appear in the `toolbar` and `context menu`
Display `Screenshot` function in the bottom control bar
Whether to display the `Screenshot` button in the bottom control bar.
<div className="run-code">▶ Run Code</div>
@@ -373,18 +374,18 @@ var art = new Artplayer({
});
```
:::warning Warning
:::warning Note
Due to browser security mechanisms, if the video source address and the website are cross-origin, screenshot failure may occur
Due to browser security mechanisms, screenshot capture may fail if the video source is cross-origin with the website.
:::
## `setting`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Display the toggle button for the `Settings Panel` in the bottom control bar
Whether to display the `Settings Panel` toggle button in the bottom control bar.
<div className="run-code">▶ Run Code</div>
@@ -395,12 +396,13 @@ var art = new Artplayer({
setting: true,
});
```
## `hotkey`
- Type: `Boolean`
- Default: `true`
- Type: `Boolean`
- Default: `true`
Whether to use hotkeys
Whether to enable hotkeys.
<div className="run-code">▶ Run Code</div>
@@ -412,25 +414,26 @@ var art = new Artplayer({
});
```
| Hotkey | Description |
| ------- | ------------------ |
| `↑` | Increase volume |
| `↓` | Decrease volume |
| `←` | Fast forward video |
| `→` | Rewind video |
| `space` | Toggle play/pause |
| Hotkey | Description |
| ------- | ------------------------- |
| `↑` | Increase volume |
| `↓` | Decrease volume |
| `←` | Seek backward |
| `→` | Seek forward |
| `space` | Toggle play/pause |
:::warning Tip
:::warning Note
These hotkeys will only work after the player gains focus (such as after clicking on the player).
These hotkeys only take effect after the player gains focus (e.g., by clicking on the player).
:::
## `pip`
- Type: `Boolean`
- Default: `false`
Show the `Picture in Picture` switch button on the bottom control bar
- Type: `Boolean`
- Default: `false`
Whether to display the `Picture-in-Picture` toggle button in the bottom control bar.
<div className="run-code">▶ Run Code</div>
@@ -447,7 +450,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `true`
If there are multiple players on the page, should only one player be allowed to play at a time
When multiple players exist on the page, whether only one player is allowed to play at a time.
<div className="run-code">▶ Run Code</div>
@@ -463,7 +466,8 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Display the `Window Fullscreen` button on the control bar at the bottom
Whether to display the `Fullscreen` button in the bottom control bar.
<div className="run-code">▶ Run Code</div>
@@ -480,7 +484,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Display the `Web Fullscreen` button on the control bar at the bottom
Whether to display the `Webpage Fullscreen` button in the bottom control bar.
<div className="run-code">▶ Run Code</div>
@@ -490,15 +494,13 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
fullscreenWeb: true,
});
```
## `subtitleOffset`
- Type: `Boolean`
- Default: `false`
Subtitle time offset, the range is `[-5s, 5s]`, appearing in the `Settings panel`
Subtitle time offset, ranging from `[-5s, 5s]`, appears in the `Settings Panel`
<div className="run-code">▶ Run Code</div>
@@ -519,7 +521,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Mini progress bar, only appears when the player loses focus and is playing
Mini progress bar, appears only when the player loses focus and is playing
<div className="run-code">▶ Run Code</div>
@@ -536,9 +538,9 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to use `SSR` (Server-Side Rendering) mount mode, useful if you want to pre-render the player's required `HTML` before the player mounts
Whether to use `SSR` mount mode. Useful if you want to pre-render the player's required `HTML` before the player is mounted.
You can access the player's required `HTML` through `Artplayer.html`
You can access the player's required `HTML` via `Artplayer.html`
<div className="run-code">▶ Run Code</div>
@@ -575,7 +577,7 @@ var art = new Artplayer({
- Type: `Array`
- Default: `[]`
Initializes custom `layers`
Initialize custom `layers`
<div className="run-code">▶ Run Code</div>
@@ -586,7 +588,7 @@ var art = new Artplayer({
url: '/assets/sample/video.mp4',
layers: [
{
name: 'poster',
name: 'potser',
html: `<img style="width: 100px" src="${img}">`,
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`
<div className="run-code">▶ Run Code</div>
@@ -657,7 +660,8 @@ var art = new Artplayer({
],
});
```
:::warning `Settings Panel` Please refer to the following address
:::warning For `Settings Panel`, please refer to:
[/component/setting.html](/component/setting.html)
@@ -668,7 +672,7 @@ var art = new Artplayer({
- Type: `Array`
- Default: `[]`
Initialize custom `context menu`
Initialize custom `Context Menu`
<div className="run-code">▶ Run Code</div>
@@ -687,7 +691,8 @@ var art = new Artplayer({
],
});
```
:::warning `Component Configuration` Please refer to the following address:
:::warning For `Component Configuration`, please refer to:
[/component/contextmenu.html](/component/contextmenu.html)- Type:
@@ -698,7 +703,7 @@ var art = new Artplayer({
- Type: `Array`
- Default: `[]`
Initializes custom bottom `control bar`
Initialize custom bottom `control bar`
<div className="run-code">▶ Run Code</div>
@@ -721,7 +726,8 @@ var art = new Artplayer({
],
});
```
:::warning `Component Configuration` Refer to the following address:
:::warning For `component configuration`, please refer to:
[/component/controls.html](/component/controls.html)
@@ -732,13 +738,13 @@ var art = new Artplayer({
- Type: `Array`
- Default: `[]`
Whether to show the `quality selection` list in the bottom control bar
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 |
| Property | Type | Description |
| --------- | --------- | ---------------- |
| `default` | `Boolean` | Default quality |
| `html` | `String` | Quality name |
| `url` | `String` | Quality URL |
<div className="run-code">▶ Run Code</div>
@@ -759,17 +765,18 @@ var art = new Artplayer({
],
});
```
## `highlight`
- Type: `Array`
- Default: `[]`
- Type: `Array`
- Default: `[]`
Show `highlight information` on the progress bar
Display `highlight information` on the progress bar
| Property | Type | Description |
| -------- | -------- | --------------------------- |
| `time` | `Number` | Highlight time (in seconds) |
| `text` | `String` | Highlight text |
| Property | Type | Description |
| -------- | -------- | ------------------------------- |
| `time` | `Number` | Highlight time (in seconds) |
| `text` | `String` | Highlight text |
<div className="run-code">▶ Run Code</div>
@@ -801,6 +808,7 @@ var art = new Artplayer({
],
});
```
## `plugins`
- Type: `Array`
@@ -840,7 +848,7 @@ Set `thumbnails` on the progress bar
| -------- | -------- | --------------------- |
| `url` | `String` | Thumbnail URL |
| `number` | `Number` | Number of thumbnails |
| `column` | `Number` | Columns of thumbnails |
| `column` | `Number` | Number of columns |
| `width` | `Number` | Thumbnail width |
| `height` | `Number` | Thumbnail height |
| `scale` | `Number` | Thumbnail scale |
@@ -858,7 +866,8 @@ var art = new Artplayer({
},
});
```
:::warning Online thumbnail generation
:::warning Generate thumbnails online
[artplayer-tool-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-tool-thumbnail/index.js&example=thumbnail)
@@ -869,17 +878,18 @@ var art = new Artplayer({
- Type: `Object`
- Default: `{}`
Set the video subtitles, supporting subtitle formats: `vtt`, `srt`, `ass`
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, default `utf-8` |
| `escape` | `Boolean` | Whether to escape `html` tags, default `true` |
| `onVttLoad` | `Function` | Function to modify `vtt` text |
| 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 |
<div className="run-code">▶ Run Code</div>
@@ -899,12 +909,13 @@ var art = new Artplayer({
},
});
```
## `moreVideoAttr`
- Type: `Object`
- Default: `{'controls': false, 'preload': 'metadata'}`
- Default: `{'controls': false,'preload': 'metadata'}`
Additional video attributes, these attributes will be directly written into the video element
More video attributes, these attributes will be directly written into the video element
<div className="run-code">▶ Run Code</div>
@@ -924,7 +935,7 @@ var art = new Artplayer({
- Type: `Object`
- Default: `{}`
Used to replace default icons, supports `Html` strings and `HTMLElement`
Used to replace default icons, supports `Html` string and `HTMLElement`
<div className="run-code">▶ Run Code</div>
@@ -933,12 +944,13 @@ var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
icons: {
loading: '<img src="/assets/img/loading.gif">',
loading: '<img src="/assets/img/ploading.gif">',
state: '<img src="/assets/img/state.png">',
},
});
```
:::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.
<div className="run-code">▶ Run Code</div>
@@ -961,25 +973,26 @@ var art = new Artplayer({
});
```
:::warning Recognition of file extensions
:::warning Suffix Recognition
The player can only parse this type of file extension: `/assets/sample/video.m3u8`
The player can only parse suffixes like this: `/assets/sample/video.m3u8`
But it cannot parse this type of file extension: `/assets/sample/video?type=m3u8`
But cannot parse suffixes like this: `/assets/sample/video?type=m3u8`
Therefore, if you use `customType`, it is best to specify `type` as well
Therefore, if you use `customType`, it is best to also specify `type`.
:::
## `customType`
- Type: `Object`
- Default: `{}`
Matches the video's `type` to delegate the video decoding to a third-party program for processing. The processing function can receive three parameters:
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 address
- `art`: Current instance
- `video` : Video `DOM` element
- `url` : Video URL
- `art` : Current instance
<div className="run-code">▶ Run Code</div>
@@ -1001,6 +1014,7 @@ var art = new Artplayer({
- Default: `navigator.language.toLowerCase()`
Default display language, currently supports: `en`, `zh-cn`
<div className="run-code">▶ Run Code</div>
```js{4}
@@ -1011,7 +1025,7 @@ var art = new Artplayer({
});
```
:::warning More language settings
:::warning More Language Settings
[/start/i18n.html](/start/i18n.html)
@@ -1022,7 +1036,7 @@ var art = new Artplayer({
- Type: `Object`
- Default: `{}`
Custom `i18n` configuration, which will be deeply merged with the built-in `i18n`
Custom `i18n` configuration, this configuration will be deeply merged with the built-in `i18n`
Add your language:
@@ -1040,7 +1054,8 @@ var art = new Artplayer({
},
});
```
Modifying the existing language
Modify existing languages:
<div className="run-code">▶ Run Code</div>
@@ -1059,7 +1074,7 @@ var art = new Artplayer({
});
```
:::warning More language settings
:::warning More Language Settings
[/start/i18n.html](/start/i18n.html)
@@ -1070,7 +1085,7 @@ var art = new Artplayer({
- Type: `Boolean`
- Default: `false`
Whether to display a `lock button` on mobile to hide the bottom `control bar`
Whether to display a `lock button` on mobile devices to hide the bottom `control bar`
<div className="run-code">▶ Run Code</div>
@@ -1085,9 +1100,10 @@ var art = new Artplayer({
## `gesture`
- Type: `Boolean`
- Default: `true`
Whether to enable gesture events on video elements on mobile devices
Whether to enable gesture events on video elements for mobile devices
<div className="run-code">▶ Run Code</div>
@@ -1101,10 +1117,10 @@ var art = new Artplayer({
## `fastForward`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to add fast forward function by long pressing on the video on mobile devices
Whether to add a long-press video fast-forward feature for mobile devices
<div className="run-code">▶ Run Code</div>
@@ -1118,10 +1134,10 @@ var art = new Artplayer({
## `autoPlayback`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to use the automatic playback feature
Whether to use the automatic `playback feature`
<div className="run-code">▶ Run Code</div>
@@ -1133,20 +1149,21 @@ var art = new Artplayer({
autoPlayback: true,
});
```
:::warning Warning
Because the player by default uses `url` as the `key` to cache the playback progress
:::warning Note
But if the `url` of the same video is different, then you need to use `id` to identify the unique `key` of the video
The player uses the `url` as the default `key` to cache playback progress.
However, if the same video has different `url`s, you need to use the `id` to identify the unique `key` for the video.
:::
## `autoOrientation`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to rotate the player on mobile web pages in full screen according to the video size and the viewport dimensions
Whether to rotate the player during fullscreen mode on mobile devices, based on the video dimensions and viewport size
<div className="run-code">▶ Run Code</div>
@@ -1160,10 +1177,10 @@ var art = new Artplayer({
## `airplay`
- Type: `Boolean`
- Default: `false`
- Type: `Boolean`
- Default: `false`
Whether to display the `airplay` button, currently only some browsers support this feature
Whether to display the `airplay` button (currently only supported by some browsers)
<div className="run-code">▶ Run Code</div>
@@ -1180,7 +1197,7 @@ var art = new Artplayer({
- Type: `Object`
- Default: `{}`
Used to change built-in CSS variables
Used to modify the built-in CSS variables
<div className="run-code">▶ Run Code</div>
@@ -1196,7 +1213,7 @@ var art = new Artplayer({
:::warning Reference for cssVar syntax
[artplayer/types/cssVar.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/cssVar.d.ts)
[artplayer/types/cssVar.d.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/cssVar.d.ts)
:::
@@ -1214,5 +1231,4 @@ var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
proxy: () => document.createElement('video')
});
```
});
+158
View File
@@ -0,0 +1,158 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import dotenv from 'dotenv'
import { glob } from 'glob'
dotenv.config()
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '../packages/artplayer-vitepress')
const dostDir = path.resolve(__dirname, '../docs')
const outputFile = path.resolve(__dirname, '../docs/llms.txt')
const API_URL = 'https://api.deepseek.com/v1/chat/completions'
const API_KEY = process.env.DEEPL_API_KEY
const MAX_CONCURRENT_REQUESTS = 3 // 每类并发请求数
if (!API_KEY) {
console.error('❌ Missing DEEPL_API_KEY in .env file')
process.exit(1)
}
async function getFiles(pattern) {
const files = await glob(pattern.replace(/\\/g, '/'), { nodir: true })
return files.sort()
}
function readFiles(files) {
let content = ''
for (const f of files) {
console.log(`📄 Reading: ${f}`)
content += `\n\n===== ${path.basename(f)} =====\n\n`
content += fs.readFileSync(f, 'utf8')
}
return content
}
function splitText(text, maxLen = 5000) {
const paragraphs = text.split(/\n{2,}/)
const chunks = []
let buffer = ''
for (const p of paragraphs) {
if ((`${buffer}\n\n${p}`).length > maxLen) {
chunks.push(buffer)
buffer = ''
}
buffer += `\n\n${p}`
}
if (buffer.trim())
chunks.push(buffer)
return chunks
}
async function askDeepSeek(prompt, text, tag, id) {
console.log(`🧠 [${tag}] Sending chunk ${id}`)
const res = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
body: JSON.stringify({
model: 'deepseek-chat',
messages: [
{ role: 'system', content: 'You are a professional technical writer.' },
{ role: 'user', content: `${prompt}\n\n${text}` },
],
temperature: 0.3,
}),
})
if (!res.ok) {
const err = await res.text()
console.error(`[${tag}] API Error:`, err)
throw new Error(`DeepSeek API error: ${res.status}`)
}
const data = await res.json()
return data.choices?.[0]?.message?.content?.trim() || ''
}
async function runConcurrent(tasks, limit = MAX_CONCURRENT_REQUESTS) {
const results = []
const executing = new Set()
for (const task of tasks) {
const p = task().finally(() => executing.delete(p))
results.push(p)
executing.add(p)
if (executing.size >= limit) {
await Promise.race(executing)
}
}
return Promise.all(results)
}
async function summarizeSection(title, files, type) {
if (files.length === 0)
return ''
const text = readFiles(files)
const chunks = splitText(text, 8000)
let prompt = ''
if (type === 'docs') {
prompt = `
You are preparing documentation content for an AI model to learn ArtPlayer.
Reorganize the following documentation into a clean, readable plain text format.
Keep all code blocks, examples, and configuration options fully intact.
Add minimal explanations or clarifications in natural English before or after each block if helpful.
Do not use Markdown syntax (no #, **, or lists). Preserve indentation for code.`
}
else if (type === 'ts') {
prompt = `
You are analyzing TypeScript declaration files that define the APIs of ArtPlayer.
Your goal is to produce a developer-oriented plain text output that preserves the actual type definitions,
interfaces, classes, and comments exactly as they are, while adding concise explanations
above or below them when necessary to clarify their purpose or usage.
Keep all code in the output, formatted as plain text (no Markdown).`
}
else if (type === 'js') {
prompt = `
You are analyzing example JavaScript files demonstrating how to use ArtPlayer and its plugins.
Produce a plain text output that includes the full example code and short inline explanations
describing what each example shows, which APIs it uses, and what feature it demonstrates.
Keep all code exactly as-is, formatted as plain text, without Markdown syntax.`
}
const tasks = chunks.map((chunk, i) => () => askDeepSeek(prompt, chunk, type, i + 1))
const results = await runConcurrent(tasks, MAX_CONCURRENT_REQUESTS)
const merged = results.join('\n\n')
return `\n\n===== ${title} =====\n\n${merged}`
}
async function main() {
console.log('🚀 Building llms.txt using DeepSeek...')
const [mdFiles, tsFiles, jsFiles] = await Promise.all([
getFiles(`${rootDir}/docs/en/**/*.md`),
getFiles(`${dostDir}/assets/ts/*.d.ts`),
getFiles(`${dostDir}/assets/example/*.js`),
])
// 并行执行三个大类任务
const [docs, ts, js] = await Promise.all([
summarizeSection('Documentation Summary', mdFiles, 'docs'),
summarizeSection('Type Definitions Overview', tsFiles, 'ts'),
summarizeSection('Examples Summary', jsFiles, 'js'),
])
const finalText = [docs, ts, js].filter(Boolean).join('\n\n')
fs.mkdirSync(path.dirname(outputFile), { recursive: true })
fs.writeFileSync(outputFile, finalText, 'utf8')
console.log(`✅ LLMs text built successfully at ${outputFile}`)
}
main().catch((err) => {
console.error('❌ Build failed:', err)
process.exit(1)
})
+1 -1
View File
@@ -27,7 +27,7 @@
"types": "./types/artplayer-plugin-{{name}}.d.ts",
"import": "./dist/artplayer-plugin-{{name}}.legacy.js",
"require": "./dist/artplayer-plugin-{{name}}.legacy.js"
}
},
"main": "dist/artplayer-plugin-{{name}}.js",
+120 -147
View File
@@ -1,175 +1,148 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import cpy from 'cpy'
import { fileURLToPath } from 'node:url'
import dotenv from 'dotenv'
import { glob } from 'glob'
import { removeDir } from './utils.js'
dotenv.config()
// 配置常量
const MAX_RETRIES = 3
const RETRY_DELAY = 1000 // 1秒
const MAX_CHARS_PER_REQUEST = 128000
const BASE_PATH = 'packages/artplayer-vitepress/docs'
const EN_PATH = 'packages/artplayer-vitepress/docs/en'
const COPY_DIRS = ['advanced', 'component', 'plugin', 'start']
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = path.resolve(__dirname, '../packages/artplayer-vitepress')
const srcDirs = ['docs/advanced', 'docs/component', 'docs/start']
const indexFile = 'docs/index.md'
const outputRoot = path.join(rootDir, 'docs/en')
const API_URL = 'https://api.deepseek.com/v1/chat/completions'
const API_KEY = process.env.DEEPL_API_KEY
function splitMarkdown(text, maxChars) {
const parts = []
let currentPart = ''
let inCodeBlock = false
let inSpecialBlock = false
const lines = text.split('\n')
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
// 检测代码块
if (line.trim().startsWith('```')) {
inCodeBlock = !inCodeBlock
}
// 检测特殊块
if (line.trim().startsWith(':::')) {
inSpecialBlock = !inSpecialBlock
}
// 添加当前行到当前部分
currentPart += `${line}\n`
// 检测是否达到字符限制
if (!inCodeBlock && !inSpecialBlock && currentPart.length > maxChars && i < lines.length - 1) {
parts.push(currentPart)
currentPart = ''
}
}
// 添加最后一部分
if (currentPart !== '') {
parts.push(currentPart)
}
return parts
if (!API_KEY) {
console.error('❌ Missing DEEPL_API_KEY in .env file')
process.exit(1)
}
async function fetchWithRetry(url, options, retries = MAX_RETRIES) {
try {
const response = await fetch(url, {
...options,
function splitMarkdown(text, maxLen = 4000) {
const lines = text.split('\n')
const chunks = []
let buffer = ''
let insideCodeBlock = false
for (const line of lines) {
if (line.trim().startsWith('```'))
insideCodeBlock = !insideCodeBlock
if ((`${buffer}\n${line}`).length > maxLen && !insideCodeBlock) {
chunks.push(buffer)
buffer = ''
}
buffer += `\n${line}`
}
if (buffer.trim())
chunks.push(buffer)
return chunks
}
function cleanTranslation(text) {
return text
.replace(/^```(markdown|md)?/gi, '')
.replace(/```$/g, '')
.replace(/^(Here('|’)s|Below is|Translation|The English version|Here is)[::]?\s*/gi, '')
.replace(/(Translation completed\.?|End of translation\.?)$/gi, '')
.trim()
}
async function translateText(text) {
const chunks = splitMarkdown(text, 4000)
let result = ''
for (let i = 0; i < chunks.length; i++) {
console.log(`🔹 Translating chunk ${i + 1}/${chunks.length}`)
const prompt = `
You are a professional English technical translator for documentation.
Translate the following Markdown content from Simplified Chinese to fluent English.
Keep all Markdown structure, code blocks, and formatting intact.
Return ONLY the translated Markdown content — do NOT add any explanations, prefixes, or summaries.
Text to translate:
${chunks[i]}
`.trim()
const res = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...options.headers,
'Authorization': `Bearer ${API_KEY}`,
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json()
}
catch (error) {
if (retries > 0) {
console.log(`Retrying... (${MAX_RETRIES - retries + 1}/${MAX_RETRIES})`)
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY))
return fetchWithRetry(url, options, retries - 1)
}
throw error
}
}
async function translateContent(content, targetLanguage) {
try {
const TRANSLATE_URL = 'https://api.deepseek.com/chat/completions'
const response = await fetchWithRetry(TRANSLATE_URL, {
headers: {
Authorization: `Bearer ${process.env.DEEPL_API_KEY}`,
},
method: 'POST',
body: JSON.stringify({
stream: false,
model: 'deepseek-chat',
messages: [
{
role: 'user',
content: `The following text is written in VitePress's extended Markdown syntax, Please translate it into ${targetLanguage}, and keep the Markdown format and don't add your explanation:\n\n${content}`,
},
],
messages: [{ role: 'user', content: prompt }],
temperature: 0.2,
}),
})
return response.choices[0].message.content
}
catch (error) {
console.error(`Translation failed: ${error.message}`)
return content // 返回原文作为回退
}
}
class ProgressTracker {
constructor(totalParts) {
this.totalParts = totalParts
this.translatedPartsCount = 0
}
update() {
this.translatedPartsCount++
const progressPercentage = ((this.translatedPartsCount / this.totalParts) * 100).toFixed(2)
console.log(`Overall progress: ${progressPercentage}% (${this.translatedPartsCount}/${this.totalParts})`)
}
}
async function translateMarkdownFiles(filePaths, targetLanguage, maxCharsPerRequest) {
// 先计算总共有多少部分需要翻译
let totalParts = 0
for (const filePath of filePaths) {
const content = fs.readFileSync(filePath, 'utf-8')
totalParts += splitMarkdown(content, maxCharsPerRequest).length
}
console.log(`Starting translation of ${filePaths.length} files, total ${totalParts} parts.`)
const progressTracker = new ProgressTracker(totalParts)
for (const filePath of filePaths) {
console.log(`Translating: ${path.relative(EN_PATH, filePath)}`)
const content = fs.readFileSync(filePath, 'utf-8')
const parts = splitMarkdown(content, maxCharsPerRequest)
const translatedParts = []
for (const part of parts) {
const translatedPart = await translateContent(part, targetLanguage)
translatedParts.push(translatedPart)
progressTracker.update()
if (!res.ok) {
const error = await res.text()
console.error('API Error:', error)
throw new Error(`DeepSeek API error: ${res.status}`)
}
const translatedContent = translatedParts.join('\n')
fs.writeFileSync(filePath, translatedContent)
const data = await res.json()
const raw = data.choices?.[0]?.message?.content?.trim() || ''
const translated = cleanTranslation(raw)
result += `\n\n${translated}`
}
return result.trim()
}
async function setupDirectoryStructure() {
// 清理并创建目录结构
removeDir(EN_PATH)
await cpy(path.resolve(BASE_PATH, 'index.md'), path.resolve(EN_PATH))
// 并行复制所有目录
await Promise.all(
COPY_DIRS.map(dir => cpy(path.resolve(BASE_PATH, dir), path.resolve(EN_PATH, dir), { flat: true })),
)
async function processFile(inputPath, outputPath) {
const content = fs.readFileSync(inputPath, 'utf8')
console.log(`🌍 Translating: ${inputPath}`)
const translated = await translateText(content)
fs.mkdirSync(path.dirname(outputPath), { recursive: true })
fs.writeFileSync(outputPath, translated, 'utf8')
console.log(`✅ Saved: ${outputPath}`)
}
(async () => {
try {
await setupDirectoryStructure()
const mdsPaths = glob.sync(path.resolve(EN_PATH, '**/*.md'))
await translateMarkdownFiles(mdsPaths, 'English', MAX_CHARS_PER_REQUEST)
console.log('Translation completed successfully!')
async function runWithConcurrency(tasks, limit = 5) {
const results = []
const executing = new Set()
for (const task of tasks) {
const p = task().finally(() => executing.delete(p))
results.push(p)
executing.add(p)
if (executing.size >= limit) {
await Promise.race(executing)
}
}
catch (error) {
console.error('Translation failed:', error)
process.exit(1)
return Promise.all(results)
}
async function main() {
console.log('🚀 Starting translation...')
fs.rmSync(outputRoot, { recursive: true, force: true })
fs.mkdirSync(outputRoot, { recursive: true })
const indexPath = path.join(rootDir, indexFile)
const indexOut = path.join(outputRoot, 'index.md')
await processFile(indexPath, indexOut)
const tasks = []
for (const dir of srcDirs) {
const fullDir = path.join(rootDir, dir)
const files = await glob(`${fullDir}/**/*.md`)
for (const file of files) {
const relative = path.relative(rootDir, file)
const outputFile = path.join(outputRoot, relative.replace(/^docs[\\/]/, ''))
tasks.push(() => processFile(file, outputFile))
}
}
})()
console.log(`🧠 Total files: ${tasks.length}, concurrency: 5`)
await runWithConcurrency(tasks, 5)
console.log('🎉 Translation complete!')
}
main().catch((err) => {
console.error('❌ Translation failed:', err)
process.exit(1)
})
+2 -2
View File
@@ -1,5 +1,5 @@
import Artplayer from 'artplayer'
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku'
console.log(Artplayer.version)
console.log(typeof artplayerPluginDanmuku)
console.warn(Artplayer.version)
console.warn(typeof artplayerPluginDanmuku)
+2 -2
View File
@@ -1,3 +1,3 @@
import id from 'artplayer/i18n/id';
import id from 'artplayer/i18n/id'
console.log(id)
console.warn(id)
+1 -1
View File
@@ -1,3 +1,3 @@
import Artplayer from 'artplayer'
console.log(Artplayer.html)
console.warn(Artplayer.html)
-77
View File
@@ -1,77 +0,0 @@
// https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
// ======================== ES6 Module ==========================
import Artplayer from '../packages/artplayer';
const art1 = new Artplayer({
container: '.artplayer-app',
url: './assets/sample/video.mp4',
});
// ======================== CommonJS Module ==========================
const Artplayer = require('../packages/artplayer');
const art2 = new Artplayer({
container: '.artplayer-app',
url: './assets/sample/video.mp4',
});
// ======================== Triple-Slash Directives ==========================
/// <reference path="../packages/artplayer" />
/**
* @type {Artplayer} - An Artplayer instance.
*/
const art3 = {};
/**
* @param {Artplayer} art4 - An Artplayer instance.
*/
function getInstance(art4) {
//
}
// ======================== @typedef ==========================
/**
* @typedef { import("../packages/artplayer") } Artplayer
*/
/**
* @type {Artplayer} - An Artplayer instance.
*/
const art5 = null;
/**
* @param {Artplayer} art6 - An Artplayer instance.
*/
function getInstance(art6) {
//
}
// ======================== @param ==========================
/**
* @param { import("../packages/artplayer") } art7 - An Artplayer instance.
*/
function getInstance(art7) {
//
}
// ======================== @option ==========================
/**
* @type {import("../packages/artplayer/types/option").Option}
*/
const option = {
container: '.artplayer-app',
url: './assets/sample/video.mp4',
};
option.volume = 0.5;
const art8 = new Artplayer(option);