mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-11 05:26:15 -08:00
refactor(auto-thumbnail): [PKG-AUTO-THUMB-03] type internal extraction contracts
This commit is contained in:
1 parent
00e81309ca
commit
6c989deccd
20 files changed
+3968
-48
No files matched your search
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;if(r=void 0,n.onloadeddata=null,n.onseeked=null,!t)return;const i=e([()=>clearTimeout(t.timer),()=>{null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,s=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,s())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},l=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,s()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?l():n.onloadeddata=l)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const r=i.duration,o=i.videoHeight,a=i.videoWidth,{height:u,canvasWidth:d,canvasHeight:s}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;i.width=a,i.height=o,i.style.width=`${a}px`,i.style.height=`${o}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=s;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=t(e,i);let h=0;const m=e.guard(()=>{h>=n.number?e.dispose():f(r*h/n.number,e.guard(()=>{if(l.drawImage(i,h%10*n.width,Math.floor(h/10)*u,n.width,u),!e.active())return;let t=!1;c.toBlob(e.guard(i=>{t||(t=!0,e.publish(i,{height:u,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(h+=1,m()))}),"image/jpeg")}))});m()}),e.active()&&(i.src=n.url))}return function(t){return async i=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=i;i=void 0,e?.dispose()}return{start:function(){if(o)return;const d=i,s=[];let c=!1;const l={active:()=>!o&&!c&&i===l,own(t){if(c){const i=e([t]);i.failed&&n(i.failure)}else s.push(t)},dispose(){if(c)return;c=!0,i===l&&(i=void 0);const t=e(s.splice(0).reverse());t.failed&&n(t.failure)},fail(e){l.active()&&(l.dispose(),n(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(n){l.fail(n)}},publish(i,o){if(!l.active())return;if(!i)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(i);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{t({url:d,...o})}catch(c){r===d&&(r=a.has(s)?s:void 0);const t=e([()=>u(d)]);throw t.failed&&n(t.failure),c}u(s)}};return i=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)rLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;if(r=void 0,n.onloadeddata=null,n.onseeked=null,!t)return;const i=e([()=>{null!==t.timer&&clearTimeout(t.timer)},()=>{null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,s=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,s())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},l=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,s()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?l():n.onloadeddata=l)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const r=i.duration,o=i.videoHeight,a=i.videoWidth,{height:u,canvasWidth:d,canvasHeight:s}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;i.width=a,i.height=o,i.style.width=`${a}px`,i.style.height=`${o}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=s;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=t(e,i);let h=0;const m=e.guard(()=>{h>=n.number?e.dispose():f(r*h/n.number,e.guard(()=>{if(l.drawImage(i,h%10*n.width,Math.floor(h/10)*u,n.width,u),!e.active())return;let t=!1;c.toBlob(e.guard(i=>{t||(t=!0,e.publish(i,{height:u,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(h+=1,m()))}),"image/jpeg")}))});m()}),e.active()&&(i.src=n.url))}return function(t){return async i=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){void 0!==e&&a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=i;i=void 0,e?.dispose()}return{start:function(){if(o)return;const d=i,s=[];let c=!1;const l={active:()=>!o&&!c&&i===l,own(t){if(c){const i=e([t]);i.failed&&n(i.failure)}else s.push(t)},dispose(){if(c)return;c=!0,i===l&&(i=void 0);const t=e(s.splice(0).reverse());t.failed&&n(t.failure)},fail(e){l.active()&&(l.dispose(),n(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(n){l.fail(n)}},publish(i,o){if(!l.active())return;if(!i)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(i);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{t({url:d,...o})}catch(c){r===d&&(r=void 0!==s&&a.has(s)?s:void 0);const t=e([()=>u(d)]);throw t.failed&&n(t.failure),c}u(s)}};return i=l,d?.dispoLine truncated
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,d,l=!1;const c=new Set;function s(e){c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(l)return;const f=u,h=[];let m=!1;const b={active:()=>!l&&!m&&u===b,own(e){if(m){const t=o([e]);t.failed&&a(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===b&&(u=void 0);const e=o(h.splice(0).reverse());e.failed&&a(e.failure)},fail(e){b.active()&&(b.dispose(),a(e))},guard:e=>(...t)=>{if(b.active())try{return e(...t)}catch(n){b.fail(n)}},publish(u,l){if(!b.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!b.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},l))}catch(m){d===f&&(d=c.has(h)?h:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),m}s(h)}};return u=b,null==f||f.dispose(),b},cancel:f,destroy:function(){if(l)return;l=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);d=void 0,e.failed&&a(e.failure)},get closed(){return l}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;if(r=void 0,t.onloadeddata=null,t.onseeked=null,!e)return;const n=o([()=>clearTimeout(e.timer),()=>{null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const d=()=>e.active()&&r===u,l=e.guard(()=>{d()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!d())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{d()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),d()&&(t.currentTime=o)},s=e.guard(()=>{d()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!d()||t.seeking)return;const e=t.currentTime;if(d())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;d()&&(f?s():t.onloadeddata=s)}}function d(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{n.onloadedmetadata=null;const r=n.duration,i=n.videoHeight,o=n.videoWidth,{height:a,canvasWidth:d,canvasHeight:l}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:i,videoWidth:o});if(!e.active())return;n.width=o,n.height=i,n.style.width=`${o}px`,n.style.height=`${i}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=l;const s=c.getContext("2d");if(!s)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=u(eLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,d,l=!1;const c=new Set;function s(e){void 0!==e&&c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(l)return;const f=u,h=[];let m=!1;const v={active:()=>!l&&!m&&u===v,own(e){if(m){const t=o([e]);t.failed&&a(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=o(h.splice(0).reverse());e.failed&&a(e.failure)},fail(e){v.active()&&(v.dispose(),a(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(n){v.fail(n)}},publish(u,l){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!v.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},l))}catch(m){d===f&&(d=void 0!==h&&c.has(h)?h:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),m}s(h)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(l)return;l=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);d=void 0,e.failed&&a(e.failure)},get closed(){return l}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;if(r=void 0,t.onloadeddata=null,t.onseeked=null,!e)return;const n=o([()=>{null!==e.timer&&clearTimeout(e.timer)},()=>{null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const d=()=>e.active()&&r===u,l=e.guard(()=>{d()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!d())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{d()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),d()&&(t.currentTime=o)},s=e.guard(()=>{d()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!d()||t.seeking)return;const e=t.currentTime;if(d())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;d()&&(f?s():t.onloadeddata=s)}}function d(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{n.onloadedmetadata=null;const r=n.duration,i=n.videoHeight,o=n.videoWidth,{height:a,canvasWidth:d,canvasHeight:l}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:i,videoWidth:o});if(!e.active())return;n.width=o,n.height=i,n.style.width=`${o}px`,n.style.height=`${i}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=l;const s=c.getContext("2d");if(!s)throw new Error("Auto-thumbnail canvas context is unavaLine truncated
|
||||
@@ -25,7 +25,7 @@ function createSession(publish, report) {
|
||||
let lastUrl;
|
||||
const urls = /* @__PURE__ */ new Set();
|
||||
function release(url) {
|
||||
if (urls.delete(url))
|
||||
if (url !== void 0 && urls.delete(url))
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
function cancel() {
|
||||
@@ -103,7 +103,7 @@ function createSession(publish, report) {
|
||||
publish({ url, ...config });
|
||||
} catch (error) {
|
||||
if (lastUrl === url)
|
||||
lastUrl = urls.has(previousUrl) ? previousUrl : void 0;
|
||||
lastUrl = previousUrl !== void 0 && urls.has(previousUrl) ? previousUrl : void 0;
|
||||
const result = cleanupAll([() => release(url)]);
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
@@ -136,7 +136,10 @@ function createFrameReader(job, video) {
|
||||
if (!previous)
|
||||
return;
|
||||
const result = cleanupAll([
|
||||
() => clearTimeout(previous.timer),
|
||||
() => {
|
||||
if (previous.timer !== null)
|
||||
clearTimeout(previous.timer);
|
||||
},
|
||||
() => {
|
||||
if (previous.frame !== null)
|
||||
video.cancelVideoFrameCallback(previous.frame);
|
||||
@@ -360,7 +363,8 @@ function artplayerPluginAutoThumbnail(option) {
|
||||
report(result.failure);
|
||||
};
|
||||
try {
|
||||
for (const [name, callback] of [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]]) {
|
||||
const events = [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]];
|
||||
for (const [name, callback] of events) {
|
||||
if (session.closed)
|
||||
break;
|
||||
subscriptions.push(() => art.off(name, callback));
|
||||
|
||||
@@ -2,4 +2,5 @@ node_modules
|
||||
.DS_Store
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
src
|
||||
src
|
||||
tsconfig.json
|
||||
@@ -7,39 +7,42 @@ for video processing.
|
||||
|
||||
## Modules and ownership
|
||||
|
||||
- `src/index.js` owns ArtPlayer subscriptions and the public factory. Options are
|
||||
- `src/index.ts` owns ArtPlayer subscriptions and the public factory. Options are
|
||||
read at each `video:loadedmetadata` event, including subsequent changes to the
|
||||
original options object. `restart` cancels the old decoder immediately. `destroy`
|
||||
closes the session and removes subscriptions. Partial registration is rolled back.
|
||||
- `src/options.js` preserves truthy defaults and computes the ten-column layout.
|
||||
- `src/options.ts` preserves truthy defaults and computes the ten-column layout.
|
||||
Coercible numeric JS inputs and fractional frame counts retain their previous
|
||||
behavior; raw option values are forwarded to the thumbnail configuration.
|
||||
Invalid/nonfinite dimensions fail before canvas allocation. Canvas dimensions
|
||||
are checked against integer/IDL bounds, not a universal memory budget.
|
||||
- `src/session.js` owns one active extraction job and the generated object URLs.
|
||||
- `src/session.ts` owns one active extraction job and the generated object URLs.
|
||||
Guards prevent obsolete callbacks from publishing or scheduling another frame.
|
||||
Cleanup runs all registered actions even if one fails. Installing a replacement
|
||||
before cleaning up its predecessor makes synchronous host reentry observable.
|
||||
- `src/extraction.js` owns the private video and canvas, metadata/seek/error
|
||||
- `src/extraction.ts` owns the private video and canvas, metadata/seek/error
|
||||
handlers, and the frame/encode sequence. Each valid draw is encoded before the
|
||||
next seek. The final decoder is paused, cleared and reset; the final sheet URL
|
||||
remains owned by the session until another usable sheet replaces it or destroy.
|
||||
- `src/video.js` creates and owns the hidden media element. It is attached to the
|
||||
- `src/video.ts` creates and owns the hidden media element. It is attached to the
|
||||
document root because detached media loses drawable pixels on Windows WebKit.
|
||||
`visibility:hidden` preserves its rendered box; `display:none` and a 1px box do
|
||||
not. Metadata locks the box to intrinsic dimensions, overriding ordinary global
|
||||
video sizing rules. It is silent, excluded from focus/accessibility, and never
|
||||
played by this implementation. Cleanup also removes the element if insertion,
|
||||
cancellation, pause or decoder reset fails.
|
||||
- `src/frames.js` owns one pending sample, its seek/data handlers, deadline and
|
||||
- `src/frames.ts` owns one pending sample, its seek/data handlers, deadline and
|
||||
native presentation callback. When request/cancel frame callbacks are both
|
||||
available it waits for loaded data, then requires both seek completion and frame
|
||||
presentation before drawing. Callback identities are invalidated on retry and
|
||||
replacement; late/duplicate delivery cannot complete a newer sample. One job
|
||||
cleanup handles every frame without accumulating per-frame cleanup closures.
|
||||
- `src/types.ts` defines internal configuration, sheet data, the minimal host and
|
||||
guarded extraction-job callbacks. `guard` retains argument/result types and the
|
||||
inactive undefined result. No public declarations are generated from this file.
|
||||
|
||||
Only the entry module receives ArtPlayer. Extraction receives a guarded job and a
|
||||
configuration snapshot. These internal modules do not add public player fields,
|
||||
configuration snapshot. These internal modules do not add public player fields,
|
||||
plugin methods, or a dependency on a particular core implementation.
|
||||
|
||||
## Compatibility and intentional fixes
|
||||
@@ -80,6 +83,7 @@ Use the root Yarn toolchain:
|
||||
|
||||
```sh
|
||||
yarn test:auto-thumbnail
|
||||
yarn exec tsc -p packages/artplayer-plugin-auto-thumbnail/tsconfig.json --noEmit
|
||||
yarn test:browser test/browser/auto-thumbnail-lifecycle.spec.js
|
||||
yarn test:browser test/browser/auto-thumbnail-pixels.spec.js
|
||||
yarn build artplayer-plugin-auto-thumbnail
|
||||
@@ -109,9 +113,18 @@ red, black, blue and yellow sections. Its command and fingerprint are in
|
||||
directory with `ARTPLAYER_FFMPEG` and `node scripts/generate-auto-thumbnail-fixture.mjs
|
||||
<new-directory>`; never silently replace the committed fixture.
|
||||
|
||||
Task04 converts these modules to strict TypeScript and resolves historical public
|
||||
declaration/CommonJS differences. Task05 verifies old/final cores and actual
|
||||
Task03's internal-type checkpoint has converted the six runtime modules to strict
|
||||
TypeScript. Numeric annotations describe the nominal options; no runtime casts or
|
||||
normalization were added, so historical coercible JS inputs retain the same
|
||||
validation/arithmetic and raw values. Missing options retain the existing behavior.
|
||||
Task04 still resolves public declarations, implementation-to-consumer contracts and
|
||||
historical CommonJS differences. Task05 verifies old/final cores and actual
|
||||
devices; task06 covers installed package entries and the real demo/editor. The
|
||||
types and package version are unchanged at this checkpoint. Use
|
||||
`refactor/baselines/auto-thumbnail-contract.md` and `auto-thumbnail-failures.md` as
|
||||
the historical evidence map; do not regenerate those baselines from this source.
|
||||
|
||||
The internal type checkpoint and its core-host assignment fixture are recorded in
|
||||
`refactor/changes/2026-09-13-PKG-AUTO-THUMB-03-internal-types.md`. A core host can
|
||||
hold partial user thumbnail options; extraction publishes a complete sheet. Do not
|
||||
require the host's existing getter to have every generated-sheet field.
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;if(r=void 0,n.onloadeddata=null,n.onseeked=null,!t)return;const i=e([()=>clearTimeout(t.timer),()=>{null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,s=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,s())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},l=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,s()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?l():n.onloadeddata=l)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const r=i.duration,o=i.videoHeight,a=i.videoWidth,{height:u,canvasWidth:d,canvasHeight:s}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;i.width=a,i.height=o,i.style.width=`${a}px`,i.style.height=`${o}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=s;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=t(e,i);let h=0;const m=e.guard(()=>{h>=n.number?e.dispose():f(r*h/n.number,e.guard(()=>{if(l.drawImage(i,h%10*n.width,Math.floor(h/10)*u,n.width,u),!e.active())return;let t=!1;c.toBlob(e.guard(i=>{t||(t=!0,e.publish(i,{height:u,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(h+=1,m()))}),"image/jpeg")}))});m()}),e.active()&&(i.src=n.url))}return function(t){return async i=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=i;i=void 0,e?.dispose()}return{start:function(){if(o)return;const d=i,s=[];let c=!1;const l={active:()=>!o&&!c&&i===l,own(t){if(c){const i=e([t]);i.failed&&n(i.failure)}else s.push(t)},dispose(){if(c)return;c=!0,i===l&&(i=void 0);const t=e(s.splice(0).reverse());t.failed&&n(t.failure)},fail(e){l.active()&&(l.dispose(),n(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(n){l.fail(n)}},publish(i,o){if(!l.active())return;if(!i)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(i);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{t({url:d,...o})}catch(c){r===d&&(r=a.has(s)?s:void 0);const t=e([()=>u(d)]);throw t.failed&&n(t.failure),c}u(s)}};return i=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)rLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";function e(e){let t,n=!1;for(const r of e)try{r()}catch(i){n||(n=!0,t=i)}return{failed:n,failure:t}}function t(t,n){const i="function"===typeof n.requestVideoFrameCallback&&"function"===typeof n.cancelVideoFrameCallback;let r;function o(){const t=r;if(r=void 0,n.onloadeddata=null,n.onseeked=null,!t)return;const i=e([()=>{null!==t.timer&&clearTimeout(t.timer)},()=>{null!==t.frame&&n.cancelVideoFrameCallback(t.frame)}]);if(i.failed)throw i.failure}return t.own(o),(e,a)=>{if(o(),!t.active())return;const u={frame:null,timer:null,sought:!1,presented:!i,retries:0,sequence:0,started:!1};r=u;const d=()=>t.active()&&r===u,s=t.guard(()=>{d()&&u.sought&&u.presented&&(o(),t.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!i)return;const e=++u.sequence;u.presented=!1;const r=u.frame;if(u.frame=null,null!==r&&n.cancelVideoFrameCallback(r),!d())return;let o=!1;const a=n.requestVideoFrameCallback(t.guard(()=>{d()&&e===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,s())}));d()&&e===u.sequence&&!o?u.frame=a:n.cancelVideoFrameCallback(a)})(),d()&&(n.currentTime=e)},l=t.guard(()=>{d()&&!u.started&&(u.started=!0,n.onloadeddata=null,n.onseeked=t.guard(()=>{if(!d()||n.seeking)return;const t=n.currentTime;if(d())if(!Number.isFinite(t)||Math.abs(t-e)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,s()}),c())});if(u.timer=setTimeout(t.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!i||n.readyState>=2;d()&&(f?l():n.onloadeddata=l)}}function n(e,n){const i=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const r=i.duration,o=i.videoHeight,a=i.videoWidth,{height:u,canvasWidth:d,canvasHeight:s}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),i=Math.trunc(10*e.width),r=Math.trunc(n*Math.ceil(e.number/10));if(![n,i,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:i,canvasHeight:r}}(n,{duration:r,videoHeight:o,videoWidth:a});if(!e.active())return;i.width=a,i.height=o,i.style.width=`${a}px`,i.style.height=`${o}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=s;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=t(e,i);let h=0;const m=e.guard(()=>{h>=n.number?e.dispose():f(r*h/n.number,e.guard(()=>{if(l.drawImage(i,h%10*n.width,Math.floor(h/10)*u,n.width,u),!e.active())return;let t=!1;c.toBlob(e.guard(i=>{t||(t=!0,e.publish(i,{height:u,column:10,number:n.number,width:n.width,scale:n.scale}),e.active()&&(h+=1,m()))}),"image/jpeg")}))});m()}),e.active()&&(i.src=n.url))}return function(t){return async i=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(t,n){let i,r,o=!1;const a=new Set;function u(e){void 0!==e&&a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=i;i=void 0,e?.dispose()}return{start:function(){if(o)return;const d=i,s=[];let c=!1;const l={active:()=>!o&&!c&&i===l,own(t){if(c){const i=e([t]);i.failed&&n(i.failure)}else s.push(t)},dispose(){if(c)return;c=!0,i===l&&(i=void 0);const t=e(s.splice(0).reverse());t.failed&&n(t.failure)},fail(e){l.active()&&(l.dispose(),n(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(n){l.fail(n)}},publish(i,o){if(!l.active())return;if(!i)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(i);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{t({url:d,...o})}catch(c){r===d&&(r=void 0!==s&&a.has(s)?s:void 0);const t=e([()=>u(d)]);throw t.failed&&n(t.failure),c}u(s)}};return i=l,d?.dispoLine truncated
|
||||
+1
-1
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,d,l=!1;const c=new Set;function s(e){c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(l)return;const f=u,h=[];let m=!1;const b={active:()=>!l&&!m&&u===b,own(e){if(m){const t=o([e]);t.failed&&a(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===b&&(u=void 0);const e=o(h.splice(0).reverse());e.failed&&a(e.failure)},fail(e){b.active()&&(b.dispose(),a(e))},guard:e=>(...t)=>{if(b.active())try{return e(...t)}catch(n){b.fail(n)}},publish(u,l){if(!b.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!b.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},l))}catch(m){d===f&&(d=c.has(h)?h:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),m}s(h)}};return u=b,null==f||f.dispose(),b},cancel:f,destroy:function(){if(l)return;l=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);d=void 0,e.failed&&a(e.failure)},get closed(){return l}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;if(r=void 0,t.onloadeddata=null,t.onseeked=null,!e)return;const n=o([()=>clearTimeout(e.timer),()=>{null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const d=()=>e.active()&&r===u,l=e.guard(()=>{d()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!d())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{d()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),d()&&(t.currentTime=o)},s=e.guard(()=>{d()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!d()||t.seeking)return;const e=t.currentTime;if(d())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;d()&&(f?s():t.onloadeddata=s)}}function d(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{n.onloadedmetadata=null;const r=n.duration,i=n.videoHeight,o=n.videoWidth,{height:a,canvasWidth:d,canvasHeight:l}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:i,videoWidth:o});if(!e.active())return;n.width=o,n.height=i,n.style.width=`${o}px`,n.style.height=`${i}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=l;const s=c.getContext("2d");if(!s)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;const f=u(eLine truncated
|
||||
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAutoThumbnail=t(),define(function(){return e.artplayerPluginAutoThumbnail})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAutoThumbnail=t()}(this,function(){"use strict";var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r;function o(e){let t,n=!1;for(const i of e)try{i()}catch(r){n||(n=!0,t=r)}return{failed:n,failure:t}}function a(e,a){let u,d,l=!1;const c=new Set;function s(e){void 0!==e&&c.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(l)return;const f=u,h=[];let m=!1;const v={active:()=>!l&&!m&&u===v,own(e){if(m){const t=o([e]);t.failed&&a(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=o(h.splice(0).reverse());e.failed&&a(e.failure)},fail(e){v.active()&&(v.dispose(),a(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(n){v.fail(n)}},publish(u,l){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(c.add(f),!v.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))n.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))r.call(o,a)&&i(e,a,o[a]);return e})({url:f},l))}catch(m){d===f&&(d=void 0!==h&&c.has(h)?h:void 0);const e=o([()=>s(f)]);throw e.failed&&a(e.failure),m}s(h)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(l)return;l=!0;const e=o([f,...[...c].map(e=>()=>s(e))]);d=void 0,e.failed&&a(e.failure)},get closed(){return l}}}function u(e,t){const n="function"===typeof t.requestVideoFrameCallback&&"function"===typeof t.cancelVideoFrameCallback;let r;function i(){const e=r;if(r=void 0,t.onloadeddata=null,t.onseeked=null,!e)return;const n=o([()=>{null!==e.timer&&clearTimeout(e.timer)},()=>{null!==e.frame&&t.cancelVideoFrameCallback(e.frame)}]);if(n.failed)throw n.failure}return e.own(i),(o,a)=>{if(i(),!e.active())return;const u={frame:null,timer:null,sought:!1,presented:!n,retries:0,sequence:0,started:!1};r=u;const d=()=>e.active()&&r===u,l=e.guard(()=>{d()&&u.sought&&u.presented&&(i(),e.active()&&a())}),c=()=>{u.sought=!1,(()=>{if(!n)return;const r=++u.sequence;u.presented=!1;const i=u.frame;if(u.frame=null,null!==i&&t.cancelVideoFrameCallback(i),!d())return;let o=!1;const a=t.requestVideoFrameCallback(e.guard(()=>{d()&&r===u.sequence&&!o&&(o=!0,u.frame=null,u.presented=!0,l())}));d()&&r===u.sequence&&!o?u.frame=a:t.cancelVideoFrameCallback(a)})(),d()&&(t.currentTime=o)},s=e.guard(()=>{d()&&!u.started&&(u.started=!0,t.onloadeddata=null,t.onseeked=e.guard(()=>{if(!d()||t.seeking)return;const e=t.currentTime;if(d())if(!Number.isFinite(e)||Math.abs(e-o)>.05){if(++u.retries>3)throw new Error("Auto-thumbnail seek did not reach the requested time");c()}else u.sought=!0,l()}),c())});if(u.timer=setTimeout(e.guard(()=>{if(d())throw new Error("Auto-thumbnail frame readiness timed out")}),3e4),!d())return void clearTimeout(u.timer);const f=!n||t.readyState>=2;d()&&(f?s():t.onloadeddata=s)}}function d(e,t){const n=function(e){const t=document.createElement("video");e.own(()=>t.remove()),e.own(()=>t.load()),e.own(()=>t.removeAttribute("src")),e.own(()=>t.pause());for(const n of["onloadedmetadata","onloadeddata","onseeked","onerror"])e.own(()=>{t[n]=null});return e.active()?(t.crossOrigin="anonymous",t.muted=!0,t.playsInline=!0,t.tabIndex=-1,t.setAttribute("aria-hidden","true"),t.style.cssText="position:fixed;left:0;top:0;visibility:hidden;pointer-events:none;display:block;width:auto;height:auto;max-width:none;max-height:none",document.documentElement.appendChild(t),e.active()||t.remove(),t):t}(e);e.active()&&(n.onerror=e.guard(()=>{throw n.error||new Error("Auto-thumbnail media failed to load")}),n.onloadedmetadata=e.guard(()=>{n.onloadedmetadata=null;const r=n.duration,i=n.videoHeight,o=n.videoWidth,{height:a,canvasWidth:d,canvasHeight:l}=function(e,t){if(!Number.isFinite(t.duration)||t.duration<=0||!Number.isFinite(t.videoWidth)||t.videoWidth<=0||!Number.isFinite(t.videoHeight)||t.videoHeight<=0)throw new TypeError("Auto-thumbnail requires finite media duration and dimensions");const n=Math.floor(e.width*t.videoHeight/t.videoWidth),r=Math.trunc(10*e.width),i=Math.trunc(n*Math.ceil(e.number/10));if(![n,r,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:n,canvasWidth:r,canvasHeight:i}}(t,{duration:r,videoHeight:i,videoWidth:o});if(!e.active())return;n.width=o,n.height=i,n.style.width=`${o}px`,n.style.height=`${i}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=d,c.height=l;const s=c.getContext("2d");if(!s)throw new Error("Auto-thumbnail canvas context is unavaLine truncated
|
||||
+8
-4
@@ -25,7 +25,7 @@ function createSession(publish, report) {
|
||||
let lastUrl;
|
||||
const urls = /* @__PURE__ */ new Set();
|
||||
function release(url) {
|
||||
if (urls.delete(url))
|
||||
if (url !== void 0 && urls.delete(url))
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
function cancel() {
|
||||
@@ -103,7 +103,7 @@ function createSession(publish, report) {
|
||||
publish({ url, ...config });
|
||||
} catch (error) {
|
||||
if (lastUrl === url)
|
||||
lastUrl = urls.has(previousUrl) ? previousUrl : void 0;
|
||||
lastUrl = previousUrl !== void 0 && urls.has(previousUrl) ? previousUrl : void 0;
|
||||
const result = cleanupAll([() => release(url)]);
|
||||
if (result.failed)
|
||||
report(result.failure);
|
||||
@@ -136,7 +136,10 @@ function createFrameReader(job, video) {
|
||||
if (!previous)
|
||||
return;
|
||||
const result = cleanupAll([
|
||||
() => clearTimeout(previous.timer),
|
||||
() => {
|
||||
if (previous.timer !== null)
|
||||
clearTimeout(previous.timer);
|
||||
},
|
||||
() => {
|
||||
if (previous.frame !== null)
|
||||
video.cancelVideoFrameCallback(previous.frame);
|
||||
@@ -360,7 +363,8 @@ function artplayerPluginAutoThumbnail(option) {
|
||||
report(result.failure);
|
||||
};
|
||||
try {
|
||||
for (const [name, callback] of [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]]) {
|
||||
const events = [["destroy", onDestroy], ["restart", session.cancel], ["video:loadedmetadata", onMetadata]];
|
||||
for (const [name, callback] of events) {
|
||||
if (session.closed)
|
||||
break;
|
||||
subscriptions.push(() => art.off(name, callback));
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
import type { ExtractionConfig, ExtractionJob } from './types'
|
||||
import createFrameReader from './frames'
|
||||
import { sheetSize } from './options'
|
||||
import createVideo from './video'
|
||||
|
||||
export default function extract(job, config) {
|
||||
export default function extract(job: ExtractionJob, config: ExtractionConfig) {
|
||||
const video = createVideo(job)
|
||||
if (!job.active())
|
||||
return
|
||||
+19
-5
@@ -1,9 +1,20 @@
|
||||
import type { ExtractionJob } from './types'
|
||||
import { cleanupAll } from './session'
|
||||
|
||||
export default function createFrameReader(job, video) {
|
||||
interface PendingFrame {
|
||||
frame: number | null
|
||||
timer: ReturnType<typeof setTimeout> | null
|
||||
sought: boolean
|
||||
presented: boolean
|
||||
retries: number
|
||||
sequence: number
|
||||
started: boolean
|
||||
}
|
||||
|
||||
export default function createFrameReader(job: ExtractionJob, video: HTMLVideoElement) {
|
||||
const presentedFrames = typeof video.requestVideoFrameCallback === 'function'
|
||||
&& typeof video.cancelVideoFrameCallback === 'function'
|
||||
let pending
|
||||
let pending: PendingFrame | undefined
|
||||
|
||||
function clear() {
|
||||
const previous = pending
|
||||
@@ -13,7 +24,10 @@ export default function createFrameReader(job, video) {
|
||||
if (!previous)
|
||||
return
|
||||
const result = cleanupAll([
|
||||
() => clearTimeout(previous.timer),
|
||||
() => {
|
||||
if (previous.timer !== null)
|
||||
clearTimeout(previous.timer)
|
||||
},
|
||||
() => {
|
||||
if (previous.frame !== null)
|
||||
video.cancelVideoFrameCallback(previous.frame)
|
||||
@@ -24,11 +38,11 @@ export default function createFrameReader(job, video) {
|
||||
}
|
||||
job.own(clear)
|
||||
|
||||
return (target, draw) => {
|
||||
return (target: number, draw: () => void) => {
|
||||
clear()
|
||||
if (!job.active())
|
||||
return
|
||||
const current = { frame: null, timer: null, sought: false, presented: !presentedFrames, retries: 0, sequence: 0, started: false }
|
||||
const current: PendingFrame = { frame: null, timer: null, sought: false, presented: !presentedFrames, retries: 0, sequence: 0, started: false }
|
||||
pending = current
|
||||
const active = () => job.active() && pending === current
|
||||
const finish = job.guard(() => {
|
||||
+7
-5
@@ -1,14 +1,15 @@
|
||||
import type { Cleanup, ThumbnailHost, ThumbnailOptions } from './types'
|
||||
import extract from './extraction'
|
||||
import { readOptions } from './options'
|
||||
import createSession, { cleanupAll } from './session'
|
||||
|
||||
export default function artplayerPluginAutoThumbnail(option) {
|
||||
return async (art) => {
|
||||
const report = error => console.warn('ArtPlayer auto-thumbnail failed:', error)
|
||||
export default function artplayerPluginAutoThumbnail(option: ThumbnailOptions) {
|
||||
return async (art: ThumbnailHost) => {
|
||||
const report = (error: unknown) => console.warn('ArtPlayer auto-thumbnail failed:', error)
|
||||
const session = createSession((config) => {
|
||||
art.thumbnails = config
|
||||
}, report)
|
||||
const subscriptions = []
|
||||
const subscriptions: Cleanup[] = []
|
||||
const onMetadata = () => {
|
||||
const job = session.start()
|
||||
if (job) {
|
||||
@@ -26,7 +27,8 @@ export default function artplayerPluginAutoThumbnail(option) {
|
||||
report(result.failure)
|
||||
}
|
||||
try {
|
||||
for (const [name, callback] of [['destroy', onDestroy], ['restart', session.cancel], ['video:loadedmetadata', onMetadata]]) {
|
||||
const events: [string, Cleanup][] = [['destroy', onDestroy], ['restart', session.cancel], ['video:loadedmetadata', onMetadata]]
|
||||
for (const [name, callback] of events) {
|
||||
if (session.closed)
|
||||
break
|
||||
subscriptions.push(() => art.off(name, callback))
|
||||
+4
-2
@@ -1,4 +1,6 @@
|
||||
export function readOptions(option, getFallbackUrl) {
|
||||
import type { ExtractionConfig, ThumbnailOptions } from './types'
|
||||
|
||||
export function readOptions(option: ThumbnailOptions, getFallbackUrl: () => string): ExtractionConfig {
|
||||
const config = {
|
||||
url: option.url || getFallbackUrl(),
|
||||
width: option.width || 160,
|
||||
@@ -10,7 +12,7 @@ export function readOptions(option, getFallbackUrl) {
|
||||
return config
|
||||
}
|
||||
|
||||
export function sheetSize(config, video) {
|
||||
export function sheetSize(config: ExtractionConfig, video: Pick<HTMLVideoElement, 'duration' | 'videoWidth' | 'videoHeight'>) {
|
||||
if (!Number.isFinite(video.duration) || video.duration <= 0 || !Number.isFinite(video.videoWidth) || video.videoWidth <= 0 || !Number.isFinite(video.videoHeight) || video.videoHeight <= 0)
|
||||
throw new TypeError('Auto-thumbnail requires finite media duration and dimensions')
|
||||
const height = Math.floor(config.width * video.videoHeight / video.videoWidth)
|
||||
+13
-11
@@ -1,5 +1,7 @@
|
||||
export function cleanupAll(actions) {
|
||||
let failure
|
||||
import type { Cleanup, ExtractionJob, ThumbnailSheet } from './types'
|
||||
|
||||
export function cleanupAll(actions: Cleanup[]) {
|
||||
let failure: unknown
|
||||
let failed = false
|
||||
for (const action of actions) {
|
||||
try {
|
||||
@@ -15,14 +17,14 @@ export function cleanupAll(actions) {
|
||||
return { failed, failure }
|
||||
}
|
||||
|
||||
export default function createSession(publish, report) {
|
||||
export default function createSession(publish: (sheet: ThumbnailSheet) => void, report: (error: unknown) => void) {
|
||||
let closed = false
|
||||
let current
|
||||
let lastUrl
|
||||
const urls = new Set()
|
||||
let current: ExtractionJob | undefined
|
||||
let lastUrl: string | undefined
|
||||
const urls = new Set<string>()
|
||||
|
||||
function release(url) {
|
||||
if (urls.delete(url))
|
||||
function release(url: string | undefined) {
|
||||
if (url !== undefined && urls.delete(url))
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
@@ -47,9 +49,9 @@ export default function createSession(publish, report) {
|
||||
return
|
||||
// Install the replacement before cleanup, which can reenter through host APIs.
|
||||
const previous = current
|
||||
const actions = []
|
||||
const actions: Cleanup[] = []
|
||||
let disposed = false
|
||||
const job = {
|
||||
const job: ExtractionJob = {
|
||||
active: () => !closed && !disposed && current === job,
|
||||
own(action) {
|
||||
if (disposed) {
|
||||
@@ -107,7 +109,7 @@ export default function createSession(publish, report) {
|
||||
}
|
||||
catch (error) {
|
||||
if (lastUrl === url)
|
||||
lastUrl = urls.has(previousUrl) ? previousUrl : undefined
|
||||
lastUrl = previousUrl !== undefined && urls.has(previousUrl) ? previousUrl : undefined
|
||||
const result = cleanupAll([() => release(url)])
|
||||
if (result.failed)
|
||||
report(result.failure)
|
||||
@@ -0,0 +1,43 @@
|
||||
// Internal contracts only. Public declarations retain their historical entrypoint.
|
||||
export interface ThumbnailOptions {
|
||||
url?: string
|
||||
width?: number
|
||||
number?: number
|
||||
scale?: number
|
||||
height?: number
|
||||
}
|
||||
|
||||
export interface ExtractionConfig {
|
||||
url: string
|
||||
width: number
|
||||
number: number
|
||||
scale: number
|
||||
}
|
||||
|
||||
export interface SheetConfig {
|
||||
height: number
|
||||
column: number
|
||||
number: number
|
||||
width: number
|
||||
scale: number
|
||||
}
|
||||
|
||||
export interface ThumbnailSheet extends SheetConfig { url: string }
|
||||
export type Cleanup = () => void
|
||||
|
||||
export interface ExtractionJob {
|
||||
active: () => boolean
|
||||
own: (action: Cleanup) => void
|
||||
dispose: Cleanup
|
||||
fail: (error: unknown) => void
|
||||
guard: <Args extends unknown[], Result>(callback: (...args: Args) => Result) => (...args: Args) => Result | undefined
|
||||
publish: (blob: Blob | null, config: SheetConfig) => void
|
||||
}
|
||||
|
||||
export interface ThumbnailHost {
|
||||
option: { url: string }
|
||||
// A host may already hold a partial user configuration; generated sheets are complete.
|
||||
thumbnails: { url: string } & Partial<SheetConfig>
|
||||
on: (event: string, callback: Cleanup) => unknown
|
||||
off: (event: string, callback: Cleanup) => unknown
|
||||
}
|
||||
+4
-2
@@ -1,10 +1,12 @@
|
||||
export default function createVideo(job) {
|
||||
import type { ExtractionJob } from './types'
|
||||
|
||||
export default function createVideo(job: ExtractionJob) {
|
||||
const video = document.createElement('video')
|
||||
job.own(() => video.remove())
|
||||
job.own(() => video.load())
|
||||
job.own(() => video.removeAttribute('src'))
|
||||
job.own(() => video.pause())
|
||||
for (const property of ['onloadedmetadata', 'onloadeddata', 'onseeked', 'onerror'])
|
||||
for (const property of ['onloadedmetadata', 'onloadeddata', 'onseeked', 'onerror'] as const)
|
||||
job.own(() => { video[property] = null })
|
||||
if (!job.active())
|
||||
return video
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "allowJs": false },
|
||||
"include": ["src/**/*.ts", "../../refactor/fixtures/implementation/auto-thumbnail.ts"]
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,42 @@
|
||||
# PKG-AUTO-THUMB-03 内部严格TS检查点
|
||||
|
||||
本检查点推进内部代码维护,03仍doing;公开声明和类型分发仍属04。没有降低
|
||||
首帧像素要求,也没有将WebKit的早期帧诊断计入完整像素验收。
|
||||
|
||||
## 改动
|
||||
|
||||
原有六个职责模块index/options/session/extraction/video/frames迁为TS,新增types.ts
|
||||
集中描述任务所有权、guard参数/返回、完整图集配置和最小宿主。新增分包严格配置,
|
||||
不启用allowJs/skipLibCheck,不引入any兜底;沿用现有构建的JS/TS共存能力。
|
||||
公开types/、入口/版本/依赖不变,注册仍为异步Promise,抽帧在后续metadata进行。
|
||||
分包tsconfig仅用于仓库实施检查,加入.npmignore,避免发布引用仓库外fixture的配置。
|
||||
|
||||
数字字段只作名义类型标注,没有加入运行时归一化、转换或额外getter读取;旧JS
|
||||
可转换字符串/小数输入、原始width/number/scale向宿主转交及读取时序继续由既有
|
||||
用例保护。URL集合不接受undefined,timer清理排除尚未取得的null句柄;有效0
|
||||
句柄和取消中重入保持原有行为。
|
||||
|
||||
新增真正使用核心公开Artplayer类型的源码接入fixture。最初最小宿主错误要求
|
||||
已存在的thumbnails配置所有字段必填,编译报TS2345(height可为undefined)。
|
||||
修正为宿主允许既有部分配置,而job.publish产出的ThumbnailSheet仍完整必填;
|
||||
最终分包严格检查包含该fixture并通过。没有修改核心或插件公开声明来迁就内部类型。
|
||||
|
||||
## 验证与限制
|
||||
|
||||
源码联合154项通过,其中52项当前生命周期/帧读取、102项历史契约与缺陷记录;
|
||||
main/legacy各52项候选单测通过。源码/main/legacy各21共63项浏览器通过,0重试/
|
||||
跳过;有原生帧回调时五格像素严格断言,无回调路径的前两格仍是诊断,不关闭
|
||||
AUTO-THUMB-PIXEL-01。三格式正常构建和docs副本一致。新源码lint及分包严格TS通过。
|
||||
Yarn实际pack的七个文件通过分发入口检查,无src或tsconfig泄漏;此检查不替代安装消费验收。
|
||||
全仓类型流程通过398个生产TS及旧/新编译器消费者;其后新增的最终宿主接入fixture
|
||||
又由分包严格检查单独验证。完整插件公开声明/安装包兼容仍待04及后续分发任务。
|
||||
|
||||
重跑:`yarn test:auto-thumbnail`、
|
||||
`yarn exec tsc -p packages/artplayer-plugin-auto-thumbnail/tsconfig.json --noEmit`、
|
||||
`yarn build artplayer-plugin-auto-thumbnail`;浏览器运行
|
||||
`yarn test:browser test/browser/auto-thumbnail-lifecycle.spec.js test/browser/auto-thumbnail-pixels.spec.js --workers=2`。
|
||||
以ARTPLAYER_AUTO_THUMBNAIL_ARTIFACT逐个选择main/legacy,必须等待终态并归档报告。
|
||||
机器结果见[内部TS证据](../baselines/auto-thumbnail-internal-types.json)。
|
||||
|
||||
03继续处理缺少原生帧回调时的首帧和其余资源边界;Mask03同时进行但文件和提交
|
||||
独立。本检查点可回退六个模块和新增类型/config/fixture,再正常构建;不推送或发布。
|
||||
@@ -0,0 +1,6 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import factory from '../../../packages/artplayer-plugin-auto-thumbnail/src'
|
||||
|
||||
declare const art: Artplayer
|
||||
const registration: Promise<{ name: string }> = factory({ width: 80, number: 5 })(art)
|
||||
export { registration }
|
||||
@@ -1,5 +1,14 @@
|
||||
# 进度与证据
|
||||
|
||||
## PKG-AUTO-THUMB-03 内部TS检查点(仍doing)
|
||||
|
||||
六个抽帧/会话/资源运行模块迁到严格TS,内部类型和实际核心宿主接入fixture齐备。
|
||||
源码154项(52候选、102历史)、产物各52项、三格式浏览器各21共63项通过;
|
||||
严格分包及全仓398生产TS流程通过,最终宿主兼容修正另经分包fixture验证。
|
||||
仅当前实现内部契约;公开声明04、WebKit无帧回调的前两格像素与资源边界仍待完成。
|
||||
详见[检查点](changes/2026-09-13-PKG-AUTO-THUMB-03-internal-types.md);不增加done数,
|
||||
不关闭像素风险。该检查点单独本地提交,Mask源码与状态不纳入同一提交。
|
||||
|
||||
## PKG-DANMUKU-07 弹幕稳定性阶段验收完成
|
||||
|
||||
12后的源码在三引擎完成新旧插件两档负载对照,每例三轮42秒原生播放;候选
|
||||
|
||||
Reference in new issue
Block a user