mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 03:46:16 -08:00
37 lines
19 KiB
JavaScript
37 lines
19 KiB
JavaScript
import{_ as i,o as n,c as e,ak as a,j as l}from"./chunks/framework.xxfEszSJ.js";const b=JSON.parse('{"title":"VTT 缩略图","description":"","frontmatter":{},"headers":[],"relativePath":"plugin/vtt-thumbnail.md","filePath":"plugin/vtt-thumbnail.md","lastUpdated":1789504112000}'),p={name:"plugin/vtt-thumbnail.md"};function t(r,s,h,k,d,c){return n(),e("div",null,s[0]||(s[0]=[a(`<h1 id="vtt-缩略图" tabindex="-1">VTT 缩略图 <a class="header-anchor" href="#vtt-缩略图" aria-label="Permalink to "VTT 缩略图""></a></h1><p><a href="./../en/plugin/vtt-thumbnail.html">English</a></p><p>读取一份 WebVTT 缩略图索引,在进度条悬停时显示对应的精灵图区域。图片和索引需要提前生成;插件不扫描视频,也不需要额外 SDK。</p><p>本页描述当前重构分支。解析和生命周期修复、<code>/runtime</code> 精确类型尚未发布;未固定版本的 npm/CDN 安装不能当作本分支代码。</p><h2 id="安装" tabindex="-1">安装 <a class="header-anchor" href="#安装" aria-label="Permalink to "安装""></a></h2><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">yarn</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> artplayer</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> artplayer-plugin-vtt-thumbnail</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Artplayer </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> artplayerPluginVttThumbnail </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer-plugin-vtt-thumbnail'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>通过 script 使用时先加载 ArtPlayer,再加载插件的 <code>dist/artplayer-plugin-vtt-thumbnail.js</code>。全局名称为 <code>artplayerPluginVttThumbnail</code>。固定依赖版本,并确保页面能读取 VTT、加载图片;跨域 VTT 请求需要服务器允许 CORS。</p><h2 id="完整示例" tabindex="-1">完整示例 <a class="header-anchor" href="#完整示例" aria-label="Permalink to "完整示例""></a></h2><p>下面与<a href="https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail" target="_blank" rel="noreferrer">在线缩略图示例</a>使用同一份代码。站点提供媒体和 <code>.artplayer-app</code> 容器,自己的应用需要替换对应地址。</p>`,10),l("div",{className:"run-code","data-libs":"./uncompiled/artplayer-plugin-vtt-thumbnail/index.js"},"▶ Run Code",-1),a(`<div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// npm i artplayer-plugin-vtt-thumbnail</span></span>
|
||
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> art</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Artplayer</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> container: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'.artplayer-app'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/assets/sample/bbb-video.mp4'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> plugins: [</span></span>
|
||
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> artplayerPluginVttThumbnail</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> vtt: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/assets/sample/bbb-thumbnails.vtt'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h2 id="配置" tabindex="-1">配置 <a class="header-anchor" href="#配置" aria-label="Permalink to "配置""></a></h2><p><code>artplayerPluginVttThumbnail(option)</code> 的配置对象必须提供。</p><table tabindex="0"><thead><tr><th>字段</th><th>类型</th><th>行为</th></tr></thead><tbody><tr><td><code>vtt</code></td><td><code>string</code>,类型中可选</td><td>VTT 文件地址。实际使用应提供有效地址;省略会请求空地址,即当前页面,不是禁用开关。</td></tr><tr><td><code>style</code></td><td><code>Partial<CSSStyleDeclaration></code>,可选</td><td>缩略图控件的初始内联样式,例如 <code>borderRadius: '4px'</code>。</td></tr></tbody></table><p>显示缩略图时,插件会更新 display、width、height、left、backgroundImage 和 backgroundPosition;不要依赖初始 style 永久覆盖这些值。尺寸和裁剪来自每条索引,插件不自动缩放精灵图。</p><h2 id="索引格式与图片路径" tabindex="-1">索引格式与图片路径 <a class="header-anchor" href="#索引格式与图片路径" aria-label="Permalink to "索引格式与图片路径""></a></h2><div class="language-text vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>WEBVTT</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>00:00.000 --> 00:05.000</span></span>
|
||
<span class="line"><span>bbb-sprite.jpg#xywh=0,0,128,72</span></span>
|
||
<span class="line"><span></span></span>
|
||
<span class="line"><span>00:05.000 --> 00:10.000</span></span>
|
||
<span class="line"><span>bbb-sprite.jpg#xywh=128,0,128,72</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p><code>x,y,w,h</code> 分别是图片内的左边位置、上边位置、宽度和高度,单位像素。x/y 必须非负,w/h 必须大于零,四项必须是有限数值。每条 cue 使用一行带裁剪片段的图片地址,不能直接把普通字幕文字当作缩略图索引。</p><p>相对图片地址按<strong>传入的 VTT 地址所在目录</strong>拼接:<code>/assets/sample/bbb-thumbnails.vtt</code> 中的 <code>bbb-sprite.jpg</code> 对应 <code>/assets/sample/bbb-sprite.jpg</code>。以 <code>/</code> 或已支持协议开头的完整地址直接使用。不以 HTTP 重定向后的 response URL 重新计算目录;有重定向或复杂相对路径时,建议索引使用明确的图片地址。</p><p>解析器支持 BOM、常见换行符、可选 cue 标识符和时间行设置,并跳过 NOTE、STYLE、REGION 块。它用于缩略图索引,不是完整 WebVTT 字幕排版实现。</p><h2 id="时间与显示边界" tabindex="-1">时间与显示边界 <a class="header-anchor" href="#时间与显示边界" aria-label="Permalink to "时间与显示边界""></a></h2><p>为保留旧行为,开始和结束时间向下取整到秒;区间的两端都包含在内,并选择文件顺序中第一条匹配项。例如在上面的精确 5 秒边界仍显示第一张,超过 5 秒才显示第二张。不要假设它提供毫秒级精确区间或“结束时间不包含”的字幕语义。</p><p>桌面悬停按进度条百分比乘以视频总时长选择图片;没有匹配项时隐藏,预览靠近边缘时会向内对齐。移动端使用带输入事件的进度拖动路径,并在最后一次拖动更新后约 500ms 隐藏。桌面测试不能替代真实触摸设备验收。</p><p>绘制位置必须严格位于进度条内部。桌面进度恰好为 0 或 1 时隐藏预览;移动端这两个端点不会绘制新预览,但已有预览仍按计时器隐藏。插件使用控件名 <code>vtt-thumbnail</code> 和样式类 <code>art-control-thumbnails</code>,请保留这些既有挂钩。</p><h2 id="异步注册、错误和销毁" tabindex="-1">异步注册、错误和销毁 <a class="header-anchor" href="#异步注册、错误和销毁" aria-label="Permalink to "异步注册、错误和销毁""></a></h2><p>注册会请求并解析 VTT,实际返回 Promise,成功结果只有 <code>name: 'artplayerPluginVttThumbnail'</code>。构造器 plugins 数组中的安装是异步的,不要在构造后立即假设结果已注册。</p><p>需要明确等待和处理请求或解析失败时,可在构造播放器后调用一次 <code>art.plugins.add()</code>:</p><div class="language-ts vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Artplayer </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thumbnails </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> 'artplayer-plugin-vtt-thumbnail/runtime'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> art</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Artplayer</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> container: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'.artplayer-app'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> url: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/video/movie.mp4'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> installThumbnails</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">() {</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> result</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> art.plugins.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">add</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">thumbnails</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ vtt: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'/video/movie.vtt'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }));</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(result.name);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (error) {</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">'Unable to load thumbnails'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, error);</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> installThumbnails</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><p>请求失败或格式错误会拒绝注册,格式错误包含行号。注册完成只说明 VTT 已加载解析并创建控件,不表示所有图片已解码;图片在浏览器显示时加载,图片请求失败不会变成已经完成的注册 Promise 的拒绝。</p><p>插件没有 update、reload 或独立 destroy 方法。切换主视频不会自动重新请求 VTT;切换到另一套视频和缩略图时,可销毁并重建播放器。不要把 <code>controls.remove()</code> 当作完整卸载,也不要用重复安装模拟一个没有提供的更新接口。</p><p>销毁播放器会取消待处理请求(环境支持 AbortController 时),结算取消的注册、移除自己的监听器和计时器,并移除仍由本次安装持有的控件。取消结算仍返回名称对象,因此名称本身不是图片可用的证明。迟到请求不会重新挂载界面。</p><h2 id="typescript-兼容" tabindex="-1">TypeScript 兼容 <a class="header-anchor" href="#typescript-兼容" aria-label="Permalink to "TypeScript 兼容""></a></h2><p>根入口和 <code>/legacy</code> 保留最新已发布 1.1.0 的旧同步返回类型与函数替换形状,实际注册始终是异步的。上面的 <code>/runtime</code> 使用相同 JavaScript 实现,准确声明 Promise 和运行时 <code>.default</code> 自引用别名,并提供 <code>Option</code>、<code>Result</code>、<code>Factory</code>、<code>RuntimeFactory</code> 类型。</p><p>1.0.x 的旧 <code>export =</code> 与 1.1.0 的默认导出声明无法同时保持相同类型提取。依赖较早 CommonJS 声明的 TypeScript 代码应迁移到 <code>/runtime</code>;NodeNext ESM 消费者也优先使用此入口,避免根入口保留的历史命名空间形状。合法旧 JavaScript 调用和历史文件入口继续保留。</p><p>浏览器验证覆盖新旧核心的进度条裁剪和清理;完整移动端、插件组合与发布产物验收仍以项目记录为准。</p>`,25)]))}const E=i(p,[["render",t]]);export{b as __pageData,E as default};
|