mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-27 01:21:20 -08:00
refactor(vtt-thumbnail): [PKG-VTT-THUMB-04] preserve legacy types and expose async runtime entry
This commit is contained in:
1 parent
7f2906ae52
commit
db358a3ae4
33 files changed
+3864
-98
No files matched your search
@@ -2,4 +2,5 @@ node_modules
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
src
|
||||
src
|
||||
tsconfig.json
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
The factory remains `artplayerPluginVttThumbnail(option)`. Its registration function is
|
||||
asynchronous and resolves to `{ name: 'artplayerPluginVttThumbnail' }`. Existing public
|
||||
declarations still describe a synchronous result; task PKG-VTT-THUMB-04 owns that conflict
|
||||
and the public declaration/consumer migration. The seven internal TS files are strict. Do not infer the return shape from those declarations.
|
||||
root/legacy declarations retain the historical synchronous result for existing type extraction
|
||||
and replacement factories. The optional `/runtime` entry describes the real Promise without
|
||||
consumer assertions. Both entries load the same binary and function. The seven internal TS
|
||||
files are strict. Never infer synchronous runtime behavior from the compatibility declarations.
|
||||
|
||||
## Modules and ownership
|
||||
|
||||
@@ -34,14 +36,16 @@ rolled back if initialization throws, preserving the original rejection.
|
||||
|
||||
## Runtime types
|
||||
|
||||
`src/types.ts` defines options, result, rectangle/cue data, owned events, cleanup and
|
||||
`types/artplayer-plugin-vtt-thumbnail.d.ts` owns Option and Result; `src/types.ts` reexports
|
||||
them and defines rectangle/cue data, owned events, cleanup and
|
||||
preview inputs. Request cancellation is typed as a void branch; actual registration is
|
||||
Promise<Result>. The lifetime accepts only destroy/setBar and uses the core event tuples.
|
||||
The preview receives only its required DOM/style/duration inputs.
|
||||
|
||||
Assertions are limited to the real Artplayer constructor boundary, validated regex groups
|
||||
and loop indexes, the completed four-key rectangle, and native responses after the closed
|
||||
check. The latter is valid because native fetch returns Response and cancellation only
|
||||
check, plus the recursive `.default` factory alias created by Object.assign. The response
|
||||
assertion is valid because native fetch returns Response and cancellation only
|
||||
resolves void after closing; malformed custom responses still throw at runtime. Numeric
|
||||
rectangle strings are explicitly converted for arithmetic while the zero style write stays
|
||||
numeric. No any, unchecked JS or skipLibCheck exception is introduced.
|
||||
@@ -49,8 +53,22 @@ numeric. No any, unchecked JS or skipLibCheck exception is introduced.
|
||||
The package tsconfig also checks test/types/vtt-thumbnail-runtime.ts. It tests the async
|
||||
result, required options, CSS/URL types, event tuples, cancellation, readonly state and raw
|
||||
rectangle strings, including expected errors. It separately proves the old public result
|
||||
is synchronous in declarations; those declarations are not silently corrected in this
|
||||
runtime checkpoint. New/old declaration consumers and export aliases remain task 04.
|
||||
is synchronous in declarations. `test/types/vtt-thumbnail-public.ts` separately checks exact
|
||||
legacy parameter/result/factory extraction, replacement factories and accurate async calls
|
||||
through `/runtime`, including negative cases. The source factory explicitly returns Promise;
|
||||
its final assertion only describes the self-reference that Object.assign creates.
|
||||
|
||||
Root and legacy use paired `.d.mts`/`.d.cts` default declarations. `/runtime` uses an ESM
|
||||
default and a CommonJS export assignment, supporting direct and `.default` require calls.
|
||||
Classic resolution uses `.d.ts` and typesVersions, including TypeScript 4.3. The generated
|
||||
editor global retains the legacy callable type; its RuntimeFactory namespace member is only
|
||||
a type, not an additional runtime global. Do not hand-edit generated editor declarations.
|
||||
|
||||
The installed-consumer command packs both core and plugin, installs outside the workspace,
|
||||
verifies member hashes, and repeats an offline frozen install. It tests five actual old npm
|
||||
declarations with classic default-import consumers on TS 4.3/5.9 and seven candidate modes.
|
||||
Historical NodeNext and raw require type replacement forms still need investigation in 04;
|
||||
these checks do not prove all historical compiler/module combinations.
|
||||
|
||||
## Compatibility and intentional fixes
|
||||
|
||||
@@ -78,9 +96,11 @@ invalid CSS or partially mounted controls. Each cue has one image/rectangle payl
|
||||
multiline subtitle text, timestamp-map offsets and full caption semantics are outside this
|
||||
plugin. Empty or comment-only input remains a valid empty preview.
|
||||
|
||||
The old 1.0.x export objects, earlier `thumbnails` control name and incorrect declarations
|
||||
are separately frozen and remain compatibility work for tasks 04-06. Current runtime work
|
||||
does not claim those consumer migrations or the full package refactor are finished.
|
||||
The exported callable has a writable self `.default` alias, restoring the usable 1.0.x
|
||||
CommonJS default access while retaining direct calls. It does not add a name property to the
|
||||
registration Promise. Earlier `thumbnails` control names and remaining historical declaration
|
||||
forms are separately frozen and remain compatibility work for tasks 04-06. The full package
|
||||
refactor is not yet finished.
|
||||
|
||||
## Verification and future changes
|
||||
|
||||
@@ -88,6 +108,8 @@ Use Yarn 1.22.22 and the repository's pinned Node version:
|
||||
|
||||
```sh
|
||||
yarn test:vtt-thumbnail
|
||||
yarn test:vtt-thumbnail-types-package
|
||||
yarn build:ts artplayer-plugin-vtt-thumbnail
|
||||
yarn test:browser test/browser/vtt-thumbnail-lifecycle.spec.js
|
||||
yarn build artplayer-plugin-vtt-thumbnail
|
||||
```
|
||||
|
||||
@@ -6,6 +6,30 @@ Vtt thumbnail plugin for ArtPlayer
|
||||
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail)
|
||||
|
||||
## TypeScript usage
|
||||
|
||||
The registration function is asynchronous. The optional runtime entry provides its accurate
|
||||
Promise type and uses the same implementation as the default entry:
|
||||
|
||||
```ts
|
||||
import Artplayer from 'artplayer'
|
||||
import vttThumbnail from 'artplayer-plugin-vtt-thumbnail/runtime'
|
||||
|
||||
const art = new Artplayer({ container: '#player', url: '/video.mp4' })
|
||||
const result = await vttThumbnail({ vtt: '/thumbnails/index.vtt' })(art)
|
||||
console.log(result.name)
|
||||
```
|
||||
|
||||
You can also pass `vttThumbnail({ vtt: '/thumbnails/index.vtt' })` in the player's `plugins`
|
||||
array. Existing default and `/legacy` imports remain available. Their declarations preserve
|
||||
the historical synchronous result type for compatibility, although registration has always
|
||||
returned a Promise at runtime. Reading `result.name` requires awaiting registration; changing
|
||||
to `/runtime` opts into that accurate type without changing runtime behavior. The option
|
||||
object remains required, and its `vtt` and `style` fields remain optional.
|
||||
|
||||
See [ARCHITECTURE.md](ARCHITECTURE.md) for module ownership, testing commands and remaining
|
||||
compatibility validation.
|
||||
|
||||
## License
|
||||
|
||||
MIT © Harvey Zhao
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function e(e,n){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(e)||t(n,"invalid timestamp");const[i,o="0"]=e.split("."),r=i.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||t(n,"timestamp exceeds the supported numeric range"),r}function n(e,n,i){const o=e.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||t(i,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&t(i,"expected four rectangle coordinates");const s={};for(let c=0;c<4;c++){const e=o[2][c],n=r[c];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(n)&&Number.isFinite(Number(n))||t(i,"rectangle coordinates must be finite non-negative decimals"),"w"!==e&&"h"!==e||0!==Number(n)||t(i,"rectangle width and height must be positive"),s[e]=n}let l=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(l)){const t=n.split("/");t.pop(),t.push(l),l=t.join("/")}return{url:l,...s}}function i({lifetime:t,thumbnails:e,progress:n,duration:i,setStyle:o,isMobile:r}){let s=null,l=0;function c(e,n,i){t.closed||o(e,n,i)}return t.own(()=>{if(l++,null!==s){const t=s;s=null,clearTimeout(t)}}),o=>async(u,a,d)=>{if(t.closed)return;const f="played"===u&&d&&r;if("hover"!==u&&!f)return;const m=n.clientWidth*a,h=a*i();if(c(o,"display","flex"),t.closed)return;const p=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,h);if(!p)return c(o,"display","none");if(m>0&&m<n.clientWidth?function(t,e,i){c(t,"backgroundImage",`url(${e.url})`),c(t,"height",`${e.h}px`),c(t,"width",`${e.w}px`),c(t,"backgroundPosition",`-${e.x}px -${e.y}px`),i<=Number(e.w)/2?c(t,"left",0):i>n.clientWidth-Number(e.w)/2?c(t,"left",n.clientWidth-Number(e.w)+"px"):c(t,"left",i-Number(e.w)/2+"px")}(o,p,m):r||c(o,"display","none"),f&&!t.closed){const e=++l;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==l||t.closed||(s=null,c(o,"display","none"))},500);t.closed||e!==l?clearTimeout(n):s=n}}}return function(o){return async r=>{const{setStyle:s,isMobile:l,addClass:c}=r.constructor.utils,{$progress:u}=r.template,a=function(t){let e=Boolean(t.isDestroy);const n=new Set;let i;const o=new Promise(t=>{i=t}),r={get closed(){return e},own:t=>(e?s(t):n.add(t),()=>n.delete(t)),listen(n,i){e||(r.own(()=>t.off(n,i)),t.on(n,i))},wait:t=>Promise.race([t,o]),dispose(){if(e)return;e=!0,i();const t=[...n].reverse();n.clear();for(const e of t)s(e)}};function s(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{r.listen("destroy",r.dispose)}catch(l){throw r.dispose(),l}return r}(r),d={name:"artplayerPluginVttThumbnail"};try{if(a.closed)return d;const f=o.vtt,m=await async function(t="",e){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,i=e.own(()=>n?.abort());try{if(e.closed)return;const i=await e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===i.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${i.status}`);if(e.closed)return;return await e.wait(i.text())}finally{i()}}(f,a);if(a.closed)return d;const h=function(i,o=""){"string"!==typeof i&&t(1,"expected text");const r=i.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let s=0;function l(){for(;s<r.length&&!r[s].trim();)s++}if(l(),s===r.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(r[s].trim())&&!r[s].includes("--\x3e")||t(s+1,"expected WEBVTT header"),s++;const c=[];for(;s<r.length&&(l(),s!==r.length);){const i=r[s].trim();if(/^NOTE(?:[\t ]|$)/.test(i)||"STYLE"===i||"REGION"===i){for(;s<r.length&&r[s].trim();)s++;continue}const u=s+1;i.includes("--\x3e")||(s++,s!==r.length&&r[s].trim()||t(u,"cue identifier must be followed by timing"));const a=s+1,d=r[s].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);d||t(a,"invalid cue timing");const f=e(d[1],a),m=e(d[2],a);m<f&&t(a,"cue end precedes its start"),s++,l(),s===r.length&&t(a,"missing sprite image");const h=n(r[s].trim(),o,s+1);c.push({start:Math.floor(f),end:Math.floor(m),...h}),s++}return c}(m,f),p=i({lifetime:a,thumbnails:h,progress:u,duration:()=>r.duration,setStyle:s,isMobile:l}),b=o.style||{};return a.closed||r.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:b,mounted(t){a.own(()=>{r.controls["vtt-thumbnail"]===t&&r.controls.remove("vtt-thumbnail")}),a.closed||(c(t,"art-control-thumbnails"),a.listen("setBar",p(t)))}}),d}catch(f){throw a.dispose(),f}}}});
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";function t(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function e(e,n){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(e)||t(n,"invalid timestamp");const[i,o="0"]=e.split("."),r=i.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||t(n,"timestamp exceeds the supported numeric range"),r}function n(e,n,i){const o=e.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||t(i,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&t(i,"expected four rectangle coordinates");const s={};for(let c=0;c<4;c++){const e=o[2][c],n=r[c];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(n)&&Number.isFinite(Number(n))||t(i,"rectangle coordinates must be finite non-negative decimals"),"w"!==e&&"h"!==e||0!==Number(n)||t(i,"rectangle width and height must be positive"),s[e]=n}let l=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(l)){const t=n.split("/");t.pop(),t.push(l),l=t.join("/")}return{url:l,...s}}function i({lifetime:t,thumbnails:e,progress:n,duration:i,setStyle:o,isMobile:r}){let s=null,l=0;function c(e,n,i){t.closed||o(e,n,i)}return t.own(()=>{if(l++,null!==s){const t=s;s=null,clearTimeout(t)}}),o=>async(u,a,d)=>{if(t.closed)return;const f="played"===u&&d&&r;if("hover"!==u&&!f)return;const m=n.clientWidth*a,h=a*i();if(c(o,"display","flex"),t.closed)return;const p=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,h);if(!p)return c(o,"display","none");if(m>0&&m<n.clientWidth?function(t,e,i){c(t,"backgroundImage",`url(${e.url})`),c(t,"height",`${e.h}px`),c(t,"width",`${e.w}px`),c(t,"backgroundPosition",`-${e.x}px -${e.y}px`),i<=Number(e.w)/2?c(t,"left",0):i>n.clientWidth-Number(e.w)/2?c(t,"left",n.clientWidth-Number(e.w)+"px"):c(t,"left",i-Number(e.w)/2+"px")}(o,p,m):r||c(o,"display","none"),f&&!t.closed){const e=++l;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==l||t.closed||(s=null,c(o,"display","none"))},500);t.closed||e!==l?clearTimeout(n):s=n}}}function o(o){return async r=>{const{setStyle:s,isMobile:l,addClass:c}=r.constructor.utils,{$progress:u}=r.template,a=function(t){let e=Boolean(t.isDestroy);const n=new Set;let i;const o=new Promise(t=>{i=t}),r={get closed(){return e},own:t=>(e?s(t):n.add(t),()=>n.delete(t)),listen(n,i){e||(r.own(()=>t.off(n,i)),t.on(n,i))},wait:t=>Promise.race([t,o]),dispose(){if(e)return;e=!0,i();const t=[...n].reverse();n.clear();for(const e of t)s(e)}};function s(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{r.listen("destroy",r.dispose)}catch(l){throw r.dispose(),l}return r}(r),d={name:"artplayerPluginVttThumbnail"};try{if(a.closed)return d;const f=o.vtt,m=await async function(t="",e){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,i=e.own(()=>n?.abort());try{if(e.closed)return;const i=await e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===i.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${i.status}`);if(e.closed)return;return await e.wait(i.text())}finally{i()}}(f,a);if(a.closed)return d;const h=function(i,o=""){"string"!==typeof i&&t(1,"expected text");const r=i.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let s=0;function l(){for(;s<r.length&&!r[s].trim();)s++}if(l(),s===r.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(r[s].trim())&&!r[s].includes("--\x3e")||t(s+1,"expected WEBVTT header"),s++;const c=[];for(;s<r.length&&(l(),s!==r.length);){const i=r[s].trim();if(/^NOTE(?:[\t ]|$)/.test(i)||"STYLE"===i||"REGION"===i){for(;s<r.length&&r[s].trim();)s++;continue}const u=s+1;i.includes("--\x3e")||(s++,s!==r.length&&r[s].trim()||t(u,"cue identifier must be followed by timing"));const a=s+1,d=r[s].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);d||t(a,"invalid cue timing");const f=e(d[1],a),m=e(d[2],a);m<f&&t(a,"cue end precedes its start"),s++,l(),s===r.length&&t(a,"missing sprite image");const h=n(r[s].trim(),o,s+1);c.push({start:Math.floor(f),end:Math.floor(m),...h}),s++}return c}(m,f),p=i({lifetime:a,thumbnails:h,progress:u,duration:()=>r.duration,setStyle:s,isMobile:l}),b=o.style||{};return a.closed||r.controls.add({name:"vtt-thumbnail",position:"top",index:20,style:b,mounted(t){a.own(()=>{r.controls["vtt-thumbnail"]===t&&r.controls.remove("vtt-thumbnail")}),a.closed||(c(t,"art-control-thumbnails"),a.listen("setBar",p(t)))}}),d}catch(f){throw a.dispose(),f}}}return Object.assign(o,{default:o})});
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t},l=(t,e,n)=>new Promise((o,r)=>{var i=t=>{try{s(n.next(t))}catch(e){r(e)}},l=t=>{try{s(n.throw(t))}catch(e){r(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(i,l);s((n=n.apply(t,e)).next())});function s(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function c(t,e){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(t)||s(e,"invalid timestamp");const[n,o="0"]=t.split("."),r=n.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||s(e,"timestamp exceeds the supported numeric range"),r}function u(t,e,n){const o=t.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||s(n,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&s(n,"expected four rectangle coordinates");const l={};for(let i=0;i<4;i++){const t=o[2][i],e=r[i];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(e)&&Number.isFinite(Number(e))||s(n,"rectangle coordinates must be finite non-negative decimals"),"w"!==t&&"h"!==t||0!==Number(e)||s(n,"rectangle width and height must be positive"),l[t]=e}let c=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(c)){const t=e.split("/");t.pop(),t.push(c),c=t.join("/")}return i({url:c},l)}function a({lifetime:t,thumbnails:e,progress:n,duration:o,setStyle:r,isMobile:i}){let s=null,c=0;function u(e,n,o){t.closed||r(e,n,o)}return t.own(()=>{if(c++,null!==s){const t=s;s=null,clearTimeout(t)}}),r=>(a,d,f)=>l(null,null,function*(){if(t.closed)return;const l="played"===a&&f&&i;if("hover"!==a&&!l)return;const m=n.clientWidth*d,p=d*o();if(u(r,"display","flex"),t.closed)return;const h=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,p);if(!h)return u(r,"display","none");if(m>0&&m<n.clientWidth?function(t,e,o){u(t,"backgroundImage",`url(${e.url})`),u(t,"height",`${e.h}px`),u(t,"width",`${e.w}px`),u(t,"backgroundPosition",`-${e.x}px -${e.y}px`),o<=Number(e.w)/2?u(t,"left",0):o>n.clientWidth-Number(e.w)/2?u(t,"left",n.clientWidth-Number(e.w)+"px"):u(t,"left",o-Number(e.w)/2+"px")}(r,h,m):i||u(r,"display","none"),l&&!t.closed){const e=++c;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==c||t.closed||(s=null,u(r,"display","none"))},500);t.closed||e!==c?clearTimeout(n):s=n}})}return function(t){return e=>l(null,null,function*(){const{setStyle:n,isMobile:o,addClass:r}=e.constructor.utils,{$progress:d}=e.template,f=function(t){let e=Boolean(t.isDestroy);const n=new Set;let o;const r=new Promise(t=>{o=t}),i={get closed(){return e},own:t=>(e?l(t):n.add(t),()=>n.delete(t)),listen(n,o){e||(i.own(()=>t.off(n,o)),t.on(n,o))},wait:t=>Promise.race([t,r]),dispose(){if(e)return;e=!0,o();const t=[...n].reverse();n.clear();for(const e of t)l(e)}};function l(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{i.listen("destroy",i.dispose)}catch(s){throw i.dispose(),s}return i}(e),m={name:"artplayerPluginVttThumbnail"};try{if(f.closed)return m;const p=t.vtt,h=yield function(t="",e){return l(this,null,function*(){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,o=e.own(()=>null==n?void 0:n.abort());try{if(e.closed)return;const o=yield e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===o.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${o.status}`);if(e.closed)return;return yield e.wait(o.text())}finally{o()}})}(p,f);if(f.closed)return m;const b=function(t,e=""){"string"!==typeof t&&s(1,"expected text");const n=t.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let o=0;function r(){for(;o<n.length&&!n[o].trim();)o++}if(r(),o===n.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(n[o].trim())&&!n[o].includes("--\x3e")||s(o+1,"expected WEBVTT header"),o++;const l=[];for(;o<n.length&&(r(),o!==n.length);){const t=n[o].trim();if(/^NOTE(?:[\t ]|$)/.test(t)||"STYLE"===t||"REGION"===t){for(;o<n.length&&n[o].trim();)o++;continue}const a=o+1;t.includes("--\x3e")||(o++,o!==n.length&&n[o].trim()||s(a,"cue identifier must be followed by timing"));const d=o+1,f=n[o].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);f||s(d,"invalid cue timing");const m=c(f[1],d),p=c(f[2],d);p<m&&s(d,"cue end precedes its start"),o++,r(),o===n.length&&s(d,"missing sprite image");const h=u(n[o].trim(),e,o+1);l.push(i({start:Math.floor(m),end:Math.floor(p)},h)),o++}return l}(h,p),y=a({lifetime:Line truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVttThumbnail=e(),define(function(){return t.artplayerPluginVttThumbnail})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVttThumbnail=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,r=(e,n,o)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[n]=o,i=(t,i)=>{for(var l in i||(i={}))n.call(i,l)&&r(t,l,i[l]);if(e)for(var l of e(i))o.call(i,l)&&r(t,l,i[l]);return t},l=(t,e,n)=>new Promise((o,r)=>{var i=t=>{try{s(n.next(t))}catch(e){r(e)}},l=t=>{try{s(n.throw(t))}catch(e){r(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(i,l);s((n=n.apply(t,e)).next())});function s(t,e){throw new TypeError(`Invalid VTT thumbnail at line ${t}: ${e}`)}function c(t,e){/^\d{2,}(?::\d{2}){0,2}(?:\.\d{3})?$/.test(t)||s(e,"invalid timestamp");const[n,o="0"]=t.split("."),r=n.split(":").reduce((t,e)=>60*t+Number(e),0)+Number(o)/1e3;return Number.isSafeInteger(Math.floor(r))||s(e,"timestamp exceeds the supported numeric range"),r}function u(t,e,n){const o=t.match(/^(.+)#([xywh]{4})=(.*)$/);o&&4===new Set(o[2]).size||s(n,"expected an image URL and four distinct xywh keys");const r=o[3].split(",").map(t=>t.trim());4!==r.length&&s(n,"expected four rectangle coordinates");const l={};for(let i=0;i<4;i++){const t=o[2][i],e=r[i];/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(e)&&Number.isFinite(Number(e))||s(n,"rectangle coordinates must be finite non-negative decimals"),"w"!==t&&"h"!==t||0!==Number(e)||s(n,"rectangle width and height must be positive"),l[t]=e}let c=o[1];if(!/^\/|(?:https?|ftp|file):\/\//i.test(c)){const t=e.split("/");t.pop(),t.push(c),c=t.join("/")}return i({url:c},l)}function a({lifetime:t,thumbnails:e,progress:n,duration:o,setStyle:r,isMobile:i}){let s=null,c=0;function u(e,n,o){t.closed||r(e,n,o)}return t.own(()=>{if(c++,null!==s){const t=s;s=null,clearTimeout(t)}}),r=>(a,d,f)=>l(null,null,function*(){if(t.closed)return;const l="played"===a&&f&&i;if("hover"!==a&&!l)return;const m=n.clientWidth*d,p=d*o();if(u(r,"display","flex"),t.closed)return;const h=function(t,e){return t.find(t=>e>=t.start&&e<=t.end)}(e,p);if(!h)return u(r,"display","none");if(m>0&&m<n.clientWidth?function(t,e,o){u(t,"backgroundImage",`url(${e.url})`),u(t,"height",`${e.h}px`),u(t,"width",`${e.w}px`),u(t,"backgroundPosition",`-${e.x}px -${e.y}px`),o<=Number(e.w)/2?u(t,"left",0):o>n.clientWidth-Number(e.w)/2?u(t,"left",n.clientWidth-Number(e.w)+"px"):u(t,"left",o-Number(e.w)/2+"px")}(r,h,m):i||u(r,"display","none"),l&&!t.closed){const e=++c;if(null!==s&&clearTimeout(s),t.closed)return;const n=setTimeout(()=>{e!==c||t.closed||(s=null,u(r,"display","none"))},500);t.closed||e!==c?clearTimeout(n):s=n}})}function d(t){return e=>l(null,null,function*(){const{setStyle:n,isMobile:o,addClass:r}=e.constructor.utils,{$progress:d}=e.template,f=function(t){let e=Boolean(t.isDestroy);const n=new Set;let o;const r=new Promise(t=>{o=t}),i={get closed(){return e},own:t=>(e?l(t):n.add(t),()=>n.delete(t)),listen(n,o){e||(i.own(()=>t.off(n,o)),t.on(n,o))},wait:t=>Promise.race([t,r]),dispose(){if(e)return;e=!0,o();const t=[...n].reverse();n.clear();for(const e of t)l(e)}};function l(t){try{t()}catch(e){console.warn("Failed to clean up VTT thumbnails:",e)}}try{i.listen("destroy",i.dispose)}catch(s){throw i.dispose(),s}return i}(e),m={name:"artplayerPluginVttThumbnail"};try{if(f.closed)return m;const p=t.vtt,h=yield function(t="",e){return l(this,null,function*(){if(e.closed)return;const n="function"===typeof AbortController?new AbortController:null,o=e.own(()=>null==n?void 0:n.abort());try{if(e.closed)return;const o=yield e.wait(n?fetch(t,{signal:n.signal}):fetch(t));if(e.closed)return;if(!1===o.ok)throw new Error(`Failed to fetch VTT thumbnails: HTTP ${o.status}`);if(e.closed)return;return yield e.wait(o.text())}finally{o()}})}(p,f);if(f.closed)return m;const b=function(t,e=""){"string"!==typeof t&&s(1,"expected text");const n=t.replace(/^\uFEFF/,"").split(/\r\n|\r|\n/);let o=0;function r(){for(;o<n.length&&!n[o].trim();)o++}if(r(),o===n.length)return[];/^WEBVTT(?:[\t ].*)?$/.test(n[o].trim())&&!n[o].includes("--\x3e")||s(o+1,"expected WEBVTT header"),o++;const l=[];for(;o<n.length&&(r(),o!==n.length);){const t=n[o].trim();if(/^NOTE(?:[\t ]|$)/.test(t)||"STYLE"===t||"REGION"===t){for(;o<n.length&&n[o].trim();)o++;continue}const a=o+1;t.includes("--\x3e")||(o++,o!==n.length&&n[o].trim()||s(a,"cue identifier must be followed by timing"));const d=o+1,f=n[o].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);f||s(d,"invalid cue timing");const m=c(f[1],d),p=c(f[2],d);p<m&&s(d,"cue end precedes its start"),o++,r(),o===n.length&&s(d,"missing sprite image");const h=u(n[o].trim(),e,o+1);l.push(i({start:Math.floor(m),end:Math.floor(p)},h)),o++}return l}(h,p),y=a({lifetime:f,thuLine truncated
|
||||
+26
-25
@@ -77,9 +77,9 @@ function rectangle(text, vttUrl, line) {
|
||||
if (values.length !== 4)
|
||||
invalid(line, "expected four rectangle coordinates");
|
||||
const rect = {};
|
||||
for (let index = 0; index < 4; index++) {
|
||||
const key = match[2][index];
|
||||
const value = values[index];
|
||||
for (let index2 = 0; index2 < 4; index2++) {
|
||||
const key = match[2][index2];
|
||||
const value = values[index2];
|
||||
if (!/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(value) || !Number.isFinite(Number(value)))
|
||||
invalid(line, "rectangle coordinates must be finite non-negative decimals");
|
||||
if ((key === "w" || key === "h") && Number(value) === 0)
|
||||
@@ -102,49 +102,49 @@ function parseVtt(text, vttUrl = "") {
|
||||
if (typeof text !== "string")
|
||||
invalid(1, "expected text");
|
||||
const lines = text.replace(/^\uFEFF/, "").split(/\r\n|\r|\n/);
|
||||
let index = 0;
|
||||
let index2 = 0;
|
||||
function skipEmpty() {
|
||||
while (index < lines.length && !lines[index].trim())
|
||||
index++;
|
||||
while (index2 < lines.length && !lines[index2].trim())
|
||||
index2++;
|
||||
}
|
||||
skipEmpty();
|
||||
if (index === lines.length)
|
||||
if (index2 === lines.length)
|
||||
return [];
|
||||
if (!/^WEBVTT(?:[\t ].*)?$/.test(lines[index].trim()) || lines[index].includes("-->"))
|
||||
invalid(index + 1, "expected WEBVTT header");
|
||||
index++;
|
||||
if (!/^WEBVTT(?:[\t ].*)?$/.test(lines[index2].trim()) || lines[index2].includes("-->"))
|
||||
invalid(index2 + 1, "expected WEBVTT header");
|
||||
index2++;
|
||||
const thumbnails = [];
|
||||
while (index < lines.length) {
|
||||
while (index2 < lines.length) {
|
||||
skipEmpty();
|
||||
if (index === lines.length)
|
||||
if (index2 === lines.length)
|
||||
break;
|
||||
const first = lines[index].trim();
|
||||
const first = lines[index2].trim();
|
||||
if (/^NOTE(?:[\t ]|$)/.test(first) || first === "STYLE" || first === "REGION") {
|
||||
while (index < lines.length && lines[index].trim())
|
||||
index++;
|
||||
while (index2 < lines.length && lines[index2].trim())
|
||||
index2++;
|
||||
continue;
|
||||
}
|
||||
const identifierLine = index + 1;
|
||||
const identifierLine = index2 + 1;
|
||||
if (!first.includes("-->")) {
|
||||
index++;
|
||||
if (index === lines.length || !lines[index].trim())
|
||||
index2++;
|
||||
if (index2 === lines.length || !lines[index2].trim())
|
||||
invalid(identifierLine, "cue identifier must be followed by timing");
|
||||
}
|
||||
const timingLine = index + 1;
|
||||
const timing = lines[index].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);
|
||||
const timingLine = index2 + 1;
|
||||
const timing = lines[index2].trim().match(/^([\d:.]+)[\t ]*-->[\t ]*([\d:.]+)(?:[\t ].*)?$/);
|
||||
if (!timing)
|
||||
invalid(timingLine, "invalid cue timing");
|
||||
const start = timestamp(timing[1], timingLine);
|
||||
const end = timestamp(timing[2], timingLine);
|
||||
if (end < start)
|
||||
invalid(timingLine, "cue end precedes its start");
|
||||
index++;
|
||||
index2++;
|
||||
skipEmpty();
|
||||
if (index === lines.length)
|
||||
if (index2 === lines.length)
|
||||
invalid(timingLine, "missing sprite image");
|
||||
const image = rectangle(lines[index].trim(), vttUrl, index + 1);
|
||||
const image = rectangle(lines[index2].trim(), vttUrl, index2 + 1);
|
||||
thumbnails.push({ start: Math.floor(start), end: Math.floor(end), ...image });
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
return thumbnails;
|
||||
}
|
||||
@@ -273,6 +273,7 @@ function artplayerPluginVttThumbnail(option) {
|
||||
}
|
||||
};
|
||||
}
|
||||
const index = Object.assign(artplayerPluginVttThumbnail, { default: artplayerPluginVttThumbnail });
|
||||
export {
|
||||
artplayerPluginVttThumbnail as default
|
||||
index as default
|
||||
};
|
||||
@@ -19,19 +19,49 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.ts",
|
||||
"import": "./dist/artplayer-plugin-vtt-thumbnail.mjs",
|
||||
"require": "./dist/artplayer-plugin-vtt-thumbnail.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.mts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.cts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.js"
|
||||
}
|
||||
},
|
||||
"./legacy": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.ts",
|
||||
"import": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js",
|
||||
"require": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js"
|
||||
"import": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.mts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.cts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js"
|
||||
}
|
||||
},
|
||||
"./runtime": {
|
||||
"import": {
|
||||
"types": "./types/runtime.d.mts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./types/runtime.d.cts",
|
||||
"default": "./dist/artplayer-plugin-vtt-thumbnail.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": "./dist/artplayer-plugin-vtt-thumbnail.js",
|
||||
"module": "./dist/artplayer-plugin-vtt-thumbnail.mjs",
|
||||
"types": "./types/artplayer-plugin-vtt-thumbnail.d.ts",
|
||||
"legacy": "./dist/artplayer-plugin-vtt-thumbnail.legacy.js",
|
||||
"browserslist": "last 1 Chrome version"
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"legacy": [
|
||||
"types/artplayer-plugin-vtt-thumbnail.d.ts"
|
||||
],
|
||||
"runtime": [
|
||||
"types/runtime.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { RuntimeFactory } from '../types/artplayer-plugin-vtt-thumbnail'
|
||||
import type { Option, Result } from './types'
|
||||
import createLifetime from './lifetime'
|
||||
import parseVtt from './parseVtt'
|
||||
import createPreview from './preview'
|
||||
import requestVtt from './request'
|
||||
|
||||
export default function artplayerPluginVttThumbnail(option: Option) {
|
||||
function artplayerPluginVttThumbnail(option: Option) {
|
||||
return async (art: Artplayer): Promise<Result> => {
|
||||
const { setStyle, isMobile, addClass } = (art.constructor as typeof Artplayer).utils
|
||||
const { $progress } = art.template
|
||||
@@ -47,3 +48,6 @@ export default function artplayerPluginVttThumbnail(option: Option) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Object.assign adds the alias to the same callable referenced by that alias.
|
||||
export default Object.assign(artplayerPluginVttThumbnail, { default: artplayerPluginVttThumbnail }) as RuntimeFactory
|
||||
@@ -1,14 +1,7 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Events, Utils } from 'artplayer'
|
||||
|
||||
export interface Option {
|
||||
vtt?: string
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginVttThumbnail'
|
||||
}
|
||||
export type { Option, Result } from '../types/artplayer-plugin-vtt-thumbnail'
|
||||
|
||||
export interface Rectangle {
|
||||
x: string
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "allowJs": false },
|
||||
"include": ["src/**/*.ts", "types/**/*.d.ts", "../../types/assets.d.ts", "../../test/types/vtt-thumbnail-runtime.ts"]
|
||||
"compilerOptions": {
|
||||
"allowJs": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"types/**/*.d.ts",
|
||||
"../../types/assets.d.ts",
|
||||
"../../test/types/vtt-thumbnail-runtime.ts",
|
||||
"types/**/*.d.mts",
|
||||
"types/**/*.d.cts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { Factory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: Factory
|
||||
export default artplayerPluginVttThumbnail
|
||||
export type { Factory, Option, Result, RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { Factory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: Factory
|
||||
export default artplayerPluginVttThumbnail
|
||||
export type { Factory, Option, Result, RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
+17
-3
@@ -1,9 +1,23 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: (option: { vtt?: string, style?: Partial<CSSStyleDeclaration> }) => (
|
||||
art: Artplayer,
|
||||
) => {
|
||||
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. */
|
||||
declare function artplayerPluginVttThumbnail(option: Option): (art: Artplayer) => Result
|
||||
export default artplayerPluginVttThumbnail
|
||||
@@ -0,0 +1,4 @@
|
||||
import type { RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: RuntimeFactory
|
||||
export = artplayerPluginVttThumbnail
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: RuntimeFactory
|
||||
export default artplayerPluginVttThumbnail
|
||||
export type { Option, Result, RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
|
||||
declare const artplayerPluginVttThumbnail: RuntimeFactory
|
||||
export default artplayerPluginVttThumbnail
|
||||
export type { Option, Result, RuntimeFactory } from './artplayer-plugin-vtt-thumbnail.js'
|
||||
Reference in new issue
Block a user