mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-23 13:51:20 -08:00
docs(site): [SITE-04] document thumbnail extraction and subtitle selection
This commit is contained in:
1 parent
94adb77fd6
commit
3317230f2e
94 files changed
+4654
-1908
No files matched your search
@@ -0,0 +1,85 @@
|
||||
# 自动缩略图
|
||||
|
||||
[English](../en/plugin/auto-thumbnail.md)
|
||||
|
||||
使用独立视频元素读取画面,在浏览器内逐步生成 JPEG 雪碧图,并更新播放器进度条的缩略图配置。本页描述未发布的重构分支;在线示例及未固定版本的 npm/CDN 包不等于当前候选。
|
||||
|
||||
## 安装和示例
|
||||
|
||||
```sh
|
||||
yarn add artplayer artplayer-plugin-auto-thumbnail
|
||||
```
|
||||
|
||||
```js
|
||||
import Artplayer from 'artplayer';
|
||||
import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
|
||||
```
|
||||
|
||||
使用 script 时先加载 ArtPlayer,再加载 `dist/artplayer-plugin-auto-thumbnail.js`,全局名为 `artplayerPluginAutoThumbnail`。以下代码保留[原在线示例](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-auto-thumbnail/index.js&example=auto.thumbnail)。工厂参数对象必填,使用 `{}` 选择默认值。
|
||||
|
||||
<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({
|
||||
//
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 配置与生成方式
|
||||
|
||||
| 字段 | 类型 | 默认值 | 含义 |
|
||||
| --- | --- | --- | --- |
|
||||
| `url` | `string` | 当前 `art.option.url` | 独立解码器读取的媒体地址;显式非空地址优先 |
|
||||
| `width` | `number` | `160` | 每格缩略图宽度,单位像素 |
|
||||
| `number` | `number` | `100` | 目标采样数量,通常使用正整数 |
|
||||
| `scale` | `number` | `1` | 传给播放器的预览显示缩放,不降低生成画布尺寸 |
|
||||
| `height` | `number` | 按视频宽高比计算 | 历史参数,实际忽略;精确 runtime 类型接受它 |
|
||||
|
||||
这些默认值沿用 `value || default` 规则,例如 `width: 0` 回退为 160。width 和 number 回退后需要为可转换成有限正数的值;旧 JavaScript 数值字符串和小数计数行为保留,但类型示例使用数字与正整数。生成高度为 `Math.floor(width * videoHeight / videoWidth)`,每行固定十列。媒体必须有有限的正时长和尺寸,不适用于直播无限时长。
|
||||
|
||||
采样时刻为 `duration * index / number`,从 index 0 开始,不包含媒体终点。时长与画布尺寸在独立视频 metadata 时固定;每次画出一格后编码整张 JPEG,再发布新的 `art.thumbnails` 配置。因此生成期间后面的格子可能尚未填充,并不是所有缩略图同时就绪。
|
||||
|
||||
较大的 width 和 number 会增加画布、解码和反复编码成本;尺寸校验不是浏览器内存预算保证。选择适合视频长度和目标设备的配置,或使用预先制作的 [VTT 缩略图](./vtt-thumbnail.md)。
|
||||
|
||||
## 注册、切源和清理
|
||||
|
||||
工厂返回异步注册函数,结果仅包含 `name: 'artplayerPluginAutoThumbnail'`。注册 Promise 在安装播放器事件后完成,不等待缩略图生成,也不表示媒体已成功读取。没有公开的进度、生成完成、update、stop 或 destroy 方法。
|
||||
|
||||
每次 `video:loadedmetadata` 启动新一轮提取,并重新读取原配置对象;之后修改原对象会影响下一轮。插件不补发安装之前已经过去的 metadata 事件。`restart` 取消旧提取,后续 metadata 才启动新任务。旧的异步帧和编码回调不能覆盖新任务。
|
||||
|
||||
独立解码器的 metadata、每帧就绪和每次 JPEG 编码各有 30 秒等待上限,不是整个任务的总时限。媒体、画布或编码失败会清理当前任务,通过 `console.warn` 报告,并保留最后一张可用预览;已完成的注册 Promise 不会因此重新拒绝。
|
||||
|
||||
完成或取消后释放独立视频与画布;最后的图片 URL 保留至被新的可用图替换或播放器销毁。只撤销插件生成的 URL,不撤销应用自己的外部缩略图地址。销毁同时移除监听器;直接调用已保留的注册函数且播放器已销毁时,只返回名称,不分配解码器,这不改变核心 `plugins.add()` 的销毁检查。
|
||||
|
||||
## 媒体访问和浏览器边界
|
||||
|
||||
独立视频固定使用 `crossOrigin = 'anonymous'`,静音且不主动播放。媒体必须允许浏览器原生读取和 Canvas 像素访问,跨域服务需要正确的 CORS 响应。播放器的自定义加载器、SDK、请求头或代理不会自动安装到这个独立解码器;必要时用 `url` 提供它能直接读取的媒体。
|
||||
|
||||
独立视频会以隐藏但具有渲染尺寸的节点挂到文档中;这不表示新增可见播放器。真实解码和首帧正确性仍依赖浏览器。当前 Windows WebKit 首帧问题尚未完成验收,不能把类型、导航或其它浏览器通过当作该问题已解决,也不代表真实 Safari/手机已验证。
|
||||
|
||||
## TypeScript 兼容入口
|
||||
|
||||
根入口和 `/legacy` 保留 npm 1.1.0 的同步结果声明,工厂对象必填,根 Option 没有 height。需要实际 Promise、旧 height 参数或 `.default` 自引用类型时,使用同一实现的 `/runtime`:
|
||||
|
||||
```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 导出 `Option`、`Result`、`Factory`、`RuntimeFactory`;Factory 是普通异步工厂,RuntimeFactory 还描述可写的 `.default` 自引用。实际 CommonJS 支持直接调用及 `.default(...)`。更早 1.0.x 的 `export =` 和 height 声明与 1.1.0 不同,需要旧导入形式时可迁到 runtime 的 `import = require`。根 NodeNext 模块形状保留,准确的可调用默认导入使用 runtime;经典 Node10 默认导入需要 `esModuleInterop`。
|
||||
@@ -0,0 +1,200 @@
|
||||
# 多重字幕
|
||||
|
||||
[English](../en/plugin/multiple-subtitles.md)
|
||||
|
||||
下载多个字幕文件,保留各自 cue 的时刻,将选中轨道合并到播放器字幕中。可以同时显示不同语言,并按名称选择或调整轨道顺序。本页描述当前未发布的重构分支;线上示例和未固定版本的包不等于当前候选。
|
||||
|
||||
## 安装和示例
|
||||
|
||||
```sh
|
||||
yarn add artplayer artplayer-plugin-multiple-subtitles
|
||||
```
|
||||
|
||||
```js
|
||||
import Artplayer from 'artplayer';
|
||||
import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
|
||||
```
|
||||
|
||||
使用 script 时先加载 ArtPlayer,再加载 `dist/artplayer-plugin-multiple-subtitles.js`,全局名为 `artplayerPluginMultipleSubtitles`。下面保留[在线示例](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles)的原始选择菜单和样式代码;菜单由应用配置,插件不自动创建菜单。
|
||||
|
||||
<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)
|
||||
}
|
||||
```
|
||||
|
||||
## 字幕配置
|
||||
|
||||
工厂需要配置对象,`subtitles` 是轨道数组。运行时 `{}` 等同空数组;旧根类型仍要求显式提供 `subtitles`。每个 `TrackOption` 的字段如下:
|
||||
|
||||
| 字段 | 类型 | 默认或行为 |
|
||||
| --- | --- | --- |
|
||||
| `url` | `string` | 字幕地址,使用浏览器 fetch;历史类型虽可选,实际用例应提供有效地址 |
|
||||
| `name` | `string` | 轨道选择和 CSS 名称;建议提供唯一、简单的名称,例如 `chinese` |
|
||||
| `type` | `'vtt' \| 'srt' \| 'ass'` | 未指定时读取 URL 扩展名;显式值优先 |
|
||||
| `encoding` | `string` | 默认 `'utf-8'`,传给 TextDecoder |
|
||||
| `onParser` | `(...args: object[]) => object` | 历史声明保留,实际不会调用 |
|
||||
|
||||
所有文件并行下载,再解码并合并。跨域文件需要服务端允许 fetch。SRT、ASS 使用核心转换工具生成 VTT;ASS 不保留完整 ASS 排版和动画,需要完整 ASS 渲染时使用 JASSUB。未知类型转为空内容,解析器尽力处理文本,格式诊断不一定拒绝全部可用 cue。
|
||||
|
||||
HTTP 非成功响应、解码或转换抛出的错误会使注册拒绝,并释放同批请求。元数据按下载完成后的原配置读取,不是深拷贝;避免在安装过程中修改轨道对象或数组。
|
||||
|
||||
## 注册与选择
|
||||
|
||||
实际注册异步完成,返回 `{ name: 'multipleSubtitles', tracks, reset }`,结果存放在 `art.plugins.multipleSubtitles`,不是全局工厂名。需要直接使用返回结果时先 await 注册;结果就绪不代表播放器已经完成字幕加载。
|
||||
|
||||
| 调用 | 结果 |
|
||||
| --- | --- |
|
||||
| `tracks(['chinese', 'japanese'])` | 按调用方名称顺序选择轨道 |
|
||||
| `tracks(['japanese'])` | 仅显示选中的轨道 |
|
||||
| `tracks()` 或 `tracks([])` | 清空选择 |
|
||||
| `reset()` | 恢复所有最初下载的轨道及其原顺序 |
|
||||
|
||||
tracks 和 reset 都同步返回 `undefined`。未知名称保留历史同步 TypeError;重复名称按每次查找的第一条轨道处理,不会自动去重。请使用已经配置的唯一名称。轨道按选择顺序合并,但并不改写不同语言 cue 的时间,不能用轨道顺序对齐本来错位的字幕。
|
||||
|
||||
每次选择都会创建新的 VTT Blob URL 并初始化播放器字幕,释放上一份插件拥有的 URL。异步字幕安装失败会警告并清理失败资源,void 方法不能用于 await 字幕就绪。切换视频不会重新下载轨道,reset 也不是重新请求服务器;插件没有公开的 update、reload 或独立 destroy。
|
||||
|
||||
## 样式与资源归属
|
||||
|
||||
字幕内容使用 `.art-subtitle-<name>` 包装,例如示例的 `.art-subtitle-chinese` 和 `.art-subtitle-japanese`。名称会进入 HTML 类名,请使用应用定义的简单标识。选择时插件设置 `art.option.subtitle.escape = false` 并接管该次字幕 URL、type 和 onVttLoad;与其它同时管理字幕的插件组合时,需要明确由谁最后写入。
|
||||
|
||||
普通 cue 文本、实体和合法标记分别处理;内联时间戳保留 cue 数据,但显示仍为整段字幕,不新增卡拉 OK 逐字高亮。较旧核心的多 active cue 显示有兼容处理;依赖自定义字幕 DOM 的监听器应在插件注册后安装,以免被后续字幕视图更新覆盖。
|
||||
|
||||
播放器销毁会取消请求、移除插件监听器、释放生成的 URL。下载中的注册会结算为不再工作的结果,保留的 tracks/reset 方法变成空操作。销毁不会恢复共享的 escape 配置,以免覆盖其他消费者之后的设置。实际语言字体、旧核心组合和 Safari/手机显示仍需相应环境验收。
|
||||
|
||||
## TypeScript 兼容入口
|
||||
|
||||
根入口和 `/legacy` 保留最新已发布 1.2.0 的工厂类型:必填 `{ subtitles: TrackOption[] }`,同步 `LegacyResult` 仅含 name,以兼容历史参数提取与替换函数。实际 Promise 和选择方法使用同一实现的 `/runtime`:
|
||||
|
||||
```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;
|
||||
}
|
||||
```
|
||||
|
||||
根命名类型为 `TrackOption`、`Option`、`RuntimeOption`、`LegacyResult`、`Result`、`Factory`、`RuntimeFactory`;runtime 导出 TrackOption、RuntimeOption、Result、RuntimeFactory。RuntimeFactory 还描述可写 `.default` 自引用;旧 Factory 不要求该属性。
|
||||
|
||||
1.0/1.1 的 export-assignment 声明与 1.2 默认模块形状冲突,根按已批准规则保留 1.2。NodeNext ESM 根类型的工厂在 `root.default`,准确的默认调用使用 runtime。经典 CommonJS 无 interop 时可使用 runtime 的 `import = require`;经典默认导入需 `esModuleInterop`。历史 JavaScript `.default(...)` 调用继续支持,不将旧声明错误宣传为原来不存在的运行时调用方式。
|
||||
Reference in new issue
Block a user