mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 03:46:16 -08:00
13439 lines
419 KiB
Plaintext
13439 lines
419 KiB
Plaintext
ArtPlayer documentation source bundle
|
||
Generated offline by yarn build:llm. Source text is preserved after LF normalization.
|
||
These are source references, not proof that every example or documented feature has passed release review.
|
||
|
||
===== Documentation Summary =====
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/built-in.md =====
|
||
|
||
# Advanced Properties
|
||
|
||
The `Advanced Properties` here refer to the `secondary properties` attached to the `instance`, which are less commonly used.
|
||
|
||
## `option`
|
||
|
||
The player's options.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.option);
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
If you directly modify this `option` object, the player will not respond immediately.
|
||
|
||
:::
|
||
|
||
## `template`
|
||
|
||
Manages all `DOM` elements of the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.template);
|
||
console.info(art.template.$video);
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
To easily distinguish between `DOM` elements and regular objects, all `DOM` elements within the player are named with a `$` prefix.
|
||
|
||
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 for the player. It essentially proxies `addEventListener` and `removeEventListener`. When using the following methods to handle events, the events will also 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.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var container = document.querySelector('.artplayer-app');
|
||
|
||
var art = new Artplayer({
|
||
container: container,
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.events.proxy(container, 'click', event => {
|
||
console.info('click', event);
|
||
});
|
||
|
||
art.events.hover(container, (event) => {
|
||
console.info('mouseenter', event);
|
||
}, (event) => {
|
||
console.info('mouseleave', event);
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
If you need `DOM` events that should only exist during the player's lifecycle, it is strongly recommended to use these functions to avoid memory leaks.
|
||
|
||
:::
|
||
|
||
## `storage`
|
||
|
||
Manages the player's local storage.
|
||
|
||
- The `name` property is used to set the cache `key`.
|
||
- The `set` method is used to set a cache.
|
||
- The `get` method is used to retrieve a cache.
|
||
- The `del` method is used to delete a cache.
|
||
- The `clear` method is used to clear all caches.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.storage.set('test', { foo: 'bar' });
|
||
const test = art.storage.get('test');
|
||
console.info(test);
|
||
art.storage.del('test');
|
||
art.storage.clear();
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
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`.
|
||
|
||
:::
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.storage.name = 'your-storage-key';
|
||
art.storage.set('test', { foo: 'bar' });
|
||
```
|
||
|
||
## `icons`
|
||
|
||
Manages all `svg` icons for the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.icons.loading);
|
||
```
|
||
|
||
:::warning This is the definition of all icons:
|
||
|
||
[artplayer/types/icons.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/icons.d.ts)
|
||
|
||
:::
|
||
|
||
## `i18n`
|
||
|
||
Manages the player's `i18n`.
|
||
|
||
- The `get` method is used to retrieve an `i18n` value.
|
||
- The `update` method is used to update the `i18n` object.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.i18n.get('Play'));
|
||
|
||
art.i18n.update({
|
||
'zh-cn': {
|
||
Play: 'Your Play'
|
||
}
|
||
});
|
||
```
|
||
|
||
:::warning
|
||
|
||
Using `art.i18n.update` can only update the `i18n` after instantiation. If you want to update `i18n` before instantiation, please use the `i18n` option in the basic settings.
|
||
|
||
:::
|
||
|
||
## `notice`
|
||
|
||
Manages the player's notifications. It only has a `show` property for displaying notifications.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.notice.show = 'Video Ready To Play';
|
||
})
|
||
```
|
||
|
||
:::warning
|
||
|
||
If you want to hide the `notice` immediately: `art.notice.show = '';`
|
||
|
||
:::
|
||
|
||
## `layers`
|
||
|
||
Manages the player's 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 displayed.
|
||
- The `toggle` method is used to toggle the display of all layers.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.layers.add({
|
||
html: 'Some Text',
|
||
});
|
||
|
||
setTimeout(() => {
|
||
art.layers.show = false;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to:
|
||
|
||
[/component/layers.html](/component/layers.html)
|
||
|
||
:::
|
||
|
||
## `controls`
|
||
|
||
Manages the player's controls.
|
||
|
||
- The `add` method is used to dynamically add a control.
|
||
- The `remove` method is used to dynamically remove a control.
|
||
|
||
- The `update` method is used to dynamically update controls
|
||
- The `show` property is used to set whether to display all controls
|
||
- The `toggle` method is used to toggle the display of all controls
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.controls.add({
|
||
html: 'Some Text',
|
||
position: 'left',
|
||
});
|
||
|
||
setTimeout(() => {
|
||
art.controls.show = false;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to:
|
||
|
||
[/component/controls.html](/component/controls.html)
|
||
|
||
:::
|
||
|
||
## `contextmenu`
|
||
|
||
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` property is used to set whether to display all menu items
|
||
- The `toggle` method is used to toggle the display of all menu items
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.contextmenu.add({
|
||
html: 'Some Text',
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
setTimeout(() => {
|
||
art.contextmenu.show = false;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to:
|
||
|
||
[/component/contextmenu.html](/component/contextmenu.html)
|
||
|
||
:::
|
||
|
||
## `subtitle`
|
||
|
||
Manages the player's subtitle functionality
|
||
|
||
- The `url` property sets and returns the current subtitle URL
|
||
- The `style` method sets the style of the current subtitle
|
||
- 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 overall list of cues
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.subtitle.url = '/assets/sample/subtitle.srt'
|
||
art.subtitle.style({
|
||
color: 'red',
|
||
});
|
||
});
|
||
```
|
||
|
||
## `info`
|
||
|
||
Manages the player's information panel, commonly used to view the current status of the player and video, such as version number, resolution, duration, etc.
|
||
|
||
- Control the panel's visibility via `art.info.show`
|
||
- The triggered event is named `info` (see the event documentation for details)
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.info.show = true;
|
||
|
||
setTimeout(() => {
|
||
art.info.show = false;
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `loading`
|
||
|
||
Manages the player's loading layer
|
||
|
||
- The `show` property is used to set whether to display the loading layer
|
||
- The `toggle` property is used to toggle the display of the loading layer
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.loading.show = true;
|
||
setTimeout(() => {
|
||
art.loading.show = false;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
## `hotkey`
|
||
|
||
Manages the player's hotkey functionality
|
||
|
||
- The `add` method is used to add hotkeys
|
||
- The `remove` method is used to remove hotkeys
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
function hotkeyEvent(event) {
|
||
console.info('click', event);
|
||
}
|
||
|
||
art.on('ready', () => {
|
||
art.hotkey.add(32, hotkeyEvent);
|
||
setTimeout(() => {
|
||
art.hotkey.remove(32, hotkeyEvent);
|
||
}, 5000);
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
These hotkeys only take effect after the player gains focus (e.g., after clicking on the player)
|
||
|
||
:::
|
||
|
||
## `mask`
|
||
|
||
Manages the player's mask layer
|
||
|
||
- The `show` property is used to set whether to display the mask layer
|
||
- The `toggle` property is used to toggle the display of the mask layer
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.mask.show = false;
|
||
setTimeout(() => {
|
||
art.mask.show = true;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
## `setting`
|
||
|
||
Manages the player's settings panel
|
||
|
||
- The `add` method is used to dynamically add settings items
|
||
- The `remove` method is used to dynamically remove settings items
|
||
- The `update` method is used to dynamically update settings items
|
||
- The `show` property is used to set whether to display all settings items
|
||
- The `toggle` method is used to toggle the display of all settings items
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
subtitleOffset: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.setting.show = true;
|
||
setTimeout(() => {
|
||
art.setting.show = false;
|
||
}, 1000);
|
||
});
|
||
```
|
||
|
||
:::warning For `Settings Panel`, please refer to
|
||
|
||
[/component/setting.html](/component/setting.html)
|
||
|
||
:::
|
||
|
||
## `plugins`
|
||
|
||
Manages the player's plugin functionality, with only one method `add` for dynamically adding plugins
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
function myPlugin(art) {
|
||
console.info(art);
|
||
return {
|
||
name: 'myPlugin',
|
||
something: 'something',
|
||
doSomething: function () {
|
||
console.info('doSomething');
|
||
},
|
||
};
|
||
}
|
||
|
||
art.on('ready', () => {
|
||
art.plugins.add(myPlugin);
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/class.md =====
|
||
|
||
# Static Properties
|
||
|
||
Here, `static properties` refer to the `first-level properties` attached to the `constructor`, which are rarely used.
|
||
|
||
## `instances`
|
||
|
||
Returns an array of all player instances. This property can be useful when you need to manage multiple players simultaneously.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info([...Artplayer.instances]);
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info([...Artplayer.instances]);
|
||
```
|
||
|
||
## `version`
|
||
|
||
Returns the version information of the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.version);
|
||
```
|
||
|
||
## `env`
|
||
|
||
Returns the environment variables of the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.env);
|
||
```
|
||
|
||
## `build`
|
||
|
||
Returns the build timestamp of the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.build);
|
||
```
|
||
|
||
## `config`
|
||
|
||
Returns the default configuration for videos.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.config);
|
||
```
|
||
|
||
## `utils`
|
||
|
||
Returns the collection of utility functions for the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.utils);
|
||
```
|
||
|
||
:::warning For all utility functions, please refer to the following address:
|
||
|
||
[artplayer/types/utils.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/utils.d.ts)
|
||
|
||
:::
|
||
|
||
## `scheme`
|
||
|
||
Returns the validation schema for player options.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.scheme);
|
||
```
|
||
|
||
## `Emitter`
|
||
|
||
Returns the constructor of the event emitter.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.Emitter);
|
||
```
|
||
|
||
## `validator`
|
||
|
||
Returns the validation function for options.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.validator);
|
||
```
|
||
|
||
## `kindOf`
|
||
|
||
Returns the type detection utility function.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.kindOf);
|
||
```
|
||
|
||
## `html`
|
||
|
||
Returns the `html` string required by the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.html);
|
||
```
|
||
|
||
## `option`
|
||
|
||
Returns the default options of the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.info(Artplayer.option);
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/event.md =====
|
||
|
||
# Instance Events
|
||
|
||
Player events are divided into two types: `native events` of the video (prefixed with `video:`), and `custom events`.
|
||
|
||
Listening to events:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('video:canplay', () => {
|
||
console.info('video:canplay');
|
||
});
|
||
```
|
||
|
||
Listening to an event only once:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.once('video:canplay', () => {
|
||
console.info('video:canplay');
|
||
});
|
||
```
|
||
|
||
Manually triggering an event:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.emit('focus');
|
||
```
|
||
|
||
Removing an event:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
const onReady = () => {
|
||
console.info('ready');
|
||
art.off('ready', onReady);
|
||
}
|
||
|
||
art.on('ready', onReady);
|
||
```
|
||
|
||
:::warning For a complete list of events, please refer to:
|
||
|
||
[artplayer/types/events.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/events.d.ts)
|
||
|
||
:::
|
||
|
||
## `ready`
|
||
|
||
Triggered when the player is ready for the first time.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info('ready');
|
||
});
|
||
```
|
||
|
||
## `restart`
|
||
|
||
Triggered when the player switches URLs and becomes ready to play.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{10}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.url = '/assets/sample/video.mp4'
|
||
});
|
||
|
||
art.on('restart', (url) => {
|
||
console.info('restart', url);
|
||
});
|
||
```
|
||
|
||
## `pause`
|
||
|
||
Triggered when the player is paused.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('pause', () => {
|
||
console.info('pause');
|
||
});
|
||
```
|
||
|
||
## `play`
|
||
|
||
Triggered when the player starts playing.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('play', () => {
|
||
console.info('play');
|
||
});
|
||
```
|
||
|
||
## `hotkey`
|
||
|
||
Triggered when a player hotkey is pressed.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('hotkey', (event) => {
|
||
console.info('hotkey', event);
|
||
});
|
||
```
|
||
|
||
## `destroy`
|
||
|
||
Triggered when the player is destroyed.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{10}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.destroy();
|
||
});
|
||
|
||
art.on('destroy', () => {
|
||
console.info('destroy');
|
||
});
|
||
```
|
||
|
||
## `focus`
|
||
|
||
Triggered when the player gains focus.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('focus', (event) => {
|
||
console.info('focus', event);
|
||
});
|
||
```
|
||
|
||
## `blur`
|
||
|
||
Triggered when the player loses focus.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('blur', (event) => {
|
||
console.info('blur', event);
|
||
});
|
||
```
|
||
|
||
## `dblclick`
|
||
|
||
Triggered when the player is double-clicked.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('dblclick', (event) => {
|
||
console.info('dblclick', event);
|
||
});
|
||
```
|
||
|
||
## `click`
|
||
|
||
Triggered when the player is clicked.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('click', (event) => {
|
||
console.info('click', event);
|
||
});
|
||
```
|
||
|
||
## `error`
|
||
|
||
Triggered when an error occurs while the player is loading a video.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/404.mp4',
|
||
});
|
||
|
||
art.on('error', (error, reconnectTime) => {
|
||
console.info(error, reconnectTime);
|
||
});
|
||
|
||
```
|
||
|
||
## `hover`
|
||
|
||
Triggered when the mouse enters or leaves the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('hover', (state, event) => {
|
||
console.info('hover', state, event);
|
||
});
|
||
```
|
||
|
||
## `mousemove`
|
||
|
||
Triggered when the mouse moves over the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('mousemove', (event) => {
|
||
console.info('mousemove', event);
|
||
});
|
||
```
|
||
|
||
## `resize`
|
||
|
||
Triggered when the player's dimensions change.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('resize', () => {
|
||
console.info('resize');
|
||
});
|
||
```
|
||
|
||
## `view`
|
||
|
||
Triggered when the player enters the viewport.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('view', (state) => {
|
||
console.info('view', state);
|
||
});
|
||
```
|
||
|
||
## `lock`
|
||
|
||
Triggered when the lock state changes on mobile devices.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lock: true,
|
||
});
|
||
|
||
art.on('lock', (state) => {
|
||
console.info('lock', state);
|
||
});
|
||
```
|
||
|
||
## `aspectRatio`
|
||
|
||
Triggered when the player's aspect ratio changes.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
aspectRatio: true,
|
||
setting: true,
|
||
});
|
||
|
||
art.on('aspectRatio', (aspectRatio) => {
|
||
console.info('aspectRatio', aspectRatio);
|
||
});
|
||
```
|
||
|
||
## `autoHeight`
|
||
|
||
Triggered when the player's height is automatically set.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{10}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.autoHeight();
|
||
});
|
||
|
||
art.on('autoHeight', (height) => {
|
||
console.info('autoHeight', height);
|
||
});
|
||
```
|
||
|
||
## `autoSize`
|
||
|
||
Triggered when the player's size is automatically set.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoSize: true,
|
||
});
|
||
|
||
art.on('autoSize', () => {
|
||
console.info('autoSize');
|
||
});
|
||
```
|
||
|
||
## `flip`
|
||
|
||
Triggered when the player is flipped.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
flip: true,
|
||
setting: true,
|
||
});
|
||
|
||
art.on('flip', (flip) => {
|
||
console.info('flip', flip);
|
||
});
|
||
```
|
||
|
||
## `fullscreen`
|
||
|
||
Triggered when the player enters or exits windowed fullscreen mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
});
|
||
|
||
art.on('fullscreen', (state) => {
|
||
console.info('fullscreen', state);
|
||
});
|
||
```
|
||
|
||
## `fullscreenError`
|
||
|
||
Triggered when a windowed fullscreen error occurs.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.fullscreen = true;
|
||
});
|
||
|
||
art.on('fullscreenError', (event) => {
|
||
console.info('fullscreenError', event);
|
||
});
|
||
```
|
||
|
||
## `fullscreenWeb`
|
||
|
||
Triggered when the player enters or exits web fullscreen mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreenWeb: true,
|
||
});
|
||
|
||
art.on('fullscreenWeb', (state) => {
|
||
console.info('fullscreenWeb', state);
|
||
});
|
||
```
|
||
|
||
## `mini`
|
||
|
||
Triggered when the player enters or exits mini mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{10}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.mini = true;
|
||
});
|
||
|
||
art.on('mini', (state) => {
|
||
console.info('mini', state);
|
||
});
|
||
```
|
||
|
||
## `pip`
|
||
|
||
Triggered when the player enters or exits Picture-in-Picture mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
pip: true,
|
||
});
|
||
|
||
art.on('pip', (state) => {
|
||
console.info('pip', state);
|
||
});
|
||
|
||
```
|
||
|
||
## `screenshot`
|
||
|
||
Triggered when the player takes a screenshot.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
screenshot: true,
|
||
});
|
||
|
||
art.on('screenshot', (dataUri) => {
|
||
console.info('screenshot', dataUri);
|
||
});
|
||
```
|
||
|
||
## `seek`
|
||
|
||
Triggered when the player performs a time seek.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('seek', (currentTime) => {
|
||
console.info('seek', currentTime);
|
||
});
|
||
```
|
||
|
||
## `subtitleOffset`
|
||
|
||
Triggered when the subtitle offset changes in the player.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitleOffset: true,
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
setting: true,
|
||
});
|
||
|
||
art.on('subtitleOffset', (offset) => {
|
||
console.info('subtitleOffset', offset);
|
||
});
|
||
```
|
||
|
||
## `subtitleBeforeUpdate`
|
||
|
||
Triggered before subtitles are updated.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
});
|
||
|
||
art.on('subtitleBeforeUpdate', (cues) => {
|
||
console.info('subtitleBeforeUpdate', cues);
|
||
});
|
||
```
|
||
|
||
## `subtitleAfterUpdate`
|
||
|
||
Triggered after subtitles are updated.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
});
|
||
|
||
art.on('subtitleAfterUpdate', (cues) => {
|
||
console.info('subtitleAfterUpdate', cues);
|
||
});
|
||
```
|
||
|
||
## `subtitleLoad`
|
||
|
||
Triggered when subtitles are loaded.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
});
|
||
|
||
art.on('subtitleLoad', (option, cues) => {
|
||
console.info('subtitleLoad', cues, option);
|
||
});
|
||
```
|
||
|
||
## `info`
|
||
|
||
Triggered when the info panel is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('info', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `layer`
|
||
|
||
Triggered when a custom layer is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('layer', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `loading`
|
||
|
||
Triggered when the loader is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('loading', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `mask`
|
||
|
||
Triggered when the mask layer is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('mask', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `subtitle`
|
||
|
||
Triggered when the subtitle layer is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('subtitle', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `contextmenu`
|
||
|
||
Triggered when the context menu is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('contextmenu', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `control`
|
||
|
||
Triggered when the control bar is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('control', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `setting`
|
||
|
||
Triggered when the settings panel is shown or hidden.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
});
|
||
|
||
art.on('setting', (state) => {
|
||
console.log(state);
|
||
});
|
||
|
||
```
|
||
|
||
## `muted`
|
||
|
||
Triggered when the muted state changes.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('muted', (state) => {
|
||
console.log(state);
|
||
});
|
||
```
|
||
|
||
## `keydown`
|
||
|
||
Listens for the `keydown` event from the `document`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('keydown', (event) => {
|
||
console.log(event.code);
|
||
});
|
||
```
|
||
|
||
## `video:canplay`
|
||
|
||
The browser can start playing the media, but estimates there is not enough data to play through to the end without stopping for further buffering.
|
||
|
||
## `video:canplaythrough`
|
||
|
||
The browser estimates it can play the media through to the end without stopping for buffering.
|
||
|
||
## `video:complete`
|
||
|
||
The OfflineAudioContext rendering is complete.
|
||
|
||
## `video:durationchange`
|
||
|
||
Triggered when the value of the `duration` property changes.
|
||
|
||
## `video:emptied`
|
||
|
||
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`
|
||
|
||
Playback has stopped because the media has reached its end.
|
||
|
||
## `video:error`
|
||
|
||
An error occurred while fetching the media data, or the resource type is not a supported media format.
|
||
|
||
## `video:loadeddata`
|
||
|
||
The first frame of the media has finished loading.
|
||
|
||
## `video:loadedmetadata`
|
||
|
||
Metadata has been loaded.
|
||
|
||
## `video:pause`
|
||
|
||
Playback has been paused.
|
||
|
||
## `video:play`
|
||
|
||
Playback has begun.
|
||
|
||
## `video:playing`
|
||
|
||
Playback is ready to start after having been paused or delayed due to lack of data.
|
||
|
||
## `video:progress`
|
||
|
||
Fired periodically as the browser loads the resource.
|
||
|
||
## `video:ratechange`
|
||
|
||
The playback rate has changed.
|
||
|
||
## `video:seeked`
|
||
|
||
A seek operation has completed.
|
||
|
||
## `video:seeking`
|
||
|
||
A seek operation has begun.
|
||
|
||
## `video:stalled`
|
||
|
||
The user agent is trying to fetch media data, but data is unexpectedly not forthcoming.
|
||
|
||
## `video:suspend`
|
||
|
||
Media data loading has been suspended.
|
||
|
||
## `video:timeupdate`
|
||
|
||
The time indicated by the `currentTime` property has changed.
|
||
|
||
## `video:volumechange`
|
||
|
||
The volume has changed.
|
||
|
||
## `video:waiting`
|
||
|
||
Playback has stopped because of a temporary lack of data.
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/global.md =====
|
||
|
||
# Global Properties
|
||
|
||
The `global properties` here 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 rarely used.
|
||
|
||
## DEBUG
|
||
|
||
Whether to enable `debug` mode, which can print all built-in video events. Default is off.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.DEBUG = true;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## STYLE
|
||
|
||
Returns the player style text.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
console.log(Artplayer.STYLE);
|
||
```
|
||
|
||
## CONTEXTMENU
|
||
|
||
Whether to enable the context menu. Default is on.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.CONTEXTMENU = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## NOTICE_TIME
|
||
|
||
The display duration of notification messages, in milliseconds. Default is `2000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.NOTICE_TIME = 5000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## SETTING_WIDTH
|
||
|
||
The default width of the settings panel, in pixels. Default is `250`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SETTING_WIDTH = 300;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
});
|
||
```
|
||
|
||
## SETTING_ITEM_WIDTH
|
||
|
||
The default width of a setting item in the settings panel, in pixels. Default is `200`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SETTING_ITEM_WIDTH = 300;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
});
|
||
```
|
||
|
||
## SETTING_ITEM_HEIGHT
|
||
|
||
The default height of a setting item in the settings panel, in pixels. Default is `35`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SETTING_ITEM_HEIGHT = 40;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
});
|
||
```
|
||
|
||
## RESIZE_TIME
|
||
|
||
The throttle time for the `resize` event, in milliseconds. Default is `200`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.RESIZE_TIME = 500;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('resize', () => {
|
||
console.log('resize');
|
||
});
|
||
```
|
||
|
||
## SCROLL_TIME
|
||
|
||
The throttle time for the `scroll` event, in milliseconds. Default is `200`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SCROLL_TIME = 500;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('scroll', () => {
|
||
console.log('scroll');
|
||
});
|
||
```
|
||
|
||
## SCROLL_GAP
|
||
|
||
The boundary tolerance distance for the `view` event, in pixels. Default is `50`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SCROLL_GAP = 100;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('scroll', () => {
|
||
console.log('scroll');
|
||
});
|
||
```
|
||
|
||
## AUTO_PLAYBACK_MAX
|
||
|
||
The maximum record count for the auto-playback feature. Default is `10`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.AUTO_PLAYBACK_MAX = 20;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoPlayback: true,
|
||
});
|
||
```
|
||
|
||
## AUTO_PLAYBACK_MIN
|
||
|
||
The minimum record duration for the auto-playback feature, in seconds. Default is `5`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.AUTO_PLAYBACK_MIN = 10;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoPlayback: true,
|
||
});
|
||
```
|
||
|
||
## AUTO_PLAYBACK_TIMEOUT
|
||
|
||
The hide delay duration for the auto-playback feature, in milliseconds. Default is `3000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.AUTO_PLAYBACK_TIMEOUT = 5000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoPlayback: true,
|
||
});
|
||
```
|
||
|
||
## RECONNECT_TIME_MAX
|
||
|
||
The maximum number of automatic reconnection attempts when a connection error occurs. Default is `5`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.RECONNECT_TIME_MAX = 10;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/404.mp4',
|
||
});
|
||
```
|
||
|
||
## RECONNECT_SLEEP_TIME
|
||
|
||
The delay time for automatic reconnection when a connection error occurs, in milliseconds. Default is `1000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.RECONNECT_SLEEP_TIME = 3000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/404.mp4',
|
||
});
|
||
|
||
```
|
||
|
||
## CONTROL_HIDE_TIME
|
||
|
||
The auto-hide delay time for the bottom control bar, in milliseconds. Default is `3000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.CONTROL_HIDE_TIME = 5000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## DBCLICK_TIME
|
||
|
||
The delay time for the double-click event, in milliseconds. Default is `300`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.DBCLICK_TIME = 500;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('dblclick', () => {
|
||
console.log('dblclick');
|
||
});
|
||
```
|
||
|
||
## DBCLICK_FULLSCREEN
|
||
|
||
On desktop, whether double-click toggles fullscreen. Default is `true`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.DBCLICK_FULLSCREEN = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## MOBILE_DBCLICK_PLAY
|
||
|
||
On mobile, whether double-click toggles play/pause. Default is `true`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.MOBILE_DBCLICK_PLAY = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## MOBILE_CLICK_PLAY
|
||
|
||
On mobile, whether single-click toggles play/pause. 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',
|
||
});
|
||
```
|
||
|
||
## AUTO_ORIENTATION_TIME
|
||
|
||
On mobile, the delay time for auto-rotation, in milliseconds. Default is `200`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.AUTO_ORIENTATION_TIME = 500;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoOrientation: true,
|
||
});
|
||
```
|
||
|
||
## INFO_LOOP_TIME
|
||
|
||
The refresh interval for the info panel, in milliseconds. Default is `1000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.INFO_LOOP_TIME = 2000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.info.show = true;
|
||
```
|
||
|
||
## FAST_FORWARD_VALUE
|
||
|
||
On mobile, the speed multiplier for long-press fast-forward. Default is `3`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.FAST_FORWARD_VALUE = 5;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fastForward: true,
|
||
});
|
||
```
|
||
|
||
## FAST_FORWARD_TIME
|
||
|
||
On mobile, the delay time for long-press fast-forward, in milliseconds. Default is `1000`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.FAST_FORWARD_TIME = 2000;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fastForward: true,
|
||
});
|
||
```
|
||
|
||
## TOUCH_MOVE_RATIO
|
||
|
||
On mobile, the speed multiplier for left/right swipe to seek. Default is `0.5`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.TOUCH_MOVE_RATIO = 1;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## VOLUME_STEP
|
||
|
||
The step size for volume adjustment via keyboard shortcuts. Default is `0.1`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.VOLUME_STEP = 0.2;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## SEEK_STEP
|
||
|
||
The step size for seeking via keyboard shortcuts, in seconds. Default is `5`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.SEEK_STEP = 10;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## PLAYBACK_RATE
|
||
|
||
The built-in list of playback rates. Default is `[0.5, 0.75, 1, 1.25, 1.5, 2]`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.PLAYBACK_RATE = [0.5, 1, 2, 3, 4, 5];
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
playbackRate: true,
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
art.setting.show = true;
|
||
```
|
||
|
||
## ASPECT_RATIO
|
||
|
||
The built-in list of video aspect ratios. Default is `['default', '4:3', '16:9']`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.ASPECT_RATIO = ['default', '1:1', '2:1', '4:3', '6:5'];
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
aspectRatio: true,
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
art.setting.show = true;
|
||
```
|
||
|
||
## FLIP
|
||
|
||
The built-in list of video flip options. Default is `['normal', 'horizontal', 'vertical']`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.FLIP = ['normal', 'horizontal'];
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
flip: true,
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
art.setting.show = true;
|
||
|
||
```
|
||
|
||
## FULLSCREEN_WEB_IN_BODY
|
||
|
||
Whether to mount the player under the `body` element during web fullscreen mode. Default is `true`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.FULLSCREEN_WEB_IN_BODY = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreenWeb: true,
|
||
});
|
||
```
|
||
|
||
## LOG_VERSION
|
||
|
||
Sets whether to print the player version. Default is `true`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.LOG_VERSION = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## USE_RAF
|
||
|
||
Sets whether to use `requestAnimationFrame`. Default is `false`. Currently, it is primarily used for smooth progress bar effects.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.USE_RAF = true;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
miniProgressBar: true,
|
||
});
|
||
```
|
||
|
||
## REMOVE_SRC_WHEN_DESTROY
|
||
|
||
Whether to remove the video's `src` attribute and call `load()` to actively release media resources when destroying the player. Default is `true`.
|
||
|
||
Enabling this can reduce video resource usage in single-page applications or scenarios where players are frequently created/destroyed. If you wish to preserve the state of the video element and only remove the UI, you can set this to `false`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
Artplayer.REMOVE_SRC_WHEN_DESTROY = false;
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
// Only destroy the UI, do not actively clear the src
|
||
art.destroy();
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/plugin.md =====
|
||
|
||
# Writing Plugins
|
||
|
||
Once you are familiar with the player's `properties`, `methods`, and `events`, writing a plugin becomes a very straightforward task.
|
||
|
||
You can load a plugin function during instantiation.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{15}
|
||
function myPlugin(art) {
|
||
console.info(art);
|
||
return {
|
||
name: 'myPlugin',
|
||
something: 'something',
|
||
doSomething: function () {
|
||
console.info('doSomething');
|
||
},
|
||
};
|
||
}
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [myPlugin],
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.plugins.myPlugin);
|
||
});
|
||
```
|
||
|
||
You can also load a plugin function after instantiation.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{17}
|
||
function myPlugin(art) {
|
||
console.info(art);
|
||
return {
|
||
name: 'myPlugin',
|
||
something: 'something',
|
||
doSomething: function () {
|
||
console.info('doSomething');
|
||
},
|
||
};
|
||
}
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.plugins.add(myPlugin);
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.plugins.myPlugin);
|
||
});
|
||
```
|
||
|
||
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) => {
|
||
art.layers.add({
|
||
name: 'ads',
|
||
html: `<img style="width: 100px" src="${option.url}">`,
|
||
style: {
|
||
display: 'none',
|
||
position: 'absolute',
|
||
top: '20px',
|
||
right: '20px',
|
||
},
|
||
});
|
||
|
||
function show() {
|
||
art.layers.ads.style.display = 'block';
|
||
}
|
||
|
||
function hide() {
|
||
art.layers.ads.style.display = 'none';
|
||
}
|
||
|
||
art.controls.add({
|
||
name: 'hide-ads',
|
||
position: 'right',
|
||
html: 'Hide Ads',
|
||
tooltip: 'Hide Ads',
|
||
click: hide,
|
||
style: {
|
||
marginRight: '20px'
|
||
}
|
||
});
|
||
|
||
art.controls.add({
|
||
name: 'show-ads',
|
||
position: 'right',
|
||
html: 'Show Ads',
|
||
tooltip: 'Show Ads',
|
||
click: show,
|
||
});
|
||
|
||
art.on('play', hide);
|
||
art.on('pause', show);
|
||
|
||
return {
|
||
name: 'adsPlugin',
|
||
show,
|
||
hide
|
||
};
|
||
}
|
||
}
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
adsPlugin({
|
||
url: '/assets/sample/layer.png'
|
||
})
|
||
],
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/advanced/property.md =====
|
||
|
||
# Instance Properties
|
||
|
||
Here, `Instance Properties` refer to the `first-level properties` mounted on the `instance`, which are commonly used.
|
||
|
||
## `play`
|
||
|
||
- Type: `Function`
|
||
|
||
Play the video.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.play();
|
||
});
|
||
```
|
||
|
||
## `pause`
|
||
|
||
- Type: `Function`
|
||
|
||
Pause the video.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.play();
|
||
|
||
setTimeout(() => {
|
||
art.pause();
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `toggle`
|
||
|
||
- Type: `Function`
|
||
|
||
Toggle video play and pause.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.toggle();
|
||
|
||
setTimeout(() => {
|
||
art.toggle();
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `destroy`
|
||
|
||
- Type: `Function`
|
||
- Parameter: `Boolean`
|
||
|
||
Destroy the player. Accepts a parameter indicating whether to also remove the player's `html` after destruction. Defaults to `true`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.destroy();
|
||
});
|
||
```
|
||
|
||
## `reset`
|
||
|
||
- Type: `Function`
|
||
|
||
Reset the player's video element: removes the current `src` and calls `load()` once. Commonly used to manually release media resources or reinitialize the video tag in single-page applications.
|
||
|
||
> Note: The global configuration `Artplayer.REMOVE_SRC_WHEN_DESTROY` will also automatically execute similar logic when `destroy()` is called.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
// Only reset the video, do not remove the interface
|
||
art.reset();
|
||
});
|
||
```
|
||
|
||
## `seek`
|
||
|
||
- Type: `Setter`
|
||
- Parameter: `Number`
|
||
|
||
Seek to a specific time in the video, in seconds.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.seek = 5;
|
||
});
|
||
```
|
||
|
||
## `forward`
|
||
|
||
- Type: `Setter`
|
||
- Parameter: `Number`
|
||
|
||
Fast-forward the video time, in seconds.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.forward = 5;
|
||
});
|
||
```
|
||
|
||
## `backward`
|
||
|
||
- Type: `Setter`
|
||
- Parameter: `Number`
|
||
|
||
Rewind the video time, in seconds.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{10}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.seek = 5;
|
||
|
||
setTimeout(() => {
|
||
art.backward = 2;
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `volume`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Number`
|
||
|
||
Set and get the video volume, range: `[0, 1]`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.volume);
|
||
art.volume = 0.5;
|
||
console.info(art.volume);
|
||
});
|
||
```
|
||
|
||
## `url`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Set and get the video URL.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.url = '/assets/sample/video.mp4?t=0';
|
||
});
|
||
```
|
||
|
||
## `switch`
|
||
|
||
- Type: `Setter`
|
||
- Parameter: `String`
|
||
|
||
Set the video URL. Similar to `art.url` when setting, but performs some optimization operations.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.seek = 10;
|
||
setTimeout(() => {
|
||
art.switch = '/assets/sample/video.mp4?t=0';
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `switchUrl`
|
||
|
||
- Type: `Function`
|
||
- Parameter: `String`
|
||
|
||
Set the video URL. Similar to `art.url` when setting, but performs some optimization operations.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.seek = 10;
|
||
setTimeout(() => {
|
||
art.switchUrl('/assets/sample/video.mp4?t=0');
|
||
}, 3000);
|
||
});
|
||
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
`art.switch` and `art.switchUrl` have the same functionality, but the `art.switchUrl` method returns a `Promise`. It `resolve`s when the new URL is playable and `reject`s when the new URL fails to load.
|
||
|
||
:::
|
||
|
||
## `switchQuality`
|
||
|
||
- Type: `Function`
|
||
- Parameter: `String`
|
||
|
||
Sets the video quality URL. Similar to `art.switchUrl`, but retains the previous playback progress.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.seek = 10;
|
||
setTimeout(() => {
|
||
art.switchQuality('/assets/sample/video.mp4?t=0');
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `muted`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Sets or gets whether the video is muted.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.muted);
|
||
art.muted = true;
|
||
console.info(art.muted);
|
||
});
|
||
```
|
||
|
||
## `currentTime`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Number`
|
||
|
||
Sets or 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>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.currentTime);
|
||
art.currentTime = 5;
|
||
console.info(art.currentTime);
|
||
});
|
||
```
|
||
|
||
## `duration`
|
||
|
||
- Type: `Getter`
|
||
|
||
Gets the duration of the video.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.duration);
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Some videos may not have a duration, such as live streams or videos that have not been fully decoded. In such cases, the obtained duration will be `0`.
|
||
|
||
:::
|
||
|
||
## `screenshot`
|
||
|
||
- Type: `Function`
|
||
|
||
Downloads a screenshot of the current video frame. An optional parameter specifies the screenshot filename.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.screenshot('your-name');
|
||
});
|
||
```
|
||
|
||
## `getDataURL`
|
||
|
||
- Type: `Function`
|
||
|
||
Gets the `base64` URL of a screenshot of the current video frame. Returns a `Promise`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', async () => {
|
||
const url = await art.getDataURL();
|
||
console.info(url)
|
||
});
|
||
```
|
||
|
||
## `getBlobUrl`
|
||
|
||
- Type: `Function`
|
||
|
||
Gets the `blob` URL of a screenshot of the current video frame. Returns a `Promise`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', async () => {
|
||
const url = await art.getBlobUrl();
|
||
console.info(url);
|
||
});
|
||
```
|
||
|
||
## `fullscreen`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Sets or gets the player's window fullscreen state.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
position: 'right',
|
||
html: 'Fullscreen Switch',
|
||
click: function () {
|
||
art.fullscreen = !art.fullscreen;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Due to browser security mechanisms, a user interaction (e.g., a click on the page) must occur before triggering window fullscreen.
|
||
|
||
:::
|
||
|
||
## `fullscreenWeb`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Sets or gets the player's web page fullscreen state.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8,11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreenWeb: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.fullscreenWeb = true;
|
||
|
||
setTimeout(() => {
|
||
art.fullscreenWeb = false;
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## `pip`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Sets or gets the player's Picture-in-Picture (PIP) mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
position: 'right',
|
||
html: 'PIP',
|
||
click: function () {
|
||
art.pip = !art.pip;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Due to browser security mechanisms, a user interaction (e.g., a click on the page) must occur before triggering Picture-in-Picture.
|
||
|
||
:::
|
||
|
||
## `poster`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Sets and gets the video poster. The poster effect is only visible before the video starts playing.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
poster: '/assets/sample/poster.jpg',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.poster);
|
||
art.poster = '/assets/sample/poster.jpg?t=0';
|
||
console.info(art.poster);
|
||
});
|
||
```
|
||
|
||
## `mini`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Sets and gets the player's mini mode.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.mini = true;
|
||
});
|
||
```
|
||
|
||
## `playing`
|
||
|
||
- Type: `Getter`
|
||
- Parameter: `Boolean`
|
||
|
||
Gets whether the video is currently playing.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.playing);
|
||
});
|
||
```
|
||
|
||
## `state`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Gets or sets the player's current state. Supported values: `standard` (normal), `mini` (mini window), `pip` (picture-in-picture), `fullscreen` (window fullscreen), `fullscreenWeb` (webpage fullscreen).
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.state); // Default is 'standard'
|
||
art.state = 'mini';
|
||
});
|
||
```
|
||
|
||
## `autoSize`
|
||
|
||
- Type: `Function`
|
||
|
||
Sets whether the video adapts its size automatically.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.autoSize();
|
||
});
|
||
```
|
||
|
||
## `rect`
|
||
|
||
- Type: `Getter`
|
||
|
||
Gets the player's dimensions and coordinate information.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(JSON.stringify(art.rect));
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
The dimension and coordinate information is obtained via `getBoundingClientRect`.
|
||
|
||
:::
|
||
|
||
## `bottom` / `top` / `left` / `right` / `x` / `y` / `width` / `height`
|
||
|
||
- Type: `Getter`
|
||
|
||
These properties provide quick access to `rect`:
|
||
|
||
- `bottom`, `top`, `left`, `right`, `x`, `y`: Correspond to the fields of the same name in `DOMRect`.
|
||
- `width`, `height`: The player's current visible width and height.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.width, art.height, art.left, art.top);
|
||
});
|
||
```
|
||
|
||
## `flip`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Sets and gets the player's flip state. Supported values: `normal`, `horizontal`, `vertical`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.flip);
|
||
art.flip = 'horizontal';
|
||
console.info(art.flip);
|
||
});
|
||
```
|
||
|
||
## `playbackRate`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Number`
|
||
|
||
Sets and gets the player's playback speed.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.playbackRate);
|
||
art.playbackRate = 2;
|
||
console.info(art.playbackRate);
|
||
});
|
||
```
|
||
|
||
## `aspectRatio`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Sets and gets the player's aspect ratio.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.aspectRatio);
|
||
art.aspectRatio = '16:9';
|
||
console.info(art.aspectRatio);
|
||
});
|
||
```
|
||
|
||
## `autoHeight`
|
||
|
||
- Type: `Function`
|
||
|
||
When the container only has a defined width, this property can automatically calculate and set the video's height.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7,11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.autoHeight();
|
||
});
|
||
|
||
art.on('resize', () => {
|
||
art.autoHeight();
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
This property is useful when your container has only a width but the exact height is unknown. It can automatically calculate the video height, but you need to determine the timing for setting this property.
|
||
|
||
:::
|
||
|
||
## `attr`
|
||
|
||
- Type: `Function`
|
||
- Parameter: `String`
|
||
|
||
Dynamically get and set attributes of the video element.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.attr('playsInline'));
|
||
art.attr('playsInline', true);
|
||
console.info(art.attr('playsInline'));
|
||
});
|
||
```
|
||
|
||
## `type`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Dynamically get and set the video type.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.type);
|
||
art.type = 'm3u8';
|
||
console.info(art.type);
|
||
});
|
||
```
|
||
|
||
## `theme`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `String`
|
||
|
||
Dynamically get and set the player's theme color.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.theme);
|
||
art.theme = '#000';
|
||
console.info(art.theme);
|
||
});
|
||
```
|
||
|
||
## `airplay`
|
||
|
||
- Type: `Function`
|
||
|
||
Initiate AirPlay.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
position: 'right',
|
||
html: 'AirPlay',
|
||
click: function () {
|
||
art.airplay();
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## `loaded`
|
||
|
||
- Type: `Getter`
|
||
|
||
The proportion of video buffered, ranging from `[0, 1]`. Often used with the `video:timeupdate` event.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('video:timeupdate', () => {
|
||
console.info(art.loaded);
|
||
});
|
||
```
|
||
|
||
## `loadedTime`
|
||
|
||
- Type: `Getter`
|
||
|
||
The buffered media duration in seconds. Typically used alongside `loaded` to display detailed buffering progress.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('video:timeupdate', () => {
|
||
console.info(art.loadedTime);
|
||
});
|
||
```
|
||
|
||
## `played`
|
||
|
||
- Type: `Getter`
|
||
|
||
The proportion of video played, ranging from `[0, 1]`. Often used with the `video:timeupdate` event.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('video:timeupdate', () => {
|
||
console.info(art.played);
|
||
});
|
||
```
|
||
|
||
## `proxy`
|
||
|
||
- Type: `Function`
|
||
|
||
A proxy function for `DOM` events, essentially proxying `addEventListener` and `removeEventListener`. When using `proxy` to handle events, the event is automatically cleaned up when the player is destroyed.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8-10}
|
||
var container = document.querySelector('.artplayer-app');
|
||
|
||
var art = new Artplayer({
|
||
container: container,
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.proxy(container, 'click', event => {
|
||
console.info(event);
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
If you need certain `DOM` events to exist only for the player's lifecycle, it is strongly recommended to use this function to avoid memory leaks.
|
||
|
||
:::
|
||
|
||
## `query`
|
||
|
||
- Type: `Function`
|
||
|
||
A `DOM` query function, similar to `document.querySelector`, but the search is scoped to the current player, preventing errors with duplicate class names.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.query('.art-video'));
|
||
```
|
||
|
||
## `video`
|
||
|
||
- Type: `Element`
|
||
|
||
Quickly returns the player's `video` element.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
console.info(art.video);
|
||
```
|
||
|
||
## `cssVar`
|
||
|
||
- Type: `Function`
|
||
|
||
Dynamically get or set `CSS` variables.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
console.log(art.cssVar('--art-theme'));
|
||
art.cssVar('--art-theme', 'green');
|
||
console.log(art.cssVar('--art-theme'));
|
||
});
|
||
```
|
||
|
||
## `quality`
|
||
|
||
- Type: `Setter`
|
||
- Parameter: `Array`
|
||
|
||
Dynamically set the quality list.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{19-29}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
quality: [
|
||
{
|
||
default: true,
|
||
html: 'SD 480P',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
{
|
||
html: 'HD 720P',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
],
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
art.quality = [
|
||
{
|
||
default: true,
|
||
html: '1080P',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
{
|
||
html: '4K',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
];
|
||
}, 3000);
|
||
})
|
||
|
||
```
|
||
|
||
## `thumbnails`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Object`
|
||
|
||
Dynamically set thumbnails.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.thumbnails = {
|
||
url: '/assets/sample/thumbnails.png',
|
||
number: 60,
|
||
column: 10,
|
||
};
|
||
});
|
||
```
|
||
|
||
## `subtitleOffset`
|
||
|
||
- Type: `Setter/Getter`
|
||
- Parameter: `Number`
|
||
|
||
Dynamically set subtitle offset.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.subtitleOffset = 1;
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/component/contextmenu.md =====
|
||
|
||
# Context Menu
|
||
|
||
## Configuration
|
||
|
||
| 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` | DOM element of the component |
|
||
| `style` | `Object` | Component style object |
|
||
| `click` | `Function` | Component click event |
|
||
| `mounted` | `Function` | Triggered after component mount |
|
||
| `tooltip` | `String` | Tooltip text for the component |
|
||
|
||
## Creation
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-13}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
contextmenu: [
|
||
{
|
||
name: 'your-menu',
|
||
html: 'Your Menu',
|
||
click: function (...args) {
|
||
console.info(args);
|
||
art.contextmenu.show = false;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
|
||
// Get the Element of contextmenu by name
|
||
console.info(art.contextmenu['your-menu']);
|
||
```
|
||
|
||
## Addition
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6-13}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.contextmenu.add({
|
||
name: 'your-menu',
|
||
html: 'Your Menu',
|
||
click: function (...args) {
|
||
console.info(args);
|
||
art.contextmenu.show = false;
|
||
},
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
|
||
// Get the Element of contextmenu by name
|
||
console.info(art.contextmenu['your-menu']);
|
||
```
|
||
|
||
## Deletion
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
contextmenu: [
|
||
{
|
||
name: 'your-menu',
|
||
html: 'Your Menu',
|
||
click: function (...args) {
|
||
console.info(args);
|
||
art.contextmenu.show = false;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Delete the contextmenu by name
|
||
art.contextmenu.remove('your-menu')
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## Update
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21-24}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
contextmenu: [
|
||
{
|
||
name: 'your-menu',
|
||
html: 'Your Menu',
|
||
click: function (...args) {
|
||
console.info(args);
|
||
art.contextmenu.show = false;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
art.contextmenu.show = true;
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Update the contextmenu by name
|
||
art.contextmenu.update({
|
||
name: 'your-menu',
|
||
html: 'Your New Menu',
|
||
})
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/component/controls.md =====
|
||
|
||
# Controls
|
||
|
||
## Configuration
|
||
|
||
| Property | Type | Description |
|
||
| ---------- | ------------------- | ------------------------------------------------ |
|
||
| `disable` | `Boolean` | Whether to disable the control |
|
||
| `name` | `String` | Unique name of the control, used for class marking |
|
||
| `index` | `Number` | Control index, determines display priority |
|
||
| `html` | `String`, `Element` | DOM element of the control |
|
||
| `style` | `Object` | Style object for the control |
|
||
| `click` | `Function` | Click event handler for the control |
|
||
| `mounted` | `Function` | Triggered after the control is mounted |
|
||
| `tooltip` | `String` | Tooltip text for the control |
|
||
| `position` | `String` | `left` or `right` - controls which side the control appears on |
|
||
| `selector` | `Array` | Array of objects for selection list |
|
||
| `onSelect` | `Function` | Function triggered when a selection list item is clicked |
|
||
|
||
## Creation
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
name: 'your-button',
|
||
index: 10,
|
||
position: 'left',
|
||
html: 'Your Button',
|
||
tooltip: 'Your Button',
|
||
style: {
|
||
color: 'red',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
},
|
||
mounted: function (...args) {
|
||
console.info('mounted', args);
|
||
},
|
||
},
|
||
{
|
||
name: 'subtitle',
|
||
position: 'right',
|
||
html: 'Subtitle',
|
||
selector: [
|
||
{
|
||
default: true,
|
||
html: '<span style="color:red">subtitle 01</span>',
|
||
},
|
||
{
|
||
html: '<span style="color:yellow">subtitle 02</span>',
|
||
},
|
||
],
|
||
onSelect: function (item, $dom) {
|
||
console.info(item, $dom);
|
||
return 'Your ' + item.html;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
// Get the Element of control by name
|
||
console.info(art.controls['your-button']);
|
||
console.info(art.controls['subtitle']);
|
||
```
|
||
|
||
## Adding
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6-21}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.controls.add({
|
||
name: 'button1',
|
||
index: 10,
|
||
position: 'left',
|
||
html: 'Your Button',
|
||
tooltip: 'Your Button',
|
||
style: {
|
||
color: 'red',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
},
|
||
mounted: function (...args) {
|
||
console.info('mounted', args);
|
||
},
|
||
});
|
||
|
||
// Get the Element of control by name
|
||
console.info(art.controls['button1']);
|
||
```
|
||
|
||
## Removal
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
name: 'button1',
|
||
index: 10,
|
||
position: 'right',
|
||
html: 'Your Button',
|
||
tooltip: 'Your Button',
|
||
style: {
|
||
color: 'red',
|
||
},
|
||
}
|
||
]
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Delete the control by name
|
||
art.controls.remove('button1');
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## Updating
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{26-40}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
name: 'button1',
|
||
index: 10,
|
||
position: 'right',
|
||
html: 'Subtitle',
|
||
selector: [
|
||
{
|
||
default: true,
|
||
html: 'subtitle 01',
|
||
},
|
||
{
|
||
html: 'subtitle 02',
|
||
},
|
||
],
|
||
}
|
||
]
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Update the control by name
|
||
art.controls.update({
|
||
name: 'button1',
|
||
index: 10,
|
||
position: 'right',
|
||
html: 'New Subtitle',
|
||
selector: [
|
||
{
|
||
default: true,
|
||
html: 'new subtitle 01',
|
||
},
|
||
{
|
||
html: 'new subtitle 02',
|
||
},
|
||
],
|
||
});
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/component/layers.md =====
|
||
|
||
# Layers
|
||
|
||
## Configuration
|
||
|
||
| 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
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{5-22}
|
||
var img = '/assets/sample/layer.png';
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
layers: [
|
||
{
|
||
name: 'potser',
|
||
html: `<img style="width: 100px" src="${img}">`,
|
||
tooltip: 'Potser Tip',
|
||
style: {
|
||
position: 'absolute',
|
||
top: '50px',
|
||
right: '50px',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
},
|
||
mounted: function (...args) {
|
||
console.info('mounted', args);
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
// Get the Element of layer by name
|
||
console.info(art.layers['potser']);
|
||
```
|
||
|
||
## Addition
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7-22}
|
||
var img = '/assets/sample/layer.png';
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
|
||
art.layers.add({
|
||
name: 'potser',
|
||
html: `<img style="width: 100px" src="${img}">`,
|
||
tooltip: 'Potser Tip',
|
||
style: {
|
||
position: 'absolute',
|
||
top: '50px',
|
||
right: '50px',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
},
|
||
mounted: function (...args) {
|
||
console.info('mounted', args);
|
||
},
|
||
});
|
||
|
||
// Get the Element of layer by name
|
||
console.info(art.layers['potser']);
|
||
```
|
||
|
||
## Removal
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21}
|
||
var img = '/assets/sample/layer.png';
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
layers: [
|
||
{
|
||
name: 'potser',
|
||
html: `<img style="width: 100px" src="${img}">`,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '50px',
|
||
right: '50px',
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Delete the layer by name
|
||
art.layers.remove('potser');
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## Update
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21-29}
|
||
var img = '/assets/sample/layer.png';
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
layers: [
|
||
{
|
||
name: 'potser',
|
||
html: `<img style="width: 100px" src="${img}">`,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '50px',
|
||
right: '50px',
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Update the layer by name
|
||
art.layers.update({
|
||
name: 'potser',
|
||
html: `<img style="width: 200px" src="${img}">`,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '50px',
|
||
left: '50px',
|
||
},
|
||
});
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/component/setting.md =====
|
||
|
||
# Settings Panel
|
||
|
||
## Built-in
|
||
|
||
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>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
subtitleOffset: true,
|
||
});
|
||
```
|
||
|
||
## Create - Button
|
||
|
||
| Property | Type | Description |
|
||
| ---------- | ------------------- | -------------------- |
|
||
| `html` | `String`, `Element` | The DOM element |
|
||
| `icon` | `String`, `Element` | The icon element |
|
||
| `onClick` | `Function` | The click event |
|
||
| `width` | `Number` | The list width |
|
||
| `tooltip` | `String` | The tooltip text |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'Button',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
tooltip: 'tooltip',
|
||
onClick(item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
return 'new tooltip';
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## Create - Selection List
|
||
|
||
| Property | Type | Description |
|
||
| ---------- | ------------------- | -------------------- |
|
||
| `html` | `String`, `Element` | The DOM element |
|
||
| `icon` | `String`, `Element` | The icon element |
|
||
| `selector` | `Array` | The list of elements |
|
||
| `onSelect` | `Function` | The click event |
|
||
| `width` | `Number` | The list width |
|
||
| `tooltip` | `String` | The tooltip text |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'Subtitle',
|
||
width: 250,
|
||
tooltip: 'Subtitle 01',
|
||
selector: [
|
||
{
|
||
default: true,
|
||
html: '<span style="color:red">Subtitle 01</span>',
|
||
url: '/assets/sample/subtitle.srt?id=1',
|
||
},
|
||
{
|
||
html: '<span style="color:yellow">Subtitle 02</span>',
|
||
url: '/assets/sample/subtitle.srt?id=2',
|
||
},
|
||
],
|
||
onSelect: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
art.subtitle.url = item.url;
|
||
return item.html;
|
||
},
|
||
},
|
||
{
|
||
html: 'Quality',
|
||
width: 150,
|
||
tooltip: '1080P',
|
||
selector: [
|
||
{
|
||
default: true,
|
||
html: '1080P',
|
||
url: '/assets/sample/video.mp4?id=1080',
|
||
},
|
||
{
|
||
html: '720P',
|
||
url: '/assets/sample/video.mp4?id=720',
|
||
},
|
||
{
|
||
html: '360P',
|
||
url: '/assets/sample/video.mp4?id=360',
|
||
},
|
||
],
|
||
onSelect: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
art.switchQuality(item.url, item.html);
|
||
return item.html;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## Create - Nested List
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'Multi-level',
|
||
selector: [
|
||
{
|
||
html: 'Setting 01',
|
||
width: 150,
|
||
selector: [
|
||
{
|
||
html: 'Setting 01 - 01',
|
||
},
|
||
{
|
||
html: 'Setting 01 - 02',
|
||
},
|
||
],
|
||
onSelect: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
return item.html;
|
||
},
|
||
},
|
||
{
|
||
html: 'Setting 02',
|
||
width: 150,
|
||
selector: [
|
||
{
|
||
html: 'Setting 02 - 01',
|
||
},
|
||
{
|
||
html: 'Setting 02 - 02',
|
||
},
|
||
],
|
||
onSelect: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
return item.html;
|
||
},
|
||
},
|
||
],
|
||
},
|
||
],
|
||
});
|
||
|
||
```
|
||
|
||
## Create - Toggle Button
|
||
|
||
| Property | Type | Description |
|
||
| ---------- | ------------------- | -------------------------- |
|
||
| `html` | `String`, `Element` | DOM element for the item |
|
||
| `icon` | `String`, `Element` | Icon for 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>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'PIP Mode',
|
||
tooltip: 'Close',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
switch: false,
|
||
onSwitch: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
const nextState = !item.switch;
|
||
art.pip = nextState;
|
||
item.tooltip = nextState ? 'Open' : 'Close';
|
||
return nextState;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## Create - Range Slider
|
||
|
||
| Property | Type | Description |
|
||
| ---------- | ------------------- | -------------------------- |
|
||
| `html` | `String`, `Element` | DOM element for the item |
|
||
| `icon` | `String`, `Element` | Icon for 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];
|
||
const value = range[0];
|
||
const min = range[1];
|
||
const max = range[2];
|
||
const step = range[3];
|
||
```
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'Slider',
|
||
tooltip: '5x',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
range: [5, 1, 10, 1],
|
||
onChange: function (item, $dom, event) {
|
||
console.info(item, $dom, event);
|
||
return item.range[0] + 'x';
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## Add
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{9-14}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
});
|
||
|
||
art.setting.show = true;
|
||
|
||
art.setting.add({
|
||
html: 'Slider',
|
||
tooltip: '5x',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
range: [5, 1, 10, 1],
|
||
});
|
||
```
|
||
|
||
## Remove
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{22}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
flip: true,
|
||
settings: [
|
||
{
|
||
name: 'slider',
|
||
html: 'Slider',
|
||
tooltip: '5x',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
range: [5, 1, 10, 1],
|
||
},
|
||
],
|
||
});
|
||
|
||
art.setting.show = true;
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Delete the setting by name
|
||
art.setting.remove('slider');
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
## Update
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{21-27}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
name: 'slider',
|
||
html: 'Slider',
|
||
tooltip: '5x',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
range: [5, 1, 10, 1],
|
||
},
|
||
],
|
||
});
|
||
|
||
art.setting.show = true;
|
||
|
||
art.on('ready', () => {
|
||
setTimeout(() => {
|
||
// Update the setting by name
|
||
art.setting.update({
|
||
name: 'slider',
|
||
html: 'PIP Mode',
|
||
tooltip: 'Close',
|
||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||
switch: false,
|
||
});
|
||
}, 3000);
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/index.md =====
|
||
|
||
# Installation and Usage
|
||
|
||
## Installation
|
||
|
||
::: code-group
|
||
|
||
```bash [npm]
|
||
npm install artplayer
|
||
```
|
||
|
||
```bash [yarn]
|
||
yarn add artplayer
|
||
```
|
||
|
||
```bash [pnpm]
|
||
pnpm add artplayer
|
||
```
|
||
|
||
```bash [bun]
|
||
bun add artplayer
|
||
```
|
||
|
||
```html [script]
|
||
<script src="path/to/artplayer.js"></script>
|
||
```
|
||
|
||
:::
|
||
|
||
## `CDN`
|
||
|
||
::: code-group
|
||
|
||
```bash [jsdelivr.net]
|
||
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.js
|
||
```
|
||
|
||
```bash [unpkg.com]
|
||
https://unpkg.com/artplayer/dist/artplayer.js
|
||
```
|
||
|
||
:::
|
||
|
||
## Usage
|
||
|
||
::: code-group
|
||
|
||
```html [index.html]
|
||
<html>
|
||
<head>
|
||
<title>ArtPlayer Demo</title>
|
||
<meta charset="UTF-8" />
|
||
<style>
|
||
.artplayer-app {
|
||
width: 400px;
|
||
height: 300px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="artplayer-app"></div>
|
||
<script src="path/to/artplayer.js"></script>
|
||
<script>
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'path/to/video.mp4',
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
:::
|
||
|
||
::: warning Note
|
||
|
||
The player's dimensions depend on the dimensions of its `container`. Therefore, your `container` must have defined dimensions.
|
||
|
||
:::
|
||
|
||
::: tip See more usage examples at the following link
|
||
|
||
[/example](https://github.com/zhw2590582/ArtPlayer/tree/master/example)
|
||
|
||
:::
|
||
|
||
## `Vue.js`
|
||
|
||
::: code-group
|
||
|
||
```vue [Artplayer.vue]
|
||
<template>
|
||
<div ref="$container" />
|
||
</template>
|
||
|
||
<script setup>
|
||
import Artplayer from 'artplayer'
|
||
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue'
|
||
|
||
const props = defineProps({
|
||
option: {
|
||
type: Object,
|
||
required: true,
|
||
},
|
||
})
|
||
|
||
const emit = defineEmits(['getInstance'])
|
||
|
||
const art = shallowRef(null)
|
||
const $container = ref(null)
|
||
|
||
onMounted(() => {
|
||
art.value = new Artplayer({
|
||
...props.option,
|
||
container: $container.value,
|
||
})
|
||
emit('getInstance', art.value)
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
art.value.destroy(false)
|
||
})
|
||
</script>
|
||
```
|
||
|
||
```vue [app.vue]
|
||
<template>
|
||
<Artplayer :option="option" :style="style" @get-instance="getInstance" />
|
||
</template>
|
||
|
||
<script setup>
|
||
import { reactive } from 'vue'
|
||
import Artplayer from './Artplayer.vue'
|
||
|
||
const option = reactive({
|
||
url: 'path/to/video.mp4',
|
||
})
|
||
|
||
const style = reactive({
|
||
width: '600px',
|
||
height: '400px',
|
||
margin: '60px auto 0',
|
||
})
|
||
|
||
function getInstance(art) {
|
||
console.log(art)
|
||
}
|
||
</script>
|
||
```
|
||
|
||
:::
|
||
|
||
::: warning Artplayer is not reactive:
|
||
|
||
Directly modifying the `option` in `Vue.js` will not update the player.
|
||
|
||
:::
|
||
|
||
## `React.js`
|
||
|
||
::: code-group
|
||
|
||
```jsx [Artplayer.jsx]
|
||
import Artplayer from 'artplayer'
|
||
import { useEffect, useRef } from 'react'
|
||
|
||
export default function Player({ option, getInstance, ...rest }) {
|
||
const $container = useRef()
|
||
|
||
useEffect(() => {
|
||
const art = new Artplayer({
|
||
...option,
|
||
container: $container.current,
|
||
})
|
||
|
||
if (typeof getInstance === 'function') {
|
||
getInstance(art)
|
||
}
|
||
|
||
return () => art.destroy(false)
|
||
}, [])
|
||
|
||
return <div ref={$container} {...rest}></div>
|
||
}
|
||
```
|
||
|
||
```jsx [app.jsx]
|
||
import Artplayer from './Artplayer.jsx'
|
||
|
||
function App() {
|
||
return (
|
||
<div>
|
||
<Artplayer
|
||
option={{
|
||
url: 'path/to/video.mp4',
|
||
}}
|
||
style={{
|
||
width: '600px',
|
||
height: '400px',
|
||
margin: '60px auto 0',
|
||
}}
|
||
getInstance={art => console.log(art)}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default App
|
||
```
|
||
|
||
:::
|
||
|
||
::: warning Artplayer is not reactive:
|
||
|
||
Directly modifying the `option` in `React.js` will not update the player.
|
||
|
||
:::
|
||
|
||
## TypeScript
|
||
|
||
The `artplayer.d.ts` file is automatically imported when you import `Artplayer`.
|
||
|
||
### Vue.js
|
||
|
||
```vue{3}
|
||
<script setup>
|
||
import Artplayer from 'artplayer';
|
||
const art = shallowRef<Artplayer>(null);
|
||
art.value = new Artplayer();
|
||
</script>
|
||
```
|
||
|
||
### React.js
|
||
|
||
```jsx{2}
|
||
import Artplayer from 'artplayer';
|
||
const art = useRef<Artplayer>(null);
|
||
art.current = new Artplayer();
|
||
```
|
||
|
||
### Option
|
||
|
||
You can also use the type for the options.
|
||
|
||
```ts{3}
|
||
import Artplayer, { type Option } from 'artplayer';
|
||
|
||
const option: Option = {
|
||
container: '.artplayer-app',
|
||
url: './assets/sample/video.mp4',
|
||
};
|
||
|
||
option.volume = 0.5;
|
||
|
||
const art = new Artplayer(option);
|
||
```
|
||
|
||
::: tip Full TypeScript Definitions
|
||
|
||
[packages/artplayer/types](https://github.com/zhw2590582/ArtPlayer/tree/master/packages/artplayer/types)
|
||
|
||
:::
|
||
|
||
## JavaScript
|
||
|
||
Sometimes your `js` files may lose `TypeScript` type hints. In such cases, you can manually import the types.
|
||
|
||
Variable:
|
||
|
||
```js{1-3}
|
||
/**
|
||
* @type {import("artplayer")}
|
||
*/
|
||
let art = null;
|
||
```
|
||
|
||
Parameter:
|
||
|
||
```js{1-3}
|
||
/**
|
||
* @param {import("artplayer")} art
|
||
*/
|
||
function getInstance(art) {
|
||
//
|
||
}
|
||
```
|
||
|
||
Property:
|
||
|
||
```js{4-6}
|
||
export default {
|
||
data() {
|
||
return {
|
||
/**
|
||
* @type {import("artplayer")}
|
||
*/
|
||
art: null,
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Option:
|
||
|
||
```js{1-3}
|
||
/**
|
||
* @type {import("artplayer/types/option").Option}
|
||
*/
|
||
|
||
const option = {
|
||
container: '.artplayer-app',
|
||
url: './assets/sample/video.mp4',
|
||
};
|
||
|
||
option.volume = 0.5;
|
||
|
||
const art8 = new Artplayer(option);
|
||
```
|
||
|
||
## Legacy Browsers
|
||
|
||
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 is compatible down to: `IE 11`.
|
||
|
||
```js
|
||
import Artplayer from 'artplayer/legacy'
|
||
```
|
||
|
||
::: code-group
|
||
|
||
```bash [jsdelivr.net]
|
||
https://cdn.jsdelivr.net/npm/artplayer/dist/artplayer.legacy.js
|
||
```
|
||
|
||
```bash [unpkg.com]
|
||
https://unpkg.com/artplayer/dist/artplayer.legacy.js
|
||
```
|
||
|
||
:::
|
||
|
||
::: 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)
|
||
|
||
Reference documentation: [browserslist](https://github.com/browserslist/browserslist#full-list)
|
||
|
||
:::
|
||
|
||
## ECMAScript Module
|
||
|
||
::: tip ESM Demo:
|
||
|
||
[https://artplayer.org/esm.html](https://artplayer.org/esm.html)
|
||
|
||
:::
|
||
|
||
Starting from version `5.2.6`, `artplayer` and all plugins also provide an `ESM` version in `mjs` format, such as:
|
||
|
||
- `artplayer/dist/artplayer.mjs`
|
||
- `artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.mjs`
|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>ArtPlayer ESM with Import Map</title>
|
||
<style>
|
||
#player {
|
||
width: 640px;
|
||
height: 360px;
|
||
margin: 50px auto;
|
||
border: 1px solid #ccc;
|
||
}
|
||
</style>
|
||
<script type="importmap">
|
||
{
|
||
"imports": {
|
||
"artplayer": "https://unpkg.com/artplayer/dist/artplayer.esm.js"
|
||
}
|
||
}
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<div id="player"></div>
|
||
<script type="module">
|
||
import Artplayer from 'artplayer';
|
||
|
||
const art = new Artplayer({
|
||
container: '#player',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
</script>
|
||
</body>
|
||
|
||
</html>
|
||
```
|
||
|
||
## Custom userAgent
|
||
|
||
Currently, the detection of whether a device is mobile is not always accurate. Sometimes you may want to adjust the player's UI by changing the `userAgent`. Therefore, starting from version `5.2.4`, a global variable `globalThis.CUSTOM_USER_AGENT` has been added.
|
||
|
||
```html
|
||
<html>
|
||
<head>
|
||
<title>ArtPlayer Demo</title>
|
||
<meta charset="UTF-8" />
|
||
<style>
|
||
.artplayer-app {
|
||
width: 400px;
|
||
height: 300px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="artplayer-app"></div>
|
||
<script>globalThis.CUSTOM_USER_AGENT = 'iphone'</script>
|
||
<script src="path/to/artplayer.js"></script>
|
||
<script>
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'path/to/video.mp4',
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
::: warning Note
|
||
|
||
You need to modify it before importing the `Artplayer` dependency for it to take effect.
|
||
|
||
:::
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/ads.md =====
|
||
|
||
# Video and HTML Ads
|
||
|
||
[简体中文](../../plugin/ads.md)
|
||
|
||
Show one preroll when content first plays, using a separate video or HTML. The plugin supplies countdown, close, details, mute and fullscreen controls without IMA. Ad-tag requests belong to the separate [VAST plugin](./vast.md). This page describes the unreleased refactor branch; online examples and unpinned packages are not the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-ads
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginAds from 'artplayer-plugin-ads';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-ads.js`; the global is `artplayerPluginAds`. The [original online example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads) below supplies both video and HTML, so the video takes precedence.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-ads/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-ads
|
||
// import artplayerPluginAds from 'artplayer-plugin-ads';
|
||
|
||
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',
|
||
|
||
// 广告跳转网址,为空则不跳转
|
||
url: 'http://artplayer.org',
|
||
|
||
// 必须观看的时长,期间不能被跳过,单位为秒
|
||
// 当该值大于或等于totalDuration时,不能提前关闭广告
|
||
// 当该值等于或小于0时,则随时都可以关闭广告
|
||
playDuration: 5,
|
||
|
||
// 广告总时长,单位为秒
|
||
totalDuration: 10,
|
||
|
||
// 多语言支持
|
||
i18n: {
|
||
close: '关闭广告',
|
||
countdown: '%s秒',
|
||
detail: '查看详情',
|
||
canBeClosed: '%s秒后可关闭广告',
|
||
},
|
||
}),
|
||
],
|
||
})
|
||
|
||
// 广告被点击
|
||
art.on('artplayerPluginAds:click', (ads) => {
|
||
console.info('广告被点击', ads)
|
||
})
|
||
|
||
// 广告被跳过
|
||
art.on('artplayerPluginAds:skip', (ads) => {
|
||
console.info('广告被跳过', ads)
|
||
})
|
||
```
|
||
|
||
## Options
|
||
|
||
Options may be omitted or supplied as `{}` to use defaults.
|
||
|
||
| Field | Type | Default | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `html` | `string` | `''` | Ad HTML, including images; not sanitized automatically, so supply trusted content |
|
||
| `video` | `string` | `''` | Ad video URL; a nonempty value overrides html |
|
||
| `url` | `string` | `''` | Destination opened from ad content or details; empty disables navigation and hides details |
|
||
| `playDuration` | `number` | `5` | Countdown seconds before the close button is enabled; does not restrict programmatic skip |
|
||
| `totalDuration` | `number` | `10` | Total countdown seconds, independent of the video duration |
|
||
| `muted` | `boolean` | `false` | Initial ad-video mute state |
|
||
| `i18n` | `Translations` | Below | Replaces the entire translations object; all four fields are required |
|
||
|
||
| Translation | Default |
|
||
| --- | --- |
|
||
| `close` | `'关闭广告'` |
|
||
| `countdown` | `'%s秒'` |
|
||
| `detail` | `'查看详情'` |
|
||
| `canBeClosed` | `'%s秒后可关闭广告'` |
|
||
|
||
`%s` is replaced with the time value. Options are shallowly merged; partial i18n objects are not supported. Use numeric seconds: string durations are rejected without coercion. Historical workspace source/type fields are not runtime aliases for video/html; supply images through an img in html.
|
||
|
||
Positive integer durations are recommended. With `playDuration <= 0`, the button allows immediate closure; with `playDuration >= totalDuration`, it is hidden. Counting advances once per timer execution and pauses while the document is hidden. It is not an exact measure of video currentTime or real elapsed time. The ad video loops; countdown completion or skip ends the ad.
|
||
|
||
## Methods and events
|
||
|
||
Registration is synchronous. The result is `art.plugins.artplayerPluginAds`, with the fixed name `artplayerPluginAds`.
|
||
|
||
| Method | Runtime behavior |
|
||
| --- | --- |
|
||
| `pause()` | Pause only the countdown, leaving ad video playback unchanged |
|
||
| `play()` | Resume only the countdown without adding duplicate timer chains |
|
||
| `skip()` | Finish once, regardless of the button's playDuration restriction |
|
||
|
||
All return `undefined` synchronously. Before initialization, play/pause do not start an ad. Early skip cancels the pending preroll and emits once without creating DOM or starting content. Repeated skip after completion is inert.
|
||
|
||
| Player event | Payload and timing |
|
||
| --- | --- |
|
||
| `artplayerPluginAds:click` | The normalized options when ad content or available details are clicked; a nonempty url is opened first |
|
||
| `artplayerPluginAds:skip` | The same normalized options on completion, including countdown expiry, programmatic skip or media failure; not solely a user-click signal |
|
||
|
||
Event options remain live, not readonly snapshots. Listener mutations affect later reads, such as totalDuration. Opening the details destination remains subject to browser window policies.
|
||
|
||
## Lifecycle and media
|
||
|
||
Install through construction options. After ready, the first play or video:playing signal creates the overlay and pauses content. Late installation does not replay an earlier ready event. Video ads wait for their own metadata before counting and requesting playback; HTML ads start counting immediately.
|
||
|
||
Ad media loading or playback failure completes the ad, and rejected internal play requests warn. Normal completion requests content playback, pauses the ad, hides the overlay and synchronously emits skip. A playback request does not guarantee the browser has started playing; direct application `art.play()` rejection behavior remains unchanged.
|
||
|
||
The hidden overlay stays until player destruction. Destroy releases the ad source, listeners, timer and overlay, removing its own `art.template.$ads` even if player HTML is retained. There is no separate public destroy, reset or replay-ad API. Existing `artplayer-plugin-ads*` classes remain; the fullscreen control uses core fullscreen.
|
||
|
||
The separate ad video must be loadable and decodable by the browser. Main-player SDKs and proxies do not automatically handle it. Native fullscreen, mobile playback policies and media behavior require target-environment validation; page navigation is not that evidence.
|
||
|
||
## TypeScript compatibility
|
||
|
||
The root and `/legacy` retain acceptance of the old erroneous `totalDuration: string` declaration, but runtime still rejects strings. The approved inference correction makes `Parameters<typeof ads>[0].totalDuration` read as `number | string | undefined`; historical source/type also become optional. Narrow those values or migrate to the accurate Option type.
|
||
|
||
New code can select `/runtime`, which uses the same implementation:
|
||
|
||
```ts
|
||
import ads from 'artplayer-plugin-ads/runtime';
|
||
import type { Option, Result } from 'artplayer-plugin-ads';
|
||
|
||
const options: Option = { video: '/advertisement.mp4', totalDuration: 10 };
|
||
const installAds = ads(options);
|
||
|
||
function pauseCountdown(plugin: Result): void {
|
||
plugin.pause();
|
||
}
|
||
```
|
||
|
||
Public types include Translations, Option, LegacyOption, WorkspaceOption, CompatOption, Result, Callable, Factory, RuntimeCallable and RuntimeFactory. Historical option types do not add runtime aliases. CommonJS supports the function and `.default(...)`; ESM uses the default export. The precise entry is not a second plugin implementation.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/ambilight.md =====
|
||
|
||
# Video ambilight
|
||
|
||
[简体中文](../../plugin/ambilight.md)
|
||
|
||
Sample colors from the video to display a blurred glow around the player. The plugin reads pixels with Canvas, needs no additional SDK, and does not change video playback or audio output.
|
||
|
||
This page describes the refactor branch. Its lifecycle fixes and accurate type entry are not published yet. The online example and unpinned npm/CDN packages are not the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-ambilight
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginAmbilight from 'artplayer-plugin-ambilight';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-ambilight.js`. The global is `artplayerPluginAmbilight`. The following code is unchanged from the [online ambilight example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ambilight/index.js&example=ambilight). Your application must provide its own container and accessible video.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-ambilight/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-ambilight
|
||
// import artplayerPluginAmbilight from 'artplayer-plugin-ambilight';
|
||
|
||
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,
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## Options
|
||
|
||
| Field | Type | Default | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `blur` | `string` | `'50px'` | CSS blur radius |
|
||
| `opacity` | `number` | `0.5` | Glow grid opacity; the example explicitly uses `1` |
|
||
| `frequency` | `number` | `10` | Maximum samples per second; use a positive value; playback and frame scheduling limit the actual rate |
|
||
| `duration` | `number` | `0.3` | Color transition duration in seconds |
|
||
| `zIndex` | `number` | Actual value fixed at `9` | Historical accepted input that does not change the grid's stacking order |
|
||
|
||
The plugin samples a 3×3 grid. Colors update only while the player is playing and the sampling interval has elapsed. `frequency` does not set the video's frame rate. Masks, clipping and an ancestor's `overflow` styles can also affect how much of the glow is visible.
|
||
|
||
## start and stop
|
||
|
||
The result has the fixed `name` of `artplayerPluginAmbilight`. When installed through the constructor options, it starts scheduling after the player's `ready` event:
|
||
|
||
```js
|
||
const light = art.plugins.artplayerPluginAmbilight;
|
||
light.stop(); // Stop sampling and retain the last colors.
|
||
light.start(); // Resume sampling while the player is playing.
|
||
```
|
||
|
||
Both methods return `undefined` synchronously and do not play or pause the video. `stop()` retains the last colors. `start()` is not a Promise that captures a frame immediately. Repeated calls do not create multiple sampling loops. If you install the plugin with `art.plugins.add(...)` after `ready` has already fired, call `start()` on the returned result yourself.
|
||
|
||
There is no plugin `update` or separate `destroy` method. Destroying the player stops frame scheduling, removes the grid and plugin subscriptions, and releases the sampling canvas. Retained `start/stop` methods do no work after destruction.
|
||
|
||
## Media access and proxies
|
||
|
||
The browser must be able to decode the video and read its pixels into Canvas. Cross-origin video needs the appropriate media CORS configuration and server response headers; successful playback alone does not grant pixel access. A failed pixel read skips that update and retains existing colors. A later readable source can recover. The plugin does not bypass browser origin restrictions.
|
||
|
||
Canvas proxy sampling uses the actual dimensions of its output canvas. Other proxies must be checked for a drawable output; a passing desktop combination does not establish support for every browser or proxy. The effect does not control a physical monitor's backlight.
|
||
|
||
## TypeScript compatibility entries
|
||
|
||
The root and `/legacy` entries retain the published 1.1.0 factory type: the options object is required, while its fields are optional. Pass `{}` for defaults with those types. JavaScript calls can still omit the argument.
|
||
|
||
For accurate optional calls, the CommonJS `.default` self-alias, or callable NodeNext ESM default types, use `/runtime`, which shares the same implementation:
|
||
|
||
```ts
|
||
import ambilight from 'artplayer-plugin-ambilight/runtime';
|
||
|
||
const installLight = ambilight();
|
||
const installDefaultLight = ambilight.default({ opacity: 0.5 });
|
||
```
|
||
|
||
The root declarations export the named types `Option`, `Result`, `Callable`, `Factory` and `RuntimeFactory`. Version 1.0.0 used `export =` and required option fields, unlike 1.1.0. Earlier `import = require` callers can move to `/runtime`; reads of optional fields need a fallback. Node10 TypeScript default imports of `/runtime` require `esModuleInterop`; `import = require` works without it.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/asr.md =====
|
||
|
||
# Audio Capture and Recognition Subtitles
|
||
|
||
[简体中文](../../plugin/asr.md)
|
||
|
||
Capture audio from the player's video, pass PCM/WAV chunks to your recognition callback, and display the returned subtitles. The plugin includes no recognition model or network service and does not access the microphone. This page describes the unreleased refactor branch; the new type entry and capture option are not claims about the live release.
|
||
|
||
## Installation and local example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-asr
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginAsr from 'artplayer-plugin-asr';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-asr.js`. The global is `artplayerPluginAsr`. This preserves the original `asr.local` example: it captures the site's sample video and displays statistics. Subtitles are simulated, audio is not uploaded, and the example does not measure recognition accuracy. Integrate your own recognition service inside the callback.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-asr/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
/* global Artplayer, artplayerPluginAsr */
|
||
// Local audio capture demo. The subtitles below are simulated, not recognized speech.
|
||
// No audio is uploaded; only the sample media is loaded from this local site.
|
||
const statistics = document.createElement('div')
|
||
statistics.textContent = 'Local ASR demo: press play. No recognition service is used.'
|
||
let chunks = 0
|
||
let pcmBytes = 0
|
||
let wavBytes = 0
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/steve-jobs.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
layers: [{
|
||
name: 'asr-local-statistics',
|
||
html: statistics,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '12px',
|
||
left: '12px',
|
||
right: '12px',
|
||
padding: '8px 12px',
|
||
background: 'rgba(0, 0, 0, 0.65)',
|
||
color: '#fff',
|
||
fontSize: '12px',
|
||
whiteSpace: 'pre-line',
|
||
pointerEvents: 'none',
|
||
},
|
||
}],
|
||
controls: [{
|
||
name: 'asr-local-stop',
|
||
position: 'right',
|
||
html: 'Stop ASR',
|
||
tooltip: 'Stop capture; pause and play to restart',
|
||
async click() {
|
||
await art.plugins.artplayerPluginAsr.stop()
|
||
if (!art.isDestroy)
|
||
statistics.textContent = 'Local capture stopped. Pause and play to restart. Nothing was uploaded.'
|
||
},
|
||
}],
|
||
plugins: [artplayerPluginAsr({
|
||
length: 2,
|
||
interval: 250,
|
||
sampleRate: 16000,
|
||
autoHideTimeout: 5000,
|
||
onAudioChunk({ pcm, wav }) {
|
||
if (art.isDestroy)
|
||
return
|
||
chunks++
|
||
pcmBytes += pcm.byteLength
|
||
wavBytes += wav.byteLength
|
||
const sampleRate = new DataView(wav).getUint32(24, true)
|
||
const samples = new DataView(pcm)
|
||
let peak = 0
|
||
for (let offset = 0; offset < pcm.byteLength; offset += 2)
|
||
peak = Math.max(peak, Math.abs(samples.getInt16(offset, true)))
|
||
const duration = (pcmBytes / 2 / sampleRate).toFixed(2)
|
||
statistics.textContent = [
|
||
'Local capture only - simulated subtitles, no speech recognition',
|
||
`Chunks: ${chunks} | ${sampleRate} Hz mono PCM16 | ${duration} seconds captured`,
|
||
`PCM: ${pcmBytes} bytes | WAV: ${wavBytes} bytes | Current peak: ${peak}`,
|
||
].join('\n')
|
||
return `Simulated local subtitle: audio chunk ${chunks} received.`
|
||
},
|
||
})],
|
||
})
|
||
```
|
||
|
||
## Options and audio chunks
|
||
|
||
| Field | Default | Meaning |
|
||
| --- | --- | --- |
|
||
| `length` | `3` | Number of final nonempty punctuation-separated segments displayed from the current subtitle, not seconds of audio |
|
||
| `interval` | `100` | Consumption timer interval and target audio duration per chunk, in milliseconds |
|
||
| `sampleRate` | `16000` | Requested sample rate in Hz; requires environment support |
|
||
| `autoHideTimeout` | `10000` | Delay before hiding an accepted subtitle, in milliseconds |
|
||
| `onAudioChunk` | Function returning `null` | Receives `{ pcm, wav }`; a returned string displays subtitles; Promises are supported |
|
||
| `audioInput` | Unset | Direct Web Audio by default; `{ type: 'capture' }` explicitly selects a captured stream |
|
||
|
||
Both `pcm` and `wav` are `ArrayBuffer` values. Audio comes from the first channel. PCM is signed 16-bit little-endian; WAV adds a 44-byte mono header. A chunk contains `Math.floor(sampleRate * interval / 1000)` samples, requiring at least one sample and a positive, finite interval. Audio availability, browser scheduling and recognition latency affect callback frequency; exact timing is not guaranteed.
|
||
|
||
At most one recognition callback is pending within the active capture generation. Partial chunks stay queued. Rejected callbacks log an error and allow later processing. A backlog exceeding the larger of about one minute of audio or two chunks pauses capture and logs an error to bound memory. Pause, source changes, stop and destroy invalidate old results. They do not cancel network requests already sent by your callback; manage those resources in your application.
|
||
|
||
## Subtitles and lifecycle
|
||
|
||
Access the result through `art.plugins.artplayerPluginAsr`; its `name` is always `artplayerPluginAsr`:
|
||
|
||
| Method | Behavior |
|
||
| --- | --- |
|
||
| `append(text)` | Returns `undefined` synchronously; displays the final `length` segments of this text and resets the hide timer, replacing earlier subtitles rather than accumulating history |
|
||
| `hide()` | Returns `undefined` synchronously; hides subtitles without stopping capture or clearing their text |
|
||
| `stop()` | Actually returns `Promise<void>`; stops the current capture and discards old results; a later play event can restart it |
|
||
|
||
Both `append` and returned strings preserve historical HTML rendering and are not automatically escaped. Supply trusted subtitles; escape or sanitize external recognition text in your application. `null`, `undefined` and other non-string callback results do not update subtitles. `stop()` does not immediately hide existing subtitles; their original auto-hide deadline remains active.
|
||
|
||
Play starts capture; pause stops recording and discards obsolete work. Source changes rebuild the applicable capture state, and media errors use a nonterminal stop. The default direct connection retains the video's audio output route until `art.destroy()`, allowing playback after stop. Destroy releases subscriptions, timers, recording resources and audio contexts. There is no separate public plugin `start()` or `destroy()`.
|
||
|
||
## Audio routing and cross-origin media
|
||
|
||
The default route reads `art.video`, not the independent Audio Track plugin's audio. The video's own volume and mute affect captured data. Cross-origin media requires `moreVideoAttr: { crossOrigin: 'anonymous' }` before loading and appropriate server CORS headers. Playable media is not necessarily readable by Web Audio: without access, the clock can advance while output is silent, samples are zero or no chunks arrive. Cross-origin redirects are also restricted.
|
||
|
||
If your application already owns a Web Audio graph, explicitly choose `audioInput: { type: 'capture' }`. It uses `captureStream/mozCaptureStream`, does not take over the existing output, and never falls back to a direct connection on failure. It releases only its own contexts and captured tracks. Pause retains this graph; stop or source changes release it, and later playback obtains a fresh stream. Unsupported capability or initialization failure is logged and resources are cleaned up.
|
||
|
||
Captured data can remain nonzero despite video volume or mute and does not include an external effects graph or independent audio mix. CORS still applies: capture may be rejected, or a track may exist without readable audio. Desktop results do not establish Safari, mobile, every proxy or physical speaker behavior.
|
||
|
||
## TypeScript entries
|
||
|
||
The root preserves historical `AsrPluginOption`, `AsrPluginInstance` and `AudioChunk` types: callbacks return `void | Promise<void>`, and stop returns void. To type returned recognition strings, await stop or select captured input, use `/runtime`, which points to the same implementation:
|
||
|
||
```ts
|
||
import asr from 'artplayer-plugin-asr/runtime';
|
||
import type { RuntimeResult } from 'artplayer-plugin-asr/runtime';
|
||
|
||
const installAsr = asr({
|
||
audioInput: { type: 'capture' },
|
||
onAudioChunk({ pcm, wav }) {
|
||
console.log(pcm.byteLength, wav.byteLength);
|
||
return null; // Replace with your recognizer; null displays no subtitle.
|
||
},
|
||
});
|
||
|
||
async function stopAsr(plugin: RuntimeResult): Promise<void> {
|
||
await plugin.stop();
|
||
}
|
||
```
|
||
|
||
Precise types are `RuntimeOption`, `RuntimeResult` and `RuntimeFactory`, with `AudioChunk` also exported. Some NodeNext ESM consumers retain the old root namespace shape; choose `/runtime` for a callable default import. CommonJS runtime supports the function itself and its `.default` self-alias; `/runtime` also supports TypeScript `import = require`.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/audio-track.md =====
|
||
|
||
# Audio Track
|
||
|
||
[中文](../../plugin/audio-track.md)
|
||
|
||
Play a separate audio file in sync with a video. The plugin creates an `HTMLAudioElement` and follows the main video's playback, pause, position, volume and playback rate. It requires no additional SDK and does not add an audio-selection menu.
|
||
|
||
This page describes the current refactor branch. Its lifecycle fixes and precise `/runtime` types are not yet published; an unpinned npm or CDN installation does not select this branch.
|
||
|
||
## Installation
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-audio-track
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginAudioTrack from 'artplayer-plugin-audio-track';
|
||
```
|
||
|
||
For script tags, load ArtPlayer before the plugin's `dist/artplayer-plugin-audio-track.js`. The global is `artplayerPluginAudioTrack`. Pin dependency versions and supply an audio URL the browser can access and decode.
|
||
|
||
## Complete example
|
||
|
||
This is the same code as the [online audio example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio.track). The demo site supplies the media files and `.artplayer-app` container; replace both when integrating it into your application.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-audio-track/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-audio-track
|
||
// import artplayerPluginAudioTrack from 'artplayer-plugin-audio-track';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/sprite-fight.mp4',
|
||
plugins: [
|
||
artplayerPluginAudioTrack({
|
||
url: '/assets/sample/sprite-fight.aac',
|
||
offset: 0,
|
||
sync: 0.3,
|
||
}),
|
||
],
|
||
});
|
||
```
|
||
|
||
## Options and synchronization
|
||
|
||
`artplayerPluginAudioTrack(option)` returns a plugin factory. The options object is required.
|
||
|
||
| Field | Type and default | Behavior |
|
||
| --- | --- | --- |
|
||
| `url` | Required `string` | Separate audio URL. An empty string at construction leaves the source unloaded. |
|
||
| `offset` | `number`, default `0` | Target audio time is video time plus this value, in seconds. A positive offset reads further ahead in the audio file. |
|
||
| `sync` | `number`, default `0.3` | Adjust audio time only when its absolute difference from the target is strictly greater than this threshold, in seconds. |
|
||
|
||
For example, video time 10 with offset 0.25 targets audio time 10.25. This corrects media-time drift; it is not a sample-accurate audio clock. Use finite, reasonable offsets and a nonnegative threshold. Negative targets or targets beyond the audio duration depend on browser media behavior; the plugin adds no delayed start, looping or silence padding.
|
||
|
||
Playback, completed seeking and playback recovery synchronize the track. Ordinary playing timeupdate events also correct drift. Buffering, source emptying, native pause, starting a seek and reaching the video's end pause the separate audio. It resumes when the main video is playing and ready to recover; canplay alone does not start audio for a paused video.
|
||
|
||
## Result and updates
|
||
|
||
After installation, access the result at `art.plugins.artplayerPluginAudioTrack`:
|
||
|
||
| Member | Behavior |
|
||
| --- | --- |
|
||
| `name` | Always `artplayerPluginAudioTrack`. |
|
||
| `audio` | The actual `HTMLAudioElement`; source updates preserve its identity. |
|
||
| `update(option)` | Synchronously updates selected fields and returns `undefined`, not a loading Promise. |
|
||
|
||
```js
|
||
const track = art.plugins.artplayerPluginAudioTrack;
|
||
track.update({ offset: 0.25, sync: 0.1 });
|
||
track.update({ url: '/audio/another-language.m4a' });
|
||
```
|
||
|
||
Changing offset or sync does not immediately force a seek; the next synchronization event uses the new values. Only a different, nonempty URL replaces the source. Reusing the same URL does not reload it, and an empty URL is not a stop or clear command. Replacing a source while the main video is playing attempts playback; observe the exposed audio element for actual loading, decoding and errors.
|
||
|
||
`art.switchUrl()` changes only the main video. Your application must keep video and audio sources paired and select the new audio with `track.update()`. Use native media events when you need to wait for readiness; `await track.update(...)` does not wait for loading.
|
||
|
||
## Volume, playback failure and destruction
|
||
|
||
The plugin does not remove the video's original sound. Use a video source without its own audio track if the separate track should provide the only sound. Player volume, mute and playback rate also apply to the separate audio. Setting `art.muted = true` mutes both; it cannot selectively mute only the main video.
|
||
|
||
Browser playback policies still apply. While the instance is active, a rejected `audio.play()` is reported through `console.warn`; it does not become a rejection from update. Successful main-video playback does not prove that the separate audio is audible. Applications can observe native playing/error events on the audio element.
|
||
|
||
Destroying ArtPlayer removes plugin subscriptions, pauses audio, removes its src attribute and releases media loading. A retained result still points to the same element, but later update calls no longer reload or play it. Your application remains responsible for listeners it adds to audio. There is no separate plugin destroy method to call.
|
||
|
||
## TypeScript
|
||
|
||
The root and `/legacy` entries preserve the old `Result.update(Option)` declaration, including its required URL, to retain parameter extraction and function-assignment behavior. Runtime updates already support partial options. Use `/runtime` for accurate partial-update types over the same implementation:
|
||
|
||
```ts
|
||
import Artplayer from 'artplayer';
|
||
import audioTrack from 'artplayer-plugin-audio-track/runtime';
|
||
|
||
const installTrack = audioTrack({ url: '/audio/dialogue.m4a' });
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/video/silent.mp4',
|
||
plugins: [(player) => {
|
||
const track = installTrack(player);
|
||
track.update({ offset: 0.25 });
|
||
return track;
|
||
}],
|
||
});
|
||
```
|
||
|
||
Named types include `Option`, `UpdateOption`, the old `Result`, `RuntimeResult` and `RuntimeFactory`. The online editor's default global retains legacy inference too. To select precise update typing, explicitly use `artplayerPluginAudioTrack as artplayerPluginAudioTrack.RuntimeFactory`. This does not create a second plugin implementation.
|
||
|
||
Actual desktop tests cover audio/video playback, pause, seeking, updates and destruction. They do not establish support for every mobile device, proxy player, audio format or long-running synchronization combination. Check browser decoding capabilities and the project's validation records for the applicable scope.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/auto-thumbnail.md =====
|
||
|
||
# Automatic Thumbnails
|
||
|
||
[简体中文](../../plugin/auto-thumbnail.md)
|
||
|
||
Read frames with a separate video element, progressively create a JPEG sprite sheet in the browser, and update the player's progress-bar thumbnails. This page describes the unreleased refactor branch; the online example and unpinned npm/CDN packages are not the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-auto-thumbnail
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-auto-thumbnail.js`; the global is `artplayerPluginAutoThumbnail`. This preserves the [original online example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-auto-thumbnail/index.js&example=auto.thumbnail). The factory requires an options object; use `{}` for defaults.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-auto-thumbnail/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-auto-thumbnail
|
||
// import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
artplayerPluginAutoThumbnail({
|
||
//
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## Options and generation
|
||
|
||
| Field | Type | Default | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `url` | `string` | Current `art.option.url` | Media read by the separate decoder; an explicit nonempty URL takes precedence |
|
||
| `width` | `number` | `160` | Width of each thumbnail cell in pixels |
|
||
| `number` | `number` | `100` | Target sample count; normally use a positive integer |
|
||
| `scale` | `number` | `1` | Preview display scale passed to the player; does not reduce the generated canvas size |
|
||
| `height` | `number` | Derived from video aspect ratio | Historical ignored option accepted by the precise runtime type |
|
||
|
||
Defaults preserve `value || default` behavior: `width: 0`, for example, uses 160. After fallback, width and number must convert to finite positive values. Historical JavaScript numeric strings and fractional counts are retained, but typed examples use numbers and positive integer counts. Height is `Math.floor(width * videoHeight / videoWidth)`, with ten columns per row. Media needs finite positive duration and dimensions; infinite-duration live streams do not qualify.
|
||
|
||
Sampling uses `duration * index / number`, starting at index 0 and excluding the media endpoint. Duration and sheet dimensions are captured at the separate video's metadata event. Each drawn cell is followed by encoding the whole JPEG and publishing a new `art.thumbnails` configuration. Later cells can therefore remain empty while generation is in progress.
|
||
|
||
Larger width and count increase canvas allocation, decoding and repeated encoding cost. Dimension checks are not a browser memory budget. Choose values appropriate for the media and device, or use prebuilt [VTT thumbnails](./vtt-thumbnail.md).
|
||
|
||
## Registration, source changes and cleanup
|
||
|
||
The factory returns an asynchronous registrar whose result contains only `name: 'artplayerPluginAutoThumbnail'`. Its Promise resolves after installing player subscriptions, before extraction. It does not confirm that media was read successfully. There are no public progress, extraction-completion, update, stop or destroy methods.
|
||
|
||
Each `video:loadedmetadata` event starts extraction and rereads the original options object, so later mutations affect the next run. Installation does not replay metadata events that already occurred. `restart` cancels the old job; a subsequent metadata event starts another. Old frame or encoding callbacks cannot overwrite the newer job.
|
||
|
||
Metadata acquisition, each frame wait and each JPEG encoding operation have separate 30-second limits, not one total extraction deadline. Media, canvas and encoding failures clean up the current job, report through `console.warn` and retain the last usable preview. They cannot reject an already-resolved registration Promise.
|
||
|
||
Completion or cancellation releases the separate video and canvas. The final image URL remains until a usable replacement is installed or the player is destroyed. Only generated URLs are revoked; application-owned thumbnail URLs are not. Destroy also removes subscriptions. Directly invoking a retained registrar after player destruction returns the same name without allocating a decoder; it does not override core `plugins.add()` destruction checks.
|
||
|
||
## Media access and browser limits
|
||
|
||
The separate video uses `crossOrigin = 'anonymous'`, is muted, and is never explicitly played. Media must support native browser loading and Canvas pixel access, including appropriate server CORS headers. Player custom loaders, SDKs, request headers and proxies are not installed into this decoder; supply a directly readable media `url` when necessary.
|
||
|
||
The hidden video is attached to the document with a rendered box; it is not an additional visible player. Actual decoding and first-frame correctness remain browser-dependent. The current Windows WebKit first-frame issue is still unresolved. Types, navigation and other browser results do not close it or establish physical Safari/mobile support.
|
||
|
||
## Compatible TypeScript entries
|
||
|
||
The root and `/legacy` preserve npm 1.1.0 synchronous result declarations and required options; the root Option does not contain height. For the actual Promise, historical height input or `.default` self-alias types, use `/runtime`, which loads the same implementation:
|
||
|
||
```ts
|
||
import type Artplayer from 'artplayer';
|
||
import autoThumbnail from 'artplayer-plugin-auto-thumbnail/runtime';
|
||
import type { Option, Result } from 'artplayer-plugin-auto-thumbnail/runtime';
|
||
|
||
const options: Option = { width: 160, number: 100, scale: 1 };
|
||
|
||
async function registerThumbnails(art: Artplayer): Promise<Result> {
|
||
return await autoThumbnail(options)(art); // Registration only, not extraction completion.
|
||
}
|
||
```
|
||
|
||
Runtime exports `Option`, `Result`, `Factory` and `RuntimeFactory`. Factory is a plain asynchronous factory; RuntimeFactory adds the writable `.default` self-alias. CommonJS runtime supports direct and `.default(...)` calls. Earlier 1.0.x `export =` and height declarations differ from 1.1.0; use the runtime `import = require` form when migrating those imports. Root NodeNext namespace behavior remains unchanged; use runtime for an accurate callable default import. Classic Node10 default imports need `esModuleInterop`.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/chapter.md =====
|
||
|
||
# Video chapters
|
||
|
||
[简体中文](../../plugin/chapter.md)
|
||
|
||
Divide the progress bar into chapters and display a title on hover while retaining the player's seeking and thumbnail controls. The plugin does not extract chapter metadata from the media file; your application supplies the times.
|
||
|
||
This page describes the refactor branch. Its candidates and fixes are not published yet. The online example and unpinned npm/CDN packages may use different code.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-chapter
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginChapter from 'artplayer-plugin-chapter';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-chapter.js`. The plugin global is `artplayerPluginChapter`. The following code is unchanged from the [online chapter example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chapter/index.js&example=chapter). The site provides its container, video and thumbnail image; replace those resources when integrating it into your application.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-chapter/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-chapter
|
||
// import artplayerPluginChapter from 'artplayer-plugin-chapter';
|
||
|
||
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: '终わり' },
|
||
],
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## chapters
|
||
|
||
The factory accepts an optional options object containing `chapters`. Each entry has these fields:
|
||
|
||
| Field | Type | Meaning |
|
||
| --- | --- | --- |
|
||
| `start` | `number` | Start time in seconds; a finite, nonnegative number |
|
||
| `end` | `number` | End time in seconds; `Infinity` means the current video's end |
|
||
| `title` | `string` | Hover title; an empty string retains an untitled interval |
|
||
|
||
Every interval must satisfy `start < end <= video duration`, without overlapping the next chapter. The plugin sorts chapters by start time and fills uncovered intervals at the beginning, end and between chapters. It **mutates the supplied array** by sorting it, inserting untitled entries and replacing `Infinity` with the current duration. Pass a fresh array and fresh entry objects whenever you need to preserve the original configuration.
|
||
|
||
Chapters are created only when the media duration is finite and positive. Missing, empty or non-array input clears the view; TypeScript still accepts only the declared array type. Invalid field types throw `TypeError`; invalid times and overlapping intervals throw `Error`. Titles are plain text, not HTML. Displayed titles are trimmed without changing the original object's `title`.
|
||
|
||
## update
|
||
|
||
The result has the fixed `name` of `artplayerPluginChapter`. `update(option)` replaces the chapters synchronously and returns `undefined`. Its options object is required; `update({})` clears the chapters:
|
||
|
||
```js
|
||
art.plugins.artplayerPluginChapter.update({
|
||
chapters: [{ start: 0, end: Infinity, title: 'Introduction' }],
|
||
});
|
||
|
||
// Clear all chapter segments and the hover title.
|
||
art.plugins.artplayerPluginChapter.update({});
|
||
```
|
||
|
||
An update clears the previous view before validating the replacement. If validation throws, the previous chapters are not retained. A successful update synchronously emits the existing `setBar('loaded', ...)` event; progress interactions continue to use the core controls.
|
||
|
||
The initial configuration is applied only on the first `video:loadedmetadata`. Switching media does not calculate new chapters automatically. After the new media loads, call `update` with fresh data for its duration. Do not reuse an object whose `Infinity` end was already replaced by the previous duration.
|
||
|
||
## Lifecycle and styling
|
||
|
||
Destroying the player removes this plugin's listeners, chapter nodes, title and `artplayer-plugin-chapter` class, including when `art.destroy(false)` retains the player HTML. Calling `update` on a retained result after destruction does not recreate the view. There is no separate plugin `destroy()` method.
|
||
|
||
The existing `.art-chapter`, `.art-chapter-title` and chapter `data-start/end/duration/title` hooks remain. Long titles are clipped to the progress bar width, while their full text remains in the text content and data attributes. The stylesheet is shared by the page and is retained when one player is destroyed.
|
||
|
||
## TypeScript
|
||
|
||
The root and `/legacy` entries share the public API and export the `Chapters`, `Option` and `Result` types. This package does not require a separate `/runtime` entry:
|
||
|
||
```ts
|
||
import artplayerPluginChapter from 'artplayer-plugin-chapter';
|
||
import type { Chapters } from 'artplayer-plugin-chapter';
|
||
|
||
const chapters: Chapters = [{ start: 0, end: Infinity, title: 'Introduction' }];
|
||
const installChapters = artplayerPluginChapter({ chapters });
|
||
```
|
||
|
||
Desktop tests cover chapters with quality selection, thumbnails and fullscreen. They do not establish support on every mobile device. The current Windows WebKit quality-switch tests still encounter stalls while reading browser state, so this page does not promise timing reliability on every platform.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/chromecast.md =====
|
||
|
||
# Chromecast
|
||
|
||
[简体中文](../../plugin/chromecast.md)
|
||
|
||
Add a right-side Cast control that selects a Cast session and loads media. Use a supported Chrome sender, HTTPS, a real receiver and receiver-accessible media. This page describes the unreleased branch. A local page, mocked SDK or successful session does not prove playback on a television.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-chromecast
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
|
||
```
|
||
|
||
For scripts, load ArtPlayer before `dist/artplayer-plugin-chromecast.js`; the global is `artplayerPluginChromecast`. This preserves the [original example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast). Supply an absolute media URL reachable by your receiver; sender localhost, relative URLs and Blob URLs are not rewritten automatically.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-chromecast/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-chromecast
|
||
// import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
|
||
|
||
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
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## Options and callbacks
|
||
|
||
An options object is required; `{}` uses defaults. The icon is captured at registration; other options and callbacks are read from the original object at the relevant operation.
|
||
|
||
| Field | Type | Behavior |
|
||
| --- | --- | --- |
|
||
| `url` | `string` | Nonempty override, otherwise current art.option.url |
|
||
| `sdk` | `string` | Override the Cast SDK script URL |
|
||
| `icon` | `string` | Trusted control HTML inside the retained art-icon/art-icon-cast wrapper |
|
||
| `mimeType` | `string` | Nonempty override, otherwise inferred from the URL extension |
|
||
| `onStateChange` | `(state) => void` | Normalized disconnected/connecting/connected/disconnecting state |
|
||
| `onCastAvailable` | `(available: boolean) => void` | SDK availability event, not playback success |
|
||
| `onCastStart` | `() => void` | Called after the current loadMedia completes |
|
||
| `onError` | `(error: unknown) => void` | SDK, connection or loading failure; not necessarily an Error instance |
|
||
|
||
Callback this is the original options object. The default SDK URL is `https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1`. Concurrent loads in the same module/window share the first pending URL; a later retry can read another URL.
|
||
|
||
MIME inference strips query/hash and lowercases the extension. mp4/webm/ogg/ogv/mp3/wav/flv/mov/avi/wmv/mpd/m3u8 map respectively to video/mp4, video/webm, video/ogg, video/ogg, audio/mp3, audio/wav, video/x-flv, video/quicktime, video/x-msvideo, video/x-ms-wmv, application/dash+xml and application/x-mpegURL. Unknown extensions use application/octet-stream. This mapping is not receiver codec support; provide mimeType explicitly when needed.
|
||
|
||
## Registration and session state
|
||
|
||
Registration returns a Promise but adds the `chromecast` control immediately. SDK loading starts on first click, so registration is not SDK readiness. The loader has a 30-second readiness limit; script load alone is insufficient without the Framework. It configures the default media receiver and ORIGIN_SCOPED auto-join policy, with no custom receiver-application option.
|
||
|
||
A click initializes the SDK and checks the current session. If absent, it requests a session, reads it again, then awaits loadMedia. Pending clicks for one controller share the operation. A successful session request without a current session is a connection error. The media URL is read when sending; later player source changes do not automatically cast again. Use the control to send the new media.
|
||
|
||
The result is at `art.plugins.artplayerPluginChromecast`:
|
||
|
||
| Member | Meaning |
|
||
| --- | --- |
|
||
| `name` | Always artplayerPluginChromecast |
|
||
| `getCastState()` | Last raw SDK SessionState, initially null; not the normalized callback state |
|
||
| `isCasting()` | Whether a session reference is retained, not proof of receiver playback |
|
||
|
||
The icon uses white for disconnected, orange for transitional and red for connected states. Session termination, failure or replacement invalidates pending work; late results cannot start stale media or show obsolete notices. SDK failures display a stage-specific notice and call onError. User callback exceptions can still propagate.
|
||
|
||
## Cleanup and shared sessions
|
||
|
||
Player destruction releases this controller's loader subscription, SDK listeners and pending operation. It does not interrupt another player waiting for the SDK or end the page-shared receiver session. Successful scripts remain; failed or last-owner-cancelled pending scripts are removed. The core owns control DOM removal.
|
||
|
||
There is no public start, stop, disconnect or destroy method, and no continuous synchronization of local pause, time or volume. Callbacks and icons describe observed controller state. Receiver playback, network reachability, source changes and disconnection require real hardware validation; local tests cannot substitute for it.
|
||
|
||
## TypeScript
|
||
|
||
Root and `/legacy` preserve npm1.1.0's required options and synchronous name-only declaration. For precise callbacks, Promise registration and state methods, use `/runtime`, with the same implementation:
|
||
|
||
```ts
|
||
import cast from 'artplayer-plugin-chromecast/runtime';
|
||
import type { RuntimeOption, RuntimeResult } from 'artplayer-plugin-chromecast/runtime';
|
||
|
||
const options: RuntimeOption = {
|
||
onStateChange(state) { console.log(state, this.url); },
|
||
onError(error) { console.error(error); },
|
||
};
|
||
const registerCast = cast(options);
|
||
function readSession(plugin: RuntimeResult): boolean {
|
||
return plugin.isCasting(); // Session presence, not receiver playback.
|
||
}
|
||
```
|
||
|
||
Root/runtime named types are Option, Chromecast, Result, Factory, ConnectionState, RuntimeOption, RuntimeResult and RuntimeFactory. Historical root NodeNext namespace behavior remains. Use runtime for accurate ESM default calls or older `import = require` syntax. JavaScript supports direct and `.default(...)` factory calls; type compatibility does not establish device capabilities.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/danmuku-mask.md =====
|
||
|
||
# Danmuku Mask
|
||
|
||
[简体中文](../../plugin/danmuku-mask.md)
|
||
|
||
Generate a CSS mask from person segmentation so danmuku avoids people in the video. The plugin masks the core `.art-danmuku` layer without changing its queue, individual items or video pixels. This describes the unreleased branch; the online example and navigation checks are not model-quality acceptance.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-danmuku artplayer-plugin-danmuku-mask
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginDanmuku from 'artplayer-plugin-danmuku';
|
||
import artplayerPluginDanmukuMask from 'artplayer-plugin-danmuku-mask';
|
||
```
|
||
|
||
For scripts, load the core and both plugin dist files. Their globals are `artplayerPluginDanmuku` and `artplayerPluginDanmukuMask`. The [original example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js%0A./uncompiled/artplayer-plugin-danmuku-mask/index.js&example=danmuku.mask) registers them in that order and loads MediaPipe assets from the site's own directory:
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js ./uncompiled/artplayer-plugin-danmuku-mask/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-danmuku-mask
|
||
// import artplayerPluginDanmukuMask from 'artplayer-plugin-danmuku-mask';
|
||
|
||
// npm i @mediapipe/selfie_segmentation
|
||
// 把 node_modules/@mediapipe/selfie_segmentation 目录复制到你的项目下
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/steve-jobs.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
autoOrientation: true,
|
||
plugins: [
|
||
artplayerPluginDanmuku({
|
||
danmuku: '/assets/sample/danmuku.xml',
|
||
}),
|
||
artplayerPluginDanmukuMask({
|
||
solutionPath: '/assets/@mediapipe/selfie_segmentation',
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
Host matching MediaPipe assets under solutionPath. Copying a directory alone does not establish script, model, WASM, network-policy or browser support.
|
||
|
||
## Options
|
||
|
||
Options may be omitted; values are captured at registration:
|
||
|
||
| Field | Type / default | Runtime use |
|
||
| --- | --- | --- |
|
||
| `solutionPath` | `string` | SDK asset root; default CDN URL is unversioned |
|
||
| `modelSelection` | `number` / `1` | Historical forwarded field, not proof that the current model changes |
|
||
| `smoothSegmentation` | `boolean` / `true` | Historical forwarded field; explicit false is retained |
|
||
| `minDetectionConfidence` | `number` / `0.5` | Historical forwarded field |
|
||
| `minTrackingConfidence` | `number` / `0.5` | Historical forwarded field |
|
||
| `selfieMode` | `boolean` / `false` | Historical forwarded field |
|
||
| `drawContour` | `boolean` / `false` | Passed to binary-mask conversion |
|
||
| `foregroundThreshold` | `number` / `0.5` | Passed to foreground threshold conversion |
|
||
| `opacity` | `number` / `1` | Passed to SDK drawMask, not directly applied as danmuku-layer opacity |
|
||
| `maskBlurAmount` | `number` / `3` | Blur argument passed to SDK drawMask |
|
||
|
||
The default solutionPath is the unversioned [MediaPipe asset root on jsDelivr](https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation).
|
||
|
||
Except for smoothSegmentation's undefined check, defaults retain `value || default`. Zero modelSelection, opacity, threshold or blur uses its default rather than disabling the effect. Use stop to disable masking.
|
||
|
||
The current selection is fixed to `runtime: 'mediapipe'` and `modelType: 'general'`. The installed adapter maps general to modelSelection 0 and ignores some extra forwarded fields. Their presence does not promise an inference change. TensorFlow first attempts webgl and tries cpu only on rejection; that does not establish MediaPipe's actual inference backend.
|
||
|
||
## Start, stop and failures
|
||
|
||
Registration synchronously returns `{ name: 'artplayerPluginDanmukuMask', start, stop }`, available at `art.plugins.artplayerPluginDanmukuMask`. The ready event starts it automatically; call start yourself if installed after ready.
|
||
|
||
| Method | Behavior |
|
||
| --- | --- |
|
||
| `start()` | Returns `Promise<void>` after initialization/scheduling, not after a complete first mask |
|
||
| `stop()` | Returns undefined synchronously; cancels scheduling and immediately sets layer maskImage to none |
|
||
|
||
Repeated start does not overlap inference loops. Stop during initialization settles public start promptly while uncancellable SDK work remains observed. Late results cannot update the mask. A subsequent start waits for old work and disposal before creating another model.
|
||
|
||
Model creation failure logs an error and can resolve start without a usable model; explicit start can retry. Backend or required DOM/Canvas initialization can still reject start. Automatic ready startup logs rejection. Inference/pixel errors log and continue scheduling while retaining the previous usable mask.
|
||
|
||
Inference runs only while video is playing, not ended, and has valid dimensions. Binary-mask conversion, drawMask and Canvas pixel processing produce a PNG data URL assigned to the whole layer. No-person results retain the preceding mask. Accuracy, performance and cross-origin pixel access need actual media checks.
|
||
|
||
## Lifecycle and types
|
||
|
||
Player destruction stops work and removes ready/destroy subscriptions. The plugin owns its private canvas; after SDK work settles it resets dimensions and disposes the model. Stop is not a GPU-release completion Promise. Private SDK disposal completion still needs separate evidence. There is no public destroy, update or new event, and no takeover of application-wide TensorFlow lifetime.
|
||
|
||
Root and `/legacy` retain optional options, synchronous registration, async start and sync stop. There is no `/runtime` subpath. Option/Result are private declaration types, extractable from the factory. This example is type-only extraction for NodeNext ESM; it does not call `.default` at runtime:
|
||
|
||
```ts
|
||
import type MaskModule from 'artplayer-plugin-danmuku-mask';
|
||
|
||
type MaskFactory = typeof MaskModule.default;
|
||
type MaskOptions = Parameters<MaskFactory>[0];
|
||
type MaskResult = ReturnType<ReturnType<MaskFactory>>;
|
||
|
||
const options: MaskOptions = { solutionPath: '/assets/@mediapipe/selfie_segmentation' };
|
||
async function restartMask(mask: MaskResult): Promise<void> {
|
||
mask.stop();
|
||
await mask.start();
|
||
}
|
||
```
|
||
|
||
The preserved NodeNext root declaration has namespace behavior; it does not give the current runtime factory a `.default` property. Current CommonJS calls the function directly, and ESM runtime uses its default export. Do not infer runtime aliases from the type namespace. Historical export forms, actual segmentation and device performance remain separate checks.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/danmuku.md =====
|
||
|
||
# Danmuku
|
||
|
||
[中文说明](../../plugin/danmuku.md)
|
||
|
||
Display timed comments over the video, with an input panel, display settings and an optional heatmap.
|
||
This guide describes the current refactor branch. The `/runtime` entrypoint and refactor fixes have not yet been published to npm; unversioned CDN links still load the published release.
|
||
|
||
## Demo
|
||
|
||
[Open the full example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku).
|
||
Run Code examples below use the site's local plugin build and sample media. In your application, use your own container and media URLs.
|
||
|
||
## Installation
|
||
|
||
::: code-group
|
||
|
||
```sh [npm]
|
||
npm install artplayer artplayer-plugin-danmuku
|
||
```
|
||
|
||
```sh [yarn]
|
||
yarn add artplayer artplayer-plugin-danmuku
|
||
```
|
||
|
||
```sh [pnpm]
|
||
pnpm add artplayer artplayer-plugin-danmuku
|
||
```
|
||
|
||
```html [script]
|
||
<script src="path/to/artplayer.js"></script>
|
||
<script src="path/to/artplayer-plugin-danmuku.js"></script>
|
||
```
|
||
|
||
:::
|
||
|
||
JavaScript projects can import the default factory from `artplayer-plugin-danmuku`.
|
||
Script builds expose `artplayerPluginDanmuku`; pass its result to the player's `plugins` array.
|
||
|
||
## CDN
|
||
|
||
::: code-group
|
||
|
||
```text [jsDelivr]
|
||
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
|
||
```
|
||
|
||
```text [unpkg]
|
||
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
|
||
```
|
||
|
||
:::
|
||
|
||
## Comment structure
|
||
|
||
Only `text` is required. Leading and trailing whitespace is removed; empty comments are ignored.
|
||
|
||
```js
|
||
({
|
||
text: 'Hello!',
|
||
time: 10, // Seconds; omitted time defaults to currentTime + 0.5
|
||
mode: 0, // 0: scrolling, 1: top, 2: bottom; defaults to option.mode
|
||
color: '#FFFFFF', // Defaults to option.color
|
||
border: false,
|
||
style: {}, // CSS properties for this comment
|
||
});
|
||
```
|
||
|
||
Explicit `time: 0` is preserved. Negative times are clamped to zero. Other than 0, 1 and 2, comment modes are ignored.
|
||
|
||
## All options
|
||
|
||
Pass an option object to the factory. At runtime, `{}` is valid and all fields have defaults.
|
||
The historical root declarations still require `danmuku`; existing TypeScript projects can keep providing it. See [TypeScript](#typescript) for accurate declarations.
|
||
|
||
```js
|
||
({
|
||
danmuku: [], // Array, XML URL, Promise of an array, or function returning an array/Promise
|
||
speed: 5, // Display duration in seconds, clamped to 1–10
|
||
margin: [10, '25%'], // Top/bottom spacing: pixels or percentages
|
||
opacity: 1, // Clamped to 0–1
|
||
color: '#FFFFFF', // Default comment color
|
||
mode: 0, // Default comment mode
|
||
modes: [0, 1, 2], // Visible modes
|
||
fontSize: 25, // Pixels or a percentage of player height
|
||
antiOverlap: true,
|
||
synchronousPlayback: false, // Follow video playbackRate when enabled
|
||
mount: undefined, // Defaults to the center of the player controls
|
||
heatmap: false, // Enable at construction: true or a heatmap options object
|
||
width: 512, // Below this width, the default input panel moves below the player
|
||
points: [], // Stored option; use the points event to draw custom data
|
||
filter: () => true, // Synchronous; do not return a Promise
|
||
beforeEmit: () => true, // Input-panel submissions only; may return a Promise
|
||
beforeVisible: () => true, // Called before display; may return a Promise
|
||
visible: true,
|
||
emitter: true, // Show the input panel's sending UI
|
||
maxLength: 200, // Input length, clamped to 1–1000
|
||
lockTime: 5, // Seconds between input-panel submissions, clamped to 1–60
|
||
theme: 'dark', // 'dark' or 'light' for an external mount
|
||
OPACITY: {},
|
||
FONT_SIZE: {},
|
||
MARGIN: {},
|
||
SPEED: {},
|
||
COLOR: [],
|
||
});
|
||
```
|
||
|
||
`OPACITY`, `FONT_SIZE`, `MARGIN` and `SPEED` override slider definitions with `min`, `max` and `steps`.
|
||
Each step can contain `name`, `value`, `hide` and `show`; margin values are pairs such as `[10, '50%']`.
|
||
`COLOR` replaces the palette with an array of CSS color strings; an empty array uses the built-in palette.
|
||
|
||
## Array, XML and asynchronous input
|
||
|
||
XML input uses Bilibili's comment format. Fetching a cross-origin XML URL requires that server to allow browser access.
|
||
An input function runs without the option object as its receiver. It may return an array directly or asynchronously.
|
||
|
||
<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: 'Hello from an array', time: 1 }],
|
||
// Alternatives:
|
||
// danmuku: '/assets/sample/danmuku.xml',
|
||
// danmuku: Promise.resolve([{ text: 'From a Promise', time: 1 }]),
|
||
// danmuku: async () => [{ text: 'From a function', time: 1 }],
|
||
}),
|
||
],
|
||
});
|
||
```
|
||
|
||
## Lifecycle callbacks
|
||
|
||
Input-panel submissions run `beforeEmit → filter → beforeVisible → artplayerPluginDanmuku:visible`.
|
||
Loaded comments and direct `emit` calls run `filter → beforeVisible → artplayerPluginDanmuku:visible`.
|
||
This describes accepted comments; callbacks can reject them, and scheduling still requires playback and an available track.
|
||
|
||
| Callback | Input | Acceptance |
|
||
| --- | --- | --- |
|
||
| `beforeEmit` | Input-panel comment | Only strict `true`, or a Promise resolving to `true`, sends it |
|
||
| `filter` | Comment with time, mode, color and style filled in | A synchronous truthy result adds it to the queue |
|
||
| `beforeVisible` | Queue item | A truthy result, including an awaited result, permits display |
|
||
|
||
Normal functions receive the current option object as `this` for all three callbacks. Arrow functions retain their lexical `this`.
|
||
`emit()` does not call `beforeEmit`: perform application validation before calling it when needed.
|
||
`beforeEmit` failures are logged in the console and leave the input available for another attempt.
|
||
|
||
An asynchronous `beforeVisible` rejection emits `artplayerPluginDanmuku:error` once for that item in the current run; other items continue.
|
||
Pause/resume, reset or replacing the callback permits a retry if the item is still eligible by time.
|
||
Pausing, seeking, hiding, resetting or destroying cancels unfinished visibility preparation.
|
||
|
||
## Methods and state
|
||
|
||
The registered plugin is available synchronously as `art.plugins.artplayerPluginDanmuku`.
|
||
|
||
| Member | Behavior and return value |
|
||
| --- | --- |
|
||
| `emit(comment)` | Processes one comment for the queue; returns a Promise |
|
||
| `load()` | Reads `option.danmuku` and replaces the queue; returns a Promise |
|
||
| `load(input)` | Appends comments from the input; returns a Promise |
|
||
| `config(partialOption)` | Synchronously merges configuration |
|
||
| `hide()` / `show()` | Synchronously hides or shows the comment layer |
|
||
| `reset()` | Clears displayed comments and returns queue items to waiting; does not delete the queue |
|
||
| `mount(target)` | Moves the panel to an existing element or selector; returns `undefined` |
|
||
| `option` | Live current configuration; use `config()` for validated updates |
|
||
| `isHide` | Read-only live visibility state: `true` when hidden |
|
||
| `isStop` | Read-only live stopped state; distinct from visibility and not a media-readiness signal |
|
||
|
||
`emit/load` Promises resolve to the internal Danmuku owner. `config/hide/show/reset` return that same owner synchronously.
|
||
The owner is **different from the registered plugin facade**. Keep using the registered facade for subsequent commands.
|
||
Awaiting `emit()` means queue processing has finished, not that the comment has appeared.
|
||
|
||
### Loading and configuration
|
||
|
||
Changing `config({ danmuku: input })` does not load the new input. Follow it with `load()` to replace the queue.
|
||
Input-read failures leave the existing queue intact; failures while filtering individual rows do not guarantee an atomic rollback of the entire batch.
|
||
Independent append operations do not cancel one another. A newer replacement cancels an unfinished older replacement.
|
||
Destroy cancels pending loads. Cancelled Promises resolve to the owner without a late `loaded` or `error` event.
|
||
|
||
Fetch and response-text failures emit `artplayerPluginDanmuku:error` and reject the corresponding public `load()` Promise.
|
||
Handle rejection with `await`/`try...catch` or `.catch(...)`. Initial automatic loading observes rejection and logs a warning.
|
||
Invalid configuration leaves the current option intact. Use `mount(target)` to move the panel; changing `option.mount` through `config()` does not perform a mount.
|
||
Enable heatmap when constructing the plugin; `config({ heatmap: true })` does not create it later.
|
||
|
||
<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: [], emitter: false })],
|
||
});
|
||
|
||
async function updateComments() {
|
||
var plugin = art.plugins.artplayerPluginDanmuku;
|
||
plugin.config({ danmuku: [{ text: 'Replacement', time: 1 }] });
|
||
await plugin.load();
|
||
await plugin.load([{ text: 'Appended', time: 2 }]);
|
||
await plugin.emit({ text: 'Scheduled from the current time' });
|
||
plugin.hide();
|
||
console.info('Hidden:', plugin.isHide);
|
||
plugin.show();
|
||
plugin.reset();
|
||
}
|
||
updateComments().catch(console.error);
|
||
```
|
||
|
||
## External mount
|
||
|
||
Create a separate mount element before constructing the plugin. The panel moves into the controls during player fullscreen or web fullscreen and returns to its configured mount on exit.
|
||
Use `theme: 'light'` on a light background. The live `mount(target)` method requires a valid target; omitting its argument does not select the default.
|
||
Destroy releases the plugin panel; the application owns any container it created.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
|
||
▶ Run Code
|
||
</div>
|
||
|
||
```js
|
||
var $danmu = document.createElement('div');
|
||
document.querySelector('.artplayer-app').after($danmu);
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreenWeb: true,
|
||
plugins: [artplayerPluginDanmuku({
|
||
danmuku: [{ text: 'External input panel', time: 1 }],
|
||
mount: $danmu,
|
||
theme: 'dark',
|
||
})],
|
||
});
|
||
art.on('destroy', () => $danmu.remove());
|
||
// Move it later with art.plugins.artplayerPluginDanmuku.mount(otherElement).
|
||
```
|
||
|
||
## Heatmap
|
||
|
||
Set `heatmap: true` at construction to sample the queue automatically. A live stream does not draw a heatmap.
|
||
Dense automatic curves now fit in the bottom quarter of the chart instead of covering the video (issue #958).
|
||
Explicit finite `yMin` or `yMax` and custom points retain their coordinate mapping.
|
||
|
||
An object can set `xMin`, `xMax`, `yMin`, `yMax`, `scale`, `opacity`, `minHeight`, `sampling`, `smoothing` and `flattening`.
|
||
Defaults are `xMin: 0`, `xMax: chartWidth`, `yMin: 0`, `yMax: 128`, `scale: 0.25`, `opacity: 0.2`,
|
||
`minHeight: floor(chartHeight * 0.05)`, `sampling: max(1, floor(chartWidth / 100))`, `smoothing: 0.2`, `flattening: 0.2`.
|
||
|
||
Send `art.emit('artplayerPluginDanmuku:points', points)` to draw custom `[x, value]` pairs.
|
||
The default x-axis uses chart pixels, not seconds. Set `xMin/xMax` explicitly if supplying another coordinate range.
|
||
Rendering mutates the inner point arrays for historical compatibility: copy each pair if reusing the original data.
|
||
The stored `points` option does not draw custom data. A resize or successful load redraws the automatic curve, so resend custom data after those events when needed.
|
||
|
||
<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: 'Heatmap example', time: 1 }],
|
||
heatmap: true,
|
||
})],
|
||
});
|
||
var points = [[0, 5], [0.25, 12], [0.5, 30], [0.75, 10], [1, 5]];
|
||
function drawPoints() {
|
||
var width = art.controls.heatmap.offsetWidth;
|
||
art.emit('artplayerPluginDanmuku:points', points.map(([ratio, value]) => [ratio * width, value]));
|
||
}
|
||
art.on('ready', drawPoints);
|
||
art.on('resize', drawPoints);
|
||
art.on('artplayerPluginDanmuku:loaded', drawPoints);
|
||
```
|
||
|
||
## Events
|
||
|
||
Subscribe with `art.on(name, callback)` and remove subscriptions with `art.off(name, callback)`.
|
||
|
||
| Event | Payload / meaning |
|
||
| --- | --- |
|
||
| `artplayerPluginDanmuku:visible` | Queue item; its `$ref` is the displayed element |
|
||
| `artplayerPluginDanmuku:loaded` | Current full queue after a successful load, including appends |
|
||
| `artplayerPluginDanmuku:error` | Original error from loading or scheduling; handle public Promise rejections separately |
|
||
| `artplayerPluginDanmuku:config` | Current configuration |
|
||
| `artplayerPluginDanmuku:start` | No payload; scheduling starts |
|
||
| `artplayerPluginDanmuku:stop` | No payload; scheduling stops |
|
||
| `artplayerPluginDanmuku:hide` | No payload; layer hidden |
|
||
| `artplayerPluginDanmuku:show` | No payload; layer shown |
|
||
| `artplayerPluginDanmuku:reset` | No payload; displayed items reset |
|
||
| `artplayerPluginDanmuku:destroy` | No payload; plugin destroyed |
|
||
| `artplayerPluginDanmuku:points` | Application-sent custom points for the heatmap |
|
||
|
||
Events are not replayed to later listeners. In particular, an initially empty array can finish loading during construction.
|
||
Subscribe before invoking a later `load()` if you need to observe its completion event.
|
||
Use `$ref.textContent` when adding text in a `visible` handler.
|
||
|
||
## TypeScript
|
||
|
||
The root and `/legacy` entrypoints keep the npm 5.3.0 declaration shapes for compatibility, including historical inaccuracies about return values.
|
||
The current branch adds `/runtime` for accurate types while loading the same runtime factory:
|
||
|
||
```ts
|
||
import Artplayer from 'artplayer';
|
||
import danmuku from 'artplayer-plugin-danmuku/runtime';
|
||
import type { RuntimeOption, Point, EventMap } from 'artplayer-plugin-danmuku/runtime';
|
||
|
||
const option: RuntimeOption = { danmuku: [], heatmap: true };
|
||
const points: Point[] = [[0, 5], [100, 10]];
|
||
const onError = (...[error]: EventMap['artplayerPluginDanmuku:error']) => console.error(error);
|
||
const art = new Artplayer({ container: '#player', url: '/video.mp4', plugins: [danmuku(option)] });
|
||
art.on('artplayerPluginDanmuku:error', onError);
|
||
```
|
||
|
||
The explicit `EventMap` describes payloads; it does not augment the core's historical event declarations automatically.
|
||
The factory also exposes the existing `icons` object for customization. Package `README.md` and `ARCHITECTURE.md` describe module ownership, maintenance commands and remaining device/combination validation.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/dash-control.md =====
|
||
|
||
# DASH Control
|
||
|
||
[中文说明](../../plugin/dash-control.md)
|
||
|
||
Add video quality and audio-track menus to a dash.js player. You create and attach the SDK instance at `art.dash`; the plugin controls that instance and releases its own menus and listeners.
|
||
|
||
This guide describes the current refactor branch. Its SDK adaptation, automatic refresh and lifecycle fixes have not yet been published. An unversioned npm/CDN install still uses the published release.
|
||
|
||
## Installation
|
||
|
||
```sh
|
||
yarn add artplayer dashjs artplayer-plugin-dash-control
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import dashjs from 'dashjs';
|
||
import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||
```
|
||
|
||
For script tags, load ArtPlayer, dash.js and `dist/artplayer-plugin-dash-control.js` before setup. The plugin global is `artplayerPluginDashControl`. Pin your dependency versions and use a browser-accessible MPD and segments.
|
||
|
||
## Complete example
|
||
|
||
The example matches the [online DASH example](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control). Replace the site's container and media URL in your application.
|
||
|
||
<div className="run-code" data-libs="https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js
|
||
./uncompiled/artplayer-plugin-dash-control/index.js"></div>
|
||
|
||
```js
|
||
// npm i dashjs
|
||
// npm i artplayer-plugin-dash-control
|
||
|
||
// import dashjs from 'dashjs';
|
||
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||
|
||
const useDash = dashjs.supportsMediaSource()
|
||
let dash
|
||
|
||
function destroyDash() {
|
||
const previous = dash
|
||
dash = undefined
|
||
if (previous)
|
||
previous.destroy()
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
|
||
setting: true,
|
||
plugins: useDash
|
||
? [
|
||
artplayerPluginDashControl({
|
||
quality: {
|
||
// Show quality choices in the controls
|
||
control: true,
|
||
// Show quality choices in settings
|
||
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() || String(track.id ?? 'Audio'),
|
||
// I18n
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
}),
|
||
]
|
||
: [],
|
||
customType: {
|
||
mpd: function playMpd(video, url, art) {
|
||
destroyDash()
|
||
if (useDash) {
|
||
dash = dashjs.MediaPlayer().create()
|
||
art.dash = dash
|
||
dash.initialize(video, url, art.option.autoplay)
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: mpd'
|
||
}
|
||
},
|
||
},
|
||
})
|
||
|
||
art.on('destroy', destroyDash)
|
||
```
|
||
|
||
The example chooses its SDK capability path once per player. If dash.js cannot use MediaSource, it displays the existing unsupported-format notice without creating an SDK or installing its controls. This example does not provide a native DASH fallback.
|
||
|
||
## Configuration
|
||
|
||
`artplayerPluginDashControl(option?)` synchronously returns a plugin factory. Both `quality` and `audio` accept:
|
||
|
||
| Field | Meaning and default |
|
||
| --- | --- |
|
||
| `control` | Display a bottom control; omitted means hidden. |
|
||
| `setting` | Display a settings entry; omitted means hidden. Also enable the player's `setting: true`. |
|
||
| `title` | Menu title, default `Quality` or `Audio`. |
|
||
| `auto` | Fallback text, default `Auto`; quality also uses it for its automatic selection row. It does not create a synthetic audio track. |
|
||
| `getName(item)` | Return a string from the original SDK level or track. It receives one argument, with no player receiver or index. |
|
||
|
||
The default quality label is `level.height + 'p'`. Default audio labels use `track.lang` or `track.id`; metadata may be missing or null. A custom formatter should return a string fallback, as the complete example does. Empty title/Auto text uses the default.
|
||
|
||
Equal text labels collapse into one displayed choice. Include bitrate or other metadata when several variants have the same height and should remain separate choices. A selected duplicate keeps the actual selected SDK key or track object. Empty track lists remove their menus.
|
||
|
||
## Quality and audio selection
|
||
|
||
Manual quality selection disables video Auto switching, then selects the SDK quality. Auto enables video Auto switching without overwriting unrelated ABR settings. A synchronous menu selection does not mean buffering or decoding has completed.
|
||
|
||
The plugin detects the SDK's available method family:
|
||
|
||
| SDK interface | Quality list and selection |
|
||
| --- | --- |
|
||
| dash.js 4 style | `getBitrateInfoListFor('video')`, `getQualityFor('video')`, `setQualityFor('video', qualityIndex)` |
|
||
| dash.js 5 style | `getRepresentationsByType('video')`, `getCurrentRepresentationForType('video')`, `setRepresentationForTypeById('video', id)` |
|
||
|
||
For the representation interface, selection uses the representation ID, including numeric zero. Do not substitute the index of a filtered array. You do not need to configure a version switch in the plugin.
|
||
|
||
Audio selection calls `setCurrentTrack()` with the original SDK track object. It matches the current track by object identity or an unambiguous combination of available id/index/lang fields. There is no extra Auto audio row.
|
||
|
||
## Refresh after external changes
|
||
|
||
Player `ready`/`restart` and SDK quality, track and stream events refresh menus. SDK event refreshes are coalesced after the current synchronous selection. Unchanged playback-time events do not redraw menus; they can detect an external Auto-setting change.
|
||
|
||
When changing SDK configuration while paused without a subsequent SDK event, refresh explicitly:
|
||
|
||
```js
|
||
art.plugins.artplayerPluginDashControl.update();
|
||
```
|
||
|
||
`update()` is synchronous and returns `undefined`. It requires `art.dash` to be attached to the player's video and can throw if that contract is not met. Assigning a different `art.dash` alone does not subscribe to it immediately; call `update()` or use the normal ready/restart flow after attachment.
|
||
|
||
Automatic refresh preserves an open, plugin-owned quality or audio settings panel. Explicit `update()` keeps its existing rebuild behavior. Reserve `dash-quality` and `dash-audio` for the plugin's menu names.
|
||
|
||
If an asynchronous SDK getter or formatter fails, the plugin warns, stops that observation and clears its menus. Fix the formatter/SDK state and call `update()` to recover. Explicit update and synchronous selection errors keep their normal throwing behavior.
|
||
|
||
## SDK ownership and source switching
|
||
|
||
Use the existing player `switchUrl()` or `switchQuality()` and handle its Promise. The complete example destroys the replaced SDK, assigns the new instance before initialization, and keeps one final player cleanup listener. It does not accumulate a new destroy listener on every load or destroy replaced engines again at the end.
|
||
|
||
The plugin does not own your SDK: it never calls `dash.destroy()`, changes the manifest URL or removes listeners belonging to other consumers. Retained callbacks from old menus become inactive after replacement or player destruction. Your application remains responsible for DRM, SDK errors, autoplay decisions and any asynchronous SDK shutdown policy its integration requires.
|
||
|
||
## TypeScript
|
||
|
||
Default callback types include quality height/width/ID/bitrate and nullable audio id/index/lang. Use the generic factory for more specific metadata. This example declares only the fields it uses and does not require importing SDK declarations:
|
||
|
||
```ts
|
||
import dashControl from 'artplayer-plugin-dash-control';
|
||
|
||
interface Level { height: number; bitrateInKbit?: number }
|
||
interface Track { id?: string | number | null; lang?: string | null }
|
||
|
||
const plugin = dashControl<Level, Track>({
|
||
quality: {
|
||
control: true,
|
||
getName: level => level.height + 'p',
|
||
},
|
||
audio: {
|
||
setting: true,
|
||
getName: track => track.lang?.toUpperCase() || String(track.id ?? 'Audio'),
|
||
},
|
||
});
|
||
```
|
||
|
||
`Option`, `Config`, `QualityLevel`, `AudioTrack` and `Result` are exported from the root. Root and legacy paths remain available. If using actual SDK declarations, dash.js 4.5.2 exposes `BitrateInfo` for quality; 5.2.1 uses `Representation`. Its declarations have different compiler/module-resolution requirements, so test your actual SDK and TypeScript combination. Describe the externally attached `art.dash` in your application's integration types.
|
||
|
||
## Validation scope
|
||
|
||
The refactor tests fixed dash.js 4.5.2 and 5.2.1 with local adaptive media and old/new core combinations. Those are tested points, not a new blanket support range. The plugin includes a targeted 4.5.2 paused-seek recovery for stale empty-buffer metrics while preserving the caller's SDK settings and media time. Windows Playwright WebKit lacks the MSE path used by these tests; it is not Safari/device playback acceptance. Test your own MPDs, DRM and target devices before adopting the unpublished refactor.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/document-pip.md =====
|
||
|
||
# Document Picture-in-Picture
|
||
|
||
[简体中文](../../plugin/document-pip.md)
|
||
|
||
Move the whole player, including its controls, into a browser Document Picture-in-Picture window. Closing the window restores the same player node to its original position. This page describes the unreleased refactor branch; the online example and unpinned npm/CDN packages are not the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-document-pip
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-document-pip.js`. The global is `artplayerPluginDocumentPip`. The following code preserves the original [online example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-document-pip/index.js&example=document.pip).
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-document-pip/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-document-pip
|
||
// import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
artplayerPluginDocumentPip({
|
||
width: 480,
|
||
height: 270,
|
||
fallbackToVideoPiP: true,
|
||
placeholder: `Playing in Document Picture-in-Picture`,
|
||
}),
|
||
],
|
||
})
|
||
|
||
art.on('document-pip', (state) => {
|
||
console.log('Document Picture-in-Picture', state)
|
||
})
|
||
```
|
||
|
||
## Options
|
||
|
||
| Field | Type | Default | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `width` | `number` | `480` | Requested window width; the browser determines the actual size |
|
||
| `height` | `number` | `270` | Requested window height |
|
||
| `placeholder` | `string` | `'Playing in Document Picture-in-Picture'` | Placeholder text at the original player position |
|
||
| `fallbackToVideoPiP` | `boolean` | `true` | Try setting `art.pip = true` when the Document PiP API is absent |
|
||
|
||
The plugin registers as `artplayerPluginDocumentPip` and adds a PiP control button. It detects `documentPictureInPicture.requestWindow`; a positive result does not guarantee that permissions, the calling context or user activation will allow opening. Call `open()` or `toggle()` directly from a user click handler, before awaiting unrelated work.
|
||
|
||
Video PiP fallback also depends on the browser and media. It does not move the whole player, set the plugin's `isActive` flag or emit a Document PiP activation event. `close()` manages the Document PiP window; use `art.pip = false` to exit video PiP. Disabling fallback does not add Document PiP support to the browser.
|
||
|
||
## State, methods and events
|
||
|
||
Access the result through `art.plugins.artplayerPluginDocumentPip`:
|
||
|
||
| Member | Runtime behavior |
|
||
| --- | --- |
|
||
| `name` | Always `artplayerPluginDocumentPip` |
|
||
| `isSupported` | Readonly getter; Document PiP API capability snapshot taken at plugin creation |
|
||
| `isActive` | Readonly getter; whether a Document PiP session is held, not video PiP state |
|
||
| `open()` | Returns `Promise<void>`; requests a window and moves the player, coalesces pending requests and does nothing when already open |
|
||
| `close()` | Returns `Promise<void>`; cancels a pending request or restores the node and closes the window |
|
||
| `toggle()` | Returns `undefined` synchronously; opens or closes the active/pending window |
|
||
|
||
Successful activation and normal closure emit the player's `document-pip` event with `true` and `false`, respectively. The plugin updates the existing `artplayer-document-pip` class, rebinds document events and schedules resize. This event does not signal successful media loading or playback.
|
||
|
||
Normal window request/restoration failures display a notice and console warning; awaiting `open()` alone is not proof that a window opened. An error thrown by the video PiP fallback setter can still reject its Promise. A window arriving after cancellation is closed without adopting the player. Destroying the player releases the window, control, subscriptions and timers, suppressing further plugin state events. There is no separate public plugin `destroy()`.
|
||
|
||
Styles are copied from the player's document on a best-effort basis. Inaccessible cross-origin styles and externally managed DOM need validation in your environment. Canvas, other proxies, keyboard focus and continuous playback also need their own checks; the capability flag cannot establish those results.
|
||
|
||
## Compatible TypeScript views
|
||
|
||
The root and `/legacy` declarations preserve the old required options object, writable `Result` flags and void actions. JavaScript permits omitted options, the runtime flags are readonly getters, and `open/close` return Promises. The old shape preserves consumer and replacement-function compatibility; it does not make the runtime getters writable.
|
||
|
||
This package has no `/runtime` subpath. For accurate types, explicitly view the real factory as `RuntimeFactory`:
|
||
|
||
```ts
|
||
import documentPip from 'artplayer-plugin-document-pip';
|
||
import type { AsyncResult, RuntimeFactory } from 'artplayer-plugin-document-pip';
|
||
|
||
const runtimeFactory = documentPip as RuntimeFactory;
|
||
const installPip = runtimeFactory();
|
||
const installDefaultPip = runtimeFactory.default({ width: 480 });
|
||
|
||
async function closePip(pip: AsyncResult): Promise<void> {
|
||
await pip.close();
|
||
}
|
||
```
|
||
|
||
Named types are `Option`, `Result`, `AsyncResult`, `Factory` and `RuntimeFactory`. Apply the precise view only to the unmodified implementation, not a void-returning mock or replaced method. CommonJS runtime supports both `require(package)(options)` and `.default(options)`. Historical `import = require` types use `.default`; use the precise factory view when direct calling is needed.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/hls-control.md =====
|
||
|
||
# HLS Control
|
||
|
||
[中文说明](../../plugin/hls-control.md)
|
||
|
||
Add quality and audio-track menus to an Hls.js player. This plugin controls the Hls.js instance you provide at `art.hls`; it does not download, create or destroy the SDK.
|
||
|
||
This guide describes the current refactor branch. The automatic refresh and lifecycle fixes described here have not yet been published. An unversioned npm/CDN install still uses the published release.
|
||
|
||
## Installation
|
||
|
||
```sh
|
||
yarn add artplayer hls.js artplayer-plugin-hls-control
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import Hls from 'hls.js';
|
||
import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||
```
|
||
|
||
For script tags, load ArtPlayer, Hls.js and the plugin's `dist/artplayer-plugin-hls-control.js` before running your setup. The plugin global is `artplayerPluginHlsControl`. Pin versions in your application and use media URLs that permit browser access.
|
||
|
||
## Complete example
|
||
|
||
The example uses the site's player container and the same source as the [online HLS example](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control). Replace the container and stream URL in your application.
|
||
|
||
<div className="run-code" data-libs="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js
|
||
./uncompiled/artplayer-plugin-hls-control/index.js"></div>
|
||
|
||
```js
|
||
// npm i hls.js
|
||
// npm i artplayer-plugin-hls-control
|
||
|
||
// import Hls from 'hls.js';
|
||
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||
|
||
const useHls = Hls.isSupported()
|
||
let hls
|
||
|
||
function destroyHls() {
|
||
const previous = hls
|
||
hls = undefined
|
||
if (previous)
|
||
previous.destroy()
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
|
||
setting: true,
|
||
plugins: useHls
|
||
? [
|
||
artplayerPluginHlsControl({
|
||
quality: {
|
||
// Show quality choices in the controls
|
||
control: true,
|
||
// Show quality choices in settings
|
||
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 || track.lang || 'Audio',
|
||
// I18n
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
}),
|
||
]
|
||
: [],
|
||
customType: {
|
||
m3u8: function playM3u8(video, url, art) {
|
||
destroyHls()
|
||
if (useHls) {
|
||
hls = new Hls()
|
||
art.hls = hls
|
||
hls.loadSource(url)
|
||
hls.attachMedia(video)
|
||
}
|
||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||
video.src = url
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: m3u8'
|
||
}
|
||
},
|
||
},
|
||
})
|
||
|
||
art.on('destroy', destroyHls)
|
||
```
|
||
|
||
Only install the control plugin when Hls.js is supported. If the browser instead plays HLS natively, the example assigns `video.src` without installing a plugin that requires `art.hls`. Native quality/audio selection is not supplied by this plugin. Keep `useHls` fixed for that player instance; recreate the player if the playback integration changes.
|
||
|
||
## Configuration
|
||
|
||
`artplayerPluginHlsControl(option?)` returns a synchronous plugin factory. Both `quality` and `audio` accept these fields:
|
||
|
||
| Field | Meaning and default |
|
||
| --- | --- |
|
||
| `control` | Show the bottom control; omitted means hidden. |
|
||
| `setting` | Show the settings entry; omitted means hidden. Enable the player's `setting: true` as well. |
|
||
| `title` | Menu title; quality defaults to `Quality`, audio to `Audio`. |
|
||
| `auto` | Fallback text, default `Auto`. Quality also uses it for its Auto option. Audio does not gain a synthetic Auto track. |
|
||
| `getName(item, index?)` | Return a string from the original SDK level or track. The current-label call omits `index`; list calls include it. |
|
||
|
||
Without a quality formatter, labels use `level.name` or `level.height + 'P'`. Audio labels use `track.name`, `track.lang`, then `track.language`. Empty titles/Auto text fall back to their defaults. Give formatters a string fallback when your source lacks metadata.
|
||
|
||
The formatter is a plain callback; it does not receive the player as `this`. Avoid using its optional index as a required field. Equal labels collapse into one displayed choice, so include bitrate or other distinguishing metadata when separate variants have the same height. Empty track lists remove their menus.
|
||
|
||
Choosing a quality writes `hls.currentLevel`; Auto writes `-1`. The selected label reflects automatic mode when `autoLevelEnabled` is true. Choosing audio writes `hls.audioTrack` with the SDK track ID. A menu selection is synchronous and does not mean the new stream has finished buffering or decoding.
|
||
|
||
## Refresh after external changes
|
||
|
||
The plugin updates on player `ready` and `restart`. When the SDK provides its event API, manifest, level, audio and destruction events also refresh or clear the menus. Current SDK state determines the selected choice.
|
||
|
||
After attaching a replacement instance to the same video and assigning `art.hls`, use the existing synchronous method when an immediate refresh is needed:
|
||
|
||
```js
|
||
art.plugins.artplayerPluginHlsControl.update();
|
||
```
|
||
|
||
`update()` returns `undefined`; it is not a Promise. Calling it without an attached Hls.js instance can throw. SDK-like integrations without supported event hooks must call it when their state changes. Reserve menu names `hls-quality` and `hls-audio` for this plugin.
|
||
|
||
## SDK ownership and source switching
|
||
|
||
Use the player's existing `switchUrl()` or `switchQuality()` for source changes and handle the returned Promise. The example's custom loader destroys the previous SDK before creating the next one, updates `art.hls`, and keeps one final cleanup listener per player. Each instance is destroyed once. Do not add a new player `destroy` listener on every load while also destroying replaced instances yourself.
|
||
|
||
The control plugin releases its own SDK subscriptions and makes retained menu callbacks inert after replacement or player destruction. It does not destroy the SDK, remove other consumers' SDK listeners, or implement Hls.js error recovery. Your application remains responsible for SDK fatal errors and playback policy.
|
||
|
||
## TypeScript
|
||
|
||
The default callback types include level height/name and audio id/name/language fields. Applications can specify their actual SDK metadata types through the existing generic factory. The example below uses only fields it needs and works without importing Hls.js declarations:
|
||
|
||
```ts
|
||
import hlsControl from 'artplayer-plugin-hls-control';
|
||
|
||
interface Level { height: number; bitrate: number }
|
||
interface Track { id: number; name: string; lang?: string }
|
||
|
||
const plugin = hlsControl<Level, Track>({
|
||
quality: {
|
||
control: true,
|
||
getName: level => level.height + 'p / ' + level.bitrate,
|
||
},
|
||
audio: {
|
||
setting: true,
|
||
getName: track => track.name || track.lang || 'Audio',
|
||
},
|
||
});
|
||
```
|
||
|
||
Public `Option`, `Config`, `QualityLevel`, `AudioTrack` and `Result` types are exported from the root entry. The root and legacy import paths remain available. The types do not pretend every ArtPlayer instance already owns an Hls.js engine; describe `art.hls` in your application's integration types.
|
||
|
||
## Validation scope
|
||
|
||
The refactor tests Hls.js 1.5.17 and 1.7.2 with local media and real workers; these are tested points, not a newly declared supported range. Firefox grouped-stream crashes and a separate switching stall remain under investigation. Windows Playwright WebKit lacks the MSE path used in those tests; it does not establish Safari/iOS native-HLS acceptance. Verify your actual streams and target devices before adopting the unpublished refactor.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/jassub.md =====
|
||
|
||
# ASS Subtitles with JASSUB
|
||
|
||
[简体中文](../../plugin/jassub.md)
|
||
|
||
Render ASS subtitles on Canvas using the JASSUB Worker and WASM. The plugin returns the actual JASSUB instance with its methods/events rather than converting ASS to plain VTT. This describes the unreleased branch; Worker, WASM, fonts and actual playback require deployment-specific validation.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-jassub
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginJassub from 'artplayer-plugin-jassub';
|
||
```
|
||
|
||
For scripts, load ArtPlayer before `dist/artplayer-plugin-jassub.js`; the global is `artplayerPluginJassub`. This preserves the [original example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub). Its Worker/WASM/font URLs are site assets, not paths automatically created in your application by installing the plugin.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-jassub/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// https://github.com/ThaUnknown/jassub
|
||
// npm i artplayer-plugin-jassub
|
||
// import artplayerPluginJassub from 'artplayer-plugin-jassub';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/jassub/FGOBD.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
plugins: [
|
||
artplayerPluginJassub({
|
||
subUrl: '/assets/jassub/FGOBD.ass',
|
||
workerUrl: '/assets/jassub/jassub-worker.js',
|
||
wasmUrl: '/assets/jassub/jassub-worker.wasm',
|
||
modernWasmUrl: '/assets/jassub/jassub-worker-modern.wasm',
|
||
availableFonts: {
|
||
'liberation sans': '/assets/jassub/default.woff2'
|
||
},
|
||
fonts: [
|
||
'/assets/jassub/fonts/Averia Sans Libre Light.ttf',
|
||
'/assets/jassub/fonts/Averia Serif Simple Light.ttf',
|
||
'/assets/jassub/fonts/Gramond.ttf'
|
||
],
|
||
timeOffset: -0.041
|
||
}),
|
||
],
|
||
});
|
||
```
|
||
|
||
Host matching Worker, WASM and fonts with correct paths, access policies and font usage rights. Missing fonts affect layout. Default relative URLs do not establish that files are deployed.
|
||
|
||
## Resource and rendering options
|
||
|
||
Runtime options are optional and default to art.video. They are read at registration; an explicit video overrides the host video. These are current local implementation defaults, including differences from old upstream comments.
|
||
|
||
| Field | Actual default or meaning |
|
||
| --- | --- |
|
||
| `video` / `canvas` | Video defaults to art.video; caller canvas allows manual DOM handling; a usable rendering target is required |
|
||
| `workerUrl` | `'jassub-worker.js'` |
|
||
| `wasmUrl` | `'jassub-worker.wasm'` |
|
||
| `legacyWasmUrl` | `'jassub-worker.wasm.js'` |
|
||
| `modernWasmUrl` | Used when supplied and SIMD is detected; otherwise wasmUrl |
|
||
| `subUrl` / `subContent` | Subtitle URL or ASS text sent to the Worker |
|
||
| `fonts` | Empty array by default; entries can be URLs or Uint8Array |
|
||
| `availableFonts` | Defaults to `{ 'liberation sans': './default.woff2' }`; font-name-to-URL/bytes map |
|
||
| `fallbackFont` | `'liberation sans'` |
|
||
| `useLocalFonts` | Enabled only when queryLocalFonts exists; current code defaults to true when available, with explicit false supported; permissions still apply |
|
||
| `blendMode` | `'js'`, with `'wasm'` also accepted |
|
||
| `asyncRender` | Defaults true, subject to createImageBitmap availability |
|
||
| `offscreenRender` | Defaults true, requiring transferControlToOffscreen and no caller canvas |
|
||
| `onDemandRender` | Defaults true, subject to requestVideoFrameCallback availability |
|
||
| `targetFps` | Defaults 24; not a fixed update guarantee in on-demand mode |
|
||
| `timeOffset` | Defaults 0 seconds |
|
||
| `debug` | Defaults false |
|
||
| `prescaleFactor` / `prescaleHeightLimit` / `maxRenderHeight` | Defaults 1 / 1080 / 0; rendering size controls, with no maximum imposed by a zero maxRenderHeight |
|
||
| `dropAllAnimations` / `dropAllBlur` | Simplification options forwarded to the Worker; not set to true by the wrapper when omitted |
|
||
| `libassMemoryLimit` / `libassGlyphLimit` | Defaults 0; libass cache limits in MiB, not a total browser-memory cap |
|
||
|
||
Capabilities can change the chosen rendering path. Async/offscreen/backend options are not universal performance guarantees. Do not mix incompatible Worker and wrapper versions.
|
||
|
||
## Instance and methods
|
||
|
||
Registration synchronously returns `{ name: 'artplayerPluginJassub', instance }`, not a Worker-ready Promise. Access it at `art.plugins.artplayerPluginJassub.instance`. It is an EventTarget: query after ready, and observe its error event rather than assuming a same-named player event.
|
||
|
||
| Method | Behavior and units |
|
||
| --- | --- |
|
||
| `resize(width?, height?, top?, left?, force?)` | Synchronous void; force is last, with omitted dimensions derived from video |
|
||
| `setVideo(video)` | Rebind video, observation and the owned container position synchronously |
|
||
| `setTrackByUrl(url)` / `setTrack(content)` / `freeTrack()` | Set subtitle URL/text or release the track |
|
||
| `setIsPaused(boolean)` / `setRate(number)` | Manually update Worker playback state/rate |
|
||
| `setCurrentTime(isPaused?, currentTime?, rate?)` | currentTime uses seconds |
|
||
| `createEvent(event)` / `setEvent(event, index)` / `removeEvent(index)` | Mutate ASS events, accepting partial fields |
|
||
| `getEvents(callback)` | Callback-based event query, not a Promise |
|
||
| `createStyle(style)` / `setStyle(style, index)` / `removeStyle(index)` | Mutate styles, accepting partial fields |
|
||
| `getStyles(callback)` | Callback-based style query, not a Promise |
|
||
| `styleOverride(style)` / `disableStyleOverride()` | Enable/disable style override |
|
||
| `setDefaultFont(font)` / `addFont(font)` | Set the default font or add a URL/byte font |
|
||
| `runBenchmark()` | Request the Worker benchmark; not an end-to-end performance conclusion |
|
||
| `sendMessage(target, data?, transferable?)` | Promise resolves after posting, or without posting after destroy; not a Worker acknowledgement |
|
||
| `destroy()` | Synchronous, idempotent cleanup; no resource-reclamation Promise |
|
||
|
||
Except sendMessage, ordinary control methods above return void; queries supply callback data. The historical destroy(error) overload returns an original Error, converts a nonempty string to Error, or retains an empty string. Normal cleanup uses no-argument destroy.
|
||
|
||
AssEvent Start/Duration use milliseconds and Style is a numeric style index. Other fields are Name, MarginL/MarginR/MarginV, Effect, Text, ReadOrder and Layer. AssStyle includes Name/FontName/FontSize, PrimaryColour/SecondaryColour/OutlineColour/BackColour, Bold/Italic/Underline/StrikeOut, ScaleX/ScaleY/Spacing/Angle, BorderStyle/Outline/Shadow/Alignment, MarginL/MarginR/MarginV, Encoding, treat_fontname_as_pattern, Blur and Justify. Query results have no `_index`; the ASS text-format style name is not the runtime numeric Style.
|
||
|
||
Successful queries call `(null, array)`; failures supply an Error or native Event without data. Destroy fails pending queries after releasing their listeners/timers. The protocol matches by response target, without a new request ID; do not assume simultaneous same-target queries have independently correlated responses.
|
||
|
||
## Lifecycle and types
|
||
|
||
The plugin-owned `.JASSUB` container uses z-index20 and is removed on destruction; caller canvas/video nodes remain. Player destruction calls the instance's current destroy method; direct destruction is also idempotent. setVideo/destroy invalidate old frame callbacks and clean Worker/observer ownership. Late bitmaps must not restart rendering. Actual offscreen stalls, browser differences and physical devices retain separate acceptance requirements.
|
||
|
||
Root and `/legacy` retain historical JassubOption/JassubInstance: three required URLs, force-first resize, inaccurate Promise method returns and open extension indexes. Use `/runtime` for accurate types with the same implementation:
|
||
|
||
```ts
|
||
import type Artplayer from 'artplayer';
|
||
import jassub from 'artplayer-plugin-jassub/runtime';
|
||
|
||
function attachSubtitles(art: Artplayer) {
|
||
const { instance } = jassub({
|
||
workerUrl: '/assets/jassub/jassub-worker.js',
|
||
wasmUrl: '/assets/jassub/jassub-worker.wasm',
|
||
subUrl: '/subtitles.ass',
|
||
})(art);
|
||
instance.addEventListener('ready', () => {
|
||
instance.getEvents((error, events) => {
|
||
if (error) console.error(error);
|
||
else console.log(events);
|
||
});
|
||
});
|
||
return instance;
|
||
}
|
||
```
|
||
|
||
Runtime exports FontSource, RuntimeOption, AssEvent, AssStyle, AssEventInput, AssStyleInput, WorkerRequestError, EventsCallback, StylesCallback, RuntimeEventMap, RuntimeInstance, RuntimeResult and RuntimeFactory. Precise instance fields include timeOffset, debug, the three sizing settings, optional busy and historical public `_canvas/_ctx`; `_ctx` may be false/null. There is no runtime factory `.default` self-alias. The old root's NodeNext namespace does not create one. Runtime supports an accurate ESM default and CommonJS `import = require`.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/multiple-subtitles.md =====
|
||
|
||
# Multiple Subtitles
|
||
|
||
[简体中文](../../plugin/multiple-subtitles.md)
|
||
|
||
Download several subtitle files, retain their individual cue times, and merge selected tracks into the player's subtitles. Display multiple languages and select or reorder them by name. This page describes the unreleased refactor branch; online examples and unpinned packages are not the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-multiple-subtitles
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-multiple-subtitles.js`; the global is `artplayerPluginMultipleSubtitles`. The following preserves the [online example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles), including its selection menu and styles. The application configures that menu; the plugin does not create one automatically.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-multiple-subtitles/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-multiple-subtitles
|
||
// import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
plugins: [
|
||
artplayerPluginMultipleSubtitles({
|
||
subtitles: [
|
||
{
|
||
name: 'chinese',
|
||
url: '/assets/sample/subtitle.cn.srt',
|
||
},
|
||
{
|
||
name: 'japanese',
|
||
url: '/assets/sample/subtitle.jp.srt',
|
||
},
|
||
],
|
||
}),
|
||
],
|
||
settings: [
|
||
{
|
||
width: 200,
|
||
html: 'Subtitle',
|
||
tooltip: 'Double',
|
||
icon: '<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
|
||
|
||
const style = `
|
||
.art-subtitle-chinese {
|
||
color: red;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.art-subtitle-japanese {
|
||
color: yellow;
|
||
font-size: 12px;
|
||
}
|
||
`
|
||
|
||
const $style = document.getElementById('artplayer-subtitle-style')
|
||
if ($style) {
|
||
$style.textContent = style
|
||
}
|
||
else {
|
||
const $style = document.createElement('style')
|
||
$style.id = 'artplayer-subtitle-style'
|
||
$style.textContent = style
|
||
document.head.appendChild($style)
|
||
}
|
||
```
|
||
|
||
## Track options
|
||
|
||
The factory requires an options object containing a `subtitles` array. Runtime `{}` uses an empty array; historical root types still require the field. Each `TrackOption` has these fields:
|
||
|
||
| Field | Type | Default or behavior |
|
||
| --- | --- | --- |
|
||
| `url` | `string` | Subtitle URL loaded with browser fetch; provide a valid URL despite the historical optional type |
|
||
| `name` | `string` | Selection and CSS name; use a unique simple identifier such as `chinese` |
|
||
| `type` | `'vtt' \| 'srt' \| 'ass'` | Explicit value takes precedence over the URL extension |
|
||
| `encoding` | `string` | Defaults to `'utf-8'`, passed to TextDecoder |
|
||
| `onParser` | `(...args: object[]) => object` | Retained historical declaration; the implementation does not call it |
|
||
|
||
Files download concurrently, then decode and merge. Cross-origin servers must allow fetch. SRT and ASS use core conversion utilities to produce VTT; full ASS layout and animation are not preserved. Use JASSUB when full ASS rendering is needed. Unknown types produce empty content. Parsing is best-effort, and diagnostics do not necessarily discard all usable cues.
|
||
|
||
Unsuccessful HTTP responses and thrown decoding/conversion errors reject registration and release sibling requests. Track metadata is read from the original configuration after downloads, not a deep copy; avoid mutating the array or track objects during installation.
|
||
|
||
## Registration and selection
|
||
|
||
Registration is asynchronous and returns `{ name: 'multipleSubtitles', tracks, reset }`. The registered result is `art.plugins.multipleSubtitles`, not the global factory name. Await registration before directly using its result; readiness of that result does not guarantee the player has finished loading subtitles.
|
||
|
||
| Call | Result |
|
||
| --- | --- |
|
||
| `tracks(['chinese', 'japanese'])` | Select tracks in the caller's name order |
|
||
| `tracks(['japanese'])` | Select only that track |
|
||
| `tracks()` or `tracks([])` | Clear the selection |
|
||
| `reset()` | Restore all originally downloaded tracks in their original order |
|
||
|
||
Both methods return `undefined` synchronously. Unknown names retain the historical synchronous TypeError. Repeated names select the first matching track on each lookup without deduplication; use unique configured names. Merging follows selection order but does not rewrite cue timestamps, so reordering cannot synchronize mistimed translations.
|
||
|
||
Each selection creates a new VTT Blob URL, initializes player subtitles and releases the previous owned URL. Async host installation failures warn and clean up the failed resource; void methods cannot be awaited for subtitle readiness. Video source changes do not refetch tracks, and reset does not reload the server files. There is no public update, reload or separate destroy method.
|
||
|
||
## Styling and resource ownership
|
||
|
||
Content is wrapped with `.art-subtitle-<name>`, such as the example's `.art-subtitle-chinese` and `.art-subtitle-japanese`. Names enter HTML class markup; use application-defined simple identifiers. Selection sets `art.option.subtitle.escape = false` and supplies the subtitle URL, type and onVttLoad. Establish ownership when combining it with other subtitle managers, since later writes replace that configuration.
|
||
|
||
Literal cue text, entities and supported markup are handled separately. Inline timestamps remain in cue data, while captions still display whole cues; this does not introduce karaoke highlighting. Older cores receive a multiple-active-cue display adapter. Install custom subtitle DOM listeners after plugin registration so the plugin's later view update does not overwrite them.
|
||
|
||
Player destruction cancels requests, removes subscriptions and releases generated URLs. Pending registration settles with an inert result; retained tracks/reset calls become no-ops. Destroy does not restore the shared escape option, because another consumer may have changed it. Fonts, historical core combinations and physical Safari/mobile display still need their own validation.
|
||
|
||
## Compatible TypeScript entries
|
||
|
||
The root and `/legacy` preserve the latest published 1.2.0 factory shape: required `{ subtitles: TrackOption[] }` and a synchronous name-only `LegacyResult`. This retains historical extraction and replacement functions. For the actual Promise and selection methods, use `/runtime`, pointing to the same implementation:
|
||
|
||
```ts
|
||
import type Artplayer from 'artplayer';
|
||
import multipleSubtitles from 'artplayer-plugin-multiple-subtitles/runtime';
|
||
import type { Result, RuntimeOption } from 'artplayer-plugin-multiple-subtitles/runtime';
|
||
|
||
const options: RuntimeOption = {
|
||
subtitles: [{ url: '/subtitles/en.vtt', name: 'en' }],
|
||
};
|
||
|
||
async function selectSubtitles(art: Artplayer): Promise<Result> {
|
||
const result = await multipleSubtitles(options)(art);
|
||
result.tracks(['en']);
|
||
result.reset();
|
||
return result;
|
||
}
|
||
```
|
||
|
||
Root named types are `TrackOption`, `Option`, `RuntimeOption`, `LegacyResult`, `Result`, `Factory` and `RuntimeFactory`. Runtime exports TrackOption, RuntimeOption, Result and RuntimeFactory. RuntimeFactory also describes the writable `.default` self-alias; the historical Factory does not require it.
|
||
|
||
The 1.0/1.1 export-assignment declarations conflict with 1.2's default-module shape; the approved policy retains 1.2 at the root. NodeNext ESM root types expose the factory at `root.default`; use runtime for accurate default calls. Classic CommonJS without interop can use runtime `import = require`; classic default imports need `esModuleInterop`. Historical JavaScript `.default(...)` calls remain supported; an old incorrect declaration does not establish a runtime call that never worked.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/vast.md =====
|
||
|
||
# VAST Ads
|
||
|
||
[简体中文](../../plugin/vast.md)
|
||
|
||
Request and display ads through Glomex VAST IMA Player and Google IMA. Unlike the separate [Ads plugin](./ads.md), this accepts ad-tag URLs or VAST responses rather than managing a local countdown ad. SDK and ad resources must be reachable; network, VPN or blocking rules can prevent loading. This page describes the unreleased refactor branch, not proof that the online example validates the current candidate.
|
||
|
||
## Installation and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-vast
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginVast from 'artplayer-plugin-vast';
|
||
```
|
||
|
||
For script usage, load ArtPlayer before `dist/artplayer-plugin-vast.js`; the global is `artplayerPluginVast`. Its Glomex dependency loads IMA, so no separate custom loader is needed. This preserves the [original online example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vast/index.js&example=vast); its external ad URL is not a local test fixture.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-vast/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// Depends on:
|
||
// https://glomex.github.io/vast-ima-player/
|
||
// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side
|
||
|
||
// Google's IMA SDK are blocked by your Ad blocker.
|
||
// Please Turn Off Your Ad Blocker.
|
||
|
||
// npm i artplayer-plugin-vast
|
||
// import artplayerPluginVast from 'artplayer-plugin-vast';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
plugins: [
|
||
artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
|
||
// Play the ad when the video is played
|
||
art.once('play', () => {
|
||
playUrl('https://artplayer.org/assets/vast/linear-ad.xml')
|
||
})
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## Initialization compatibility
|
||
|
||
`artplayerPluginVast(callback?, options?)` returns an asynchronous registrar. It loads the SDK, creates the appropriate context and awaits the callback before resolving. A callback can return a Promise. Registration does not imply an ad was requested or played.
|
||
|
||
| Behavior | Default npm mode | `{ compatibility: 'workspace-1.2' }` |
|
||
| --- | --- | --- |
|
||
| Callback entry | SDK player and container already allocated | Allocation waits for init/playUrl/playRes |
|
||
| IMA settings | SDK defaults preserved | Preloading and restoration of custom playback state default to true |
|
||
| Resource fields | Writable imaPlayer/id/$container data fields | Live readonly getters, null before allocation and after release |
|
||
| Requests | Wrapper forwards every explicit request | New requests are suppressed during an active ad |
|
||
| Container | SDK manages visibility with default styles | Black overlay, four ad events manage visibility and active state |
|
||
|
||
This implements the approved decision: published npm1.0.0 calls retain their default behavior. Code relying on unpublished workspace1.2 lazy initialization must select it explicitly. The mode is captured once at factory creation; unknown values immediately throw TypeError before SDK loading.
|
||
|
||
## Callback context
|
||
|
||
| Field | Runtime purpose |
|
||
| --- | --- |
|
||
| `art` | Current ArtPlayer instance |
|
||
| `ima` | Loaded IMA SDK |
|
||
| `adsRenderingSettings` | IMA AdsRenderingSettings passed to a newly allocated SDK player |
|
||
| `playerOptions` | Glomex PlayerOptions passed to a newly allocated SDK player |
|
||
| `imaPlayer` | SDK player; already created in default mode, nullable in workspace mode |
|
||
| `id` / `$container` | Container ID/element, with the mode-specific snapshot/null rules above |
|
||
| `container` | Live readonly container getter in both modes, null before allocation or after release |
|
||
| `init()` | Return or create the current SDK player; null after terminal disposal |
|
||
| `playUrl(url, config?)` | Create an AdsRequest, set adTagUrl and request ads; returns void synchronously |
|
||
| `playRes(response, config?)` | Create an AdsRequest, set adsResponse and request ads; returns void synchronously |
|
||
|
||
The extra config fields retain historical for-in copying, including enumerable inherited fields. Copying follows the primary assignment, so config can override adTagUrl/adsResponse. Use application-controlled configuration. Request construction or SDK synchronous errors can throw; void does not signal success or provide an ad-completion Promise.
|
||
|
||
To configure before SDK player allocation, select workspace mode and mutate the original settings/options objects before init or request methods. The default mode's first player already exists on callback entry; do not assume later option changes retroactively alter construction.
|
||
|
||
Default imaPlayer/id/$container fields retain the last allocation after release, even though that SDK is destroyed and its container removed. They are not active resources. Explicit recreation updates them, and assigning these fields does not transfer internal ownership. In workspace mode, keep the context and read getters when needed rather than destructuring their initial null values.
|
||
|
||
## Events and destruction
|
||
|
||
Subscribe to SDK events on imaPlayer; they are not same-named ArtPlayer events. Workspace mode listens to `AdContentPauseRequested`, `AdContentResumeRequested`, `AdStarted` and `AdError` to update its overlay and active state, logging AdError details. Default mode does not add those workspace listeners. The SDK handles content pause/resume; the wrapper does not duplicate it.
|
||
|
||
The result is named `artplayerPluginVast` and registered at `art.plugins.artplayerPluginVast`. Its synchronous `destroy()` releases the current session. While the core remains alive, retained context init/playUrl/playRes methods can create a new session. A recreated SDK player is a different object; reinstall your own SDK subscriptions on it.
|
||
|
||
Core destruction makes this attachment terminal: late SDK completion cannot invoke the callback or allocate a container, init returns null and request methods become inert. It does not cancel a shared SDK script load for other instances. SDK loading or callback failure cleans up the attachment and preserves the original rejection value. Cleanup errors can be observable while remaining resources are still released. Plugin destroy and core destroy therefore have different restart semantics.
|
||
|
||
Real ad playback depends on an available response, IMA, browser policies and devices. When SDK loading is blocked, mocks, guide navigation or continued main-content playback cannot count as successful ads. Validate those separately on the target network and device.
|
||
|
||
## TypeScript entries
|
||
|
||
The root and `/legacy` preserve npm1.0.0's required callback, any SDK fields and inaccurate synchronous name-only result. Plain historical replacement factories do not need a `.default` property. Registration has always been asynchronous. Use `/runtime` for accurate types, optional callback, the second parameter and destroy, with the same implementation:
|
||
|
||
```ts
|
||
import vast from 'artplayer-plugin-vast/runtime';
|
||
import type { RuntimeResult } from 'artplayer-plugin-vast/runtime';
|
||
|
||
const installPublished = vast(({ imaPlayer }) => {
|
||
imaPlayer.addEventListener('AdStarted', () => console.log('Ad started'));
|
||
});
|
||
|
||
const installWorkspace = vast((context) => {
|
||
context.playerOptions.autoResize = false;
|
||
context.init()?.addEventListener('AdStarted', () => console.log('Ad started'));
|
||
}, { compatibility: 'workspace-1.2' });
|
||
|
||
function releaseAd(result: RuntimeResult): void {
|
||
result.destroy();
|
||
}
|
||
```
|
||
|
||
Runtime exports RequestConfig, CompatibilityOptions, Context, PublishedContext, WorkspaceContext, RuntimeContext, RuntimeCallback, RuntimeResult, Registration and RuntimeFactory, plus the historical workspace aliases ArtplayerPluginVastOption and ArtplayerPluginVastInstance. Those aliases describe the workspace callback and awaited result, respectively. CommonJS without interop can use runtime `import = require`, supporting both direct and `.default` calls. These types do not modify the old root declaration.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/plugin/vtt-thumbnail.md =====
|
||
|
||
# VTT Thumbnail
|
||
|
||
[中文](../../plugin/vtt-thumbnail.md)
|
||
|
||
Load a WebVTT thumbnail index and show the selected sprite region when hovering over the progress bar. Generate the index and images beforehand; this plugin does not scan the video or require another SDK.
|
||
|
||
This page describes the current refactor branch. Parser and lifecycle fixes and the precise `/runtime` types are not published yet. An unpinned npm or CDN installation is not evidence of this branch's behavior.
|
||
|
||
## Installation
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-plugin-vtt-thumbnail
|
||
```
|
||
|
||
```js
|
||
import Artplayer from 'artplayer';
|
||
import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
|
||
```
|
||
|
||
For script loading, load ArtPlayer first, followed by `dist/artplayer-plugin-vtt-thumbnail.js`. The global is `artplayerPluginVttThumbnail`. Pin dependency versions and make the VTT and images accessible. Cross-origin VTT requests require appropriate server CORS headers.
|
||
|
||
## Complete example
|
||
|
||
This is the exact code from the [online thumbnail example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail). The demo site supplies the media and `.artplayer-app` container; replace them in your application.
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-vtt-thumbnail/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-plugin-vtt-thumbnail
|
||
// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/bbb-video.mp4',
|
||
plugins: [
|
||
artplayerPluginVttThumbnail({
|
||
vtt: '/assets/sample/bbb-thumbnails.vtt',
|
||
}),
|
||
],
|
||
})
|
||
```
|
||
|
||
## Options
|
||
|
||
The options object passed to `artplayerPluginVttThumbnail(option)` is required.
|
||
|
||
| Field | Type | Behavior |
|
||
| --- | --- | --- |
|
||
| `vtt` | `string`, optional in the declaration | VTT file URL. Supply a valid URL in practice: omission fetches an empty URL, meaning the current page, rather than disabling the plugin. |
|
||
| `style` | Optional `Partial<CSSStyleDeclaration>` | Initial inline styles on the thumbnail control, such as `borderRadius: '4px'`. |
|
||
|
||
Rendering updates display, width, height, left, backgroundImage and backgroundPosition. Initial styles cannot permanently override these properties. Each cue supplies the crop dimensions; the plugin does not automatically scale the sprite.
|
||
|
||
## Index format and image paths
|
||
|
||
```text
|
||
WEBVTT
|
||
|
||
00:00.000 --> 00:05.000
|
||
bbb-sprite.jpg#xywh=0,0,128,72
|
||
|
||
00:05.000 --> 00:10.000
|
||
bbb-sprite.jpg#xywh=128,0,128,72
|
||
```
|
||
|
||
The four values `x,y,w,h` are the left position, top position, width and height within the image, in pixels. x/y must be nonnegative and w/h positive; all four must be finite numbers. Each cue has one image URL line with a crop fragment. Ordinary subtitle text is not a thumbnail index.
|
||
|
||
Relative images are joined to the directory of the **supplied VTT URL**. For example, `bbb-sprite.jpg` inside `/assets/sample/bbb-thumbnails.vtt` becomes `/assets/sample/bbb-sprite.jpg`. Root-relative URLs and full URLs with supported protocols are kept as supplied. The directory is not recalculated from a redirected HTTP response URL. Prefer explicit image URLs when redirects or complex relative paths are involved.
|
||
|
||
The parser supports a BOM, common line endings, optional cue identifiers and timing settings, and skips NOTE, STYLE and REGION blocks. It is a thumbnail index parser, not a complete WebVTT subtitle layout engine.
|
||
|
||
## Timing and display boundaries
|
||
|
||
For historical compatibility, start and end times are rounded down to whole seconds. Both interval endpoints are included, and the first matching cue in file order wins. At exactly 5 seconds in the example above, the first image still applies; the second appears after 5 seconds. Do not assume millisecond precision or exclusive end times.
|
||
|
||
Desktop hover selects a cue using the progress percentage multiplied by the video duration. Gaps hide the preview, and previews near the edges are aligned inward. The mobile path responds to progress dragging with an input event and hides about 500ms after the last drag update. Desktop coverage does not establish real touch-device support.
|
||
|
||
## Asynchronous registration, errors and cleanup
|
||
|
||
Registration fetches and parses the VTT and actually returns a Promise. Its success result contains only `name: 'artplayerPluginVttThumbnail'`. Installation through the constructor's plugins array is asynchronous; do not assume that the result is registered immediately after construction.
|
||
|
||
To wait explicitly and handle request or parse errors, call `art.plugins.add()` once after constructing the player:
|
||
|
||
```ts
|
||
import Artplayer from 'artplayer';
|
||
import thumbnails from 'artplayer-plugin-vtt-thumbnail/runtime';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/video/movie.mp4',
|
||
});
|
||
|
||
async function installThumbnails() {
|
||
try {
|
||
const result = await art.plugins.add(thumbnails({ vtt: '/video/movie.vtt' }));
|
||
console.log(result.name);
|
||
}
|
||
catch (error) {
|
||
console.error('Unable to load thumbnails', error);
|
||
}
|
||
}
|
||
void installThumbnails();
|
||
```
|
||
|
||
Request and format errors reject registration; format errors include a line number. Registration completion establishes that the VTT was parsed and the control created, not that every image has decoded. Images load when the browser displays them; a later image failure does not reject an already settled registration Promise.
|
||
|
||
There is no update, reload or independent destroy method. Switching the main video does not refetch the VTT. For a different video and thumbnail set, you can destroy and recreate the player. Removing a control is not a complete uninstall; repeated installation is not an update API.
|
||
|
||
Destroying the player cancels outstanding requests where AbortController is available, settles canceled registration, removes owned listeners and timers, and removes the control only if this installation still owns it. Cancellation still returns the name object, so the name alone does not prove an image is available. Late requests cannot remount the interface.
|
||
|
||
## TypeScript compatibility
|
||
|
||
The root and `/legacy` entrances preserve the latest published 1.1.0 synchronous return declaration and replacement-function shape, although registration is asynchronous at runtime. The `/runtime` entrance above uses the same JavaScript implementation and accurately declares the Promise and runtime `.default` self-alias. It also exposes `Option`, `Result`, `Factory` and `RuntimeFactory` types.
|
||
|
||
The older 1.0.x `export =` shape cannot preserve the same type extraction as the 1.1.0 default export. TypeScript consumers relying on those earlier CommonJS declarations should migrate to `/runtime`. NodeNext ESM consumers should also prefer this entrance to avoid the historical namespace shape retained by the root. Legal older JavaScript calls and distribution file entrances remain available.
|
||
|
||
Browser checks cover cropping and cleanup with published and candidate cores. Complete mobile, plugin combination and release-artifact acceptance remains tracked separately.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/proxy/canvas.md =====
|
||
|
||
# Canvas video proxy
|
||
|
||
[简体中文](../../proxy/canvas.md)
|
||
|
||
Decode audio/video with a real video element, draw its picture to Canvas and optionally post-process each draw. Install through ArtPlayer's proxy option, not its plugins array. This page describes the unreleased branch; decoding, pixel access and device limitations still apply.
|
||
|
||
## Install and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-proxy-canvas
|
||
```
|
||
|
||
ESM uses `import canvas from 'artplayer-proxy-canvas'`. Scripts load `dist/artplayer-proxy-canvas.js`, exposing `artplayerProxyCanvas`. The [original example](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-canvas/index.js&example=canvas) is retained below:
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-proxy-canvas/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-proxy-canvas
|
||
// import artplayerProxyCanvas from 'artplayer-proxy-canvas';
|
||
|
||
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,
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
thumbnails: {
|
||
url: '/assets/sample/thumbnails.png',
|
||
number: 60,
|
||
column: 10,
|
||
scale: 0.85,
|
||
},
|
||
proxy: artplayerProxyCanvas(),
|
||
})
|
||
```
|
||
|
||
The optional argument is a drawing callback, not an options object:
|
||
|
||
```js
|
||
proxy: artplayerProxyCanvas((context, video) => {
|
||
context.fillStyle = 'rgba(0, 0, 0, 0.4)';
|
||
context.fillRect(0, 0, context.canvas.width, 32);
|
||
context.fillStyle = '#fff';
|
||
context.fillText(video.currentTime.toFixed(1), 10, 22);
|
||
})
|
||
```
|
||
|
||
It receives the actual CanvasRenderingContext2D and backing HTMLVideoElement. The base picture is drawn and any acquired ImageBitmap closed before the synchronous callback. Return values are unused; an async callback's Promise is not awaited. Set required Canvas state yourself; changing dimensions resets drawing state.
|
||
|
||
## Returned element and media surface
|
||
|
||
Initialization synchronously returns an actual HTMLCanvasElement for ArtPlayer's media position. The backing video is connected to the player before playback, transparent and unfocusable, without another visible player.
|
||
|
||
Native Canvas members win: width/height, DOM events, getContext and toDataURL remain Canvas operations. Only enumerated video members absent from Canvas are forwarded; this is not a complete runtime copy of HTMLVideoElement. Access the real video through the draw callback when needed.
|
||
|
||
Backing media events are forwarded as ArtPlayer `video:<type>` events with the original Event. Canvas addEventListener('play', ...) is not a backing-video listener; use art.on('video:play', ...). Assigning media src/srcObject or invoking load invalidates old draws.
|
||
|
||
Normal ArtPlayer subtitle options remain supported. The active proxy's appendChild specially routes HTML tracks to the video; ordinary nodes still belong to Canvas. Core owns subtitle track replacement and URLs. The initial empty metadata track is removed before the first real subtitle is attached. Its final parent is VIDEO.
|
||
|
||
## Drawing, dimensions and events
|
||
|
||
| Trigger | Behavior |
|
||
| --- | --- |
|
||
| Play | One RAF drawing chain without overlapping asynchronous acquisitions |
|
||
| Pause/source emptying | Cancel pending draws, keeping the displayed picture |
|
||
| Paused seek | Request one fresh picture |
|
||
| Resize | Coalesce requests and invalidate old asynchronous results |
|
||
| loadedmetadata | Set Canvas dimensions when intrinsic video size is valid |
|
||
| autoSize=false | Fit the video aspect ratio into the container with centering padding on resize |
|
||
| autoSize=true | Skip that proxy fit; let the player handle automatic sizing |
|
||
|
||
Drawing needs readyState>=2, no seek in progress, and valid video/Canvas dimensions. It uses createImageBitmap when available, otherwise drawImage(video). This does not guarantee a callback for every decoded frame. Cross-origin CORS settings/responses still determine screenshot and pixel-read access.
|
||
|
||
| Custom event | Arguments and order |
|
||
| --- | --- |
|
||
| `artplayerProxyCanvas:draw` | Context and backing video, after a successful callback |
|
||
| `artplayerProxyCanvas:error` | Original failure value from drawing, callback or initialization |
|
||
|
||
A missing2D context reports an error. The specific first-frame createImageBitmap InvalidStateError before decoding waits for another draw request; callback/drawImage errors are not broadly treated as first-frame delays. Destroying the player in the callback prevents a subsequent draw event or restarted loop.
|
||
|
||
## Cleanup and capabilities
|
||
|
||
Player destruction cancels RAF/deferred setup, removes internal subscriptions, pauses/unloads the video, clears srcObject and releases Canvas buffers. Late bitmaps are still closed. Clearing the stream reference does not stop caller-owned media tracks. Cleanup attempts all resources before throwing its first error. Escaped media methods/forwarded setters cannot restart playback or source loading; native Canvas methods still act on the same element.
|
||
|
||
There is no separate public start/stop/destroy control object; use ArtPlayer lifecycle. The original example's PiP/fullscreen/screenshot options remain subject to actual browser capabilities. Their presence is not proof of universal support, and Windows results do not establish Safari/iPhone/Android acceptance.
|
||
|
||
## TypeScript and historical types
|
||
|
||
Root and `/legacy` retain published1.1.0's optional callback, plain factory and exact HTMLCanvasElement result. Ordinary replacement functions remain assignable. The conflicting1.0 export= required-callback shape follows the approved latest-root policy. Use `/runtime` for accurate ESM/older CommonJS invocation and self-alias types with the same implementation:
|
||
|
||
```ts
|
||
import Artplayer from 'artplayer';
|
||
import canvas from 'artplayer-proxy-canvas/runtime';
|
||
import type { MediaCanvas, Option } from 'artplayer-proxy-canvas/runtime';
|
||
|
||
const overlay: Option = (context, video) => {
|
||
context.fillText(video.currentTime.toFixed(1), 10, 22);
|
||
};
|
||
const art = new Artplayer({ container: '#player', url: '/movie.mp4', proxy: canvas(overlay) });
|
||
const media = art.template.$video as MediaCanvas;
|
||
function play(): Promise<void> { return media.play(); }
|
||
```
|
||
|
||
Public types are Option, Result, Factory, Callable, MediaCanvas and RuntimeFactory. MediaCanvas is an explicit view preserving native Canvas collisions; it adds no runtime capabilities and does not narrow factory return inference. The root's historical NodeNext ESM namespace remains; use runtime for accurate default calls. JavaScript root and `.default` reference the same factory; runtime types describe the alias as readonly. CommonJS can require the function directly, and older TS import=require callers can choose runtime.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/proxy/mediabunny.md =====
|
||
|
||
# Mediabunny video proxy
|
||
|
||
[简体中文](../../proxy/mediabunny.md)
|
||
|
||
Read media through Mediabunny and expose a video-like surface backed by Canvas and an audio pipeline, including HLS quality/audio selection. Install through ArtPlayer's proxy option. This describes the unreleased branch; it does not supply missing decoders or every HTMLVideoElement capability.
|
||
|
||
## Install and example
|
||
|
||
```sh
|
||
yarn add artplayer artplayer-proxy-mediabunny
|
||
```
|
||
|
||
ESM uses `import mediabunny from 'artplayer-proxy-mediabunny'`. Scripts load `dist/artplayer-proxy-mediabunny.js`, exposing `artplayerProxyMediabunny`. This is the [original HLS example](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-mediabunny/index.js&example=mediabunny); its remote stream is not an offline fixture:
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-proxy-mediabunny/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-proxy-mediabunny
|
||
// import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||
autoSize: true,
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
miniProgressBar: true,
|
||
autoPlayback: true,
|
||
autoOrientation: true,
|
||
proxy: artplayerProxyMediabunny({
|
||
m3u8: {
|
||
quality: {
|
||
control: true,
|
||
setting: true,
|
||
getName: level => level.height ? `${level.height}P` : level.name,
|
||
title: 'Quality',
|
||
auto: 'Auto',
|
||
},
|
||
audio: {
|
||
control: true,
|
||
setting: true,
|
||
getName: track => track.name || track.language,
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
},
|
||
}),
|
||
})
|
||
```
|
||
|
||
The optional-options factory synchronously initializes an actual HTMLCanvasElement and installs art.mediabunny. Native Canvas members win collisions: DOM event/attribute methods do not become shim methods. Use ArtPlayer video:* events or the explicit shim for media operations.
|
||
|
||
## Inputs and options
|
||
|
||
| Option | Default or behavior |
|
||
| --- | --- |
|
||
| `source` | Initial source; a truthy value precedes art.option.url, but later host assignments can replace it |
|
||
| `loadTimeout` | 0, no deadline; a finite positive value limits loading in milliseconds |
|
||
| `timeupdateInterval` | 250ms renderer update interval, not an exact clock guarantee |
|
||
| `avSyncTolerance` | 0.12 seconds, used in the late-frame threshold when dropping is enabled |
|
||
| `dropLateFrames` | false; enable to skip sufficiently late pictures |
|
||
| `poster` | Empty by default; captured by the video engine at initialization |
|
||
| `preflightRange` | false; optional HEAD check for ordinary URLs |
|
||
| `volume` / `muted` | Initial shim values0.7 / false; later player settings may override them |
|
||
| `autoplay` / `loop` | Compatibility readback values defaulting false, not standalone autoplay/loop execution |
|
||
| `crossOrigin` | Compatibility readback defaulting empty; does not configure SDK fetch credentials/CORS |
|
||
| `m3u8` | Optional quality/audio menus, below |
|
||
|
||
Use ArtPlayer's own autoplay/loop configuration for player behavior, subject to browser playback policy. Shim autoplay/loop/crossOrigin setters remain inert. Changing shim.poster updates its option readback, not necessarily the poster already captured by the video engine.
|
||
|
||
The source declaration accepts URL strings, Blobs and byte ReadableStreams. Runtime also passes SDK Source/SourceRef values to SDK validation. Case-insensitive `.m3u8` suffixes, optionally followed by query/hash, select HLS_FORMATS; other sources use ALL_FORMATS. A URL without that suffix does not enable this proxy's HLS menu state merely from response content. Random access/reloading a stream depends on its source capabilities.
|
||
|
||
When enabled, preflight sends HEAD only for non-HLS strings. Missing accept-ranges or a value of none emits error with a RangeNotSupported Event detail and stops that preflight path, without setting shim.error. Network failures warn and continue; HLS/non-string sources skip HEAD. This is not a complete Range GET or codec-support check. Media responses must still be readable with suitable CORS.
|
||
|
||
## HLS menus and selection
|
||
|
||
Both m3u8.quality and m3u8.audio accept control, setting, title, auto and getName. No menu appears unless control or setting is enabled; setting also needs the player's settings panel.
|
||
|
||
| Setting | Default |
|
||
| --- | --- |
|
||
| `quality.title` / `audio.title` | Quality / Audio |
|
||
| Either `auto` | Auto |
|
||
| `quality.getName(level)` | level.name, otherwise height plus P |
|
||
| `audio.getName(track)` | First available name, lang or language |
|
||
|
||
Levels provide id, index, name, height and bitrate; audio entries provide id, index, name, lang, language and bitrate. Full state also includes SDK track objects. Name can be null; return a displayable string from getName.
|
||
|
||
Quality needs video levels; audio needs at least two pairable tracks. Quality sorts by descending height. Equal labels are merged, favoring the selected item. Highlight/button text follows the actual current track, so auto mode may still display its chosen track rather than Auto.
|
||
|
||
```js
|
||
const shim = art.mediabunny;
|
||
const state = await shim.getM3u8State();
|
||
if (state?.levels.length) {
|
||
await shim.switchM3u8Quality(state.levels[0].id);
|
||
}
|
||
await shim.switchM3u8Audio('auto');
|
||
```
|
||
|
||
Pass a numeric state id or literal 'auto', not an index, label or numeric string. Auto selects the SDK primary track; the proxy does not thereby measure bandwidth and continuously adapt bitrate. Quality changes retain pairable audio when possible, otherwise choose primary pairable audio; audio selection also maintains video pairing. Unknown IDs retain the current track. Methods are no-ops without an active HLS source.
|
||
|
||
Menu names are mediabunny-quality and mediabunny-audio. Metadata/restart refreshes them; loadstart/error/destruction clears them. A source without a capability removes its old UI. Stale menu callbacks and superseded choices cannot replace current state. Active asynchronous selection failures can reject.
|
||
|
||
## Shim members
|
||
|
||
| Member | Behavior |
|
||
| --- | --- |
|
||
| `canvas` | Native output element |
|
||
| `src` / `currentSrc` | Source value; truthy src assignments load, empty assignments do not unload |
|
||
| `play()` / `pause()` / `load()` | Promise playback, synchronous pause, reload current src; load has no completion Promise |
|
||
| `currentTime` | Seconds; assignment starts an asynchronous seek without an awaitable setter |
|
||
| `duration` | Seconds, possibly NaN when unknown or Infinity for live input |
|
||
| `volume` / `muted` | Volume is numerically coerced/clamped0–1 and unmutes; muted is boolean-coerced |
|
||
| `playbackRate` | Defaults1; accepts coerced positive non-NaN values and emits ratechange |
|
||
| `paused` / `playing` / `ended` / `seeking` | Coordinator states; playing does not prove a real frame is displayed |
|
||
| `readyState` / `networkState` / `error` | Compatibility state and `{code, message}` or null |
|
||
| `videoWidth` / `videoHeight` | Video-engine dimensions |
|
||
| `buffered` / `played` / `seekable` | Synthetic0-to-duration/current-time/duration ranges, not measured network buffering |
|
||
| `createTimeRanges(start, end)` | Same synthetic helper, length0 or1; does not implement native index-range exceptions |
|
||
| `canPlayType(type)` | Always maybe, without probing support |
|
||
| `getM3u8State()` | Promise of state, or null for non-HLS/obsolete state |
|
||
| `switchM3u8Quality(value)` / `switchM3u8Audio(value)` | Promise-based track selection |
|
||
| `addEventListener` / `removeEventListener` | Shim media events, not Canvas DOM listeners |
|
||
| `getBoundingClientRect()` | Delegate to Canvas |
|
||
| `setAttribute(name, value)` | Shim handles src/muted, uses inert autoplay/loop setters, otherwise delegates to Canvas |
|
||
| `destroy()` | Synchronous terminal shim/engine cleanup, idempotent |
|
||
|
||
Poster/autoplay/loop/crossOrigin follow the rules above. Controls=false, playsInline=true, preload='auto', defaultMuted=false and defaultPlaybackRate=1 have inert setters. Direct canvas.setAttribute is native Canvas behavior, unlike shim.setAttribute. Normally use art.destroy to also release host menus, alias and subscriptions.
|
||
|
||
HlsState contains levels, audios, currentLevel, currentAudio, videoMode and audioMode. Current entries may be null; modes are auto/manual. Audios are pairable with the selected video, so audio-only input does not guarantee menu entries. Narrow unknown track objects with the SDK types used by your application.
|
||
|
||
## Events, frame callbacks and cleanup
|
||
|
||
Shim events forward to ArtPlayer video:* as Event plus detail. Ordinary listeners retain duplicates, first-match removal, live-array iteration and exception propagation. This is not the complete native EventTarget API and does not accept native listener options.
|
||
|
||
Successful loading publishes loadedmetadata/durationchange/progress after participants prepare, then loadeddata/canplay/canplaythrough/progress. Waiting/loadstart remain deferred notifications. If neither selected track can decode, report code4 without success readiness; one usable track can support partial playback. Seek emits seeking/waiting, then seeked; track replacement also refreshes metadata/readiness. Each step checks for newer operations/destruction.
|
||
|
||
requestVideoFrameCallback(callback) returns a cancellable RAF ID for one synthetic notification, not a newly decoded-frame guarantee; it may run while paused. Callback now/captureTime/receiveTime use RAF time, expectedDisplayTime estimates now+16.6, and presentationTime/mediaTime are media seconds. Width/height come from the engine; presentedFrames, processingDuration and rtpTimestamp are always0. Do not use these values as decoder-throughput or network-latency measurements.
|
||
|
||
Source changes, cancellation and destruction invalidate old asynchronous work. Pause cancels pending playback and prevents old seeks from resuming it. Superseded operations may resolve normally; resolution does not prove their original intent ran. Active play/selection errors can reject. Src/load errors report through media events, normally code4; Range preflight is the separate path described above.
|
||
|
||
Destruction cancels input/preflight, frame callbacks, timers, audio nodes/context and decoder resources. Host cleanup also removes owned UI/subscriptions and deletes art.mediabunny only if it still belongs to this proxy. Late results cannot reactivate it. Cleanup is not a Promise of physical GPU/browser reclamation; long-duration and real-device acceptance remain separate.
|
||
|
||
## TypeScript
|
||
|
||
Root and `/legacy` preserve optional options and exact HTMLCanvasElement return inference. There is no `/runtime` subpath. Use explicit views for media capabilities:
|
||
|
||
```ts
|
||
import Artplayer from 'artplayer';
|
||
import mediabunny from 'artplayer-proxy-mediabunny';
|
||
import type { MediaBunnyPlayer } from 'artplayer-proxy-mediabunny';
|
||
|
||
const art: MediaBunnyPlayer = new Artplayer({
|
||
container: '#player', url: '/movie.m3u8',
|
||
proxy: mediabunny({ m3u8: { quality: { control: true } } }),
|
||
});
|
||
async function selectFirstLevel(): Promise<void> {
|
||
const shim = art.mediabunny;
|
||
if (!shim) return;
|
||
const state = await shim.getM3u8State();
|
||
if (state?.levels.length) await shim.switchM3u8Quality(state.levels[0].id);
|
||
}
|
||
```
|
||
|
||
Public types are Option, Result, HlsLevel, HlsAudio, HlsState, MediaBunnyCanvas, MediaBunnyPlayer, MediaBunnyShim, MediaListener, SyntheticFrameCallback and SyntheticFrameMetadata. The Canvas view preserves native collisions; the optional player alias is removed on host destruction. CommonJS runtime supports direct and historical .default calls while the factory type remains plain callable. The legacy build does not polyfill WebCodecs, Web Audio or other browser capabilities.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/start/i18n.md =====
|
||
|
||
# Language Settings
|
||
|
||
::: danger
|
||
|
||
Due to the increasing number of bundled multilingual resources, starting from version `5.1.0`, the core `artplayer.js` code will no longer bundle any languages other than `Simplified Chinese` and `English`. You will need to manually import any other languages you require.
|
||
|
||
:::
|
||
|
||
:::warning
|
||
|
||
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`. No manual import is required.
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lang: 'zh-cn', // or 'en'
|
||
});
|
||
```
|
||
|
||
## Importing Languages
|
||
|
||
Language files before bundling are located at: `artplayer/src/i18n/*.js`. Contributions for new languages are welcome.
|
||
|
||
Bundled language files are located at: `artplayer/dist/i18n/*.js`
|
||
|
||
::: code-group
|
||
|
||
```js [import]
|
||
import id from 'artplayer/i18n/id';
|
||
import zhTw from 'artplayer/i18n/zh-tw';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
i18n: {
|
||
id: id,
|
||
'zh-tw': zhTw,
|
||
},
|
||
lang: 'zh-tw',
|
||
});
|
||
```
|
||
|
||
```js [script]
|
||
<script src="artplayer/dist/i18n/id.js"></script>
|
||
<script src="artplayer/dist/i18n/zh-tw.js"></script>
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
i18n: {
|
||
id: window['artplayer-i18n-id'],
|
||
'zh-tw': window['artplayer-i18n-zh-tw'],
|
||
},
|
||
lang: 'zh-tw',
|
||
});
|
||
```
|
||
|
||
:::
|
||
|
||
## Adding a New Language
|
||
|
||
```js{4-9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lang: 'your-lang',
|
||
i18n: {
|
||
'your-lang': {
|
||
Play: 'Your Play'
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
## Modifying a Language
|
||
|
||
```js
|
||
import zhTw from 'artplayer/i18n/zh-tw';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
i18n: {
|
||
// Change the default language
|
||
'zh-cn': {
|
||
Play: 'Your Play'
|
||
},
|
||
// Change the imported language
|
||
'zh-tw': {
|
||
...zhTw,
|
||
Play: 'Your Play'
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/start/option.md =====
|
||
|
||
# Basic Options
|
||
|
||
## `container`
|
||
|
||
- Type: `String, Element`
|
||
- Default: `#artplayer`
|
||
|
||
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: document.querySelector('.artplayer-app'),
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
You may need to set the size of the container element, for example:
|
||
|
||
```css{2-3}
|
||
.artplayer-app {
|
||
width: 400px;
|
||
height: 300px;
|
||
}
|
||
```
|
||
|
||
Or use `aspect-ratio`:
|
||
|
||
```css{2}
|
||
.artplayer-app {
|
||
aspect-ratio: 16/9;
|
||
}
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Among all options, only `container` is required.
|
||
|
||
:::
|
||
|
||
## `url`
|
||
|
||
- Type: `String`
|
||
- Default: `''`
|
||
|
||
The video source URL.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{3}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
Sometimes the `url` is not known immediately. In such cases, you can set the `url` asynchronously.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{6}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
});
|
||
|
||
setTimeout(() => {
|
||
art.url = '/assets/sample/video.mp4';
|
||
}, 1000);
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
By default, three video file formats are supported: `.mp4`, `.ogg`, `.webm`.
|
||
|
||
To play other formats like `.m3u8` or `.flv`, please refer to the `Third-party Libraries` section on the left.
|
||
|
||
:::
|
||
|
||
## `id`
|
||
|
||
- Type: `String`
|
||
- Default: `''`
|
||
|
||
The unique identifier for the player. Currently used only for playback memory `autoplayback`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{2}
|
||
var art = new Artplayer({
|
||
id: 'your-url-id',
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
});
|
||
```
|
||
|
||
## `onReady`
|
||
|
||
- Type: `Function`
|
||
- Default: `undefined`
|
||
|
||
The constructor accepts a function as the second parameter. This function 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>
|
||
|
||
```js{7-9}
|
||
var art = new Artplayer(
|
||
{
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
},
|
||
function onReady(art) {
|
||
this.play()
|
||
},
|
||
);
|
||
```
|
||
|
||
Equivalent to:
|
||
|
||
```js{7-9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
|
||
art.on('ready', () => {
|
||
art.play();
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
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.
|
||
|
||
:::
|
||
|
||
## `poster`
|
||
|
||
- Type: `String`
|
||
- Default: `''`
|
||
|
||
The video poster image, which only appears when the player is initialized and not yet playing.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
poster: '/assets/sample/poster.jpg',
|
||
});
|
||
```
|
||
|
||
## `theme`
|
||
|
||
- Type: `String`
|
||
- Default: `#f00`
|
||
|
||
The player's theme color, currently used for the `progress bar` and `highlighted elements`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
theme: '#ffad00',
|
||
});
|
||
```
|
||
|
||
## `volume`
|
||
|
||
- Type: `Number`
|
||
- Default: `0.7`
|
||
|
||
The player's default volume.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
volume: 0.5,
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
The player caches the last volume setting. Upon the next initialization (e.g., page refresh), the player will read this cached value.
|
||
|
||
:::
|
||
|
||
## `isLive`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Enable live streaming mode. This will hide the progress bar and playback time.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
isLive: true,
|
||
});
|
||
```
|
||
|
||
## `muted`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to start muted by default.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
muted: true,
|
||
});
|
||
```
|
||
|
||
## `autoplay`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to autoplay.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoplay: true,
|
||
muted: true,
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
If you want the video to autoplay immediately upon page load, `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`
|
||
|
||
By default, the player's dimensions fill the entire `container`, often resulting in black bars. This option automatically adjusts the player size to hide black bars, similar to `css`'s `object-fit: cover;`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoSize: true,
|
||
});
|
||
|
||
```
|
||
|
||
## `autoMini`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Automatically enters `Mini Player` mode when the player scrolls out of the browser viewport.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoMini: true,
|
||
});
|
||
```
|
||
|
||
## `loop`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to loop playback.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
loop: true,
|
||
});
|
||
```
|
||
|
||
## `flip`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the video flip function. Currently only appears in the `Settings Panel` and `Context Menu`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
flip: true,
|
||
setting: true,
|
||
});
|
||
```
|
||
|
||
## `playbackRate`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the video playback speed function. It will appear in the `Settings Panel` and `Context Menu`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
playbackRate: true,
|
||
setting: true,
|
||
});
|
||
```
|
||
|
||
## `aspectRatio`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the video aspect ratio function. It will appear in the `Settings Panel` and `Context Menu`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
aspectRatio: true,
|
||
setting: true,
|
||
});
|
||
```
|
||
|
||
## `screenshot`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the `Screenshot` function in the bottom control bar.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
screenshot: true,
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Due to browser security mechanisms, screenshotting may fail if the video source URL is cross-origin with the website.
|
||
|
||
:::
|
||
|
||
## `setting`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the toggle button for the `Settings Panel` in the bottom control bar.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
});
|
||
```
|
||
|
||
## `hotkey`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
Whether to use hotkeys.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
hotkey: true,
|
||
});
|
||
```
|
||
|
||
| Hotkey | Description |
|
||
| ------- | -------------------- |
|
||
| `↑` | Increase volume |
|
||
| `↓` | Decrease volume |
|
||
| `←` | Seek forward |
|
||
| `→` | Seek backward |
|
||
| `space` | Toggle play/pause |
|
||
|
||
:::warning Note
|
||
|
||
These hotkeys only take effect after the player gains focus (e.g., after clicking on the player).
|
||
|
||
:::
|
||
|
||
## `pip`
|
||
|
||
- 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>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
pip: true,
|
||
});
|
||
```
|
||
|
||
## `mutex`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
If multiple players exist on the page simultaneously, whether only one player is allowed to play at a time.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
mutex: true,
|
||
});
|
||
```
|
||
|
||
## `backdrop`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
Whether to enable the backdrop blur effect for the player UI. When enabled, overlays such as the settings panel, context menu, and volume bar will apply a `backdrop-filter` frosted glass effect for a more transparent look. However, this may cause performance or compatibility issues on some low-performance devices or older browsers.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
backdrop: false, // Disable frosted glass effect
|
||
});
|
||
```
|
||
|
||
## `fullscreen`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the player `Window Fullscreen` button in the bottom control bar.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
});
|
||
```
|
||
|
||
## `fullscreenWeb`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the player `Web Fullscreen` button in the bottom control bar.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreenWeb: true,
|
||
});
|
||
```
|
||
|
||
## `subtitleOffset`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Subtitle time offset, ranging from `[-5s, 5s]`. Appears in the `Settings Panel`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitleOffset: true,
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
setting: true,
|
||
});
|
||
|
||
```
|
||
|
||
## `miniProgressBar`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
A mini progress bar that only appears when the player loses focus and is playing.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
miniProgressBar: true,
|
||
});
|
||
```
|
||
|
||
## `useSSR`
|
||
|
||
- 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 is mounted.
|
||
|
||
You can access the player's required HTML via `Artplayer.html`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{7}
|
||
var $container = document.querySelector('.artplayer-app');
|
||
$container.innerHTML = Artplayer.html;
|
||
|
||
var art = new Artplayer({
|
||
container: $container,
|
||
url: '/assets/sample/video.mp4',
|
||
useSSR: true,
|
||
});
|
||
```
|
||
|
||
## `playsInline`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
Whether to use `playsInline` mode on mobile devices.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
playsInline: true,
|
||
});
|
||
```
|
||
|
||
## `layers`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Initialize custom layers.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{5-23}
|
||
var img = '/assets/sample/layer.png';
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
layers: [
|
||
{
|
||
name: 'potser',
|
||
html: `<img style="width: 100px" src="${img}">`,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '20px',
|
||
right: '20px',
|
||
opacity: '.9',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
art.layers.show = false;
|
||
},
|
||
mounted: function (...args) {
|
||
console.info('mounted', args);
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to:
|
||
|
||
[/component/layers.html](/component/layers.html)
|
||
|
||
:::
|
||
|
||
## `settings`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Initialize custom settings panels.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{5-34}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
settings: [
|
||
{
|
||
html: 'setting01',
|
||
selector: [
|
||
{
|
||
html: 'setting01-01',
|
||
},
|
||
{
|
||
html: 'setting01-02',
|
||
},
|
||
],
|
||
onSelect: function (...args) {
|
||
console.info(args);
|
||
},
|
||
},
|
||
{
|
||
html: 'setting02',
|
||
selector: [
|
||
{
|
||
html: 'setting02-01',
|
||
},
|
||
{
|
||
html: 'setting02-02',
|
||
},
|
||
],
|
||
onSelect: function (...args) {
|
||
console.info(args);
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
:::warning For `Settings Panel`, please refer to:
|
||
|
||
[/component/setting.html](/component/setting.html)
|
||
|
||
:::
|
||
|
||
## `contextmenu`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Initialize custom context menus.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-12}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
contextmenu: [
|
||
{
|
||
html: 'your-menu',
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
art.contextmenu.show = false;
|
||
},
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to:
|
||
|
||
[/component/contextmenu.html](/component/contextmenu.html)
|
||
|
||
:::
|
||
|
||
## `controls`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Initialize custom bottom control bar.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-16}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
controls: [
|
||
{
|
||
position: 'left',
|
||
html: 'your-control',
|
||
tooltip: 'Your Control',
|
||
style: {
|
||
color: 'green',
|
||
},
|
||
click: function (...args) {
|
||
console.info('click', args);
|
||
},
|
||
},
|
||
],
|
||
});
|
||
|
||
```
|
||
|
||
:::warning For `Component Configuration`, please refer to the following address:
|
||
|
||
[/component/controls.html](/component/controls.html)
|
||
|
||
:::
|
||
|
||
## `quality`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Whether to display the `Quality Selection` list in the bottom control bar.
|
||
|
||
| Property | Type | Description |
|
||
| --------- | --------- | ---------------- |
|
||
| `default` | `Boolean` | Default quality |
|
||
| `html` | `String` | Quality name |
|
||
| `url` | `String` | Quality URL |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-14}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
quality: [
|
||
{
|
||
default: true,
|
||
html: 'SD 480P',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
{
|
||
html: 'HD 720P',
|
||
url: '/assets/sample/video.mp4',
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## `highlight`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Display `Highlight Information` on the progress bar.
|
||
|
||
| Property | Type | Description |
|
||
| -------- | -------- | ------------------------------- |
|
||
| `time` | `Number` | Highlight time (in seconds) |
|
||
| `text` | `String` | Highlight text |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-25}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
highlight: [
|
||
{
|
||
time: 60,
|
||
text: 'One more chance',
|
||
},
|
||
{
|
||
time: 120,
|
||
text: '谁でもいいはずなのに',
|
||
},
|
||
{
|
||
time: 180,
|
||
text: '夏の想い出がまわる',
|
||
},
|
||
{
|
||
time: 240,
|
||
text: 'こんなとこにあるはずもないのに',
|
||
},
|
||
{
|
||
time: 300,
|
||
text: '--终わり--',
|
||
},
|
||
],
|
||
});
|
||
```
|
||
|
||
## `plugins`
|
||
|
||
- Type: `Array`
|
||
- Default: `[]`
|
||
|
||
Initialize custom `plugins`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{15}
|
||
function myPlugin(art) {
|
||
console.info(art);
|
||
return {
|
||
name: 'myPlugin',
|
||
something: 'something',
|
||
doSomething: function () {
|
||
console.info('doSomething');
|
||
},
|
||
};
|
||
}
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [myPlugin],
|
||
});
|
||
```
|
||
|
||
## `thumbnails`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Set `Preview Thumbnails` on the progress bar.
|
||
|
||
| Property | Type | Description |
|
||
| -------- | -------- | -------------------------- |
|
||
| `url` | `String` | Thumbnail image URL |
|
||
| `number` | `Number` | Number of thumbnails |
|
||
| `column` | `Number` | Number of thumbnail columns|
|
||
| `width` | `Number` | Thumbnail width |
|
||
| `height` | `Number` | Thumbnail height |
|
||
| `scale` | `Number` | Thumbnail scale |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
thumbnails: {
|
||
url: '/assets/sample/thumbnails.png',
|
||
number: 60,
|
||
column: 10,
|
||
},
|
||
});
|
||
```
|
||
|
||
:::warning Generate Thumbnails Online
|
||
|
||
[artplayer-tool-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-tool-thumbnail/index.js&example=thumbnail)
|
||
|
||
:::
|
||
|
||
## `subtitle`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Set video subtitles. Supported subtitle formats: `vtt`, `srt`, `ass`.
|
||
|
||
| Property | Type | Description |
|
||
| ----------- | ---------- | ------------------------------------------------ |
|
||
| `name` | `String` | Subtitle name |
|
||
| `url` | `String` | Subtitle URL |
|
||
| `type` | `String` | Subtitle type, options: `vtt`, `srt`, `ass` |
|
||
| `style` | `Object` | Subtitle style |
|
||
| `encoding` | `String` | Subtitle encoding, default `utf-8` |
|
||
| `escape` | `Boolean` | Whether to escape `html` tags, default `true` |
|
||
| `onVttLoad` | `Function` | Function for modifying `vtt` text |
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-12}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
type: 'srt',
|
||
encoding: 'utf-8',
|
||
escape: true,
|
||
style: {
|
||
color: '#03A9F4',
|
||
'font-size': '30px',
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
## `moreVideoAttr`
|
||
|
||
- Type: `Object`
|
||
- Default: `{'controls': false, 'preload': 'metadata'}` (In Safari, it will automatically adjust to `preload: 'auto'` for better loading experience.)
|
||
|
||
More video attributes. These attributes will be written directly into the video element.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
moreVideoAttr: {
|
||
'webkit-playsinline': true,
|
||
playsInline: true,
|
||
},
|
||
});
|
||
|
||
```
|
||
|
||
## `icons`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Used to replace default icons. Supports `Html` strings and `HTMLElement`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-7}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
icons: {
|
||
loading: '<img src="/assets/img/ploading.gif">',
|
||
state: '<img src="/assets/img/state.png">',
|
||
},
|
||
});
|
||
```
|
||
|
||
:::warning All Icon Definitions
|
||
|
||
[artplayer/types/icons.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/icons.d.ts)
|
||
|
||
:::
|
||
|
||
## `type`
|
||
|
||
- Type: `String`
|
||
- Default: `''`
|
||
|
||
Used to specify the video format. It needs to be used together with `customType`. By default, the video format is determined by the suffix of the video URL (e.g., `.m3u8`, `.mkv`, `.ts`). However, sometimes the video URL may not have the correct suffix, so it needs to be explicitly specified.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.m3u8',
|
||
type: 'm3u8',
|
||
});
|
||
```
|
||
|
||
:::warning Suffix Recognition
|
||
|
||
The player can only parse suffixes like this: `/assets/sample/video.m3u8`
|
||
|
||
But cannot parse suffixes like this: `/assets/sample/video?type=m3u8`
|
||
|
||
Therefore, if you use `customType`, it's best to also specify the `type`.
|
||
|
||
:::
|
||
|
||
## `customType`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Matches based on the video's `type` and delegates video decoding to third-party programs for processing. The processing function can receive three parameters:
|
||
|
||
- `video`: The video `DOM` element
|
||
- `url`: The video URL
|
||
- `art`: The current instance
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-8}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.m3u8',
|
||
customType: {
|
||
m3u8: function (video, url, art) {
|
||
//
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
## `lang`
|
||
|
||
- Type: `String`
|
||
- Default: `navigator.language.toLowerCase()`
|
||
|
||
The default display language. Currently supported: `en`, `zh-cn`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lang: 'en',
|
||
});
|
||
```
|
||
|
||
:::warning More Language Settings
|
||
|
||
[/start/i18n.html](/start/i18n.html)
|
||
|
||
:::
|
||
|
||
## `i18n`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Custom `i18n` configuration. This configuration will be deeply merged with the built-in `i18n`.
|
||
|
||
Add your language:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-9}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lang: 'your-lang',
|
||
i18n: {
|
||
'your-lang': {
|
||
Play: 'Your Play'
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
Modify an existing language:
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-11}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
i18n: {
|
||
'zh-cn': {
|
||
Play: 'Your Play'
|
||
},
|
||
'zh-tw': {
|
||
Play: 'Your Play'
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
:::warning More Language Settings
|
||
|
||
[/start/i18n.html](/start/i18n.html)
|
||
|
||
:::
|
||
|
||
## `lock`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display a `lock button` on mobile devices to hide the bottom `control bar`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
lock: true,
|
||
});
|
||
```
|
||
|
||
## `gesture`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `true`
|
||
|
||
Whether to enable gesture events on the video element on mobile devices.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
gesture: false,
|
||
});
|
||
```
|
||
|
||
## `fastForward`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to add a long-press video fast-forward feature on mobile devices.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fastForward: true,
|
||
});
|
||
```
|
||
|
||
## `autoPlayback`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to use the automatic `playback feature`.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4-5}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
id: 'your-url-id',
|
||
autoPlayback: true,
|
||
});
|
||
```
|
||
|
||
:::warning Note
|
||
|
||
Because the player uses the `url` as the `key` to cache playback progress by default.
|
||
|
||
However, if the `url` for the same video is different, then you need to use `id` to identify the unique `key` for the video.
|
||
|
||
:::
|
||
|
||
## `autoOrientation`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to rotate the player in fullscreen mode on mobile web, based on the video dimensions and viewport dimensions.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoOrientation: true,
|
||
});
|
||
```
|
||
|
||
## `airplay`
|
||
|
||
- Type: `Boolean`
|
||
- Default: `false`
|
||
|
||
Whether to display the `airplay` button. Currently, only some browsers support this feature.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
airplay: true,
|
||
});
|
||
```
|
||
|
||
## `cssVar`
|
||
|
||
- Type: `Object`
|
||
- Default: `{}`
|
||
|
||
Used to modify the built-in CSS variables.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
cssVar: {
|
||
//
|
||
},
|
||
});
|
||
```
|
||
|
||
:::warning Reference for `cssVar` Syntax
|
||
|
||
[artplayer/types/cssVar.d.ts](https://github.com/zhw2590582/ArtPlayer/blob/master/packages/artplayer/types/cssVar.d.ts)
|
||
|
||
:::
|
||
|
||
## `proxy`
|
||
|
||
- Type: `function`
|
||
- Default: `undefined`
|
||
|
||
The function can return a third-party `HTMLCanvasElement` or `HTMLVideoElement`. For example, it can proxy an existing `video` DOM element.
|
||
|
||
<div className="run-code">▶ Run Code</div>
|
||
|
||
```js{4}
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
proxy: () => document.createElement('video')
|
||
});
|
||
```
|
||
|
||
===== packages/artplayer-vitepress/docs/en/tool/iframe.md =====
|
||
|
||
# Iframe communication tool
|
||
|
||
[简体中文](../../tool/iframe.md)
|
||
|
||
Control a player inside an iframe and receive child-page notifications. This is a standalone constructor, not an ArtPlayer plugins-array factory. This page describes the unreleased branch; deploy both parent and child pages yourself.
|
||
|
||
## Install and connect both pages
|
||
|
||
```sh
|
||
yarn add artplayer-tool-iframe
|
||
```
|
||
|
||
The parent uses `import ArtplayerToolIframe from 'artplayer-tool-iframe'`. For scripts, load `dist/artplayer-tool-iframe.js`; its global is `ArtplayerToolIframe`.
|
||
|
||
The child must also load the tool and call inject. To create a player there, load ArtPlayer and provide a container too. The repository's `/iframe.html` uses:
|
||
|
||
```html
|
||
<div class="artplayer-app" style="width:100%;height:100%"></div>
|
||
<script src="./uncompiled/artplayer/index.js"></script>
|
||
<script src="./uncompiled/artplayer-tool-iframe/index.js"></script>
|
||
<script>ArtplayerToolIframe.inject();</script>
|
||
```
|
||
|
||
These are this site's development paths; replace them with deployed build paths. The [original parent example](https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe) below creates an iframe pointing to `/iframe.html`:
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-tool-iframe/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
// npm i artplayer-tool-iframe
|
||
// import ArtplayerToolIframe from 'artplayer-tool-iframe';
|
||
|
||
const $iframe = document.createElement('iframe')
|
||
$iframe.allowFullscreen = true
|
||
$iframe.width = '100%'
|
||
$iframe.height = '100%'
|
||
|
||
const $container = document.querySelector('.artplayer-app')
|
||
$container.innerHTML = ''
|
||
$container.appendChild($iframe)
|
||
|
||
const iframe = new ArtplayerToolIframe({
|
||
iframe: $iframe,
|
||
url: '/iframe.html',
|
||
})
|
||
|
||
window.addEventListener('artplayer:example:cleanup', () => {
|
||
iframe.destroy()
|
||
$iframe.remove()
|
||
}, { once: true })
|
||
|
||
iframe.message(({ type, data }) => {
|
||
switch (type) {
|
||
case 'fullscreenWeb':
|
||
if (data) {
|
||
$iframe.classList.add('fullscreenWeb')
|
||
}
|
||
else {
|
||
$iframe.classList.remove('fullscreenWeb')
|
||
}
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
})
|
||
|
||
iframe.commit(() => {
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
})
|
||
|
||
art.on('fullscreenWeb', (state) => {
|
||
ArtplayerToolIframe.postMessage({
|
||
type: 'fullscreenWeb',
|
||
data: state,
|
||
})
|
||
})
|
||
}).catch((error) => {
|
||
if (!iframe.destroyed)
|
||
console.error(error)
|
||
})
|
||
```
|
||
|
||
## Parent instance
|
||
|
||
Both options are required: `{ iframe: HTMLIFrameElement, url: string }`. Construction sets iframe.src and subscribes to messages; it does not install scripts in the child. The caller creates and removes the iframe element.
|
||
|
||
| Member | Behavior |
|
||
| --- | --- |
|
||
| `commit(callback)` | Extract the function body and execute it in the child; returns a response Promise |
|
||
| `postMessage({ type, data, id? })` | Send a request and await its response; allocate a numeric id when sending, ignoring a supplied id |
|
||
| `message(callback)` | Set one notification callback; the next call replaces it; synchronous void |
|
||
| `onMessage(event)` | Parent receiver, normally invoked by the installed native message listener |
|
||
| `destroy()` | Synchronous and idempotent; remove owned listeners/navigation observation and reject sent/waiting requests |
|
||
| `url` / `$iframe` | Initial configured address and element; changing url alone does not navigate |
|
||
| `injected` / `destroyed` | Injection and destruction state |
|
||
| `promises` | Pending request object, retaining the historical `resove` and `reject` callback keys |
|
||
| `messageCallback` | Current callback; initially a function, also nullable at runtime |
|
||
|
||
Notifications receive only `{ type, data }`, with the tool as this, without id or private document metadata. Any matching non-error response settles its request; error responses reject with Error. Custom message types remain valid, but the application must implement their child responses. There is no default response timeout.
|
||
|
||
Before injection, requests poll every200ms; inject does not flush them synchronously. IDs are correlation numbers, not necessarily Date.now. Destruction rejects unfinished requests with `The instance has been destroyed`; handle Promise failures.
|
||
|
||
## How commit executes
|
||
|
||
A normal function body can return a structured-cloneable result. Asynchronous results use the historical literal `resolve(...)` convention:
|
||
|
||
```js
|
||
const title = await iframe.commit(() => {
|
||
return document.title; // Read in the child page.
|
||
});
|
||
const answer = await iframe.commit((resolve) => {
|
||
setTimeout(() => resolve(42), 100);
|
||
});
|
||
```
|
||
|
||
The body is sliced from a string and evaluated with new Function. Closures, parent locals, function arguments and imports are not transferred. Keep braces; do not use expression arrows, async function bodies, top-level await or a renamed asynchronous resolve parameter. Detection is a text match, not a JavaScript parser. Results must support postMessage; a Promise object itself cannot be sent as a normal result. Execution errors send an error response and also reject the child's receiver.
|
||
|
||
## Child statics and trust
|
||
|
||
| Member | Behavior |
|
||
| --- | --- |
|
||
| `ArtplayerToolIframe.iframe` | Runtime readonly getter: whether this page is inside an iframe |
|
||
| `inject()` | Announce injection and install the receiver; repeated calls retain one listener set |
|
||
| `postMessage({ type, data, id? })` | Send a parent notification/response; id defaults0; returns void |
|
||
| `onMessage(event)` | Actually async; handles commit, while custom types need application handling |
|
||
|
||
The three methods require an iframe context; top-level use throws or rejects. Receivers check the selected window peer and basic packet shape, retaining wildcard targetOrigin rather than pinning the initial URL's origin. Trust the parent and child content. Commit executes code and requires a compatible CSP; it is neither a sandbox nor a payload validator.
|
||
|
||
## Navigation, cleanup and types
|
||
|
||
Upgraded peers negotiate document markers to reject obsolete replies and cancel work when document departure is confirmed. These markers are not authentication credentials. A src replacement pauses sends; confirmed cross-document departure cancels old requests, while a matching same-document hash change preserves them. Work queued for the next page is tracked separately. Legacy children cannot identify same-address reloads or internal navigation reliably; ordinary navigation tests do not establish BFCache restoration.
|
||
|
||
Destroy does not remove the iframe, destroy its player or provide a new static child destroy method. The parent can remove its iframe after releasing the tool. Player events, fullscreen permissions and physical devices require actual integration checks.
|
||
|
||
Root and `/legacy` preserve the historical class, including required Message.data, readonly fields, void static onMessage and ReturnType-based commit inference. Import accurate erased views from the same entry; there is no `/runtime` subpath:
|
||
|
||
```ts
|
||
import Iframe from 'artplayer-tool-iframe';
|
||
import type { ResolverInstance, RuntimeConstructor } from 'artplayer-tool-iframe';
|
||
|
||
function connectFrame(element: HTMLIFrameElement) {
|
||
const Runtime = Iframe as RuntimeConstructor;
|
||
const tool = new Runtime({ iframe: element, url: '/iframe.html' }) as ResolverInstance;
|
||
tool.message(function (message) { console.log(this.url, message.type, message.data); });
|
||
const answer = tool.commit<number>((resolve) => { resolve(42); });
|
||
return { tool, answer };
|
||
}
|
||
```
|
||
|
||
Public types are Option, Message, Callbacks, Notification, MessageCallback, OutboundMessage, ProtocolMessage, Resolve, ResolverCallback, RuntimeInstance, ResolverInstance and RuntimeConstructor. Views neither validate responses nor alter execution. Modern CommonJS TS can use `import Iframe = require('artplayer-tool-iframe')`; ESM uses the default import. The constructor has no `.default` self-alias. The old `artplayer-plugin-iframe` name, namespace and separate helper are not identical to this tool; renaming the dependency alone does not preserve every old entrypoint.
|
||
|
||
|
||
===== packages/artplayer-vitepress/docs/en/tool/thumbnail.md =====
|
||
|
||
# Local video thumbnail tool
|
||
|
||
[简体中文](../../tool/thumbnail.md)
|
||
|
||
Generate a PNG thumbnail sheet from a selected local video, then download it or use it with the player's thumbnails option. This is a standalone constructor, not the Auto Thumbnail plugin. This page describes the unreleased branch and its approved compatibility modes.
|
||
|
||
## Install and example
|
||
|
||
```sh
|
||
yarn add artplayer-tool-thumbnail
|
||
```
|
||
|
||
ESM uses `import ArtplayerToolThumbnail from 'artplayer-tool-thumbnail'`. Scripts load `dist/artplayer-tool-thumbnail.js`, exposing `ArtplayerToolThumbnail`. The tool does not depend on the player; the [original example](https://artplayer.org/?libs=./uncompiled/artplayer-tool-thumbnail/index.js&example=tool.thumbnail) below uses this site's DOM and ArtPlayer to display the result:
|
||
|
||
<div className="run-code" data-libs="./uncompiled/artplayer-tool-thumbnail/index.js">▶ Run Code</div>
|
||
|
||
```js
|
||
if (window.lastThumbnail) {
|
||
window.lastThumbnail.destroy();
|
||
}
|
||
|
||
var $popups = document.querySelector('.popups');
|
||
var $popinner = document.querySelector('.popinner');
|
||
var $artplayer = document.querySelector('.artplayer-app');
|
||
|
||
$artplayer.innerHTML = 'Drop video file here or click to upload.';
|
||
var thumbnail = new ArtplayerToolThumbnail({
|
||
fileInput: $artplayer,
|
||
number: 60, // 数量
|
||
width: 160, // 宽度
|
||
column: 10, // 列数
|
||
begin: 0, // 开始
|
||
end: NaN, // 结束
|
||
});
|
||
|
||
window.lastThumbnail = thumbnail;
|
||
|
||
thumbnail.on('file', function (file) {
|
||
console.log('Read video successfully: ' + file.name);
|
||
});
|
||
|
||
thumbnail.on('video', function (video) {
|
||
console.log('Video size: ' + video.videoWidth + ' x ' + video.videoHeight);
|
||
console.log('Video duration: ' + video.duration + 's');
|
||
thumbnail.start();
|
||
});
|
||
|
||
thumbnail.on('canvas', function (canvas) {
|
||
console.log('Build canvas successfully');
|
||
console.log('Canvas size: ' + canvas.width + ' x ' + canvas.height);
|
||
console.log('Preview density: ' + thumbnail.density + ' p/s');
|
||
});
|
||
|
||
thumbnail.on('update', function (url, percentage) {
|
||
console.log('Processing: ' + Math.floor(percentage.toFixed(2) * 100) + '%');
|
||
$popups.style.display = 'flex';
|
||
$popinner.style.backgroundImage = 'url(' + url + ')';
|
||
});
|
||
|
||
thumbnail.on('download', function (name) {
|
||
console.log('Start download preview: ' + name);
|
||
});
|
||
|
||
thumbnail.on('done', function () {
|
||
$popups.style.display = 'none';
|
||
thumbnail.download();
|
||
console.log('Build preview image complete');
|
||
|
||
[...Artplayer.instances].forEach(function (art) {
|
||
art.destroy(true);
|
||
});
|
||
|
||
new Artplayer({
|
||
container: $artplayer,
|
||
url: thumbnail.videoUrl,
|
||
autoSize: true,
|
||
poster: thumbnail.thumbnailUrl,
|
||
thumbnails: {
|
||
url: thumbnail.thumbnailUrl,
|
||
number: thumbnail.option.number,
|
||
column: thumbnail.option.column,
|
||
},
|
||
});
|
||
|
||
console.log('Build player complete');
|
||
});
|
||
```
|
||
|
||
File selection loads the video without automatically extracting images; the example calls start from the video event. Application code should handle both synchronous start errors and Promise rejection. The video notification does not guarantee metadata readiness; start waits for it. Subscribe before loading, especially with synchronous workspace-mode notifications.
|
||
|
||
## Options and defaults
|
||
|
||
Successful construction needs fileInput: an existing file input or an Element upload wrapper. Missing input throws synchronously even though the type allows omitted constructor options. A wrapper receives an owned transparent input; caller inputs remain caller-owned. Selection/drop reads only the first file.
|
||
|
||
| Field | Default | Meaning |
|
||
| --- | --- | --- |
|
||
| `fileInput` | Required for construction | File input or upload wrapper |
|
||
| `compatibility` | published-3.5 behavior | Alternatively choose `workspace-4.4` |
|
||
| `number` | `60` | Frame count, numerically clamped to10–1000 |
|
||
| `width` | `160` | Frame width, clamped to10–1000 |
|
||
| `height` | `90` | Fixed default-mode height, clamped to10–1000 |
|
||
| `column` | `10` | Columns, clamped to1–1000 |
|
||
| `begin` | `0` | Start time in seconds |
|
||
| `end` | `NaN` | End time in seconds; NaN/0 uses media duration |
|
||
| `delay` | `300` | Default-mode milliseconds, clamped to10–1000 |
|
||
|
||
Use valid finite dimensions and integer counts/columns; historical numeric checks are not integer validation. Start normalizes the interval against media duration and requires end greater than begin, finite duration and `number / intervalSeconds <= 1`. The default60 frames therefore needs an interval of at least60 seconds; change the count for shorter files.
|
||
|
||
| Behavior | Default / published-3.5 | workspace-4.4 |
|
||
| --- | --- | --- |
|
||
| Height | Keep configured height | Derive from video aspect ratio at start and update option.height |
|
||
| video event | After src assignment plus delay | Synchronously after src assignment |
|
||
| Frame wait | Policy delay after each seek plus frame readiness | Frame readiness without a fixed extra delay |
|
||
| done | Another delay × 2 after the last update | No fixed final wait |
|
||
| Input value | Retained | Cleared after reading the selected file |
|
||
|
||
Consumers of unpublished4.4 workspace behavior add `compatibility: 'workspace-4.4'`; this mode ignores delay. Static DEFAULTS returns a fresh default object including published delay on every access, regardless of instance mode. Browser scheduling means delays are not exact timestamps.
|
||
|
||
## Methods, state and output
|
||
|
||
| Method | Behavior |
|
||
| --- | --- |
|
||
| `setup(options?)` | Merge partial options, retain extra fields and transfer input listeners when needed; returns this |
|
||
| `loadVideo(file?)` | Accept File; absent input is a no-op; check canPlayType and create a Blob URL |
|
||
| `start()` | One extraction job returning `Promise<void>`; duplicates and ready-metadata preflight can throw synchronously |
|
||
| `creatScreenshotDate()` | Historical spelling; return `{ time, x, y }[]`, with time in seconds |
|
||
| `creatCanvas()` | Historical spelling; create the sheet with black background and footer text |
|
||
| `download()` | Trigger PNG download when idle with file/image available; returns this, throws if not ready |
|
||
| `inputChange(event)` / `ondrop(event)` | Bound input handlers, normally installed by the tool |
|
||
| `errorHandle(condition, message)` | Emit error and throw when the condition fails |
|
||
| `destroy()` | Synchronous, idempotent cancellation and owned-resource cleanup |
|
||
|
||
Static creatVideo creates an offscreen muted/controls video in the document; callers invoking it directly own that extra node. Static ondragover calls preventDefault. Historical creat* names remain unchanged.
|
||
|
||
Fields include processing, option, video, duration, density, file, videoUrl, thumbnailUrl and optional event registry e. Duration is the selected interval, not necessarily full media duration; density is frames per interval second. File/URLs/density may be absent before their operation. Canvas listeners observe processing=false, update listeners true, and done listeners false.
|
||
|
||
Frames sample interval midpoints: `begin + (i + 0.5) * duration / number`. Sheet width is width × column; height is ceil(number / column) × height + 30. The30px footer retains source/layout text. Fractional coordinates keep historical behavior. Each frame produces a PNG update; previous thumbnail Blob URLs are revoked, leaving the latest thumbnailUrl. Download naming removes the last extension segment and adds `.png`; extensionless names retain the historical `.png` result.
|
||
|
||
## Events and cleanup
|
||
|
||
on/once/emit/off return this. The third on/once argument sets callback this. off(name) removes all listeners for that event; off(name, callback) removes matches. Custom string, number and symbol events are supported. A listener exception stops the remaining callbacks in that dispatch.
|
||
|
||
| Event | Arguments and timing |
|
||
| --- | --- |
|
||
| `file` | File, synchronously before video.src assignment |
|
||
| `video` | HTMLVideoElement; timing depends on mode |
|
||
| `canvas` | HTMLCanvasElement before extraction |
|
||
| `update` | Latest URL and0–1 progress |
|
||
| `done` | No arguments, before the start Promise resolves |
|
||
| `download` | Filename after link click; not proof of completed disk writing |
|
||
| `error` | Usually a message string; user callback failures can carry other values |
|
||
| `destroy` | No arguments, once after resource cleanup |
|
||
|
||
Start can wait for the first file selection with no new metadata deadline. Replacing an existing source or destroying the instance rejects old work with AbortError without an error event for cancellation. Source, seek, draw, encoding and callback failures settle the job. Stale callbacks cannot update a newer result.
|
||
|
||
Destroy removes the owned video/generated input/listeners/Blob URLs and restores wrapper position if the tool still owns that write. Caller inputs and the emitter registry remain. Cleanup attempts all steps, then throws its first failure. Destroyed instances cannot recreate input/source resources; start rejects cancellation. Keep the tool alive while a player depends on videoUrl/thumbnailUrl: those URLs remain tool-owned.
|
||
|
||
MIME canPlayType, actual decoding, Canvas encoding and Blob URL support are separate conditions. Windows WebKit has a recorded native Blob-loading gap; successful guide navigation or HTTP video playback is not proof of local-file extraction.
|
||
|
||
## TypeScript
|
||
|
||
Root and `/legacy` share one class declaration, with no `/runtime` or runtime `.default` self-alias. CommonJS TS supports `import Thumbnail = require('artplayer-tool-thumbnail')`; ESM uses default/type imports:
|
||
|
||
```ts
|
||
import Thumbnail, { type Option } from 'artplayer-tool-thumbnail';
|
||
|
||
function createTool(input: HTMLInputElement) {
|
||
const options: Option = { fileInput: input, number: 10, height: 90 };
|
||
const tool = new Thumbnail(options);
|
||
tool.on('update', (url, progress) => console.log(url, progress));
|
||
tool.on('video', () => {
|
||
void (async () => {
|
||
try { await tool.start(); }
|
||
catch (error) { console.error(error); }
|
||
})();
|
||
});
|
||
return tool;
|
||
}
|
||
```
|
||
|
||
Types include SheetOptions, Compatibility, DefaultOptions, Option, ResolvedOption, ScreenshotPoint, Events, EventArgs, Listener and EventRegistry. Known events have precise arguments; custom protocols remain application-defined. The old workspace referenced a missing declaration, so the new types are not claimed as a recovered historical TS baseline. Missing complete old npm archives and rollback acceptance remain separately tracked.
|
||
|
||
|
||
===== Type Definitions Overview =====
|
||
|
||
===== docs/assets/ts/artplayer-plugin-ads.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginAds {
|
||
interface Translations {
|
||
close: string
|
||
countdown: string
|
||
detail: string
|
||
canBeClosed: string
|
||
}
|
||
/** Implemented options. Video takes precedence over HTML. */
|
||
interface Option {
|
||
html?: string
|
||
video?: string
|
||
url?: string
|
||
/** Seconds before the close button becomes available. @default 5 */
|
||
playDuration?: number
|
||
/** Total advertisement duration in seconds. @default 10 */
|
||
totalDuration?: number
|
||
/** Initial ad-video mute state. @default false */
|
||
muted?: boolean
|
||
/** All four fields replace the default translation object together. */
|
||
i18n?: Translations
|
||
}
|
||
/** Historical published declaration. String durations still fail runtime validation. */
|
||
interface LegacyOption extends Omit<Option, 'totalDuration'> {
|
||
/** @deprecated Incorrect in the old declaration; use a numeric duration. */
|
||
totalDuration?: string
|
||
}
|
||
/** Historical unpublished workspace declaration; these fields are not runtime aliases. */
|
||
interface WorkspaceOption extends Option {
|
||
/** @deprecated Ignored by the runtime. Use html or video instead. */
|
||
source: string
|
||
/** @deprecated Ignored by the runtime. Images are supplied through html. */
|
||
type: 'video' | 'image' | 'html'
|
||
}
|
||
/** Input acceptance for both historical declaration families. */
|
||
interface CompatOption extends Omit<Option, 'totalDuration'> {
|
||
/** @deprecated The string branch exists for old types only and is rejected at runtime. */
|
||
totalDuration?: number | string
|
||
/** @deprecated Ignored by the runtime. Use html or video instead. */
|
||
source?: string
|
||
/** @deprecated Ignored by the runtime. Images are supplied through html. */
|
||
type?: 'video' | 'image' | 'html'
|
||
}
|
||
interface Result {
|
||
name: 'artplayerPluginAds'
|
||
/** Complete once; before initialization this cancels the pending preroll. */
|
||
skip: () => void
|
||
/** Pause only the countdown, leaving ad video playback unchanged. */
|
||
pause: () => void
|
||
/** Resume only the countdown without adding extra timers. */
|
||
play: () => void
|
||
}
|
||
interface Callable {
|
||
(option?: Option): (art: Artplayer) => Result
|
||
/** @deprecated Compatibility with erroneous old string-duration declarations only. */
|
||
(option: LegacyOption): (art: Artplayer) => Result
|
||
(option: WorkspaceOption): (art: Artplayer) => Result
|
||
(option?: CompatOption): (art: Artplayer) => Result
|
||
/** Required final signature keeps Parameters extraction free of top-level undefined. */
|
||
(option: CompatOption): (art: Artplayer) => Result
|
||
}
|
||
interface Factory extends Callable {
|
||
/** Same function; supports historical require(package).default calls. */
|
||
readonly default: Callable
|
||
}
|
||
interface RuntimeCallable {
|
||
(option?: Option): (art: Artplayer) => Result
|
||
(option: Option): (art: Artplayer) => Result
|
||
}
|
||
/** Accurate typing for the identical implementation at /runtime. */
|
||
interface RuntimeFactory extends RuntimeCallable {
|
||
readonly default: RuntimeCallable
|
||
}
|
||
}
|
||
declare const artplayerPluginAds: artplayerPluginAds.Factory
|
||
export = artplayerPluginAds
|
||
export as namespace artplayerPluginAds;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-ambilight.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginAmbilightDefinitions {
|
||
export interface Option {
|
||
/** CSS blur radius. @default '50px' */
|
||
blur?: string
|
||
/** Grid cell opacity. @default 0.5 */
|
||
opacity?: number
|
||
/** Maximum sampling frequency in frames per second. @default 10 */
|
||
frequency?: number
|
||
/** Historical input retained for compatibility; runtime uses a fixed z-index of 9. */
|
||
zIndex?: number
|
||
/** Background color transition duration in seconds. @default 0.3 */
|
||
duration?: number
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginAmbilight'
|
||
/** Start sampling; does nothing after the player is destroyed. */
|
||
start: () => void
|
||
/** Stop sampling while retaining the last colors. */
|
||
stop: () => void
|
||
}
|
||
/** Published 1.1.0 factory shape; the options argument remains required. */
|
||
export type Callable = (option: Option) => (art: Artplayer) => Result
|
||
export type Factory = Callable
|
||
/** Accurate optional invocation and CommonJS self alias, exposed by /runtime. */
|
||
export interface RuntimeFactory {
|
||
(option?: Option): (art: Artplayer) => Result
|
||
readonly default: RuntimeFactory
|
||
}
|
||
export const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginAmbilight: typeof artplayerPluginAmbilightDefinitions.artplayerPluginAmbilight
|
||
declare namespace artplayerPluginAmbilight {
|
||
export type Option = artplayerPluginAmbilightDefinitions.Option
|
||
export type Result = artplayerPluginAmbilightDefinitions.Result
|
||
export type Callable = artplayerPluginAmbilightDefinitions.Callable
|
||
export type Factory = artplayerPluginAmbilightDefinitions.Factory
|
||
export type RuntimeFactory = artplayerPluginAmbilightDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginAmbilight
|
||
export as namespace artplayerPluginAmbilight;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-asr.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginAsrDefinitions {
|
||
export interface AudioChunk {
|
||
pcm: ArrayBuffer
|
||
wav: ArrayBuffer
|
||
}
|
||
export interface AsrPluginOption {
|
||
length?: number
|
||
interval?: number
|
||
sampleRate?: number
|
||
autoHideTimeout?: number
|
||
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
|
||
}
|
||
export interface AsrPluginInstance {
|
||
name: 'artplayerPluginAsr'
|
||
stop: () => void
|
||
hide: () => void
|
||
append: (subtitle: string) => void
|
||
}
|
||
/** Historical factory shape, including void stop and callback results. */
|
||
export type Factory = (option?: AsrPluginOption) => (art: Artplayer) => AsrPluginInstance
|
||
/** Accurate asynchronous view available through the /runtime entry. */
|
||
export interface RuntimeOption extends Omit<AsrPluginOption, 'onAudioChunk'> {
|
||
/** Capture the media stream without taking ownership of its playback route. */
|
||
audioInput?: {
|
||
type: 'capture'
|
||
}
|
||
onAudioChunk?: (chunk: AudioChunk) => string | void | null | Promise<string | void | null>
|
||
}
|
||
export interface RuntimeResult extends Omit<AsrPluginInstance, 'stop'> {
|
||
stop: () => Promise<void>
|
||
}
|
||
export interface RuntimeFactory {
|
||
(option?: RuntimeOption): (art: Artplayer) => RuntimeResult
|
||
readonly default: RuntimeFactory
|
||
}
|
||
export function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
|
||
}
|
||
declare const artplayerPluginAsr: typeof artplayerPluginAsrDefinitions.artplayerPluginAsr
|
||
declare namespace artplayerPluginAsr {
|
||
export type AudioChunk = artplayerPluginAsrDefinitions.AudioChunk
|
||
export type AsrPluginOption = artplayerPluginAsrDefinitions.AsrPluginOption
|
||
export type AsrPluginInstance = artplayerPluginAsrDefinitions.AsrPluginInstance
|
||
export type Factory = artplayerPluginAsrDefinitions.Factory
|
||
export type RuntimeOption = artplayerPluginAsrDefinitions.RuntimeOption
|
||
export type RuntimeResult = artplayerPluginAsrDefinitions.RuntimeResult
|
||
export type RuntimeFactory = artplayerPluginAsrDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginAsr
|
||
export as namespace artplayerPluginAsr;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-audio-track.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginAudioTrackDefinitions {
|
||
export interface Option {
|
||
/**
|
||
* Audio track URL
|
||
*/
|
||
url: string
|
||
/**
|
||
* Time offset in seconds between video and audio
|
||
* Positive value means audio plays ahead of video
|
||
* Negative value means audio plays behind video
|
||
* @default 0
|
||
*/
|
||
offset?: number
|
||
/**
|
||
* Synchronization threshold in seconds
|
||
* @default 0.3
|
||
*/
|
||
sync?: number
|
||
}
|
||
export type UpdateOption = Partial<Option>
|
||
export interface Result {
|
||
name: 'artplayerPluginAudioTrack'
|
||
/**
|
||
* The audio element
|
||
*/
|
||
audio: HTMLAudioElement
|
||
/**
|
||
* Historical update signature. Runtime also accepts partial options.
|
||
* Import the /runtime entry for the precise partial-update signature.
|
||
*/
|
||
update: (option: Option) => void
|
||
}
|
||
export interface RuntimeResult extends Result {
|
||
/** Update selected fields without replacing the audio element. */
|
||
update: (option: UpdateOption) => void
|
||
}
|
||
/** Precise typing for the same runtime factory, without changing legacy inference. */
|
||
export type RuntimeFactory = (option: Option) => (art: Artplayer) => RuntimeResult
|
||
export function artplayerPluginAudioTrack(option: Option): (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginAudioTrack: typeof artplayerPluginAudioTrackDefinitions.artplayerPluginAudioTrack
|
||
declare namespace artplayerPluginAudioTrack {
|
||
export type Option = artplayerPluginAudioTrackDefinitions.Option
|
||
export type UpdateOption = artplayerPluginAudioTrackDefinitions.UpdateOption
|
||
export type Result = artplayerPluginAudioTrackDefinitions.Result
|
||
export type RuntimeResult = artplayerPluginAudioTrackDefinitions.RuntimeResult
|
||
export type RuntimeFactory = artplayerPluginAudioTrackDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginAudioTrack
|
||
export as namespace artplayerPluginAudioTrack;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginAutoThumbnailDefinitions {
|
||
export interface Option {
|
||
url?: string
|
||
width?: number
|
||
number?: number
|
||
scale?: number
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginAutoThumbnail'
|
||
}
|
||
export const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginAutoThumbnail: typeof artplayerPluginAutoThumbnailDefinitions.artplayerPluginAutoThumbnail
|
||
declare namespace artplayerPluginAutoThumbnail { }
|
||
export = artplayerPluginAutoThumbnail
|
||
export as namespace artplayerPluginAutoThumbnail;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-chapter.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginChapterDefinitions {
|
||
export type Chapters = {
|
||
start: number
|
||
end: number
|
||
title: string
|
||
}[]
|
||
export interface Option {
|
||
chapters?: Chapters
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginChapter'
|
||
update: (option: Option) => void
|
||
}
|
||
export const artplayerPluginChapter: (option?: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginChapter: typeof artplayerPluginChapterDefinitions.artplayerPluginChapter
|
||
declare namespace artplayerPluginChapter {
|
||
export type Chapters = artplayerPluginChapterDefinitions.Chapters
|
||
export type Option = artplayerPluginChapterDefinitions.Option
|
||
export type Result = artplayerPluginChapterDefinitions.Result
|
||
}
|
||
export = artplayerPluginChapter
|
||
export as namespace artplayerPluginChapter;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-chromecast.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginChromecastDefinitions {
|
||
export interface Option {
|
||
url?: string
|
||
sdk?: string
|
||
icon?: string
|
||
mimeType?: string
|
||
}
|
||
export interface Chromecast {
|
||
name: 'artplayerPluginChromecast'
|
||
}
|
||
/** Published 1.1.0 result; actual registration is asynchronous. */
|
||
export type Result = Chromecast
|
||
export type Factory = (option: Option) => (art: Artplayer) => Chromecast
|
||
export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'disconnecting'
|
||
export interface RuntimeOption extends Option {
|
||
onStateChange?: (this: RuntimeOption, state: ConnectionState) => void
|
||
onCastAvailable?: (this: RuntimeOption, available: boolean) => void
|
||
onCastStart?: (this: RuntimeOption) => void
|
||
onError?: (this: RuntimeOption, error: unknown) => void
|
||
}
|
||
export interface RuntimeResult extends Chromecast {
|
||
/** Last raw SDK SessionState, initially null; not the normalized callback state. */
|
||
getCastState: () => string | null
|
||
/** Whether this controller retains a session; does not prove receiver playback. */
|
||
isCasting: () => boolean
|
||
}
|
||
export interface RuntimeFactory {
|
||
(option: RuntimeOption): (art: Artplayer) => Promise<RuntimeResult>
|
||
default: RuntimeFactory
|
||
}
|
||
export const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
|
||
}
|
||
declare const artplayerPluginChromecast: typeof artplayerPluginChromecastDefinitions.artplayerPluginChromecast
|
||
declare namespace artplayerPluginChromecast {
|
||
export type Option = artplayerPluginChromecastDefinitions.Option
|
||
export type Chromecast = artplayerPluginChromecastDefinitions.Chromecast
|
||
export type Result = artplayerPluginChromecastDefinitions.Result
|
||
export type Factory = artplayerPluginChromecastDefinitions.Factory
|
||
export type ConnectionState = artplayerPluginChromecastDefinitions.ConnectionState
|
||
export type RuntimeOption = artplayerPluginChromecastDefinitions.RuntimeOption
|
||
export type RuntimeResult = artplayerPluginChromecastDefinitions.RuntimeResult
|
||
export type RuntimeFactory = artplayerPluginChromecastDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginChromecast
|
||
export as namespace artplayerPluginChromecast;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginDanmukuMaskDefinitions {
|
||
export interface Option {
|
||
solutionPath?: string
|
||
modelSelection?: number
|
||
smoothSegmentation?: boolean
|
||
minDetectionConfidence?: number
|
||
minTrackingConfidence?: number
|
||
selfieMode?: boolean
|
||
drawContour?: boolean
|
||
foregroundThreshold?: number
|
||
opacity?: number
|
||
maskBlurAmount?: number
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginDanmukuMask'
|
||
start: () => Promise<void>
|
||
stop: () => void
|
||
}
|
||
export const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginDanmukuMask: typeof artplayerPluginDanmukuMaskDefinitions.artplayerPluginDanmukuMask
|
||
declare namespace artplayerPluginDanmukuMask { }
|
||
export = artplayerPluginDanmukuMask
|
||
export as namespace artplayerPluginDanmukuMask;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-danmuku.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginDanmukuDefinitions {
|
||
export type Mode = 0 | 1 | 2
|
||
export type Danmuku = Danmu[] | string // URL
|
||
| (() => Promise<Danmu[]>) | Promise<Danmu[]>
|
||
export interface Slider {
|
||
min?: number
|
||
max?: number
|
||
steps?: {
|
||
name?: string
|
||
value?: number | string
|
||
show?: boolean
|
||
}[]
|
||
}
|
||
export interface Danmu {
|
||
/**
|
||
* 弹幕文本
|
||
*/
|
||
text: string
|
||
/**
|
||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||
*/
|
||
mode?: Mode
|
||
/**
|
||
* 弹幕颜色
|
||
*/
|
||
color?: string
|
||
/**
|
||
* 弹幕出现的时间,单位为秒
|
||
*/
|
||
time?: number
|
||
/**
|
||
* 弹幕是否有描边, 默认为 false
|
||
*/
|
||
border?: boolean
|
||
/**
|
||
* 弹幕自定义样式
|
||
*/
|
||
style?: Partial<CSSStyleDeclaration>
|
||
}
|
||
export interface Option {
|
||
/**
|
||
* 弹幕数据: 函数,数组,Promise,URL
|
||
*/
|
||
danmuku: Danmuku
|
||
/**
|
||
* 弹幕持续时间,范围在[1 ~ 10]
|
||
*/
|
||
speed?: number
|
||
/**
|
||
* 弹幕上下边距,支持像素数字和百分比
|
||
*/
|
||
margin?: [
|
||
number | `${number}%`,
|
||
number | `${number}%`,
|
||
]
|
||
/**
|
||
* 弹幕透明度,范围在[0 ~ 1]
|
||
*/
|
||
opacity?: number
|
||
/**
|
||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||
*/
|
||
color?: string
|
||
/**
|
||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||
*/
|
||
mode?: Mode
|
||
/**
|
||
* 弹幕可见的模式
|
||
*/
|
||
modes?: Mode[]
|
||
/**
|
||
* 弹幕字体大小,支持像素数字和百分比
|
||
*/
|
||
fontSize?: number | `${number}%`
|
||
/**
|
||
* 弹幕是否防重叠
|
||
*/
|
||
antiOverlap?: boolean
|
||
/**
|
||
* 是否同步播放速度
|
||
*/
|
||
synchronousPlayback?: boolean
|
||
/**
|
||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||
*/
|
||
mount?: HTMLDivElement | string
|
||
/**
|
||
* 是否开启弹幕热度图
|
||
*/
|
||
heatmap?: boolean | {
|
||
xMin?: number
|
||
xMax?: number
|
||
yMin?: number
|
||
yMax?: number
|
||
scale?: number
|
||
opacity?: number
|
||
minHeight?: number
|
||
sampling?: number
|
||
smoothing?: number
|
||
flattening?: number
|
||
}
|
||
/**
|
||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||
*/
|
||
width?: number
|
||
/**
|
||
* 热力图数据
|
||
*/
|
||
points?: {
|
||
time: number
|
||
value: number
|
||
}[]
|
||
/**
|
||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||
*/
|
||
filter?: (danmu: Danmu) => boolean
|
||
/**
|
||
* 弹幕发送前的过滤器,支持返回 Promise
|
||
*/
|
||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||
/**
|
||
* 弹幕显示前的过滤器,支持返回 Promise
|
||
*/
|
||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||
/**
|
||
* 弹幕是否可见
|
||
*/
|
||
visible?: boolean
|
||
/**
|
||
* 是否开启弹幕发射器
|
||
*/
|
||
emitter?: boolean
|
||
/**
|
||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||
*/
|
||
maxLength?: number
|
||
/**
|
||
* 输入框锁定时间,范围在[1 ~ 60]
|
||
*/
|
||
lockTime?: number
|
||
/**
|
||
* 弹幕主题,只在自定义挂载时生效
|
||
*/
|
||
theme?: 'light' | 'dark'
|
||
/**
|
||
* 不透明度配置项
|
||
*/
|
||
OPACITY?: Slider
|
||
/**
|
||
* 弹幕速度配置项
|
||
*/
|
||
SPEED?: Slider
|
||
/**
|
||
* 显示区域配置项
|
||
*/
|
||
MARGIN?: Slider
|
||
/**
|
||
* 弹幕字号配置项
|
||
*/
|
||
FONT_SIZE?: Slider
|
||
/**
|
||
* 颜色列表配置项
|
||
*/
|
||
COLOR?: string[]
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginDanmuku'
|
||
/**
|
||
* 发送一条实时弹幕
|
||
*/
|
||
emit: (danmu: Danmu) => Result
|
||
/**
|
||
* 重载弹幕源,或者切换新弹幕
|
||
*/
|
||
load: (danmuku?: Danmuku) => Promise<Result>
|
||
/**
|
||
* 实时改变弹幕配置
|
||
*/
|
||
config: (option: Option) => Result
|
||
/**
|
||
* 隐藏弹幕层
|
||
*/
|
||
hide: () => Result
|
||
/**
|
||
* 显示弹幕层
|
||
*/
|
||
show: () => Result
|
||
/**
|
||
* 挂载弹幕输入框
|
||
*/
|
||
mount: (el?: HTMLDivElement | string) => void
|
||
/**
|
||
* 重置弹幕
|
||
*/
|
||
reset: () => Result
|
||
/**
|
||
* 弹幕配置
|
||
*/
|
||
option: Option
|
||
/**
|
||
* 是否隐藏弹幕层
|
||
*/
|
||
isHide: boolean
|
||
/**
|
||
* 是否弹幕层停止状态
|
||
*/
|
||
isStop: boolean
|
||
}
|
||
export const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginDanmuku: typeof artplayerPluginDanmukuDefinitions.artplayerPluginDanmuku
|
||
declare namespace artplayerPluginDanmuku {
|
||
export type Mode = artplayerPluginDanmukuDefinitions.Mode
|
||
export type Danmuku = artplayerPluginDanmukuDefinitions.Danmuku
|
||
export type Slider = artplayerPluginDanmukuDefinitions.Slider
|
||
export type Danmu = artplayerPluginDanmukuDefinitions.Danmu
|
||
export type Option = artplayerPluginDanmukuDefinitions.Option
|
||
export type Result = artplayerPluginDanmukuDefinitions.Result
|
||
}
|
||
export = artplayerPluginDanmuku
|
||
export as namespace artplayerPluginDanmuku;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-dash-control.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginDashControlDefinitions {
|
||
export interface QualityLevel {
|
||
height: number
|
||
width?: number
|
||
id?: string | number
|
||
qualityIndex?: number
|
||
bitrate?: number
|
||
bitrateInKbit?: number
|
||
}
|
||
export interface AudioTrack {
|
||
id?: string | number | null
|
||
index?: number | null
|
||
lang?: string | null
|
||
}
|
||
export interface Config<Item extends object = object> {
|
||
control?: boolean
|
||
setting?: boolean
|
||
title?: string
|
||
auto?: string
|
||
/** Called without a receiver or index, with the original SDK object. */
|
||
getName?: (item: Item) => string
|
||
}
|
||
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
|
||
quality?: Config<Level>
|
||
audio?: Config<Track>
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginDashControl'
|
||
update: () => void
|
||
}
|
||
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||
// Preserve the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||
export function artplayerPluginDashControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginDashControl: typeof artplayerPluginDashControlDefinitions.artplayerPluginDashControl
|
||
declare namespace artplayerPluginDashControl {
|
||
export type QualityLevel = artplayerPluginDashControlDefinitions.QualityLevel
|
||
export type AudioTrack = artplayerPluginDashControlDefinitions.AudioTrack
|
||
export type Config<Item extends object = object> = artplayerPluginDashControlDefinitions.Config<Item>
|
||
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginDashControlDefinitions.Option<Level, Track>
|
||
export type Result = artplayerPluginDashControlDefinitions.Result
|
||
}
|
||
export = artplayerPluginDashControl
|
||
export as namespace artplayerPluginDashControl;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-document-pip.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginDocumentPipDefinitions {
|
||
export interface Option {
|
||
/** Requested window width. @default 480 */
|
||
width?: number
|
||
/** Requested window height. @default 270 */
|
||
height?: number
|
||
/** Text displayed in the original player container while the window is active. */
|
||
placeholder?: string
|
||
/** Use the core video PiP property when Document PiP is unavailable. @default true */
|
||
fallbackToVideoPiP?: boolean
|
||
}
|
||
/** Historical assignable result; preserved for direct and extracted return types. */
|
||
export interface Result {
|
||
name: 'artplayerPluginDocumentPip'
|
||
/** Runtime is a readonly capability snapshot; the published field stays assignable. */
|
||
isSupported: boolean
|
||
/** Runtime is a readonly live getter; the published field stays assignable. */
|
||
isActive: boolean
|
||
/** Runtime returns Promise<void>; the published void action remains assignable here. */
|
||
open: () => void
|
||
/** Runtime returns Promise<void>; the published void action remains assignable here. */
|
||
close: () => void
|
||
toggle: () => void
|
||
}
|
||
/** Exact view of an unmodified runtime result. */
|
||
export interface AsyncResult extends Omit<Result, 'isSupported' | 'isActive' | 'open' | 'close'> {
|
||
readonly isSupported: boolean
|
||
readonly isActive: boolean
|
||
open: () => Promise<void>
|
||
close: () => Promise<void>
|
||
}
|
||
/** Exact published factory signature, including compatibility with replacement functions. */
|
||
export type Factory = (option: Option) => (art: Artplayer) => Result
|
||
/** Opt-in runtime view with omitted options, self default and precise async actions. */
|
||
export interface RuntimeFactory {
|
||
(option?: Option): (art: Artplayer) => AsyncResult
|
||
readonly default: RuntimeFactory
|
||
}
|
||
/** Keep the published callable type; use RuntimeFactory explicitly for its broader runtime shape. */
|
||
export function artplayerPluginDocumentPip(option: Option): (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginDocumentPip: typeof artplayerPluginDocumentPipDefinitions.artplayerPluginDocumentPip
|
||
declare namespace artplayerPluginDocumentPip {
|
||
export type Option = artplayerPluginDocumentPipDefinitions.Option
|
||
export type Result = artplayerPluginDocumentPipDefinitions.Result
|
||
export type AsyncResult = artplayerPluginDocumentPipDefinitions.AsyncResult
|
||
export type Factory = artplayerPluginDocumentPipDefinitions.Factory
|
||
export type RuntimeFactory = artplayerPluginDocumentPipDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginDocumentPip
|
||
export as namespace artplayerPluginDocumentPip;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-hls-control.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginHlsControlDefinitions {
|
||
export interface QualityLevel {
|
||
height: number
|
||
name?: string
|
||
}
|
||
export interface AudioTrack {
|
||
id: number
|
||
name: string
|
||
lang?: string
|
||
language?: string
|
||
}
|
||
export interface Config<Item extends object = object> {
|
||
control?: boolean
|
||
setting?: boolean
|
||
title?: string
|
||
auto?: string
|
||
/** Plain callback; current-label calls omit index. SDK objects retain their identity. */
|
||
getName?: (item: Item, index?: number) => string
|
||
}
|
||
export interface Option<Level extends object = QualityLevel, Track extends object = AudioTrack> {
|
||
quality?: Config<Level>
|
||
audio?: Config<Track>
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginHlsControl'
|
||
update: () => void
|
||
}
|
||
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option?: Option<Level, Track>): (art: Artplayer) => Result
|
||
// Keep the required last signature for historical Parameters<typeof factory>[0] consumers.
|
||
export function artplayerPluginHlsControl<Level extends object = QualityLevel, Track extends object = AudioTrack>(option: Option<Level, Track>): (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginHlsControl: typeof artplayerPluginHlsControlDefinitions.artplayerPluginHlsControl
|
||
declare namespace artplayerPluginHlsControl {
|
||
export type QualityLevel = artplayerPluginHlsControlDefinitions.QualityLevel
|
||
export type AudioTrack = artplayerPluginHlsControlDefinitions.AudioTrack
|
||
export type Config<Item extends object = object> = artplayerPluginHlsControlDefinitions.Config<Item>
|
||
export type Option<Level extends object = QualityLevel, Track extends object = AudioTrack> = artplayerPluginHlsControlDefinitions.Option<Level, Track>
|
||
export type Result = artplayerPluginHlsControlDefinitions.Result
|
||
}
|
||
export = artplayerPluginHlsControl
|
||
export as namespace artplayerPluginHlsControl;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-jassub.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginJassubDefinitions {
|
||
export interface JassubOption {
|
||
workerUrl: string
|
||
wasmUrl: string
|
||
modernWasmUrl: string
|
||
subUrl?: string
|
||
subContent?: string
|
||
timeOffset?: number
|
||
debug?: boolean
|
||
prescaleFactor?: number
|
||
prescaleHeightLimit?: number
|
||
maxRenderHeight?: number
|
||
fonts?: string[] | Uint8Array[]
|
||
availableFonts?: Record<string, Uint8Array | string>
|
||
fallbackFont?: string
|
||
useLocalFonts?: boolean
|
||
libassMemoryLimit?: number
|
||
libassGlyphLimit?: number
|
||
[key: string]: any
|
||
}
|
||
export interface JassubInstance {
|
||
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
|
||
setVideo: (video: HTMLVideoElement) => Promise<void>
|
||
destroy: () => Promise<void>
|
||
[key: string]: any
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginJassub'
|
||
instance: JassubInstance
|
||
}
|
||
export const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginJassub: typeof artplayerPluginJassubDefinitions.artplayerPluginJassub
|
||
declare namespace artplayerPluginJassub {
|
||
export type JassubOption = artplayerPluginJassubDefinitions.JassubOption
|
||
export type JassubInstance = artplayerPluginJassubDefinitions.JassubInstance
|
||
}
|
||
export = artplayerPluginJassub
|
||
export as namespace artplayerPluginJassub;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginMultipleSubtitlesDefinitions {
|
||
export interface TrackOption {
|
||
url?: string
|
||
name?: string
|
||
type?: 'vtt' | 'srt' | 'ass'
|
||
encoding?: string
|
||
onParser?: (...args: object[]) => object
|
||
}
|
||
export interface Option {
|
||
subtitles: TrackOption[]
|
||
}
|
||
export interface RuntimeOption {
|
||
subtitles?: TrackOption[]
|
||
}
|
||
export interface LegacyResult {
|
||
name: 'multipleSubtitles'
|
||
}
|
||
export interface Result extends LegacyResult {
|
||
tracks: (names?: string[]) => void
|
||
reset: () => void
|
||
}
|
||
/** Historical synchronous extraction; actual registration is asynchronous. */
|
||
export type Factory = (option: Option) => (art: Artplayer) => LegacyResult
|
||
/** Accurate runtime view available through the /runtime entry. */
|
||
export interface RuntimeFactory {
|
||
(option: RuntimeOption): (art: Artplayer) => Promise<Result>
|
||
default: RuntimeFactory
|
||
}
|
||
/** Preserve existing parameter extraction and replacement-function compatibility. */
|
||
export function artplayerPluginMultipleSubtitles(option: Option): (art: Artplayer) => LegacyResult
|
||
}
|
||
declare const artplayerPluginMultipleSubtitles: typeof artplayerPluginMultipleSubtitlesDefinitions.artplayerPluginMultipleSubtitles
|
||
declare namespace artplayerPluginMultipleSubtitles {
|
||
export type TrackOption = artplayerPluginMultipleSubtitlesDefinitions.TrackOption
|
||
export type Option = artplayerPluginMultipleSubtitlesDefinitions.Option
|
||
export type RuntimeOption = artplayerPluginMultipleSubtitlesDefinitions.RuntimeOption
|
||
export type LegacyResult = artplayerPluginMultipleSubtitlesDefinitions.LegacyResult
|
||
export type Result = artplayerPluginMultipleSubtitlesDefinitions.Result
|
||
export type Factory = artplayerPluginMultipleSubtitlesDefinitions.Factory
|
||
export type RuntimeFactory = artplayerPluginMultipleSubtitlesDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginMultipleSubtitles
|
||
export as namespace artplayerPluginMultipleSubtitles;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-vast.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-use-before-define, ts/consistent-type-definitions -- Preserve historical export ordering and private aliases. */
|
||
export = artplayerPluginVast
|
||
export as namespace artplayerPluginVast;
|
||
type Option = (params: {
|
||
art: Artplayer
|
||
id: string
|
||
ima: any
|
||
imaPlayer: any
|
||
$container: HTMLDivElement
|
||
playUrl: (url: string) => void
|
||
playRes: (res: string) => void
|
||
}) => void
|
||
type Result = {
|
||
name: 'artplayerPluginVast'
|
||
}
|
||
declare const artplayerPluginVast: (option: Option) => (art: Artplayer) => Result
|
||
|
||
|
||
===== docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerPluginVttThumbnailDefinitions {
|
||
export interface Option {
|
||
vtt?: string
|
||
style?: Partial<CSSStyleDeclaration>
|
||
}
|
||
export interface Result {
|
||
name: 'artplayerPluginVttThumbnail'
|
||
}
|
||
/** Historical factory type. Actual registration is asynchronous. */
|
||
export type Factory = (option: Option) => (art: Artplayer) => Result
|
||
/** Accurate runtime view available without casts through the /runtime entry. */
|
||
export interface RuntimeFactory {
|
||
(option: Option): (art: Artplayer) => Promise<Result>
|
||
default: RuntimeFactory
|
||
}
|
||
/** Preserve historical extraction and replacement-function compatibility. */
|
||
export function artplayerPluginVttThumbnail(option: Option): (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerPluginVttThumbnail: typeof artplayerPluginVttThumbnailDefinitions.artplayerPluginVttThumbnail
|
||
declare namespace artplayerPluginVttThumbnail {
|
||
export type Option = artplayerPluginVttThumbnailDefinitions.Option
|
||
export type Result = artplayerPluginVttThumbnailDefinitions.Result
|
||
export type Factory = artplayerPluginVttThumbnailDefinitions.Factory
|
||
export type RuntimeFactory = artplayerPluginVttThumbnailDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerPluginVttThumbnail
|
||
export as namespace artplayerPluginVttThumbnail;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-proxy-canvas.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerProxyCanvasDefinitions {
|
||
/** Runs after drawing and bitmap release, before the draw event. */
|
||
export type Option = (ctx: CanvasRenderingContext2D, video: HTMLVideoElement) => void
|
||
/** Preserve the exact published 1.1.0 return type and its assignability. */
|
||
export type Result = HTMLCanvasElement
|
||
export type Factory = (option?: Option) => (art: Artplayer) => Result
|
||
export type Callable = Factory
|
||
/** Explicit view of forwarded media members; native Canvas members win. */
|
||
export type MediaCanvas = HTMLCanvasElement & Pick<HTMLVideoElement, Exclude<keyof HTMLVideoElement, keyof HTMLCanvasElement>>
|
||
/** Opt-in runtime identity; the historical root factory has no required properties. */
|
||
export interface RuntimeFactory extends Factory {
|
||
readonly default: RuntimeFactory
|
||
}
|
||
export const artplayerProxyCanvas: (option?: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerProxyCanvas: typeof artplayerProxyCanvasDefinitions.artplayerProxyCanvas
|
||
declare namespace artplayerProxyCanvas {
|
||
export type Option = artplayerProxyCanvasDefinitions.Option
|
||
export type Result = artplayerProxyCanvasDefinitions.Result
|
||
export type Factory = artplayerProxyCanvasDefinitions.Factory
|
||
export type Callable = artplayerProxyCanvasDefinitions.Callable
|
||
export type MediaCanvas = artplayerProxyCanvasDefinitions.MediaCanvas
|
||
export type RuntimeFactory = artplayerProxyCanvasDefinitions.RuntimeFactory
|
||
}
|
||
export = artplayerProxyCanvas
|
||
export as namespace artplayerProxyCanvas;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-proxy-mediabunny.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace artplayerProxyMediabunnyDefinitions {
|
||
export interface Option {
|
||
m3u8?: {
|
||
quality?: {
|
||
control?: boolean
|
||
setting?: boolean
|
||
title?: string
|
||
auto?: string
|
||
getName?: (level: {
|
||
id: number
|
||
index: number
|
||
name: null | string
|
||
height: number
|
||
bitrate: number
|
||
}) => string
|
||
}
|
||
audio?: {
|
||
control?: boolean
|
||
setting?: boolean
|
||
title?: string
|
||
auto?: string
|
||
getName?: (track: {
|
||
id: number
|
||
index: number
|
||
name: null | string
|
||
lang: string
|
||
language: string
|
||
bitrate: number
|
||
}) => string
|
||
}
|
||
}
|
||
/**
|
||
* Timeout for loading media in milliseconds
|
||
* @default 0
|
||
*/
|
||
loadTimeout?: number
|
||
/**
|
||
* Interval for timeupdate events in milliseconds
|
||
* @default 250
|
||
*/
|
||
timeupdateInterval?: number
|
||
/**
|
||
* Audio-video synchronization tolerance in seconds
|
||
* @default 0.12
|
||
*/
|
||
avSyncTolerance?: number
|
||
/**
|
||
* Whether to drop late video frames
|
||
* @default false
|
||
*/
|
||
dropLateFrames?: boolean
|
||
/**
|
||
* Poster image URL
|
||
*/
|
||
poster?: string
|
||
/**
|
||
* Media source (URL, Blob, or ReadableStream)
|
||
*/
|
||
source?: string | Blob | ReadableStream<Uint8Array>
|
||
/**
|
||
* Check if server supports range requests before loading
|
||
* @default false
|
||
*/
|
||
preflightRange?: boolean
|
||
/**
|
||
* Initial volume (0-1)
|
||
* @default 0.7
|
||
*/
|
||
volume?: number
|
||
/**
|
||
* Initial muted state
|
||
* @default false
|
||
*/
|
||
muted?: boolean
|
||
/**
|
||
* Autoplay
|
||
* @default false
|
||
*/
|
||
autoplay?: boolean
|
||
/**
|
||
* Loop playback
|
||
* @default false
|
||
*/
|
||
loop?: boolean
|
||
/**
|
||
* Cross-origin setting
|
||
*/
|
||
crossOrigin?: string
|
||
}
|
||
export type Result = HTMLCanvasElement
|
||
export interface HlsLevel {
|
||
id: number
|
||
index: number
|
||
name: string | null
|
||
height: number
|
||
bitrate: number
|
||
/** SDK object; narrow with the SDK version used by your application. */
|
||
track: unknown
|
||
}
|
||
export interface HlsAudio {
|
||
id: number
|
||
index: number
|
||
name: string | null
|
||
lang: string
|
||
language: string
|
||
bitrate: number
|
||
/** SDK object; narrow with the SDK version used by your application. */
|
||
track: unknown
|
||
}
|
||
export interface HlsState {
|
||
levels: HlsLevel[]
|
||
audios: HlsAudio[]
|
||
currentLevel: HlsLevel | null
|
||
currentAudio: HlsAudio | null
|
||
videoMode: 'auto' | 'manual'
|
||
audioMode: 'auto' | 'manual'
|
||
}
|
||
/** Historical RAF estimates, not decoded-frame or network timing measurements. */
|
||
export interface SyntheticFrameMetadata {
|
||
/** Historical media time in seconds, unlike the native video API. */
|
||
presentationTime: number
|
||
expectedDisplayTime: number
|
||
width: number
|
||
height: number
|
||
mediaTime: number
|
||
presentedFrames: number
|
||
processingDuration: number
|
||
captureTime: number
|
||
receiveTime: number
|
||
rtpTimestamp: number
|
||
}
|
||
export type SyntheticFrameCallback = (now: number, metadata: SyntheticFrameMetadata) => void
|
||
export type MediaListener = (event: Event & {
|
||
detail: unknown
|
||
}) => unknown
|
||
/** Opt-in media surface of art.mediabunny; decoder internals are not part of this view. */
|
||
export interface MediaBunnyShim {
|
||
canvas: HTMLCanvasElement
|
||
/** Runtime also accepts SDK sources; the default Option keeps its historical input union. */
|
||
src: unknown
|
||
readonly currentSrc: unknown
|
||
currentTime: number
|
||
readonly duration: number
|
||
/** Synthetic full-duration/current-time ranges, not measured network buffers. */
|
||
readonly buffered: TimeRanges
|
||
readonly played: TimeRanges
|
||
readonly seekable: TimeRanges
|
||
readonly paused: boolean
|
||
readonly playing: boolean
|
||
readonly ended: boolean
|
||
readonly seeking: boolean
|
||
readonly readyState: number
|
||
readonly networkState: number
|
||
readonly error: {
|
||
code: number
|
||
message: string
|
||
} | null
|
||
volume: number
|
||
muted: boolean
|
||
playbackRate: number
|
||
readonly videoWidth: number
|
||
readonly videoHeight: number
|
||
poster: string
|
||
/** The following setters are inert; use Option for autoplay/loop/crossOrigin. */
|
||
autoplay: boolean
|
||
loop: boolean
|
||
controls: boolean
|
||
playsInline: boolean
|
||
crossOrigin: string
|
||
preload: string
|
||
defaultMuted: boolean
|
||
defaultPlaybackRate: number
|
||
play: () => Promise<void>
|
||
pause: () => void
|
||
load: () => void
|
||
/** Always returns "maybe"; it does not probe codec/browser support. */
|
||
canPlayType: (type: string) => 'maybe'
|
||
getM3u8State: () => Promise<HlsState | null>
|
||
switchM3u8Quality: (value: unknown) => Promise<void>
|
||
switchM3u8Audio: (value: unknown) => Promise<void>
|
||
createTimeRanges: (start: number, end: number) => TimeRanges
|
||
requestVideoFrameCallback: (callback: SyntheticFrameCallback) => number
|
||
cancelVideoFrameCallback: (id: number) => void
|
||
addEventListener: (type: string, listener: MediaListener) => void
|
||
removeEventListener: (type: string, listener: MediaListener) => void
|
||
getBoundingClientRect: () => DOMRect
|
||
setAttribute: (name: string, value: unknown) => void
|
||
destroy: () => void
|
||
}
|
||
/** Native Canvas methods win collisions, including DOM event and attribute methods. */
|
||
export type MediaBunnyCanvas = HTMLCanvasElement & Omit<MediaBunnyShim, keyof HTMLCanvasElement>
|
||
/** The alias is installed by the proxy and removed on player destruction. */
|
||
export type MediaBunnyPlayer = Artplayer & {
|
||
mediabunny?: MediaBunnyShim
|
||
}
|
||
export const artplayerProxyMediabunny: (option?: Option) => (art: Artplayer) => Result
|
||
}
|
||
declare const artplayerProxyMediabunny: typeof artplayerProxyMediabunnyDefinitions.artplayerProxyMediabunny
|
||
declare namespace artplayerProxyMediabunny {
|
||
export type Option = artplayerProxyMediabunnyDefinitions.Option
|
||
export type Result = artplayerProxyMediabunnyDefinitions.Result
|
||
export type HlsLevel = artplayerProxyMediabunnyDefinitions.HlsLevel
|
||
export type HlsAudio = artplayerProxyMediabunnyDefinitions.HlsAudio
|
||
export type HlsState = artplayerProxyMediabunnyDefinitions.HlsState
|
||
export type SyntheticFrameMetadata = artplayerProxyMediabunnyDefinitions.SyntheticFrameMetadata
|
||
export type SyntheticFrameCallback = artplayerProxyMediabunnyDefinitions.SyntheticFrameCallback
|
||
export type MediaListener = artplayerProxyMediabunnyDefinitions.MediaListener
|
||
export type MediaBunnyShim = artplayerProxyMediabunnyDefinitions.MediaBunnyShim
|
||
export type MediaBunnyCanvas = artplayerProxyMediabunnyDefinitions.MediaBunnyCanvas
|
||
export type MediaBunnyPlayer = artplayerProxyMediabunnyDefinitions.MediaBunnyPlayer
|
||
}
|
||
export = artplayerProxyMediabunny
|
||
export as namespace artplayerProxyMediabunny;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-tool-iframe.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||
declare namespace ArtplayerToolIframeDefinitions {
|
||
export interface Option {
|
||
iframe: HTMLIFrameElement
|
||
url: string
|
||
}
|
||
/** Historical open envelope. data remains required in the default class API. */
|
||
export interface Message<T = any> {
|
||
type: string
|
||
data: T
|
||
id?: number
|
||
}
|
||
export interface Callbacks {
|
||
resove: (...args: any[]) => any
|
||
reject: (...args: any[]) => any
|
||
}
|
||
/** Public notifications omit the request id and all private session metadata. */
|
||
export interface Notification<T = unknown> {
|
||
type: string
|
||
data: T
|
||
}
|
||
export type MessageCallback = (this: ArtplayerToolIframe, message: Notification) => void
|
||
/** Actual outgoing calls allow an omitted data field. Custom message types remain valid. */
|
||
export interface OutboundMessage<T = unknown> {
|
||
type: string
|
||
data?: T
|
||
id?: number
|
||
}
|
||
/** Known built-in envelopes; use Message/OutboundMessage for application protocols. */
|
||
export type ProtocolMessage<T = unknown> = {
|
||
type: 'inject'
|
||
data?: undefined
|
||
id?: number
|
||
} | {
|
||
type: 'commit'
|
||
data: string
|
||
id: number
|
||
} | {
|
||
type: 'response'
|
||
data: T
|
||
id: number
|
||
} | {
|
||
type: 'error'
|
||
data: unknown
|
||
id: number
|
||
}
|
||
export type Resolve<T> = (value: T | PromiseLike<T>) => void
|
||
export type ResolverCallback<T> = (resolve: Resolve<T>) => void
|
||
/** Opt-in view. Response T is supplied by the application's protocol, not validated at runtime. */
|
||
export interface RuntimeInstance extends Omit<ArtplayerToolIframe, 'messageCallback' | 'postMessage' | 'message'> {
|
||
messageCallback: MessageCallback | null
|
||
postMessage: <T = unknown>(message: OutboundMessage) => Promise<T>
|
||
message: (callback: MessageCallback) => void
|
||
}
|
||
/** For the existing serialized resolve(...) protocol; callback bodies must use that exact name. */
|
||
export interface ResolverInstance extends Omit<RuntimeInstance, 'commit'> {
|
||
commit: <T>(callback: ResolverCallback<T>) => Promise<T>
|
||
}
|
||
/** Opt-in static async/optional-data view. There is no runtime self-default property. */
|
||
export interface RuntimeConstructor {
|
||
new (option: Option): RuntimeInstance
|
||
readonly prototype: RuntimeInstance
|
||
readonly iframe: boolean
|
||
postMessage: (message: OutboundMessage) => void
|
||
onMessage: (event: MessageEvent<OutboundMessage>) => Promise<void>
|
||
inject: () => void
|
||
}
|
||
export class ArtplayerToolIframe {
|
||
constructor(option: Option)
|
||
static iframe: boolean
|
||
static postMessage(message: Message): void
|
||
static onMessage(event: MessageEvent & {
|
||
data: Message
|
||
}): void
|
||
static inject(): void
|
||
readonly promises: Record<number, Callbacks>
|
||
readonly injected: boolean
|
||
readonly destroyed: boolean
|
||
readonly $iframe: HTMLIFrameElement
|
||
readonly url: string
|
||
readonly messageCallback: (...args: any[]) => any
|
||
onMessage(event: MessageEvent & {
|
||
data: Message
|
||
}): void
|
||
postMessage(message: Message): Promise<any>
|
||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>
|
||
message(callback: (...args: any[]) => any): void
|
||
destroy(): void
|
||
}
|
||
}
|
||
declare const ArtplayerToolIframe: typeof ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||
type ArtplayerToolIframe = ArtplayerToolIframeDefinitions.ArtplayerToolIframe
|
||
declare namespace ArtplayerToolIframe {
|
||
export type Option = ArtplayerToolIframeDefinitions.Option
|
||
export type Message<T = any> = ArtplayerToolIframeDefinitions.Message<T>
|
||
export type Callbacks = ArtplayerToolIframeDefinitions.Callbacks
|
||
export type Notification<T = unknown> = ArtplayerToolIframeDefinitions.Notification<T>
|
||
export type MessageCallback = ArtplayerToolIframeDefinitions.MessageCallback
|
||
export type OutboundMessage<T = unknown> = ArtplayerToolIframeDefinitions.OutboundMessage<T>
|
||
export type ProtocolMessage<T = unknown> = ArtplayerToolIframeDefinitions.ProtocolMessage<T>
|
||
export type Resolve<T> = ArtplayerToolIframeDefinitions.Resolve<T>
|
||
export type ResolverCallback<T> = ArtplayerToolIframeDefinitions.ResolverCallback<T>
|
||
export type RuntimeInstance = ArtplayerToolIframeDefinitions.RuntimeInstance
|
||
export type ResolverInstance = ArtplayerToolIframeDefinitions.ResolverInstance
|
||
export type RuntimeConstructor = ArtplayerToolIframeDefinitions.RuntimeConstructor
|
||
}
|
||
export = ArtplayerToolIframe
|
||
export as namespace ArtplayerToolIframe;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-tool-thumbnail.d.ts =====
|
||
|
||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||
/** Extract PNG thumbnail sheets from a locally selected video file. */
|
||
declare class ArtplayerToolThumbnail {
|
||
constructor(option?: ArtplayerToolThumbnail.Option)
|
||
static readonly DEFAULTS: ArtplayerToolThumbnail.DefaultOptions
|
||
static ondragover(event: DragEvent): void
|
||
static creatVideo(): HTMLVideoElement
|
||
processing: boolean
|
||
option: ArtplayerToolThumbnail.ResolvedOption
|
||
video: HTMLVideoElement
|
||
duration: number
|
||
density: number | undefined
|
||
file: File | undefined
|
||
videoUrl: string | undefined
|
||
thumbnailUrl: string | undefined
|
||
e?: ArtplayerToolThumbnail.EventRegistry
|
||
setup(option?: ArtplayerToolThumbnail.Option): this
|
||
inputChange(event: Event): void
|
||
ondrop(event: DragEvent): void
|
||
loadVideo(file?: File | null): void
|
||
/** Ready-metadata preflight may throw synchronously. Cancellation rejects with AbortError. */
|
||
start(): Promise<void>
|
||
creatScreenshotDate(): ArtplayerToolThumbnail.ScreenshotPoint[]
|
||
creatCanvas(): HTMLCanvasElement
|
||
download(): this
|
||
errorHandle(condition: unknown, message: string): void
|
||
destroy(): void
|
||
on<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
|
||
once<Name extends PropertyKey, Custom extends unknown[], Context>(name: Name, callback: (this: Context, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>) => unknown, ctx?: Context): this
|
||
emit<Name extends PropertyKey, Custom extends unknown[]>(name: Name, ...args: ArtplayerToolThumbnail.EventArgs<Name, Custom>): this
|
||
off<Name extends PropertyKey, Custom extends unknown[]>(name: Name, callback?: ArtplayerToolThumbnail.Listener<ArtplayerToolThumbnail.EventArgs<Name, Custom>>): this
|
||
}
|
||
declare namespace ArtplayerToolThumbnail {
|
||
interface SheetOptions {
|
||
number: number
|
||
width: number
|
||
height: number
|
||
column: number
|
||
begin: number
|
||
end: number
|
||
}
|
||
type Compatibility = 'published-3.5' | 'workspace-4.4'
|
||
interface DefaultOptions extends SheetOptions {
|
||
delay: number
|
||
}
|
||
/** fileInput must be a file input or an Element wrapper when constructing. */
|
||
interface Option extends Partial<SheetOptions> {
|
||
fileInput?: Element
|
||
compatibility?: Compatibility
|
||
/** Published mode delay in milliseconds, clamped to 10-1000. */
|
||
delay?: number
|
||
[name: string]: unknown
|
||
}
|
||
interface ResolvedOption extends SheetOptions {
|
||
fileInput: HTMLInputElement
|
||
compatibility?: Compatibility
|
||
delay?: number
|
||
[name: string]: unknown
|
||
}
|
||
interface ScreenshotPoint {
|
||
time: number
|
||
x: number
|
||
y: number
|
||
}
|
||
interface Events {
|
||
file: [
|
||
file: File,
|
||
]
|
||
video: [
|
||
video: HTMLVideoElement,
|
||
]
|
||
canvas: [
|
||
canvas: HTMLCanvasElement,
|
||
]
|
||
update: [
|
||
url: string,
|
||
progress: number,
|
||
]
|
||
done: [
|
||
]
|
||
download: [
|
||
name: string,
|
||
]
|
||
/** Built-in failures are strings; user callbacks may throw any message value. */
|
||
error: [
|
||
message: unknown,
|
||
]
|
||
destroy: [
|
||
]
|
||
}
|
||
type EventArgs<Name extends PropertyKey, Custom extends unknown[] = unknown[]> = Name extends keyof Events ? [
|
||
...Events[Name],
|
||
] : Custom
|
||
type Listener<Args extends unknown[]> = ((...args: Args) => unknown) & {
|
||
_?: (...args: Args) => unknown
|
||
}
|
||
/** Heterogeneous listener storage; dispatch through emit to retain event argument checks. */
|
||
type EventRegistry = Partial<Record<PropertyKey, {
|
||
fn: Listener<never[]>
|
||
ctx: unknown
|
||
}[]>>
|
||
}
|
||
export = ArtplayerToolThumbnail
|
||
export as namespace ArtplayerToolThumbnail;
|
||
|
||
|
||
===== docs/assets/ts/artplayer.d.ts =====
|
||
|
||
// Generated from packages/artplayer/public/artplayer.ts by yarn build:ts. Do not edit.
|
||
/* eslint-disable ts/no-redeclare -- UMD constructor and named types share the global export. */
|
||
declare namespace ArtplayerDefinitions {
|
||
export interface ComponentInput extends Omit<ComponentOption, 'html'> {
|
||
html?: string | HTMLElement | number
|
||
}
|
||
export interface Selector {
|
||
/**
|
||
* Whether the default is selected
|
||
*/
|
||
default?: boolean
|
||
/**
|
||
* Html string of selector
|
||
*/
|
||
html: string | HTMLElement
|
||
/**
|
||
* Value of selector item
|
||
*/
|
||
value?: string | number
|
||
/**
|
||
* Allow custom properties
|
||
*/
|
||
[key: string]: any
|
||
}
|
||
export interface Component {
|
||
/**
|
||
* Component self-increasing id
|
||
*/
|
||
readonly id: number
|
||
/**
|
||
* Component parent name
|
||
*/
|
||
readonly name: string | undefined
|
||
/**
|
||
* Component parent element
|
||
*/
|
||
readonly $parent: HTMLElement | undefined
|
||
/**
|
||
* Whether to show component parent
|
||
*/
|
||
get show(): boolean
|
||
/**
|
||
* Whether to show component parent
|
||
*/
|
||
set show(state: boolean)
|
||
/**
|
||
* Toggle the component parent
|
||
*/
|
||
toggle: () => void
|
||
/**
|
||
* Dynamic add a component
|
||
*/
|
||
add: {
|
||
(option: ComponentOption | ((art: Artplayer) => ComponentOption)): HTMLElement | undefined
|
||
(option: ComponentInput | ((art: Artplayer) => ComponentInput)): HTMLElement | undefined
|
||
}
|
||
/**
|
||
* Dynamic remove a component by name
|
||
*/
|
||
remove: (name: string) => void
|
||
/**
|
||
* Dynamic update a component
|
||
*/
|
||
update: {
|
||
(option: ComponentOption): HTMLElement | undefined
|
||
(option: ComponentInput): HTMLElement | undefined
|
||
}
|
||
}
|
||
export interface ComponentOption {
|
||
/**
|
||
* Html string or html element of component
|
||
*/
|
||
html?: string | HTMLElement
|
||
/**
|
||
* Whether to disable component
|
||
*/
|
||
disable?: boolean
|
||
/**
|
||
* Unique name for component
|
||
*/
|
||
name?: string
|
||
/**
|
||
* Component sort index
|
||
*/
|
||
index?: number
|
||
/**
|
||
* Component style object
|
||
*/
|
||
style?: Partial<CSSStyleDeclaration>
|
||
/**
|
||
* Component click event
|
||
*/
|
||
click?: (this: Artplayer, component: Component, event: Event) => void
|
||
/**
|
||
* When the component was mounted
|
||
*/
|
||
mounted?: (this: Artplayer, element: HTMLElement) => void
|
||
/**
|
||
* When the component was before unmount
|
||
*/
|
||
beforeUnmount?: (this: Artplayer, element: HTMLElement) => void
|
||
/**
|
||
* Component tooltip, use in controls
|
||
*/
|
||
tooltip?: string
|
||
/**
|
||
* Component position, use in controls
|
||
*/
|
||
position?: 'top' | 'left' | 'right' | (string & Record<never, never>)
|
||
/**
|
||
* Custom selector list, use in controls
|
||
*/
|
||
selector?: Selector[]
|
||
/**
|
||
* When selector item click, use in controls
|
||
*/
|
||
onSelect?: (this: Artplayer, selector: Selector, element: HTMLElement, event: Event) => void
|
||
}
|
||
export interface Config {
|
||
readonly properties: readonly [
|
||
'audioTracks',
|
||
'autoplay',
|
||
'buffered',
|
||
'controller',
|
||
'controls',
|
||
'crossOrigin',
|
||
'currentSrc',
|
||
'currentTime',
|
||
'defaultMuted',
|
||
'defaultPlaybackRate',
|
||
'duration',
|
||
'ended',
|
||
'error',
|
||
'loop',
|
||
'mediaGroup',
|
||
'muted',
|
||
'networkState',
|
||
'paused',
|
||
'playbackRate',
|
||
'played',
|
||
'preload',
|
||
'readyState',
|
||
'seekable',
|
||
'seeking',
|
||
'src',
|
||
'startDate',
|
||
'textTracks',
|
||
'videoTracks',
|
||
'volume',
|
||
]
|
||
readonly methods: readonly [
|
||
'addTextTrack',
|
||
'canPlayType',
|
||
'load',
|
||
'play',
|
||
'pause',
|
||
]
|
||
readonly events: readonly [
|
||
'abort',
|
||
'canplay',
|
||
'canplaythrough',
|
||
'durationchange',
|
||
'emptied',
|
||
'ended',
|
||
'error',
|
||
'loadeddata',
|
||
'loadedmetadata',
|
||
'loadstart',
|
||
'pause',
|
||
'play',
|
||
'playing',
|
||
'progress',
|
||
'ratechange',
|
||
'seeked',
|
||
'seeking',
|
||
'stalled',
|
||
'suspend',
|
||
'timeupdate',
|
||
'volumechange',
|
||
'waiting',
|
||
]
|
||
readonly prototypes: readonly [
|
||
'width',
|
||
'height',
|
||
'videoWidth',
|
||
'videoHeight',
|
||
'poster',
|
||
'webkitDecodedFrameCount',
|
||
'webkitDroppedFrameCount',
|
||
'playsInline',
|
||
'webkitSupportsFullscreen',
|
||
'webkitDisplayingFullscreen',
|
||
'onenterpictureinpicture',
|
||
'onleavepictureinpicture',
|
||
'disablePictureInPicture',
|
||
'cancelVideoFrameCallback',
|
||
'requestVideoFrameCallback',
|
||
'getVideoPlaybackQuality',
|
||
'requestPictureInPicture',
|
||
'webkitEnterFullScreen',
|
||
'webkitEnterFullscreen',
|
||
'webkitExitFullScreen',
|
||
'webkitExitFullscreen',
|
||
]
|
||
}
|
||
/** The event bus exposed by Artplayer.Emitter; no new runtime export. */
|
||
export interface Emitter<Events extends {
|
||
[Name in keyof Events]: readonly unknown[];
|
||
} = Record<PropertyKey, unknown[]>> {
|
||
e?: {
|
||
[Name in keyof Events]?: {
|
||
fn: (...args: [
|
||
...Events[Name],
|
||
]) => unknown
|
||
ctx: unknown
|
||
}[];
|
||
}
|
||
on: <Name extends keyof Events, Context>(name: Name, fn: (this: Context, ...args: [
|
||
...Events[Name],
|
||
]) => unknown, ctx?: Context) => this
|
||
once: <Name extends keyof Events, Context>(name: Name, fn: (this: Context, ...args: [
|
||
...Events[Name],
|
||
]) => unknown, ctx?: Context) => this
|
||
emit: <Name extends keyof Events>(name: Name, ...args: [
|
||
...Events[Name],
|
||
]) => this
|
||
off: <Name extends keyof Events>(name: Name, fn?: (...args: [
|
||
...Events[Name],
|
||
]) => unknown) => this
|
||
}
|
||
export interface CssVar {
|
||
'--art-theme': string
|
||
'--art-font-color': string
|
||
'--art-background-color': string
|
||
'--art-text-shadow-color': string
|
||
'--art-transition-duration': string
|
||
'--art-padding': string
|
||
'--art-border-radius': string
|
||
'--art-progress-height': string
|
||
'--art-progress-color': string
|
||
'--art-progress-top-gap': string
|
||
'--art-hover-color': string
|
||
'--art-loaded-color': string
|
||
'--art-state-size': string
|
||
'--art-state-opacity': number
|
||
'--art-bottom-height': string
|
||
'--art-bottom-offset': string
|
||
'--art-bottom-gap': string
|
||
'--art-highlight-width': string
|
||
'--art-highlight-color': string
|
||
'--art-control-height': string
|
||
'--art-control-opacity': number
|
||
'--art-control-icon-size': string
|
||
'--art-control-icon-scale': number
|
||
'--art-volume-height': string
|
||
'--art-volume-handle-size': string
|
||
'--art-lock-size': string
|
||
'--art-indicator-scale': number
|
||
'--art-indicator-size': string
|
||
'--art-fullscreen-web-index': 9999
|
||
'--art-settings-icon-size': string
|
||
'--art-settings-max-height': string
|
||
'--art-selector-max-height': string
|
||
'--art-contextmenus-min-width': string
|
||
'--art-subtitle-font-size': string
|
||
'--art-subtitle-gap': string
|
||
'--art-subtitle-bottom': string
|
||
'--art-subtitle-border': string
|
||
'--art-widget-background': string
|
||
'--art-tip-background': string
|
||
'--art-scrollbar-size': string
|
||
'--art-scrollbar-background': string
|
||
'--art-scrollbar-background-hover': string
|
||
'--art-mini-progress-height': string
|
||
}
|
||
export type I18nKeys = 'en' | 'zh-cn' | 'zh-tw' | 'pl' | 'cs' | 'es' | 'fa' | 'fr' | 'id' | 'ru' | 'tr' | 'ar' | 'vi' | (string & Record<never, never>)
|
||
export interface I18nValue {
|
||
'Context Menu'?: string
|
||
'Lock'?: string
|
||
'Video Info': string
|
||
'Close': string
|
||
'Video Load Failed': string
|
||
'Volume': string
|
||
'Progress'?: string
|
||
'Back'?: string
|
||
'Settings'?: string
|
||
'Play': string
|
||
'Pause': string
|
||
'Rate': string
|
||
'Mute': string
|
||
'Video Flip': string
|
||
'Horizontal': string
|
||
'Vertical': string
|
||
'Reconnect': string
|
||
'Show Setting': string
|
||
'Hide Setting': string
|
||
'Screenshot': string
|
||
'Play Speed': string
|
||
'Aspect Ratio': string
|
||
'Default': string
|
||
'Normal': string
|
||
'Open': string
|
||
'Switch Video': string
|
||
'Switch Subtitle': string
|
||
'Fullscreen': string
|
||
'Exit Fullscreen': string
|
||
'Web Fullscreen': string
|
||
'Exit Web Fullscreen': string
|
||
'Mini Player': string
|
||
'PIP Mode': string
|
||
'Exit PIP Mode': string
|
||
'PIP Not Supported': string
|
||
'Fullscreen Not Supported': string
|
||
'Subtitle Offset': string
|
||
'Last Seen': string
|
||
'Jump Play': string
|
||
'AirPlay': string
|
||
'AirPlay Not Available': string
|
||
}
|
||
export type I18n = Partial<Record<I18nKeys, Partial<I18nValue>>>
|
||
export interface Icons {
|
||
readonly loading: HTMLDivElement
|
||
readonly state: HTMLDivElement
|
||
readonly play: HTMLDivElement
|
||
readonly pause: HTMLDivElement
|
||
readonly check: HTMLDivElement
|
||
readonly volume: HTMLDivElement
|
||
readonly volumeClose: HTMLDivElement
|
||
readonly screenshot: HTMLDivElement
|
||
readonly setting: HTMLDivElement
|
||
readonly pip: HTMLDivElement
|
||
readonly arrowLeft: HTMLDivElement
|
||
readonly arrowRight: HTMLDivElement
|
||
readonly playbackRate: HTMLDivElement
|
||
readonly aspectRatio: HTMLDivElement
|
||
readonly config: HTMLDivElement
|
||
readonly lock: HTMLDivElement
|
||
readonly flip: HTMLDivElement
|
||
readonly unlock: HTMLDivElement
|
||
readonly fullscreenOff: HTMLDivElement
|
||
readonly fullscreenOn: HTMLDivElement
|
||
readonly fullscreenWebOff: HTMLDivElement
|
||
readonly fullscreenWebOn: HTMLDivElement
|
||
readonly switchOn: HTMLDivElement
|
||
readonly switchOff: HTMLDivElement
|
||
readonly error: HTMLDivElement
|
||
readonly close: HTMLDivElement
|
||
readonly airplay: HTMLDivElement
|
||
readonly [key: string]: HTMLDivElement
|
||
}
|
||
export type PluginFactory<Host = Artplayer, Result = unknown> = (this: Host, art: Host) => Result
|
||
/** Augment this interface with installed plugin results; augmentation does not register a plugin. */
|
||
export interface Plugins {
|
||
/** Legacy signature: synchronous factories return this registry; Promise factories return a Promise of it. */
|
||
add: (plugin: PluginFactory) => Promise<Plugins>
|
||
[name: string]: unknown
|
||
}
|
||
export interface Quality {
|
||
/**
|
||
* Whether the default is selected
|
||
*/
|
||
default?: boolean
|
||
/**
|
||
* Html string of quality
|
||
*/
|
||
html: string | HTMLElement
|
||
/**
|
||
* Video quality url
|
||
*/
|
||
url: string
|
||
}
|
||
export interface SettingOption extends Omit<Setting, 'html' | 'icon' | 'tooltip'> {
|
||
html: string
|
||
icon: string | undefined
|
||
tooltip: string | undefined
|
||
$item: HTMLDivElement
|
||
$icon: HTMLDivElement | undefined
|
||
$html: HTMLDivElement
|
||
$tooltip: HTMLDivElement | undefined
|
||
$switch: HTMLDivElement | undefined
|
||
$range: HTMLInputElement | undefined
|
||
$parent: SettingOption | undefined
|
||
$parents: SettingOption[]
|
||
$option: SettingOption[]
|
||
$events: Array<() => void>
|
||
$formatted: boolean
|
||
}
|
||
export interface Setting {
|
||
/**
|
||
* Html string or html element of setting name
|
||
*/
|
||
html: string | HTMLElement
|
||
/**
|
||
* Html string or html element of setting icon
|
||
*/
|
||
icon?: string | HTMLElement
|
||
/**
|
||
* The width of setting
|
||
*/
|
||
width?: number
|
||
/**
|
||
* The tooltip of setting
|
||
*/
|
||
tooltip?: string | HTMLElement
|
||
/**
|
||
* Whether the default is selected
|
||
*/
|
||
default?: boolean
|
||
/**
|
||
* Custom selector list
|
||
*/
|
||
selector?: Setting[]
|
||
/**
|
||
* When the setting was mounted
|
||
*/
|
||
mounted?: (this: Artplayer, panel: HTMLDivElement, item: Setting) => void
|
||
/**
|
||
* When selector item click
|
||
*/
|
||
onSelect?: (this: Artplayer, item: SettingOption, element: HTMLDivElement, event: Event) => void
|
||
/**
|
||
* Custom switch item
|
||
*/
|
||
switch?: boolean
|
||
/**
|
||
* When switch item click
|
||
*/
|
||
onSwitch?: (this: Artplayer, item: SettingOption, element: HTMLDivElement, event: Event) => void
|
||
/**
|
||
* Custom range item
|
||
*/
|
||
range?: [
|
||
value?: number,
|
||
min?: number,
|
||
max?: number,
|
||
step?: number,
|
||
]
|
||
/**
|
||
* When range item change
|
||
*/
|
||
onRange?: (this: Artplayer, item: SettingOption, element: HTMLDivElement, event: Event) => void
|
||
/**
|
||
* When range item change in real time
|
||
*/
|
||
onChange?: (this: Artplayer, item: SettingOption, element: HTMLDivElement, event: Event) => void
|
||
/**
|
||
* When range item change in real time
|
||
*/
|
||
onClick?: (this: Artplayer, item: SettingOption, element: HTMLDivElement, event: Event) => void
|
||
/**
|
||
* Allow custom properties
|
||
*/
|
||
[key: string]: any
|
||
}
|
||
export interface Subtitle {
|
||
/**
|
||
* The subtitle url
|
||
*/
|
||
url?: string
|
||
/**
|
||
* The subtitle name
|
||
*/
|
||
name?: string
|
||
/**
|
||
* The subtitle type
|
||
*/
|
||
type?: 'vtt' | 'srt' | 'ass' | (string & Record<never, never>)
|
||
/**
|
||
* The subtitle style object
|
||
*/
|
||
style?: Partial<CSSStyleDeclaration>
|
||
/**
|
||
* The subtitle encoding, default utf-8
|
||
*/
|
||
encoding?: string
|
||
/**
|
||
* Whether use escape, default true
|
||
*/
|
||
escape?: boolean
|
||
/**
|
||
* Change the vtt text
|
||
*/
|
||
onVttLoad?: (vtt: string) => string
|
||
}
|
||
export type CustomType = 'flv' | 'm3u8' | 'hls' | 'ts' | 'mpd' | 'torrent' | (string & Record<never, never>)
|
||
export interface Thumbnails {
|
||
/**
|
||
* The thumbnail image url
|
||
*/
|
||
url: string
|
||
/**
|
||
* The thumbnail item number
|
||
*/
|
||
number?: number
|
||
/**
|
||
* The thumbnail column size
|
||
*/
|
||
column?: number
|
||
/**
|
||
* The thumbnail width
|
||
*/
|
||
width?: number
|
||
/**
|
||
* The thumbnail height
|
||
*/
|
||
height?: number
|
||
/**
|
||
* The thumbnail scale
|
||
*/
|
||
scale?: number
|
||
}
|
||
/** Constructor input; Option retains its historical required URL/read types. */
|
||
export interface OptionInput extends Omit<Option$1, 'url' | 'controls' | 'layers' | 'contextmenu'> {
|
||
url?: string
|
||
controls?: ComponentInput[]
|
||
layers?: ComponentInput[]
|
||
contextmenu?: ComponentInput[]
|
||
}
|
||
export interface Option$1 {
|
||
/**
|
||
* The player id
|
||
*/
|
||
id?: string
|
||
/**
|
||
* The container mounted by the player
|
||
*/
|
||
container: string | HTMLDivElement
|
||
/**
|
||
* Video url
|
||
*/
|
||
url: string
|
||
/**
|
||
* Video poster image url
|
||
*/
|
||
poster?: string
|
||
/**
|
||
* Video url type
|
||
*/
|
||
type?: CustomType
|
||
/**
|
||
* Player color theme
|
||
*/
|
||
theme?: string
|
||
/**
|
||
* Player language
|
||
*/
|
||
lang?: keyof I18n
|
||
/**
|
||
* Player default volume
|
||
*/
|
||
volume?: number
|
||
/**
|
||
* Whether live broadcast mode
|
||
*/
|
||
isLive?: boolean
|
||
/**
|
||
* Whether video muted
|
||
*/
|
||
muted?: boolean
|
||
/**
|
||
* Whether video auto play
|
||
*/
|
||
autoplay?: boolean
|
||
/**
|
||
* Whether player auto resize
|
||
*/
|
||
autoSize?: boolean
|
||
/**
|
||
* Whether player auto run mini mode
|
||
*/
|
||
autoMini?: boolean
|
||
/**
|
||
* Whether video auto loop
|
||
*/
|
||
loop?: boolean
|
||
/**
|
||
* Whether show video flip button
|
||
*/
|
||
flip?: boolean
|
||
/**
|
||
* Whether show video playback rate button
|
||
*/
|
||
playbackRate?: boolean
|
||
/**
|
||
* Whether show video aspect ratio button
|
||
*/
|
||
aspectRatio?: boolean
|
||
/**
|
||
* Whether show video screenshot button
|
||
*/
|
||
screenshot?: boolean
|
||
/**
|
||
* Whether show video setting button
|
||
*/
|
||
setting?: boolean
|
||
/**
|
||
* Whether to enable player hotkey
|
||
*/
|
||
hotkey?: boolean
|
||
/**
|
||
* Whether show video pip button
|
||
*/
|
||
pip?: boolean
|
||
/**
|
||
* Do you want to run only one player at a time
|
||
*/
|
||
mutex?: boolean
|
||
/**
|
||
* Whether use backdrop in UI
|
||
*/
|
||
backdrop?: boolean
|
||
/**
|
||
* Whether show video window fullscreen button
|
||
*/
|
||
fullscreen?: boolean
|
||
/**
|
||
* Whether show video web fullscreen button
|
||
*/
|
||
fullscreenWeb?: boolean
|
||
/**
|
||
* Whether to enable player subtitle offset
|
||
*/
|
||
subtitleOffset?: boolean
|
||
/**
|
||
* Whether to enable player mini progress bar
|
||
*/
|
||
miniProgressBar?: boolean
|
||
/**
|
||
* Whether use SSR function
|
||
*/
|
||
useSSR?: boolean
|
||
/**
|
||
* Whether use playsInline in mobile
|
||
*/
|
||
playsInline?: boolean
|
||
/**
|
||
* Whether use lock in mobile
|
||
*/
|
||
lock?: boolean
|
||
/**
|
||
* Whether use gesture in mobile
|
||
*/
|
||
gesture?: boolean
|
||
/**
|
||
* Whether use fast forward in mobile
|
||
*/
|
||
fastForward?: boolean
|
||
/**
|
||
* Whether use auto playback
|
||
*/
|
||
autoPlayback?: boolean
|
||
/**
|
||
* Whether use auto orientation in mobile
|
||
*/
|
||
autoOrientation?: boolean
|
||
/**
|
||
* Whether use airplay
|
||
*/
|
||
airplay?: boolean
|
||
/**
|
||
* Custom video proxy
|
||
*/
|
||
proxy?: (this: Artplayer, art: Artplayer) => HTMLCanvasElement | HTMLVideoElement | undefined
|
||
/**
|
||
* Custom plugin list
|
||
*/
|
||
plugins?: PluginFactory[]
|
||
/**
|
||
* Custom layer list
|
||
*/
|
||
layers?: ComponentOption[]
|
||
/**
|
||
* Custom contextmenu list
|
||
*/
|
||
contextmenu?: ComponentOption[]
|
||
/**
|
||
* Custom control list
|
||
*/
|
||
controls?: ComponentOption[]
|
||
/**
|
||
* Custom setting list
|
||
*/
|
||
settings?: Setting[]
|
||
/**
|
||
* Custom video quality list
|
||
*/
|
||
quality?: Quality[]
|
||
/**
|
||
* Custom highlight list
|
||
*/
|
||
highlight?: {
|
||
/**
|
||
* The highlight time
|
||
*/
|
||
time: number
|
||
/**
|
||
* The highlight text
|
||
*/
|
||
text: string
|
||
}[]
|
||
/**
|
||
* Custom thumbnail
|
||
*/
|
||
thumbnails?: Thumbnails
|
||
/**
|
||
* Custom subtitle option
|
||
*/
|
||
subtitle?: Subtitle
|
||
/**
|
||
* Other video attribute
|
||
*/
|
||
moreVideoAttr?: Partial<Readonly<{
|
||
[K in keyof HTMLVideoElement as HTMLVideoElement[K] extends (...args: unknown[]) => unknown ? never : K]: HTMLVideoElement[K];
|
||
}>>
|
||
/**
|
||
* Custom i18n
|
||
*/
|
||
i18n?: I18n
|
||
/**
|
||
* Custom default icons
|
||
*/
|
||
icons?: {
|
||
[key in keyof Icons]?: HTMLElement | string;
|
||
}
|
||
/**
|
||
* Custom css variables
|
||
*/
|
||
cssVar?: Partial<CssVar>
|
||
/**
|
||
* Custom video type function
|
||
*/
|
||
customType?: Partial<Record<CustomType, (this: Artplayer, video: HTMLVideoElement, url: string, art: Artplayer) => unknown | Promise<unknown>>>
|
||
}
|
||
export type AspectRatio = 'default' | '4:3' | '16:9' | (`${number}:${number}` & Record<never, never>)
|
||
export type PlaybackRate = 0.5 | 0.75 | 1 | 1.25 | 1.5 | 1.75 | 2 | (number & Record<never, never>)
|
||
export type Flip = 'normal' | 'horizontal' | 'vertical' | (string & Record<never, never>)
|
||
export type State = 'standard' | 'mini' | 'pip' | 'fullscreen' | 'fullscreenWeb'
|
||
export class Player {
|
||
get aspectRatio(): AspectRatio
|
||
set aspectRatio(ratio: AspectRatio)
|
||
get state(): State
|
||
set state(state: State)
|
||
get type(): CustomType
|
||
set type(name: CustomType)
|
||
get playbackRate(): PlaybackRate
|
||
set playbackRate(rate: PlaybackRate)
|
||
get currentTime(): number
|
||
set currentTime(time: number)
|
||
get duration(): number
|
||
get played(): number
|
||
get playing(): boolean
|
||
get flip(): Flip
|
||
set flip(state: Flip)
|
||
get fullscreen(): boolean
|
||
set fullscreen(state: boolean)
|
||
get fullscreenWeb(): boolean
|
||
set fullscreenWeb(state: boolean)
|
||
get loaded(): number
|
||
get loadedTime(): number
|
||
get mini(): boolean
|
||
set mini(state: boolean)
|
||
get pip(): boolean
|
||
set pip(state: boolean)
|
||
get poster(): string
|
||
set poster(url: string)
|
||
get rect(): DOMRect
|
||
get bottom(): number
|
||
get height(): number
|
||
get left(): number
|
||
get right(): number
|
||
get top(): number
|
||
get width(): number
|
||
get x(): number
|
||
get y(): number
|
||
set seek(time: number)
|
||
get seek(): number
|
||
set forward(time: number)
|
||
get forward(): number
|
||
set backward(time: number)
|
||
get backward(): number
|
||
get url(): string
|
||
set url(url: string)
|
||
get volume(): number
|
||
set volume(percentage: number)
|
||
get muted(): boolean
|
||
set muted(state: boolean)
|
||
get theme(): string
|
||
set theme(theme: string)
|
||
get subtitleOffset(): number
|
||
set subtitleOffset(time: number)
|
||
get switch(): string
|
||
set switch(url: string)
|
||
get quality(): Quality[]
|
||
set quality(quality: Quality[])
|
||
get thumbnails(): Thumbnails
|
||
set thumbnails(thumbnails: Thumbnails)
|
||
pause(): void
|
||
play(): Promise<void>
|
||
/** Legacy signature; runtime preserves pause's synchronous result or play's Promise. */
|
||
toggle(): void
|
||
attr(key: string, value?: unknown): unknown
|
||
cssVar<T extends keyof CssVar>(key: T, value?: CssVar[T]): CssVar[T]
|
||
switchUrl(url: string): Promise<void>
|
||
switchQuality(url: string): Promise<void>
|
||
getDataURL(): Promise<string>
|
||
getBlobUrl(): Promise<string>
|
||
screenshot(name?: string): Promise<string>
|
||
airplay(): void
|
||
autoSize(): void
|
||
autoHeight(): void
|
||
reset(): void
|
||
}
|
||
export type Bar = 'loaded' | 'played' | 'hover'
|
||
/** Actual built-in subtitle update payloads; legacy Events keeps its scalar types. */
|
||
export interface SubtitleUpdateEvents {
|
||
subtitleBeforeUpdate: [
|
||
cues: VTTCue[],
|
||
]
|
||
subtitleAfterUpdate: [
|
||
cues: VTTCue[],
|
||
]
|
||
}
|
||
export interface Events {
|
||
'document:click': [
|
||
event: Event,
|
||
]
|
||
'document:mouseup': [
|
||
event: Event,
|
||
]
|
||
'document:keydown': [
|
||
event: Event,
|
||
]
|
||
'document:touchend': [
|
||
event: Event,
|
||
]
|
||
'document:touchcancel': [
|
||
event: Event,
|
||
]
|
||
'document:touchmove': [
|
||
event: Event,
|
||
]
|
||
'document:mousemove': [
|
||
event: Event,
|
||
]
|
||
'document:pointerup': [
|
||
event: Event,
|
||
]
|
||
'document:contextmenu': [
|
||
event: Event,
|
||
]
|
||
'document:pointermove': [
|
||
event: Event,
|
||
]
|
||
'document:visibilitychange': [
|
||
event: Event,
|
||
]
|
||
'document:webkitfullscreenchange': [
|
||
event: Event,
|
||
]
|
||
'window:resize': [
|
||
event: Event,
|
||
]
|
||
'window:scroll': [
|
||
event: Event,
|
||
]
|
||
'window:orientationchange': [
|
||
event: Event,
|
||
]
|
||
'video:abort': [
|
||
event: Event,
|
||
]
|
||
'video:canplay': [
|
||
event: Event,
|
||
]
|
||
'video:canplaythrough': [
|
||
event: Event,
|
||
]
|
||
'video:complete': [
|
||
event: Event,
|
||
]
|
||
'video:durationchange': [
|
||
event: Event,
|
||
]
|
||
'video:emptied': [
|
||
event: Event,
|
||
]
|
||
'video:encrypted': [
|
||
event: Event,
|
||
]
|
||
'video:ended': [
|
||
event: Event,
|
||
]
|
||
'video:error': [
|
||
error: Error,
|
||
]
|
||
'video:loadeddata': [
|
||
event: Event,
|
||
]
|
||
'video:loadedmetadata': [
|
||
event: Event,
|
||
]
|
||
'video:loadstart': [
|
||
event: Event,
|
||
]
|
||
'video:pause': [
|
||
event: Event,
|
||
]
|
||
'video:play': [
|
||
event: Event,
|
||
]
|
||
'video:playing': [
|
||
event: Event,
|
||
]
|
||
'video:progress': [
|
||
event: Event,
|
||
]
|
||
'video:ratechange': [
|
||
event: Event,
|
||
]
|
||
'video:seeked': [
|
||
event: Event,
|
||
]
|
||
'video:seeking': [
|
||
event: Event,
|
||
]
|
||
'video:stalled': [
|
||
event: Event,
|
||
]
|
||
'video:suspend': [
|
||
event: Event,
|
||
]
|
||
'video:timeupdate': [
|
||
event: Event,
|
||
]
|
||
'video:volumechange': [
|
||
event: Event,
|
||
]
|
||
'video:waiting': [
|
||
event: Event,
|
||
]
|
||
'info': [
|
||
state: boolean,
|
||
]
|
||
'layer': [
|
||
state: boolean,
|
||
]
|
||
'loading': [
|
||
state: boolean,
|
||
]
|
||
'mask': [
|
||
state: boolean,
|
||
]
|
||
'subtitle': [
|
||
state: boolean,
|
||
]
|
||
'contextmenu': [
|
||
state: boolean,
|
||
]
|
||
'control': [
|
||
state: boolean,
|
||
]
|
||
'setting': [
|
||
state: boolean,
|
||
]
|
||
'hotkey': [
|
||
event: KeyboardEvent,
|
||
]
|
||
'destroy': [
|
||
]
|
||
'subtitleOffset': [
|
||
offset: number,
|
||
]
|
||
/** Legacy contextual type; annotate listeners with VTTCue[] for the runtime payload. */
|
||
'subtitleBeforeUpdate': [
|
||
cue: VTTCue,
|
||
]
|
||
/** Legacy contextual type; annotate listeners with VTTCue[] for the runtime payload. */
|
||
'subtitleAfterUpdate': [
|
||
cue: VTTCue,
|
||
]
|
||
'subtitleLoad': [
|
||
cues: VTTCue[],
|
||
option: Subtitle,
|
||
]
|
||
'focus': [
|
||
event: Event,
|
||
]
|
||
'blur': [
|
||
event: Event,
|
||
]
|
||
'dblclick': [
|
||
event: Event,
|
||
]
|
||
'click': [
|
||
event: Event,
|
||
]
|
||
'hover': [
|
||
state: boolean,
|
||
event: Event,
|
||
]
|
||
'mousemove': [
|
||
event: Event,
|
||
]
|
||
'resize': [
|
||
]
|
||
'view': [
|
||
state: boolean,
|
||
]
|
||
'lock': [
|
||
state: boolean,
|
||
]
|
||
'aspectRatio': [
|
||
aspectRatio: AspectRatio,
|
||
]
|
||
'autoHeight': [
|
||
height: number,
|
||
]
|
||
'autoSize': [
|
||
size: {
|
||
width: number
|
||
height: number
|
||
},
|
||
]
|
||
'ready': [
|
||
]
|
||
'airplay': [
|
||
]
|
||
'raf': [
|
||
]
|
||
'error': [
|
||
error: Error,
|
||
reconnectTime: number,
|
||
]
|
||
'flip': [
|
||
flip: Flip,
|
||
]
|
||
'fullscreen': [
|
||
state: boolean,
|
||
]
|
||
'fullscreenError': [
|
||
event: Event,
|
||
]
|
||
'fullscreenWeb': [
|
||
state: boolean,
|
||
]
|
||
'mini': [
|
||
state: boolean,
|
||
]
|
||
'pause': [
|
||
]
|
||
'pip': [
|
||
state: boolean,
|
||
]
|
||
'play': [
|
||
]
|
||
'screenshot': [
|
||
dataUri: string,
|
||
]
|
||
'seek': [
|
||
currentTime: number,
|
||
time: number,
|
||
]
|
||
'restart': [
|
||
url: string,
|
||
]
|
||
'muted': [
|
||
state: boolean,
|
||
]
|
||
'setBar': [
|
||
type: Bar,
|
||
percentage: number,
|
||
event?: Event | undefined,
|
||
]
|
||
'keydown': [
|
||
event: KeyboardEvent,
|
||
]
|
||
}
|
||
/** Accurate playback method view; assign an existing player without a runtime wrapper. */
|
||
export interface PlaybackControls {
|
||
play: () => Promise<void>
|
||
pause: () => void
|
||
toggle: () => Promise<void> | void
|
||
}
|
||
export interface Template {
|
||
readonly html: string
|
||
readonly $container: HTMLDivElement
|
||
readonly $player: HTMLDivElement
|
||
readonly $video: HTMLVideoElement
|
||
readonly $track: HTMLTrackElement
|
||
readonly $poster: HTMLDivElement
|
||
readonly $subtitle: HTMLDivElement
|
||
readonly $danmuku: HTMLDivElement
|
||
readonly $bottom: HTMLDivElement
|
||
readonly $progress: HTMLDivElement
|
||
readonly $controls: HTMLDivElement
|
||
readonly $controlsLeft: HTMLDivElement
|
||
readonly $controlsCenter: HTMLDivElement
|
||
readonly $controlsRight: HTMLDivElement
|
||
readonly $layer: HTMLDivElement
|
||
readonly $loading: HTMLDivElement
|
||
readonly $notice: HTMLDivElement
|
||
readonly $noticeInner: HTMLDivElement
|
||
readonly $mask: HTMLDivElement
|
||
readonly $state: HTMLDivElement
|
||
readonly $setting: HTMLDivElement
|
||
readonly $info: HTMLDivElement
|
||
readonly $infoPanel: HTMLDivElement
|
||
readonly $infoClose: HTMLDivElement
|
||
readonly $contextmenu: HTMLDivElement
|
||
}
|
||
export interface Utils {
|
||
isBrowser: boolean
|
||
userAgent: string
|
||
isMobile: boolean
|
||
isSafari: boolean
|
||
isIOS: boolean
|
||
isIOS13: boolean
|
||
query: <T extends Element = Element>(selector: string, parent?: Document | HTMLElement) => T | null
|
||
queryAll: <T extends Element = Element>(selector: string, parent?: Document | HTMLElement) => T[]
|
||
addClass: (target: HTMLElement, className: string) => void
|
||
removeClass: (target: HTMLElement, className: string) => void
|
||
hasClass: (target: HTMLElement, className: string) => boolean
|
||
append: (target: HTMLElement, child: HTMLElement | string) => Element | ChildNode
|
||
remove: (target: HTMLElement) => HTMLElement
|
||
replaceElement: (newChild: HTMLElement, oldChild: HTMLElement) => HTMLElement
|
||
siblings: (target: HTMLElement) => HTMLElement[]
|
||
inverseClass: (target: HTMLElement, className: string) => void
|
||
createElement: <K extends keyof HTMLElementTagNameMap>(tag: K) => HTMLElementTagNameMap[K]
|
||
setStyle: <T extends keyof CSSStyleDeclaration>(element: HTMLElement, key: T, value: string | CSSStyleDeclaration[T]) => HTMLElement
|
||
setStyles: (element: HTMLElement, styles: Partial<CSSStyleDeclaration>) => HTMLElement
|
||
getStyle: {
|
||
(element: HTMLElement, key: keyof CSSStyleDeclaration, numberType?: true): number
|
||
(element: HTMLElement, key: keyof CSSStyleDeclaration, numberType: false): string
|
||
}
|
||
setStyleText: (id: string, cssText: string) => void
|
||
getRect: (el: HTMLElement) => {
|
||
top: number
|
||
left: number
|
||
width: number
|
||
height: number
|
||
}
|
||
tooltip: (target: HTMLElement, msg: string, pos?: string) => void
|
||
isInViewport: (target: HTMLElement, offset?: number) => boolean
|
||
includeFromEvent: (event: Event, target: HTMLElement) => boolean
|
||
getSafeAreaInsets: () => {
|
||
top: number
|
||
right: number
|
||
bottom: number
|
||
left: number
|
||
}
|
||
srtToVtt: (srtText: string) => string
|
||
vttToBlob: (vttText: string) => string
|
||
assToVtt: (assText: string) => string
|
||
getExt: (url: string) => string
|
||
download: (url: string, name: string) => void
|
||
loadImg: (url: string, scale?: number) => Promise<HTMLImageElement>
|
||
errorHandle: <T extends boolean>(condition: T, msg: string) => T extends true ? T : never
|
||
silencePromise: <T>(value: T) => T extends Promise<infer R> ? Promise<R | undefined> : T
|
||
def: {
|
||
/** Historical string-key signature; runtime returns obj. */
|
||
(obj: object, name: string, value: unknown): void
|
||
<T>(obj: T, name: PropertyKey, value: PropertyDescriptor & ThisType<T>): T
|
||
}
|
||
has: (obj: object, name: PropertyKey) => boolean
|
||
get: (obj: object, name: PropertyKey) => PropertyDescriptor | undefined
|
||
mergeDeep: <T extends object[]>(...args: T) => T[number]
|
||
sleep: (ms?: number) => Promise<void>
|
||
/** Historical return type; runtime discards the callback result and ignores context. */
|
||
debounce: <F extends (...args: any[]) => any>(func: F, wait: number, context?: object) => (...args: Parameters<F>) => ReturnType<F>
|
||
/** Historical return type; runtime discards the callback result. */
|
||
throttle: <F extends (...args: any[]) => any>(func: F, wait: number) => (...args: Parameters<F>) => ReturnType<F>
|
||
clamp: (num: number, a: number, b: number) => number
|
||
secondToTime: (second: number) => string
|
||
escape: (str: string) => string
|
||
unescape: (str: string) => string
|
||
capitalize: (str: string) => string
|
||
ArtPlayerError: new (message?: string, context?: ((...args: never[]) => unknown) | (abstract new (...args: never[]) => object)) => Error
|
||
getIcon: (key?: string, html?: string | HTMLElement) => HTMLElement
|
||
getComposedPath: (event: Event) => EventTarget[]
|
||
supportsFlex: () => boolean
|
||
}
|
||
export class Artplayer extends Player {
|
||
constructor(option: Option$1, readyCallback?: (this: Artplayer, art: Artplayer) => unknown)
|
||
constructor(option: OptionInput, readyCallback?: (this: Artplayer, art: Artplayer) => unknown)
|
||
static readonly instances: Artplayer[]
|
||
static readonly version: string
|
||
static readonly env: 'development' | 'production'
|
||
static readonly build: string
|
||
static readonly config: Config
|
||
static readonly utils: Utils
|
||
static readonly scheme: Record<keyof Option$1, unknown>
|
||
static readonly Emitter: new <Events extends {
|
||
[Name in keyof Events]: readonly unknown[];
|
||
} = Record<PropertyKey, unknown[]>>(...args: unknown[]) => Emitter<Events>
|
||
|
||
static readonly validator: <T extends object>(option: T, scheme: object) => T
|
||
static readonly kindOf: (item: unknown) => string
|
||
static readonly html: Artplayer['template']['html']
|
||
static readonly option: Option$1
|
||
static STYLE: string
|
||
static DEBUG: boolean
|
||
static CONTEXTMENU: boolean
|
||
static NOTICE_TIME: number
|
||
static SETTING_WIDTH: number
|
||
static SETTING_ITEM_WIDTH: number
|
||
static SETTING_ITEM_HEIGHT: number
|
||
static RESIZE_TIME: number
|
||
static SCROLL_TIME: number
|
||
static SCROLL_GAP: number
|
||
static AUTO_PLAYBACK_MAX: number
|
||
static AUTO_PLAYBACK_MIN: number
|
||
static AUTO_PLAYBACK_TIMEOUT: number
|
||
static RECONNECT_TIME_MAX: number
|
||
static RECONNECT_SLEEP_TIME: number
|
||
static CONTROL_HIDE_TIME: number
|
||
static DBCLICK_TIME: number
|
||
static DBCLICK_FULLSCREEN: boolean
|
||
static MOBILE_DBCLICK_PLAY: boolean
|
||
static MOBILE_CLICK_PLAY: boolean
|
||
static AUTO_ORIENTATION_TIME: number
|
||
static INFO_LOOP_TIME: number
|
||
static FAST_FORWARD_VALUE: number
|
||
static FAST_FORWARD_TIME: number
|
||
static TOUCH_MOVE_RATIO: number
|
||
static VOLUME_STEP: number
|
||
static SEEK_STEP: number
|
||
static PLAYBACK_RATE: number[]
|
||
static ASPECT_RATIO: string[]
|
||
static FLIP: string[]
|
||
static FULLSCREEN_WEB_IN_BODY: boolean
|
||
static LOG_VERSION: boolean
|
||
static USE_RAF: boolean
|
||
static REMOVE_SRC_WHEN_DESTROY: boolean
|
||
readonly id: number
|
||
readonly option: Option$1
|
||
readonly isLock: boolean
|
||
readonly isReady: boolean
|
||
readonly isFocus: boolean
|
||
readonly isInput: boolean
|
||
readonly isRotate: boolean
|
||
readonly isDestroy: boolean
|
||
flv?: unknown
|
||
m3u8?: unknown
|
||
hls?: unknown
|
||
ts?: unknown
|
||
mpd?: unknown
|
||
torrent?: unknown
|
||
on<T extends keyof Events>(name: T, fn: (...args: Events[T]) => unknown, ctx?: object): this
|
||
on<T extends keyof SubtitleUpdateEvents>(name: T, fn: (...args: SubtitleUpdateEvents[T]) => unknown, ctx?: object): this
|
||
on(name: string, fn: (...args: unknown[]) => unknown, ctx?: object): this
|
||
once<T extends keyof Events>(name: T, fn: (...args: Events[T]) => unknown, ctx?: object): this
|
||
once<T extends keyof SubtitleUpdateEvents>(name: T, fn: (...args: SubtitleUpdateEvents[T]) => unknown, ctx?: object): this
|
||
once(name: string, fn: (...args: unknown[]) => unknown, ctx?: object): this
|
||
emit<T extends keyof Events>(name: T, ...args: Events[T]): this
|
||
emit<T extends keyof SubtitleUpdateEvents>(name: T, ...args: SubtitleUpdateEvents[T]): this
|
||
emit(name: string, ...args: unknown[]): this
|
||
off<T extends keyof Events>(name: T, callback?: (...args: Events[T]) => unknown): this
|
||
off<T extends keyof SubtitleUpdateEvents>(name: T, callback?: (...args: SubtitleUpdateEvents[T]) => unknown): this
|
||
off(name: string, callback?: (...args: unknown[]) => unknown): this
|
||
query: Artplayer['template']['query']
|
||
proxy: Artplayer['events']['proxy']
|
||
video: Artplayer['template']['$video']
|
||
e: {
|
||
[K in keyof Events]?: {
|
||
fn: (...args: Events[K]) => unknown
|
||
ctx: unknown
|
||
}[];
|
||
}
|
||
|
||
destroy(removeHtml?: boolean): void
|
||
reset(): void
|
||
readonly template: {
|
||
get html(): string
|
||
query: <T extends Element = Element>(selector: string) => T | null
|
||
} & Template
|
||
|
||
readonly events: {
|
||
proxy: {
|
||
(target: EventTarget, eventName: string, handler: (event: Event) => void, options?: boolean | AddEventListenerOptions): () => void
|
||
(target: EventTarget, eventName: string[], handler: (event: Event) => void, options?: boolean | AddEventListenerOptions): Array<() => void>
|
||
}
|
||
hover: (element: HTMLElement, mouseenter?: (event: Event) => any, mouseleave?: (event: Event) => any) => void
|
||
remove: (destroyEvent: () => void) => void
|
||
destroy: () => void
|
||
bindGlobalEvents: (source?: {
|
||
window?: Window
|
||
document?: Document
|
||
}) => void
|
||
}
|
||
|
||
readonly storage: {
|
||
name: string
|
||
settings: Record<string, unknown>
|
||
get: {
|
||
(key: string): unknown
|
||
(): Record<string, unknown>
|
||
}
|
||
set: (key: string, value: unknown) => void
|
||
del: (key: string) => void
|
||
clear: () => void
|
||
}
|
||
|
||
readonly icons: Icons
|
||
readonly i18n: {
|
||
languages: I18n
|
||
language: Partial<Record<string, string>>
|
||
init: () => void
|
||
get: (key: string) => string
|
||
update: (language: Partial<I18n>) => void
|
||
}
|
||
|
||
readonly notice: {
|
||
timer: number | null
|
||
get show(): string | Error | false | ''
|
||
set show(msg: string | Error | false | '')
|
||
destroy: () => void
|
||
}
|
||
|
||
readonly layers: Record<string, HTMLElement | undefined> & Component
|
||
readonly controls: Record<string, HTMLElement | undefined> & Component
|
||
readonly contextmenu: Record<string, HTMLElement | undefined> & Component
|
||
readonly subtitle: {
|
||
get url(): string
|
||
set url(url: string)
|
||
get textTrack(): TextTrack | undefined
|
||
get activeCues(): VTTCue[]
|
||
get cues(): VTTCue[]
|
||
style: (name: string | Partial<CSSStyleDeclaration>, value?: string) => void
|
||
switch: (url: string, option?: Subtitle) => Promise<string>
|
||
init: (subtitle: Subtitle) => Promise<string | null | undefined>
|
||
} & Component
|
||
|
||
readonly info: Component
|
||
readonly loading: Component
|
||
readonly hotkey: {
|
||
keys: Record<string, ((event: KeyboardEvent) => any)[]>
|
||
add: (key: string, callback: (this: Artplayer, event: KeyboardEvent) => any) => Artplayer['hotkey']
|
||
remove: (key: string, callback: (event: KeyboardEvent) => any) => Artplayer['hotkey']
|
||
}
|
||
|
||
readonly mask: Component
|
||
readonly setting: {
|
||
option: SettingOption[]
|
||
updateStyle: (width?: number) => void
|
||
/** Legacy return signature; a missing runtime entry is null. */
|
||
find: (name: string) => SettingOption | undefined
|
||
/** Legacy return signature; runtime returns the formatted input item. */
|
||
add: (setting: Setting) => Artplayer['setting']
|
||
/** Legacy return signature; runtime returns the updated or added item. */
|
||
update: (settings: Setting) => Artplayer['setting']
|
||
/** Legacy return signature; runtime returns undefined. */
|
||
remove: (name: string) => Artplayer['setting']
|
||
} & Component
|
||
|
||
readonly plugins: Plugins
|
||
}
|
||
}
|
||
declare const Artplayer: typeof ArtplayerDefinitions.Artplayer
|
||
type Artplayer = ArtplayerDefinitions.Artplayer
|
||
declare namespace Artplayer {
|
||
export type Config = ArtplayerDefinitions.Config
|
||
export type Emitter<Events extends {
|
||
[Name in keyof Events]: readonly unknown[];
|
||
} = Record<PropertyKey, unknown[]>> = ArtplayerDefinitions.Emitter<Events>
|
||
export type I18n = ArtplayerDefinitions.I18n
|
||
export type Icons = ArtplayerDefinitions.Icons
|
||
export type PluginFactory<Host = Artplayer, Result = unknown> = ArtplayerDefinitions.PluginFactory<Host, Result>
|
||
export type Plugins = ArtplayerDefinitions.Plugins
|
||
export type SettingOption = ArtplayerDefinitions.SettingOption
|
||
export type Setting = ArtplayerDefinitions.Setting
|
||
export type Subtitle = ArtplayerDefinitions.Subtitle
|
||
export type OptionInput = ArtplayerDefinitions.OptionInput
|
||
export type Player = ArtplayerDefinitions.Player
|
||
export type SubtitleUpdateEvents = ArtplayerDefinitions.SubtitleUpdateEvents
|
||
export type Events = ArtplayerDefinitions.Events
|
||
export type PlaybackControls = ArtplayerDefinitions.PlaybackControls
|
||
export type Template = ArtplayerDefinitions.Template
|
||
export type Utils = ArtplayerDefinitions.Utils
|
||
export type Option = ArtplayerDefinitions.Option$1
|
||
}
|
||
export = Artplayer
|
||
export as namespace Artplayer;
|
||
|
||
|
||
===== docs/assets/ts/artplayer-i18n.d.ts =====
|
||
|
||
declare module 'artplayer/i18n/*' {
|
||
const language: NonNullable<Artplayer.I18n['en']>
|
||
export default language
|
||
}
|
||
|
||
|
||
===== Examples Summary =====
|
||
|
||
===== docs/assets/example/ads.js =====
|
||
|
||
// npm i artplayer-plugin-ads
|
||
// import artplayerPluginAds from 'artplayer-plugin-ads';
|
||
|
||
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',
|
||
|
||
// 广告跳转网址,为空则不跳转
|
||
url: 'http://artplayer.org',
|
||
|
||
// 必须观看的时长,期间不能被跳过,单位为秒
|
||
// 当该值大于或等于totalDuration时,不能提前关闭广告
|
||
// 当该值等于或小于0时,则随时都可以关闭广告
|
||
playDuration: 5,
|
||
|
||
// 广告总时长,单位为秒
|
||
totalDuration: 10,
|
||
|
||
// 多语言支持
|
||
i18n: {
|
||
close: '关闭广告',
|
||
countdown: '%s秒',
|
||
detail: '查看详情',
|
||
canBeClosed: '%s秒后可关闭广告',
|
||
},
|
||
}),
|
||
],
|
||
})
|
||
|
||
// 广告被点击
|
||
art.on('artplayerPluginAds:click', (ads) => {
|
||
console.info('广告被点击', ads)
|
||
})
|
||
|
||
// 广告被跳过
|
||
art.on('artplayerPluginAds:skip', (ads) => {
|
||
console.info('广告被跳过', ads)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/ambilight.js =====
|
||
|
||
// npm i artplayer-plugin-ambilight
|
||
// import artplayerPluginAmbilight from 'artplayer-plugin-ambilight';
|
||
|
||
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,
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/asr.js =====
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/steve-jobs.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
moreVideoAttr: {
|
||
// crossOrigin: 'anonymous',
|
||
},
|
||
plugins: [
|
||
artplayerPluginAsr({
|
||
length: 2,
|
||
interval: 40,
|
||
sampleRate: 16000,
|
||
autoHideTimeout: 10000,
|
||
// Use your AI tool to convert pcm into subtitles
|
||
onAudioChunk: ({ pcm }) => startAsr(pcm),
|
||
}),
|
||
],
|
||
})
|
||
|
||
let ws = null
|
||
let loading = false
|
||
|
||
function stopAsr() {
|
||
try {
|
||
ws.send(JSON.stringify({ type: 'end' }))
|
||
ws.close()
|
||
}
|
||
catch {}
|
||
ws = null
|
||
loading = false
|
||
}
|
||
|
||
async function startAsr(buffer) {
|
||
if (loading)
|
||
return
|
||
if (!ws) {
|
||
loading = true
|
||
const api = 'https://api.aimu.app/asr/tencent?engine_model_type=16k_en'
|
||
const { url } = await (await fetch(api)).json()
|
||
ws = new WebSocket(url)
|
||
ws.binaryType = 'arraybuffer'
|
||
ws.onmessage = (event) => {
|
||
const { code, result, message } = JSON.parse(event.data)
|
||
if (code === 0) {
|
||
art.plugins.artplayerPluginAsr.append(result?.voice_text_str)
|
||
}
|
||
else {
|
||
console.error(code, message)
|
||
stopAsr()
|
||
}
|
||
}
|
||
loading = false
|
||
}
|
||
if (ws?.readyState === WebSocket.OPEN) {
|
||
ws.send(buffer)
|
||
}
|
||
}
|
||
|
||
art.on('destroy', stopAsr)
|
||
|
||
|
||
===== docs/assets/example/asr.local.js =====
|
||
|
||
/* global Artplayer, artplayerPluginAsr */
|
||
// Local audio capture demo. The subtitles below are simulated, not recognized speech.
|
||
// No audio is uploaded; only the sample media is loaded from this local site.
|
||
const statistics = document.createElement('div')
|
||
statistics.textContent = 'Local ASR demo: press play. No recognition service is used.'
|
||
let chunks = 0
|
||
let pcmBytes = 0
|
||
let wavBytes = 0
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/steve-jobs.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
layers: [{
|
||
name: 'asr-local-statistics',
|
||
html: statistics,
|
||
style: {
|
||
position: 'absolute',
|
||
top: '12px',
|
||
left: '12px',
|
||
right: '12px',
|
||
padding: '8px 12px',
|
||
background: 'rgba(0, 0, 0, 0.65)',
|
||
color: '#fff',
|
||
fontSize: '12px',
|
||
whiteSpace: 'pre-line',
|
||
pointerEvents: 'none',
|
||
},
|
||
}],
|
||
controls: [{
|
||
name: 'asr-local-stop',
|
||
position: 'right',
|
||
html: 'Stop ASR',
|
||
tooltip: 'Stop capture; pause and play to restart',
|
||
async click() {
|
||
await art.plugins.artplayerPluginAsr.stop()
|
||
if (!art.isDestroy)
|
||
statistics.textContent = 'Local capture stopped. Pause and play to restart. Nothing was uploaded.'
|
||
},
|
||
}],
|
||
plugins: [artplayerPluginAsr({
|
||
length: 2,
|
||
interval: 250,
|
||
sampleRate: 16000,
|
||
autoHideTimeout: 5000,
|
||
onAudioChunk({ pcm, wav }) {
|
||
if (art.isDestroy)
|
||
return
|
||
chunks++
|
||
pcmBytes += pcm.byteLength
|
||
wavBytes += wav.byteLength
|
||
const sampleRate = new DataView(wav).getUint32(24, true)
|
||
const samples = new DataView(pcm)
|
||
let peak = 0
|
||
for (let offset = 0; offset < pcm.byteLength; offset += 2)
|
||
peak = Math.max(peak, Math.abs(samples.getInt16(offset, true)))
|
||
const duration = (pcmBytes / 2 / sampleRate).toFixed(2)
|
||
statistics.textContent = [
|
||
'Local capture only - simulated subtitles, no speech recognition',
|
||
`Chunks: ${chunks} | ${sampleRate} Hz mono PCM16 | ${duration} seconds captured`,
|
||
`PCM: ${pcmBytes} bytes | WAV: ${wavBytes} bytes | Current peak: ${peak}`,
|
||
].join('\n')
|
||
return `Simulated local subtitle: audio chunk ${chunks} received.`
|
||
},
|
||
})],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/audio.track.js =====
|
||
|
||
// npm i artplayer-plugin-audio-track
|
||
// import artplayerPluginAudioTrack from 'artplayer-plugin-audio-track';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/sprite-fight.mp4',
|
||
plugins: [
|
||
artplayerPluginAudioTrack({
|
||
url: '/assets/sample/sprite-fight.aac',
|
||
offset: 0,
|
||
sync: 0.3,
|
||
}),
|
||
],
|
||
});
|
||
|
||
===== docs/assets/example/auto.thumbnail.js =====
|
||
|
||
// npm i artplayer-plugin-auto-thumbnail
|
||
// import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
artplayerPluginAutoThumbnail({
|
||
//
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/canvas.js =====
|
||
|
||
// npm i artplayer-proxy-canvas
|
||
// import artplayerProxyCanvas from 'artplayer-proxy-canvas';
|
||
|
||
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,
|
||
subtitle: {
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
thumbnails: {
|
||
url: '/assets/sample/thumbnails.png',
|
||
number: 60,
|
||
column: 10,
|
||
scale: 0.85,
|
||
},
|
||
proxy: artplayerProxyCanvas(),
|
||
})
|
||
|
||
|
||
===== docs/assets/example/chapter.js =====
|
||
|
||
// npm i artplayer-plugin-chapter
|
||
// import artplayerPluginChapter from 'artplayer-plugin-chapter';
|
||
|
||
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: '终わり' },
|
||
],
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/chromecast.js =====
|
||
|
||
// npm i artplayer-plugin-chromecast
|
||
// import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
|
||
|
||
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
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/danmuku.js =====
|
||
|
||
// npm i artplayer-plugin-danmuku
|
||
// import artplayerPluginDanmuku from 'artplayer-plugin-danmuku';
|
||
// 使用文档 https://artplayer.org/document/plugin/danmuku.html
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
autoOrientation: true,
|
||
plugins: [
|
||
artplayerPluginDanmuku({
|
||
danmuku: '/assets/sample/danmuku.xml',
|
||
|
||
// 以下为非必填
|
||
speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
|
||
margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
|
||
opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
|
||
color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
|
||
mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||
modes: [0, 1, 2], // 弹幕可见的模式
|
||
fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
|
||
antiOverlap: true, // 弹幕是否防重叠
|
||
synchronousPlayback: false, // 是否同步播放速度
|
||
mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||
heatmap: true, // 是否开启热力图
|
||
width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||
points: [], // 热力图数据
|
||
filter: danmu => danmu.text.length <= 100, // 弹幕载入前的过滤器
|
||
beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
|
||
visible: true, // 弹幕层是否可见
|
||
emitter: true, // 是否开启弹幕发射器
|
||
maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||
lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
|
||
theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
|
||
OPACITY: {}, // 不透明度配置项
|
||
FONT_SIZE: {}, // 弹幕字号配置项
|
||
MARGIN: {}, // 显示区域配置项
|
||
SPEED: {}, // 弹幕速度配置项
|
||
COLOR: [], // 颜色列表配置项
|
||
|
||
// 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
|
||
beforeEmit(danmu) {
|
||
return new Promise((resolve) => {
|
||
console.log(danmu)
|
||
setTimeout(() => {
|
||
resolve(true)
|
||
}, 1000)
|
||
})
|
||
},
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/danmuku.mask.js =====
|
||
|
||
// npm i artplayer-plugin-danmuku-mask
|
||
// import artplayerPluginDanmukuMask from 'artplayer-plugin-danmuku-mask';
|
||
|
||
// npm i @mediapipe/selfie_segmentation
|
||
// 把 node_modules/@mediapipe/selfie_segmentation 目录复制到你的项目下
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/steve-jobs.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
autoOrientation: true,
|
||
plugins: [
|
||
artplayerPluginDanmuku({
|
||
danmuku: '/assets/sample/danmuku.xml',
|
||
}),
|
||
artplayerPluginDanmukuMask({
|
||
solutionPath: '/assets/@mediapipe/selfie_segmentation',
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/dash.control.js =====
|
||
|
||
// npm i dashjs
|
||
// npm i artplayer-plugin-dash-control
|
||
|
||
// import dashjs from 'dashjs';
|
||
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||
|
||
const useDash = dashjs.supportsMediaSource()
|
||
let dash
|
||
|
||
function destroyDash() {
|
||
const previous = dash
|
||
dash = undefined
|
||
if (previous)
|
||
previous.destroy()
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
|
||
setting: true,
|
||
plugins: useDash
|
||
? [
|
||
artplayerPluginDashControl({
|
||
quality: {
|
||
// Show quality choices in the controls
|
||
control: true,
|
||
// Show quality choices in settings
|
||
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() || String(track.id ?? 'Audio'),
|
||
// I18n
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
}),
|
||
]
|
||
: [],
|
||
customType: {
|
||
mpd: function playMpd(video, url, art) {
|
||
destroyDash()
|
||
if (useDash) {
|
||
dash = dashjs.MediaPlayer().create()
|
||
art.dash = dash
|
||
dash.initialize(video, url, art.option.autoplay)
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: mpd'
|
||
}
|
||
},
|
||
},
|
||
})
|
||
|
||
art.on('destroy', destroyDash)
|
||
|
||
|
||
===== docs/assets/example/dash.js =====
|
||
|
||
// npm i dashjs
|
||
// import dashjs from 'dashjs';
|
||
|
||
function playMpd(video, url, art) {
|
||
if (dashjs.supportsMediaSource()) {
|
||
if (art.dash)
|
||
art.dash.destroy()
|
||
const dash = dashjs.MediaPlayer().create()
|
||
dash.initialize(video, url, art.option.autoplay)
|
||
art.dash = dash
|
||
art.on('destroy', () => dash.destroy())
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: mpd'
|
||
}
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
|
||
type: 'mpd',
|
||
customType: {
|
||
mpd: playMpd,
|
||
},
|
||
})
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.dash)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/document.pip.js =====
|
||
|
||
// npm i artplayer-plugin-document-pip
|
||
// import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
artplayerPluginDocumentPip({
|
||
width: 480,
|
||
height: 270,
|
||
fallbackToVideoPiP: true,
|
||
placeholder: `Playing in Document Picture-in-Picture`,
|
||
}),
|
||
],
|
||
})
|
||
|
||
art.on('document-pip', (state) => {
|
||
console.log('Document Picture-in-Picture', state)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/flv.js =====
|
||
|
||
// npm i flv.js
|
||
// import flvjs from 'flv.js';
|
||
|
||
function playFlv(video, url, art) {
|
||
if (flvjs.isSupported()) {
|
||
if (art.flv)
|
||
art.flv.destroy()
|
||
const flv = flvjs.createPlayer({ type: 'flv', url })
|
||
flv.attachMediaElement(video)
|
||
flv.load()
|
||
art.flv = flv
|
||
art.on('destroy', () => flv.destroy())
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: flv'
|
||
}
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.flv',
|
||
type: 'flv',
|
||
customType: {
|
||
flv: playFlv,
|
||
},
|
||
})
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.flv)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/hls.control.js =====
|
||
|
||
// npm i hls.js
|
||
// npm i artplayer-plugin-hls-control
|
||
|
||
// import Hls from 'hls.js';
|
||
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||
|
||
const useHls = Hls.isSupported()
|
||
let hls
|
||
|
||
function destroyHls() {
|
||
const previous = hls
|
||
hls = undefined
|
||
if (previous)
|
||
previous.destroy()
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
|
||
setting: true,
|
||
plugins: useHls
|
||
? [
|
||
artplayerPluginHlsControl({
|
||
quality: {
|
||
// Show quality choices in the controls
|
||
control: true,
|
||
// Show quality choices in settings
|
||
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 || track.lang || 'Audio',
|
||
// I18n
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
}),
|
||
]
|
||
: [],
|
||
customType: {
|
||
m3u8: function playM3u8(video, url, art) {
|
||
destroyHls()
|
||
if (useHls) {
|
||
hls = new Hls()
|
||
art.hls = hls
|
||
hls.loadSource(url)
|
||
hls.attachMedia(video)
|
||
}
|
||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||
video.src = url
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: m3u8'
|
||
}
|
||
},
|
||
},
|
||
})
|
||
|
||
art.on('destroy', destroyHls)
|
||
|
||
|
||
===== docs/assets/example/hls.js =====
|
||
|
||
// npm i hls.js
|
||
// import Hls from 'hls.js';
|
||
|
||
function playM3u8(video, url, art) {
|
||
if (Hls.isSupported()) {
|
||
if (art.hls)
|
||
art.hls.destroy()
|
||
const hls = new Hls()
|
||
hls.loadSource(url)
|
||
hls.attachMedia(video)
|
||
art.hls = hls
|
||
art.on('destroy', () => hls.destroy())
|
||
}
|
||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||
video.src = url
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: m3u8'
|
||
}
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||
type: 'm3u8',
|
||
customType: {
|
||
m3u8: playM3u8,
|
||
},
|
||
})
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.hls)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/iframe.js =====
|
||
|
||
// npm i artplayer-tool-iframe
|
||
// import ArtplayerToolIframe from 'artplayer-tool-iframe';
|
||
|
||
const $iframe = document.createElement('iframe')
|
||
$iframe.allowFullscreen = true
|
||
$iframe.width = '100%'
|
||
$iframe.height = '100%'
|
||
|
||
const $container = document.querySelector('.artplayer-app')
|
||
$container.innerHTML = ''
|
||
$container.appendChild($iframe)
|
||
|
||
const iframe = new ArtplayerToolIframe({
|
||
iframe: $iframe,
|
||
url: '/iframe.html',
|
||
})
|
||
|
||
window.addEventListener('artplayer:example:cleanup', () => {
|
||
iframe.destroy()
|
||
$iframe.remove()
|
||
}, { once: true })
|
||
|
||
iframe.message(({ type, data }) => {
|
||
switch (type) {
|
||
case 'fullscreenWeb':
|
||
if (data) {
|
||
$iframe.classList.add('fullscreenWeb')
|
||
}
|
||
else {
|
||
$iframe.classList.remove('fullscreenWeb')
|
||
}
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
})
|
||
|
||
iframe.commit(() => {
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
})
|
||
|
||
art.on('fullscreenWeb', (state) => {
|
||
ArtplayerToolIframe.postMessage({
|
||
type: 'fullscreenWeb',
|
||
data: state,
|
||
})
|
||
})
|
||
}).catch((error) => {
|
||
if (!iframe.destroyed)
|
||
console.error(error)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/index.js =====
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
poster: '/assets/sample/poster.jpg',
|
||
volume: 0.5,
|
||
isLive: false,
|
||
muted: false,
|
||
autoplay: false,
|
||
pip: true,
|
||
autoSize: true,
|
||
autoMini: true,
|
||
screenshot: true,
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
subtitleOffset: true,
|
||
miniProgressBar: true,
|
||
mutex: true,
|
||
backdrop: true,
|
||
playsInline: true,
|
||
autoPlayback: true,
|
||
airplay: true,
|
||
theme: '#23ade5',
|
||
lang: navigator.language.toLowerCase(),
|
||
moreVideoAttr: {
|
||
crossOrigin: 'anonymous',
|
||
},
|
||
settings: [
|
||
{
|
||
width: 200,
|
||
html: 'Subtitle',
|
||
tooltip: 'Bilingual',
|
||
icon: '<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
|
||
},
|
||
},
|
||
{
|
||
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
|
||
},
|
||
},
|
||
{
|
||
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`
|
||
},
|
||
},
|
||
{
|
||
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">',
|
||
},
|
||
})
|
||
|
||
|
||
===== docs/assets/example/jassub.js =====
|
||
|
||
// https://github.com/ThaUnknown/jassub
|
||
// npm i artplayer-plugin-jassub
|
||
// import artplayerPluginJassub from 'artplayer-plugin-jassub';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/jassub/FGOBD.mp4',
|
||
autoSize: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
plugins: [
|
||
artplayerPluginJassub({
|
||
subUrl: '/assets/jassub/FGOBD.ass',
|
||
workerUrl: '/assets/jassub/jassub-worker.js',
|
||
wasmUrl: '/assets/jassub/jassub-worker.wasm',
|
||
modernWasmUrl: '/assets/jassub/jassub-worker-modern.wasm',
|
||
availableFonts: {
|
||
'liberation sans': '/assets/jassub/default.woff2'
|
||
},
|
||
fonts: [
|
||
'/assets/jassub/fonts/Averia Sans Libre Light.ttf',
|
||
'/assets/jassub/fonts/Averia Serif Simple Light.ttf',
|
||
'/assets/jassub/fonts/Gramond.ttf'
|
||
],
|
||
timeOffset: -0.041
|
||
}),
|
||
],
|
||
});
|
||
|
||
===== docs/assets/example/mediabunny.js =====
|
||
|
||
// npm i artplayer-proxy-mediabunny
|
||
// import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||
autoSize: true,
|
||
setting: true,
|
||
loop: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
miniProgressBar: true,
|
||
autoPlayback: true,
|
||
autoOrientation: true,
|
||
proxy: artplayerProxyMediabunny({
|
||
m3u8: {
|
||
quality: {
|
||
control: true,
|
||
setting: true,
|
||
getName: level => level.height ? `${level.height}P` : level.name,
|
||
title: 'Quality',
|
||
auto: 'Auto',
|
||
},
|
||
audio: {
|
||
control: true,
|
||
setting: true,
|
||
getName: track => track.name || track.language,
|
||
title: 'Audio',
|
||
auto: 'Auto',
|
||
},
|
||
},
|
||
}),
|
||
})
|
||
|
||
|
||
===== docs/assets/example/mobile.js =====
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
poster: '/assets/sample/poster.jpg',
|
||
autoSize: true,
|
||
loop: true,
|
||
mutex: true,
|
||
setting: true,
|
||
flip: true,
|
||
lock: true,
|
||
fastForward: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
theme: '#ff0057',
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
miniProgressBar: true,
|
||
autoOrientation: true,
|
||
airplay: true,
|
||
moreVideoAttr: {
|
||
'x5-video-player-type': 'h5',
|
||
'x5-video-player-fullscreen': false,
|
||
'x5-video-orientation': 'portraint',
|
||
'preload': 'metadata',
|
||
},
|
||
thumbnails: {
|
||
url: '/assets/sample/thumbnails.png',
|
||
number: 60,
|
||
column: 10,
|
||
scale: 0.6,
|
||
},
|
||
subtitle: {
|
||
name: '中日双语',
|
||
url: '/assets/sample/subtitle.srt',
|
||
style: {
|
||
color: '#48aff0',
|
||
fontSize: '16px',
|
||
},
|
||
},
|
||
layers: [
|
||
{
|
||
html: `<img width="50" src="/assets/sample/layer.png">`,
|
||
click() {
|
||
art.notice.show = '你点击了自定义层'
|
||
},
|
||
style: {
|
||
position: 'absolute',
|
||
top: '10px',
|
||
right: '10px',
|
||
opacity: '.9',
|
||
},
|
||
},
|
||
],
|
||
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(item) {
|
||
item.tooltip = item.switch ? '隐藏' : '显示'
|
||
art.subtitle.show = !item.switch
|
||
return !item.switch
|
||
},
|
||
},
|
||
{
|
||
default: true,
|
||
html: '双语',
|
||
url: '/assets/sample/subtitle.srt',
|
||
},
|
||
{
|
||
html: '中文',
|
||
url: '/assets/sample/subtitle.cn.srt',
|
||
},
|
||
{
|
||
html: '日文',
|
||
url: '/assets/sample/subtitle.jp.srt',
|
||
},
|
||
],
|
||
onSelect(item) {
|
||
art.subtitle.switch(item.url, {
|
||
name: item.html,
|
||
})
|
||
return item.html
|
||
},
|
||
},
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/mpegts.js =====
|
||
|
||
// npm i mpegts
|
||
// import mpegts from 'mpegts';
|
||
|
||
function playFlv(video, url, art) {
|
||
if (mpegts.isSupported()) {
|
||
if (art.flv)
|
||
art.flv.destroy()
|
||
|
||
const flv = mpegts.createPlayer({
|
||
type: 'flv',
|
||
url,
|
||
})
|
||
flv.attachMediaElement(video)
|
||
flv.load()
|
||
flv.play()
|
||
|
||
art.flv = flv
|
||
art.on('destroy', () => flv.destroy())
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: flv'
|
||
}
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.flv',
|
||
type: 'flv',
|
||
customType: {
|
||
flv: playFlv,
|
||
},
|
||
})
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.flv)
|
||
})
|
||
|
||
|
||
===== docs/assets/example/multiple.subtitles.js =====
|
||
|
||
// npm i artplayer-plugin-multiple-subtitles
|
||
// import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
plugins: [
|
||
artplayerPluginMultipleSubtitles({
|
||
subtitles: [
|
||
{
|
||
name: 'chinese',
|
||
url: '/assets/sample/subtitle.cn.srt',
|
||
},
|
||
{
|
||
name: 'japanese',
|
||
url: '/assets/sample/subtitle.jp.srt',
|
||
},
|
||
],
|
||
}),
|
||
],
|
||
settings: [
|
||
{
|
||
width: 200,
|
||
html: 'Subtitle',
|
||
tooltip: 'Double',
|
||
icon: '<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
|
||
|
||
const style = `
|
||
.art-subtitle-chinese {
|
||
color: red;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.art-subtitle-japanese {
|
||
color: yellow;
|
||
font-size: 12px;
|
||
}
|
||
`
|
||
|
||
const $style = document.getElementById('artplayer-subtitle-style')
|
||
if ($style) {
|
||
$style.textContent = style
|
||
}
|
||
else {
|
||
const $style = document.createElement('style')
|
||
$style.id = 'artplayer-subtitle-style'
|
||
$style.textContent = style
|
||
document.head.appendChild($style)
|
||
}
|
||
|
||
|
||
===== docs/assets/example/setting.test.js =====
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
setting: true,
|
||
flip: true,
|
||
playbackRate: true,
|
||
aspectRatio: true,
|
||
subtitleOffset: true,
|
||
settings: [
|
||
{
|
||
width: 200,
|
||
html: 'Subtitle',
|
||
name: 'subtitle',
|
||
tooltip: 'Bilingual',
|
||
icon: '<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
|
||
},
|
||
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)
|
||
}
|
||
})
|
||
|
||
|
||
===== docs/assets/example/thumbnail.js =====
|
||
|
||
// npm i artplayer-plugin-thumbnail
|
||
// import artplayerPluginThumbnail from 'artplayer-plugin-thumbnail';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
plugins: [
|
||
artplayerPluginThumbnail({
|
||
width: 160,
|
||
number: 100,
|
||
scale: 1,
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/tool.thumbnail.js =====
|
||
|
||
if (window.lastThumbnail) {
|
||
window.lastThumbnail.destroy();
|
||
}
|
||
|
||
var $popups = document.querySelector('.popups');
|
||
var $popinner = document.querySelector('.popinner');
|
||
var $artplayer = document.querySelector('.artplayer-app');
|
||
|
||
$artplayer.innerHTML = 'Drop video file here or click to upload.';
|
||
var thumbnail = new ArtplayerToolThumbnail({
|
||
fileInput: $artplayer,
|
||
number: 60, // 数量
|
||
width: 160, // 宽度
|
||
column: 10, // 列数
|
||
begin: 0, // 开始
|
||
end: NaN, // 结束
|
||
});
|
||
|
||
window.lastThumbnail = thumbnail;
|
||
|
||
thumbnail.on('file', function (file) {
|
||
console.log('Read video successfully: ' + file.name);
|
||
});
|
||
|
||
thumbnail.on('video', function (video) {
|
||
console.log('Video size: ' + video.videoWidth + ' x ' + video.videoHeight);
|
||
console.log('Video duration: ' + video.duration + 's');
|
||
thumbnail.start();
|
||
});
|
||
|
||
thumbnail.on('canvas', function (canvas) {
|
||
console.log('Build canvas successfully');
|
||
console.log('Canvas size: ' + canvas.width + ' x ' + canvas.height);
|
||
console.log('Preview density: ' + thumbnail.density + ' p/s');
|
||
});
|
||
|
||
thumbnail.on('update', function (url, percentage) {
|
||
console.log('Processing: ' + Math.floor(percentage.toFixed(2) * 100) + '%');
|
||
$popups.style.display = 'flex';
|
||
$popinner.style.backgroundImage = 'url(' + url + ')';
|
||
});
|
||
|
||
thumbnail.on('download', function (name) {
|
||
console.log('Start download preview: ' + name);
|
||
});
|
||
|
||
thumbnail.on('done', function () {
|
||
$popups.style.display = 'none';
|
||
thumbnail.download();
|
||
console.log('Build preview image complete');
|
||
|
||
[...Artplayer.instances].forEach(function (art) {
|
||
art.destroy(true);
|
||
});
|
||
|
||
new Artplayer({
|
||
container: $artplayer,
|
||
url: thumbnail.videoUrl,
|
||
autoSize: true,
|
||
poster: thumbnail.thumbnailUrl,
|
||
thumbnails: {
|
||
url: thumbnail.thumbnailUrl,
|
||
number: thumbnail.option.number,
|
||
column: thumbnail.option.column,
|
||
},
|
||
});
|
||
|
||
console.log('Build player complete');
|
||
});
|
||
|
||
|
||
===== docs/assets/example/vast.js =====
|
||
|
||
// Depends on:
|
||
// https://glomex.github.io/vast-ima-player/
|
||
// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side
|
||
|
||
// Google's IMA SDK are blocked by your Ad blocker.
|
||
// Please Turn Off Your Ad Blocker.
|
||
|
||
// npm i artplayer-plugin-vast
|
||
// import artplayerPluginVast from 'artplayer-plugin-vast';
|
||
|
||
var art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/video.mp4',
|
||
fullscreen: true,
|
||
fullscreenWeb: true,
|
||
plugins: [
|
||
artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
|
||
// Play the ad when the video is played
|
||
art.once('play', () => {
|
||
playUrl('https://artplayer.org/assets/vast/linear-ad.xml')
|
||
})
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/vtt.thumbnail.js =====
|
||
|
||
// npm i artplayer-plugin-vtt-thumbnail
|
||
// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: '/assets/sample/bbb-video.mp4',
|
||
plugins: [
|
||
artplayerPluginVttThumbnail({
|
||
vtt: '/assets/sample/bbb-thumbnails.vtt',
|
||
}),
|
||
],
|
||
})
|
||
|
||
|
||
===== docs/assets/example/webtorrent.js =====
|
||
|
||
// npm i webtorrent
|
||
// import WebTorrent from 'webtorrent';
|
||
|
||
async function playTorrent(video, url, art) {
|
||
if (WebTorrent.WEBRTC_SUPPORT) {
|
||
if (art.torrent)
|
||
art.torrent.destroy()
|
||
art.torrent = new WebTorrent()
|
||
|
||
await navigator.serviceWorker.register('/webtorrent.sw.min.js')
|
||
art.torrent.loadWorker(navigator.serviceWorker.controller)
|
||
|
||
art.torrent.add(url, (torrent) => {
|
||
const file = torrent.files.find((file) => {
|
||
return file.name.endsWith('.mp4')
|
||
})
|
||
file.streamTo(video)
|
||
})
|
||
|
||
art.on('destroy', () => art.torrent.destroy())
|
||
}
|
||
else {
|
||
art.notice.show = 'Unsupported playback format: torrent'
|
||
}
|
||
}
|
||
|
||
const art = new Artplayer({
|
||
container: '.artplayer-app',
|
||
url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
|
||
type: 'torrent',
|
||
customType: {
|
||
torrent: playTorrent,
|
||
},
|
||
})
|
||
|
||
art.on('ready', () => {
|
||
console.info(art.torrent)
|
||
})
|
||
|
||
|
||
===== Third-party Type Notices =====
|
||
|
||
===== docs/assets/ts/artplayer-plugin-vast.LICENSE.txt =====
|
||
|
||
@glomex/vast-ima-player
|
||
Apache License
|
||
Version 2.0, January 2004
|
||
http://www.apache.org/licenses/
|
||
|
||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||
|
||
1. Definitions.
|
||
|
||
"License" shall mean the terms and conditions for use, reproduction,
|
||
and distribution as defined by Sections 1 through 9 of this document.
|
||
|
||
"Licensor" shall mean the copyright owner or entity authorized by
|
||
the copyright owner that is granting the License.
|
||
|
||
"Legal Entity" shall mean the union of the acting entity and all
|
||
other entities that control, are controlled by, or are under common
|
||
control with that entity. For the purposes of this definition,
|
||
"control" means (i) the power, direct or indirect, to cause the
|
||
direction or management of such entity, whether by contract or
|
||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||
|
||
"You" (or "Your") shall mean an individual or Legal Entity
|
||
exercising permissions granted by this License.
|
||
|
||
"Source" form shall mean the preferred form for making modifications,
|
||
including but not limited to software source code, documentation
|
||
source, and configuration files.
|
||
|
||
"Object" form shall mean any form resulting from mechanical
|
||
transformation or translation of a Source form, including but
|
||
not limited to compiled object code, generated documentation,
|
||
and conversions to other media types.
|
||
|
||
"Work" shall mean the work of authorship, whether in Source or
|
||
Object form, made available under the License, as indicated by a
|
||
copyright notice that is included in or attached to the work
|
||
(an example is provided in the Appendix below).
|
||
|
||
"Derivative Works" shall mean any work, whether in Source or Object
|
||
form, that is based on (or derived from) the Work and for which the
|
||
editorial revisions, annotations, elaborations, or other modifications
|
||
represent, as a whole, an original work of authorship. For the purposes
|
||
of this License, Derivative Works shall not include works that remain
|
||
separable from, or merely link (or bind by name) to the interfaces of,
|
||
the Work and Derivative Works thereof.
|
||
|
||
"Contribution" shall mean any work of authorship, including
|
||
the original version of the Work and any modifications or additions
|
||
to that Work or Derivative Works thereof, that is intentionally
|
||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||
or by an individual or Legal Entity authorized to submit on behalf of
|
||
the copyright owner. For the purposes of this definition, "submitted"
|
||
means any form of electronic, verbal, or written communication sent
|
||
to the Licensor or its representatives, including but not limited to
|
||
communication on electronic mailing lists, source code control systems,
|
||
and issue tracking systems that are managed by, or on behalf of, the
|
||
Licensor for the purpose of discussing and improving the Work, but
|
||
excluding communication that is conspicuously marked or otherwise
|
||
designated in writing by the copyright owner as "Not a Contribution."
|
||
|
||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||
on behalf of whom a Contribution has been received by Licensor and
|
||
subsequently incorporated within the Work.
|
||
|
||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||
this License, each Contributor hereby grants to You a perpetual,
|
||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||
copyright license to reproduce, prepare Derivative Works of,
|
||
publicly display, publicly perform, sublicense, and distribute the
|
||
Work and such Derivative Works in Source or Object form.
|
||
|
||
3. Grant of Patent License. Subject to the terms and conditions of
|
||
this License, each Contributor hereby grants to You a perpetual,
|
||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||
(except as stated in this section) patent license to make, have made,
|
||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||
where such license applies only to those patent claims licensable
|
||
by such Contributor that are necessarily infringed by their
|
||
Contribution(s) alone or by combination of their Contribution(s)
|
||
with the Work to which such Contribution(s) was submitted. If You
|
||
institute patent litigation against any entity (including a
|
||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||
or a Contribution incorporated within the Work constitutes direct
|
||
or contributory patent infringement, then any patent licenses
|
||
granted to You under this License for that Work shall terminate
|
||
as of the date such litigation is filed.
|
||
|
||
4. Redistribution. You may reproduce and distribute copies of the
|
||
Work or Derivative Works thereof in any medium, with or without
|
||
modifications, and in Source or Object form, provided that You
|
||
meet the following conditions:
|
||
|
||
(a) You must give any other recipients of the Work or
|
||
Derivative Works a copy of this License; and
|
||
|
||
(b) You must cause any modified files to carry prominent notices
|
||
stating that You changed the files; and
|
||
|
||
(c) You must retain, in the Source form of any Derivative Works
|
||
that You distribute, all copyright, patent, trademark, and
|
||
attribution notices from the Source form of the Work,
|
||
excluding those notices that do not pertain to any part of
|
||
the Derivative Works; and
|
||
|
||
(d) If the Work includes a "NOTICE" text file as part of its
|
||
distribution, then any Derivative Works that You distribute must
|
||
include a readable copy of the attribution notices contained
|
||
within such NOTICE file, excluding those notices that do not
|
||
pertain to any part of the Derivative Works, in at least one
|
||
of the following places: within a NOTICE text file distributed
|
||
as part of the Derivative Works; within the Source form or
|
||
documentation, if provided along with the Derivative Works; or,
|
||
within a display generated by the Derivative Works, if and
|
||
wherever such third-party notices normally appear. The contents
|
||
of the NOTICE file are for informational purposes only and
|
||
do not modify the License. You may add Your own attribution
|
||
notices within Derivative Works that You distribute, alongside
|
||
or as an addendum to the NOTICE text from the Work, provided
|
||
that such additional attribution notices cannot be construed
|
||
as modifying the License.
|
||
|
||
You may add Your own copyright statement to Your modifications and
|
||
may provide additional or different license terms and conditions
|
||
for use, reproduction, or distribution of Your modifications, or
|
||
for any such Derivative Works as a whole, provided Your use,
|
||
reproduction, and distribution of the Work otherwise complies with
|
||
the conditions stated in this License.
|
||
|
||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||
any Contribution intentionally submitted for inclusion in the Work
|
||
by You to the Licensor shall be under the terms and conditions of
|
||
this License, without any additional terms or conditions.
|
||
Notwithstanding the above, nothing herein shall supersede or modify
|
||
the terms of any separate license agreement you may have executed
|
||
with Licensor regarding such Contributions.
|
||
|
||
6. Trademarks. This License does not grant permission to use the trade
|
||
names, trademarks, service marks, or product names of the Licensor,
|
||
except as required for reasonable and customary use in describing the
|
||
origin of the Work and reproducing the content of the NOTICE file.
|
||
|
||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||
agreed to in writing, Licensor provides the Work (and each
|
||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||
implied, including, without limitation, any warranties or conditions
|
||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||
appropriateness of using or redistributing the Work and assume any
|
||
risks associated with Your exercise of permissions under this License.
|
||
|
||
8. Limitation of Liability. In no event and under no legal theory,
|
||
whether in tort (including negligence), contract, or otherwise,
|
||
unless required by applicable law (such as deliberate and grossly
|
||
negligent acts) or agreed to in writing, shall any Contributor be
|
||
liable to You for damages, including any direct, indirect, special,
|
||
incidental, or consequential damages of any character arising as a
|
||
result of this License or out of the use or inability to use the
|
||
Work (including but not limited to damages for loss of goodwill,
|
||
work stoppage, computer failure or malfunction, or any and all
|
||
other commercial damages or losses), even if such Contributor
|
||
has been advised of the possibility of such damages.
|
||
|
||
9. Accepting Warranty or Additional Liability. While redistributing
|
||
the Work or Derivative Works thereof, You may choose to offer,
|
||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||
or other liability obligations and/or rights consistent with this
|
||
License. However, in accepting such obligations, You may act only
|
||
on Your own behalf and on Your sole responsibility, not on behalf
|
||
of any other Contributor, and only if You agree to indemnify,
|
||
defend, and hold each Contributor harmless for any liability
|
||
incurred by, or claims asserted against, such Contributor by reason
|
||
of your accepting any such warranty or additional liability.
|
||
|
||
END OF TERMS AND CONDITIONS
|
||
|
||
APPENDIX: How to apply the Apache License to your work.
|
||
|
||
To apply the Apache License to your work, attach the following
|
||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||
replaced with your own identifying information. (Don't include
|
||
the brackets!) The text should be enclosed in the appropriate
|
||
comment syntax for the file format. We also recommend that a
|
||
file or class name and description of purpose be included on the
|
||
same "printed page" as the copyright notice for easier
|
||
identification within third-party archives.
|
||
|
||
Copyright 2020 glomex GmbH
|
||
|
||
Licensed under the Apache License, Version 2.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing, software
|
||
distributed under the License is distributed on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
|
||
@alugha/ima
|
||
# The MIT License (MIT)
|
||
|
||
**Copyright 2020 Alugha GmbH**
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
this software and associated documentation files (the "Software"), to deal in
|
||
the Software without restriction, including without limitation the rights to
|
||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||
subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all
|
||
copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|