docs(site): [SITE-04] complete bilingual guides for JASSUB Mask and Cast

This commit is contained in:
Harvey Zhao committed 2026-09-16 03:37:35 +08:00
1 parent 558e946ae5
commit 3aad294aa5
106 files changed
+5268 -2065

No files matched your search

@@ -0,0 +1,99 @@
# Chromecast
[English](../en/plugin/chromecast.md)
在播放器右侧添加 Chromecast 按钮,通过 Cast SDK 选择会话并加载媒体。需要受支持的 Chrome 发送端、HTTPS 页面、实际接收设备和接收端能访问的媒体地址。本页描述未发布分支;本地页面、模拟 SDK 或成功建立会话均不证明电视已播放。
## 安装和示例
```sh
yarn add artplayer artplayer-plugin-chromecast
```
```js
import Artplayer from 'artplayer';
import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
```
script 先加载 ArtPlayer,再加载 `dist/artplayer-plugin-chromecast.js`,全局名为 `artplayerPluginChromecast`。以下保留[原在线示例](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast)。部署到接收设备时请提供它实际能够访问的绝对媒体 URL;发送端的 localhost、相对地址或 Blob 地址不会被插件自动转换。
<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
}),
],
})
```
## 配置与回调
配置对象必填,`{}` 使用默认值。除了注册时捕获的 icon,其余选项和回调在对应操作时读取原对象。
| 字段 | 类型 | 行为 |
| --- | --- | --- |
| `url` | `string` | 优先使用非空值,否则读取当前 art.option.url |
| `sdk` | `string` | 可覆盖 Cast SDK 脚本地址 |
| `icon` | `string` | 替换按钮内部 HTML;使用可信内容,保留 art-icon/art-icon-cast 包装 |
| `mimeType` | `string` | 优先使用非空值,否则按 URL 扩展名推断 |
| `onStateChange` | `(state) => void` | normalized state:disconnected/connecting/connected/disconnecting |
| `onCastAvailable` | `(available: boolean) => void` | SDK 设备可用性事件,不是接收端播放成功 |
| `onCastStart` | `() => void` | 当前媒体 loadMedia 完成后调用 |
| `onError` | `(error: unknown) => void` | SDK 初始化、连接或加载失败;错误不一定是 Error 实例 |
回调中的 this 是原配置对象。默认 SDK 地址为 `https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1`。同一模块、同一 window 的并发 SDK 加载共享任务,以首个请求地址为准;失败后重试可读取新地址。
MIME 推断忽略 query/hash 并将扩展名转小写:mp4/webm/ogg/ogv/mp3/wav/flv/mov/avi/wmv/mpd/m3u8 分别使用 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、application/x-mpegURL;未知扩展名使用 application/octet-stream。映射不是接收设备对所有格式的支持承诺,必要时显式提供 mimeType。
## 注册和连接状态
注册实际返回 Promise,但添加 `chromecast` 控件发生在等待之前;SDK 在首次点击时才加载。注册完成不是 SDK ready。加载器有 30 秒就绪期限,单纯 script load 但 Framework 未准备好不算成功。使用默认媒体接收应用及 ORIGIN_SCOPED 自动加入策略,不提供自定义接收应用配置选项。
一次控件点击初始化 SDK、读取当前会话;没有会话则请求会话,再重新读取当前会话,然后等待 loadMedia。同一播放器的重复待处理点击共享操作。请求成功但仍无会话会报告连接错误。源地址在发送时读取;播放器之后切源不会自动再次投屏,应通过控件重新发送需要的媒体。
结果位于 `art.plugins.artplayerPluginChromecast`:
| 成员 | 含义 |
| --- | --- |
| `name` | 固定 artplayerPluginChromecast |
| `getCastState()` | 最近一次原始 SDK SessionState,初始 null;不是回调里的标准化状态 |
| `isCasting()` | 是否保留会话引用,不证明接收端媒体正在播放 |
控件图标以白色、橙色、红色表达断开、过渡、连接状态。会话结束、启动失败或被替换会使旧请求失效,迟到结果不启动旧媒体或显示陈旧通知。SDK 错误显示阶段对应 notice 并传给 onError;用户回调抛错仍可传播。
## 清理和共享会话
播放器销毁释放该实例的加载订阅、SDK 监听器和待处理操作,不中断其他播放器的 SDK 加载,也不结束页面共享的接收会话。成功加载的 SDK 脚本留在页面,失败或最后一个等待者取消时移除待加载脚本。控件 DOM 由核心管理。
插件没有公开的 start、stop、disconnect 或 destroy 方法,不负责持续同步本地暂停、进度和音量。回调与图标只描述该控制器观察到的状态。真实设备播放、网络可达性、切源与断连需用接收端验证,现有本地测试不能替代。
## TypeScript
根入口和 `/legacy` 保留 npm1.1.0 的必填配置、同步且仅含 name 的声明。准确回调、Promise 和状态方法使用同一实现的 `/runtime`:
```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.
}
```
根和 runtime 可导出的类型为 Option、Chromecast、Result、Factory、ConnectionState、RuntimeOption、RuntimeResult、RuntimeFactory。旧根 NodeNext 命名空间形状保持不变;准确 ESM 默认调用和较早的 `import = require` 用法使用 runtime。JavaScript 支持直接工厂及 `.default(...)`;这些兼容类型不扩展实际设备能力。
@@ -0,0 +1,108 @@
# 弹幕遮罩
[English](../en/plugin/danmuku-mask.md)
通过人体分割结果生成 CSS 遮罩,让弹幕避开视频中的人物区域。插件处理核心的 `.art-danmuku` 层,不修改弹幕队列、条目或视频画面。本页描述未发布重构分支,不将在线示例或导航验证视为模型效果验收。
## 安装和示例
```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';
```
script 用法先加载核心及两个插件的 dist 文件,全局名分别为 `artplayerPluginDanmuku`、`artplayerPluginDanmukuMask`。[原在线示例](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js%0A./uncompiled/artplayer-plugin-danmuku-mask/index.js&example=danmuku.mask)按此顺序注册,并从站点自己的路径加载 MediaPipe 资源:
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js&#10;./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',
}),
],
})
```
部署时确保 solutionPath 下有匹配的 MediaPipe 资源。复制目录本身不证明所有脚本、模型、WASM、网络策略和浏览器能力都可用。
## 配置
配置可省略,注册时读取并保存这些值:
| 字段 | 类型 / 默认值 | 实际用途 |
| --- | --- | --- |
| `solutionPath` | `string` | SDK 资源根路径;默认 CDN 未固定版本 |
| `modelSelection` | `number` / `1` | 历史转发字段,不能据此认为当前模型已切换 |
| `smoothSegmentation` | `boolean` / `true` | 历史转发字段,显式 false 保留 |
| `minDetectionConfidence` | `number` / `0.5` | 历史转发字段 |
| `minTrackingConfidence` | `number` / `0.5` | 历史转发字段 |
| `selfieMode` | `boolean` / `false` | 历史转发字段 |
| `drawContour` | `boolean` / `false` | 传给二值遮罩转换 |
| `foregroundThreshold` | `number` / `0.5` | 传给前景阈值转换 |
| `opacity` | `number` / `1` | 传给 SDK drawMask,不是直接设置弹幕层 opacity |
| `maskBlurAmount` | `number` / `3` | 传给 SDK drawMask 的模糊量 |
solutionPath 默认指向未固定版本的 [jsDelivr MediaPipe 资源根目录](https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation)。
除 smoothSegmentation 的 undefined 判断外,默认值沿用 `value || default`。例如 modelSelection、opacity、threshold、blur 的 0 会回退默认值,不能用于关闭功能;停止遮罩使用 stop。
当前固定选择 `runtime: 'mediapipe'` 和 `modelType: 'general'`。已安装的 adapter 把 general 映射为 modelSelection 0,并忽略部分额外转发字段;保留参数不是承诺这些字段都会改变推理。TensorFlow 后端先尝试 webgl,只有拒绝时才尝试 cpu;这也不能证明 MediaPipe 实际使用哪种推理后端。
## start、stop 与失败
注册同步返回 `{ name: 'artplayerPluginDanmukuMask', start, stop }`,可从 `art.plugins.artplayerPluginDanmukuMask` 访问。ready 自动启动;如果在 ready 之后安装,需要自行调用 start。
| 方法 | 行为 |
| --- | --- |
| `start()` | 返回 `Promise<void>`;初始化并启动调度,不等待第一张完整遮罩 |
| `stop()` | 同步返回 undefined;取消当前调度并立刻将层的 maskImage 设为 none |
重复 start 不创建重叠推理循环。stop 可在初始化过程中调用,使公共 start 及时结算;不可取消的 SDK 工作仍被观察,迟到结果不再写入遮罩。之后 start 等待旧任务和释放过程结束再重新初始化,不以多个模型并行掩盖停止问题。
模型创建失败会记录错误且 start 可正常结算,但没有可用模型;可显式再次 start 重试。后端或必要 DOM/Canvas 初始化失败仍可能拒绝 start。自动 ready 启动会记录拒绝。推理或像素读取失败记录错误并继续下一次调度,保留上一张可用遮罩。
只在视频播放、未结束且有有效尺寸时执行分割。结果经二值遮罩、drawMask 和 Canvas 像素转换生成 PNG data URL,写入整层 maskImage。没有人物结果时保留之前的遮罩;遮罩精度、性能和跨域像素访问需要实际视频验证。
## 生命周期和类型
播放器销毁停止运行并移除 ready/destroy 监听器。私有画布归插件所有,SDK 工作完成后重置其尺寸并释放模型。stop 不是 GPU 内存回收完成的 Promise;SDK 的私有资源实际释放完成仍需独立证据。插件不提供公开 destroy、update 或新事件,也不接管其他应用的全局 TensorFlow 生命周期。
根和 `/legacy` 保留历史声明:可选配置、同步注册、异步 start 和同步 stop;没有 `/runtime` 子路径。Option/Result 是声明内部类型,可通过工厂提取。下面仅展示 NodeNext ESM 下的类型提取,不执行 `.default` 调用:
```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();
}
```
保留的 NodeNext 根类型有模块命名空间行为;这不代表当前运行时工厂有 `.default` 属性。当前 CommonJS 工厂直接调用,ESM 运行时使用默认导出;不要从类型命名空间推断运行时别名。旧版导出形状、模型真实运行和真机性能各自独立验证。
@@ -0,0 +1,137 @@
# ASS 字幕:JASSUB
[English](../en/plugin/jassub.md)
使用 JASSUB Worker/WASM 在 Canvas 上渲染 ASS 字幕。插件返回真实 JASSUB 实例,保留其方法与事件,不将字幕转换成普通 VTT。本页描述当前未发布分支;Worker、WASM、字体和实际视频效果仍需按部署环境验证。
## 安装和示例
```sh
yarn add artplayer artplayer-plugin-jassub
```
```js
import Artplayer from 'artplayer';
import artplayerPluginJassub from 'artplayer-plugin-jassub';
```
script 先加载 ArtPlayer,再加载 `dist/artplayer-plugin-jassub.js`,全局名为 `artplayerPluginJassub`。下面保留[原在线示例](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub);其中的 Worker/WASM 和字体地址属于站点资产,不会因为安装插件而自动出现在应用中。
<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
}),
],
});
```
自行托管相互匹配的 Worker、WASM 和字体,确认路径、访问策略及字体使用许可。缺失字体会影响排版;相对默认路径存在不等于文件已部署。
## 资源和渲染选项
实际配置可省略,默认绑定 art.video;配置在注册时读取,显式 video 可覆盖它。以下按当前本地实现描述,不照搬上游注释中的旧默认值。
| 字段 | 实际默认或含义 |
| --- | --- |
| `video` / `canvas` | 默认 video 为 art.video;提供自己的 canvas 可手动管理节点,至少需要可用的渲染目标 |
| `workerUrl` | `'jassub-worker.js'` |
| `wasmUrl` | `'jassub-worker.wasm'` |
| `legacyWasmUrl` | `'jassub-worker.wasm.js'` |
| `modernWasmUrl` | 检测到 SIMD 且提供此地址时优先使用,否则使用 wasmUrl |
| `subUrl` / `subContent` | 字幕地址或 ASS 文本,传给 Worker |
| `fonts` | 默认空数组,元素可为 URL 或 Uint8Array |
| `availableFonts` | 默认 `{ 'liberation sans': './default.woff2' }`,字体名到 URL/字节映射 |
| `fallbackFont` | `'liberation sans'` |
| `useLocalFonts` | 只有存在 queryLocalFonts 时启用;未指定时当前实现为 true,可显式 false;仍受权限限制 |
| `blendMode` | `'js'`,也可选 `'wasm'` |
| `asyncRender` | 默认 true,但需 createImageBitmap 能力 |
| `offscreenRender` | 默认 true,但需 transferControlToOffscreen 且没有传入自有 canvas |
| `onDemandRender` | 默认 true,但需 requestVideoFrameCallback 能力 |
| `targetFps` | 默认 24,按需渲染时不作为固定更新承诺 |
| `timeOffset` | 默认 0,单位秒 |
| `debug` | 默认 false |
| `prescaleFactor` / `prescaleHeightLimit` / `maxRenderHeight` | 默认 1 / 1080 / 0,控制渲染尺寸;0 的最大高度表示不设置此上限 |
| `dropAllAnimations` / `dropAllBlur` | 转发给 Worker 的简化渲染选项,未指定时不在包装层设置为 true |
| `libassMemoryLimit` / `libassGlyphLimit` | 默认 0,libass 缓存限制参数,单位 MiB;不是浏览器总内存上限 |
若平台缺少能力,渲染路径会与配置意图不同。不要把异步、离屏或后端选项视为所有设备的速度保证,也不要在不同版本 Worker 与包装层之间混用资源。
## 实例和方法
注册同步返回 `{ name: 'artplayerPluginJassub', instance }`,不是 Worker ready Promise。通过 `art.plugins.artplayerPluginJassub.instance` 取得实例。实例是 EventTarget,监听 ready 后再进行查询;error 事件属于该实例,不是播放器的同名事件。
| 方法 | 行为与单位 |
| --- | --- |
| `resize(width?, height?, top?, left?, force?)` | 同步返回 void;实际 force 在最后,省略尺寸时依据视频计算 |
| `setVideo(video)` | 同步切换绑定视频、观察器和自有容器位置 |
| `setTrackByUrl(url)` / `setTrack(content)` / `freeTrack()` | 切换地址、ASS 文本或释放字幕轨道 |
| `setIsPaused(boolean)` / `setRate(number)` | 手动更新 Worker 的播放状态/倍率 |
| `setCurrentTime(isPaused?, currentTime?, rate?)` | currentTime 使用秒 |
| `createEvent(event)` / `setEvent(event, index)` / `removeEvent(index)` | 增删改 ASS event,修改对象为部分字段 |
| `getEvents(callback)` | 回调返回 event 数组,非 Promise |
| `createStyle(style)` / `setStyle(style, index)` / `removeStyle(index)` | 增删改样式,修改对象为部分字段 |
| `getStyles(callback)` | 回调返回样式数组,非 Promise |
| `styleOverride(style)` / `disableStyleOverride()` | 设置/取消样式覆盖 |
| `setDefaultFont(font)` / `addFont(font)` | 设置默认字体或添加 URL/字节字体 |
| `runBenchmark()` | 请求 Worker 基准操作,不代表端到端性能结论 |
| `sendMessage(target, data?, transferable?)` | Promise 仅表示已发送,或销毁后无需发送,不等待 Worker 确认 |
| `destroy()` | 同步清理并可重复调用,没有资源回收完成 Promise |
除 sendMessage 外,上表普通控制方法返回 void;查询通过回调提供数据。`destroy(error)` 保留历史返回行为:原 Error 原样返回,非空字符串转为 Error,空字符串原样返回。正常调用使用无参 destroy。
AssEvent 的 Start/Duration 为毫秒,Style 是数字样式索引;其余字段为 Name、MarginL/MarginR/MarginV、Effect、Text、ReadOrder、Layer。AssStyle 包含 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、Justify。查询结果没有 `_index`,不要混淆 ASS 文本格式的样式名称与运行时 Style 数字。
查询回调成功为 `(null, array)`;失败为 Error 或原生 Event 且没有数据。销毁会在清理监听器/定时器后使待处理查询失败。协议按响应 target 匹配,没有新的请求 ID;避免把同时发出的同类查询当作独立关联响应。
## 生命周期和类型
插件创建的 `.JASSUB` 容器设为 z-index 20,销毁时移除;调用方传入的 canvas/video 保留。播放器销毁调用实例当前的 destroy,直接销毁也保持幂等。setVideo 和销毁会使旧帧回调失效,Worker 和自有观察器会清理;晚到的异步位图不应重新启动渲染。真实离屏停顿、浏览器差异和物理设备仍有独立验收要求。
根和 `/legacy` 保留旧 JassubOption/JassubInstance 类型:三个资源 URL 必填、force-first resize,以及错误的 Promise 方法返回和任意扩展索引。准确类型使用同一实现的 `/runtime`:
```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 导出 FontSource、RuntimeOption、AssEvent、AssStyle、AssEventInput、AssStyleInput、WorkerRequestError、EventsCallback、StylesCallback、RuntimeEventMap、RuntimeInstance、RuntimeResult、RuntimeFactory。精确实例字段包括 timeOffset、debug、三项尺寸设置、可选 busy,以及历史公开 `_canvas/_ctx`;`_ctx` 可能为 false/null。没有运行时工厂 `.default` 自引用;NodeNext 根类型的命名空间不能当作这种别名。runtime 支持准确 ESM 默认导入和 CommonJS `import = require`。