docs(dash): [SITE-DASH-01] add bilingual guides and fix example lifecycle

This commit is contained in:
Harvey Zhao committed 2026-09-15 18:09:30 +08:00
1 parent 4ea0ba94ae
commit 319dccb605
70 files changed
+4005 -1695

No files matched your search

@@ -148,6 +148,20 @@ and checked standalone against both TS 4.3.5 and 5.9.3, then consumed by real Mo
## Validation and next work
The bilingual `artplayer-vitepress/docs/{en/,}plugin/dash-control.md` guides contain
the exact `docs/assets/example/dash.control.js` setup. The example keeps one final
SDK cleanup listener, releases replaced instances once, skips SDK-dependent controls
when MediaSource is unsupported, and formats nullable language metadata safely.
`test/dash-example.test.js` exercises the actual source against these old failures.
`document-dash.spec.js` requires both guides to match that source, then runs it with
both frozen SDK generations and published/candidate core. WebKit's unsupported
branch is capability evidence only. The original SDK initialization settings and
plugin APIs are unchanged; full SDK/device/DRM acceptance remains separate.
When changing the example, update both guides, run the example and browser tests,
rebuild the LLM corpus/docs and refresh the site inventory. `document-site.spec.js`
checks guide navigation and the two-library Run Code parameters in both languages.
Run at the workspace root with pinned Node and Yarn:
```sh
@@ -2,6 +2,11 @@
Dash control plugin for ArtPlayer
Complete usage and SDK ownership:
[English guide](../artplayer-vitepress/docs/en/plugin/dash-control.md) /
[中文指南](../artplayer-vitepress/docs/plugin/dash-control.md).
These guides describe the current refactor branch; its fixes are not published yet.
Accepts a caller-owned dash.js instance at `art.dash`. Quality selection adapts to the
dash.js 4.x quality methods or 5.x representation methods. Version 5 selection uses
representation IDs so bitrate filtering does not change the selected quality.
+8 -2
View File
@@ -12,14 +12,15 @@ not a VitePress page. Keep both URL surfaces compatible.
| `docs/en` | English counterparts | `/document/en/` |
| `docs/plugin/danmuku.md`, `docs/en/plugin/danmuku.md` | Danmuku options, callbacks, commands, heatmap and types in both languages | `/document/plugin/danmuku.html`, `/document/en/plugin/danmuku.html` |
| `docs/plugin/hls-control.md`, `docs/en/plugin/hls-control.md` | HLS SDK setup, menus, lifecycle and types | `/document/plugin/hls-control.html`, `/document/en/plugin/hls-control.html` |
| `docs/plugin/dash-control.md`, `docs/en/plugin/dash-control.md` | DASH SDK generations, menus, lifecycle and types | `/document/plugin/dash-control.html`, `/document/en/plugin/dash-control.html` |
| `docs/.vitepress/config.js` | Navigation, base URL, output path, page head | Repository `docs/document/` |
| `docs/vite.config.ts` | Search plugin configuration | VitePress/Vite integration; real search acceptance remains pending |
| `docs/public/main.js` | Run Code links and first-visit language redirect | Copied into the built site |
| `docs/public/style.css` | Documentation presentation | Copied into the built site |
Edit Markdown and public sources here. Do not edit the generated repository
`docs/document/`. The current inventory contains 30 Markdown pages: 15 Chinese
and 15 English. Danmuku and HLS have dedicated guides and navigation in both languages. Other plugins currently
`docs/document/`. The current inventory contains 32 Markdown pages: 16 Chinese
and 16 English. Danmuku, HLS and DASH have dedicated guides and navigation in both languages. Other plugins currently
use their package README, architecture notes and linked editor examples;
navigation links alone are not complete API documentation.
@@ -131,3 +132,8 @@ root. `test/browser/document-hls.spec.js` enforces that parity and checks the
source lifecycle with frozen real SDKs. `document-site.spec.js` checks both sidebar
links and the two-library Run Code destination. Preserve the native-HLS capability
boundary and SDK ownership explanation when editing either language.
The DASH guides use the same exact-example rule with `docs/assets/example/dash.control.js`
and `test/browser/document-dash.spec.js`. Their formatter has one argument, unlike
the optional HLS list index. Preserve the distinction between SDK 4 qualityIndex
and SDK 5 representation IDs, nullable language fields, and synchronous update.
@@ -71,7 +71,7 @@ const config = {
{ text: '视频广告', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads' },
{ text: 'Iframe 控制', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe' },
{ text: 'HLS 控制', link: '/plugin/hls-control' },
{ text: 'DASH 控制', link: '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' },
{ text: 'DASH 控制', link: '/plugin/dash-control' },
{ text: 'VTT 缩略图', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail' },
{ text: '多重字幕', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles' },
{ text: 'ASS 字幕 - JASSUB', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub' },
@@ -143,7 +143,7 @@ const config = {
{ text: 'Advertise', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads' },
{ text: 'Iframe Control', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe' },
{ text: 'HLS Control', link: '/en/plugin/hls-control' },
{ text: 'DASH Control', link: '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' },
{ text: 'DASH Control', link: '/en/plugin/dash-control' },
{ text: 'VTT Thumbnail', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail' },
{ text: 'Multiple Subtitles', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles' },
{ text: 'ASS Subtitle - JASSUB', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub' },
@@ -0,0 +1,178 @@
# 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.
@@ -0,0 +1,178 @@
# DASH 控制
[English](../en/plugin/dash-control.md)
为 dash.js 播放器添加画质和音轨菜单。你负责创建 SDK、绑定 video 并赋给 `art.dash`;插件控制这个实例,只清理自己创建的菜单和监听器。
本页描述当前重构分支。这里的 SDK 适配、自动刷新和生命周期修复尚未发布;未固定版本的 npm/CDN 安装仍使用已发布版本。
## 安装
```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';
```
使用 script 标签时,在初始化前加载 ArtPlayer、dash.js 和 `dist/artplayer-plugin-dash-control.js`。插件全局名称为 `artplayerPluginDashControl`。应用应固定依赖版本,并使用浏览器可访问的 MPD 和媒体片段。
## 完整示例
下面与[在线 DASH 示例](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)使用相同代码。接入应用时替换站点容器和视频地址。
<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)
```
示例在创建播放器时固定 SDK 能力分支。若 dash.js 无法使用 MediaSource,则保留原来的格式不支持提示,不创建 SDK 或安装依赖它的控制插件。这个示例没有提供原生 DASH 回退。
## 配置
`artplayerPluginDashControl(option?)` 同步返回插件工厂。`quality` 和 `audio` 都支持:
| 字段 | 含义与默认行为 |
| --- | --- |
| `control` | 显示底部控制器;省略时不显示。 |
| `setting` | 显示设置项;省略时不显示,还需播放器配置 `setting: true`。 |
| `title` | 菜单标题,默认 `Quality` 或 `Audio`。 |
| `auto` | 回退文字,默认 `Auto`;画质还用于自动选项,不会新增一个虚拟音轨。 |
| `getName(item)` | 根据原始 SDK 档位或轨道对象返回字符串。只有一个参数,不提供索引或播放器 this。 |
默认画质标签为 `level.height + 'p'`,音轨标签取 `track.lang` 或 `track.id`。这些元数据可能缺失或为 null,自定义回调应像完整示例一样返回字符串回退。空标题或空 Auto 文字会使用默认值。
相同文字标签会合并成一个选项。若同高度的多个档位需要分别显示,可以在标签中加入码率或其他元数据。选中重复项时,会保留实际选中的 SDK 标识或轨道对象。轨道列表变空时移除对应菜单。
## 画质和音轨选择
手动选画质先关闭视频的自动码率选择,再调用 SDK 选择档位;Auto 只启用视频自动选择,不覆盖其他 ABR 设置。同步选择菜单不代表缓冲或解码已经完成。
插件根据 SDK 实际提供的方法选择适配方式:
| SDK 接口 | 画质列表与选择 |
| --- | --- |
| dash.js 4 风格 | `getBitrateInfoListFor('video')`、`getQualityFor('video')`、`setQualityFor('video', qualityIndex)` |
| dash.js 5 风格 | `getRepresentationsByType('video')`、`getCurrentRepresentationForType('video')`、`setRepresentationForTypeById('video', id)` |
representation 接口使用 ID 选择,数字零也是合法 ID;不能用过滤后数组的索引代替。无需给插件额外设置 SDK 版本开关。
选择音轨时,把原始 SDK 轨道对象交给 `setCurrentTrack()`。当前项优先通过对象身份匹配,再通过可用 id/index/lang 字段的唯一组合匹配,不会任意选中有歧义的项。音轨列表没有额外 Auto 行。
## 外部修改后的刷新
播放器 ready/restart 和 SDK 的画质、音轨、流事件会刷新菜单。SDK 事件刷新在当前同步选择结束后合并执行;未变化的播放时间事件不重绘菜单,但可以发现外部 Auto 设置变化。
暂停时直接修改 SDK 配置、且没有后续 SDK 事件,可以手动刷新:
```js
art.plugins.artplayerPluginDashControl.update();
```
`update()` 同步返回 `undefined`,要求 `art.dash` 已绑定到播放器的 video,否则可能抛错。仅赋值一个新的 `art.dash` 不会立即订阅它;绑定后调用 `update()`,或走正常 ready/restart 流程。
自动刷新会保留已打开、由插件管理的画质或音轨设置子菜单;显式 `update()` 保留原有重建行为。插件使用 `dash-quality` 和 `dash-audio` 菜单名,其他菜单请避开这些名称。
异步 SDK getter 或格式回调失败时,插件会输出警告、停止该观察并清除菜单;修正回调或 SDK 状态后调用 `update()` 恢复。显式更新和同步选择的错误仍按原语义抛出。
## SDK 所有权与换源
换源使用播放器已有的 `switchUrl()` 或 `switchQuality()`,并处理返回的 Promise。完整示例先销毁被替换的 SDK,在初始化前赋值新实例,每个播放器只注册一个最终清理监听器,不在每次加载时累积新的 destroy 回调,也不在最后重复销毁旧实例。
控制插件不会调用 `dash.destroy()`、更换清单地址或移除其他使用者的监听器;替换实例或销毁播放器后,旧菜单回调失效。应用仍负责 DRM、SDK 错误、自动播放策略,以及自身集成所需的异步 SDK 关闭策略。
## TypeScript
默认回调类型包含画质高度/宽度/ID/码率,以及允许为空的音轨 id/index/lang。可以通过泛型声明更具体的元数据;下面只声明实际使用的字段,无需导入 SDK 声明:
```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` 和 `Result`,原根入口与 legacy 路径继续保留。使用实际 SDK 声明时,dash.js 4.5.2 的画质类型为 `BitrateInfo`,5.2.1 使用 `Representation`;其编译器与模块解析要求不同,应验证实际 SDK/TypeScript 组合。在应用的集成类型中描述外部附加的 `art.dash`。
## 验证范围
重构使用固定 dash.js 4.5.2 / 5.2.1、本地自适应媒体和新旧核心组合验证;这两个版本是验证点,不是新定义的完整支持范围。插件对4.5.2暂停拖动后空缓冲指标陈旧的问题有定向恢复,保留调用方 SDK 设置和媒体时间。Windows Playwright WebKit 缺少相关 MSE 路径,不能代表 Safari 或真机播放已验收。采用未发布重构前,应验证自己的 MPD、DRM 和目标设备。
@@ -50,5 +50,5 @@
}
// <stdin>
installNavigation(window, ["advanced/built-in.html", "advanced/built-in", "advanced/class.html", "advanced/class", "advanced/event.html", "advanced/event", "advanced/global.html", "advanced/global", "advanced/plugin.html", "advanced/plugin", "advanced/property.html", "advanced/property", "component/contextmenu.html", "component/contextmenu", "component/controls.html", "component/controls", "component/layers.html", "component/layers", "component/setting.html", "component/setting", "", "index.html", "plugin/danmuku.html", "plugin/danmuku", "plugin/hls-control.html", "plugin/hls-control", "start/i18n.html", "start/i18n", "start/option.html", "start/option"]);
installNavigation(window, ["advanced/built-in.html", "advanced/built-in", "advanced/class.html", "advanced/class", "advanced/event.html", "advanced/event", "advanced/global.html", "advanced/global", "advanced/plugin.html", "advanced/plugin", "advanced/property.html", "advanced/property", "component/contextmenu.html", "component/contextmenu", "component/controls.html", "component/controls", "component/layers.html", "component/layers", "component/setting.html", "component/setting", "", "index.html", "plugin/danmuku.html", "plugin/danmuku", "plugin/dash-control.html", "plugin/dash-control", "plugin/hls-control.html", "plugin/hls-control", "start/i18n.html", "start/i18n", "start/option.html", "start/option"]);
})();