diff --git a/docs/compiled/artplayer-plugin-auto-thumbnail.js b/docs/compiled/artplayer-plugin-auto-thumbnail.js index 8b86f9ee5..92ad75057 100644 --- a/docs/compiled/artplayer-plugin-auto-thumbnail.js +++ b/docs/compiled/artplayer-plugin-auto-thumbnail.js @@ -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,t){const i=document.createElement("video");e.own(()=>i.load()),e.own(()=>i.removeAttribute("src")),e.own(()=>i.pause());for(const n of["onloadedmetadata","onseeked","onerror"])e.own(()=>{i[n]=null});e.active()&&(i.crossOrigin="anonymous",i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const n=i.duration,{height:r,canvasWidth:o,canvasHeight:a}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:i.videoHeight,videoWidth:i.videoWidth});if(!e.active())return;const u=document.createElement("canvas");if(!e.active())return;u.width=o,u.height=a;const d=u.getContext("2d");if(!d)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let c=0;const s=e.guard(()=>{c>=t.number?e.dispose():(i.onseeked=e.guard(()=>{if(i.onseeked=null,d.drawImage(i,c%10*t.width,Math.floor(c/10)*r,t.width,r),!e.active())return;let n=!1;u.toBlob(e.guard(i=>{n||(n=!0,e.publish(i,{height:r,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(c+=1,s()))}),"image/jpeg")}),e.active()&&(i.currentTime=n*c/t.number))});s()}),e.active()&&(i.src=t.url))}function t(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}return function(i){return async n=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(e,i){let n,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=n;n=void 0,e?.dispose()}return{start:function(){if(o)return;const d=n,c=[];let s=!1;const l={active:()=>!o&&!s&&n===l,own(e){if(s){const n=t([e]);n.failed&&i(n.failure)}else c.push(e)},dispose(){if(s)return;s=!0,n===l&&(n=void 0);const e=t(c.splice(0).reverse());e.failed&&i(e.failure)},fail(e){l.active()&&(l.dispose(),i(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(i){l.fail(i)}},publish(n,o){if(!l.active())return;if(!n)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(n);if(a.add(d),!l.active())return void u(d);const c=r;r=d;try{e({url:d,...o})}catch(s){r===d&&(r=a.has(c)?c:void 0);const e=t([()=>u(d)]);throw e.failed&&i(e.failure),s}u(c)}};return n=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)return;o=!0;const e=t([d,...[...a].map(e=>()=>u(e))]);r=void 0,e.failed&&i(e.failure)},get closed(){return o}}}(e=>{n.thumbnails=e},r),a=[],u=()=>{const t=o.start();t&&t.guard(()=>{const r=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(i,()=>n.option.url);t.active()&&e(t,r)})()},d=()=>{const e=a.splice(0),i=t([o.destroy,...e]);i.failed&&r(i.failure)};try{for(const[e,t]of[["destroy",d],["restart",o.cancel],["video:loadedmetadata",u]]){if(o.closed)break;a.push(()=>n.off(e,t)),n.on(e,t),o.closed&&n.off(e,t)}}catch(c){throw d(),c}return{name:"artplayerPluginAutoThumbnail"}}}}); +!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,t){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 i of["onloadedmetadata","onseeked","onerror"])e.own(()=>{t[i]=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 n=i.duration,r=i.videoHeight,o=i.videoWidth,{height:a,canvasWidth:u,canvasHeight:d}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:r,videoWidth:o});if(!e.active())return;i.width=o,i.height=r,i.style.width=`${o}px`,i.style.height=`${r}px`;const s=document.createElement("canvas");if(!e.active())return;s.width=u,s.height=d;const c=s.getContext("2d");if(!c)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let l=0;const h=e.guard(()=>{if(l>=t.number)return void e.dispose();const r=n*l/t.number;let o=0;i.onseeked=e.guard(()=>{if(i.seeking)return;const n=i.currentTime;if(!e.active())return;if(!Number.isFinite(n)||Math.abs(n-r)>.05){if(++o>3)throw new Error("Auto-thumbnail seek did not reach the requested time");return void(i.currentTime=r)}if(i.onseeked=null,c.drawImage(i,l%10*t.width,Math.floor(l/10)*a,t.width,a),!e.active())return;let u=!1;s.toBlob(e.guard(i=>{u||(u=!0,e.publish(i,{height:a,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(l+=1,h()))}),"image/jpeg")}),e.active()&&(i.currentTime=r)});h()}),e.active()&&(i.src=t.url))}function t(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}return function(i){return async n=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(e,i){let n,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=n;n=void 0,e?.dispose()}return{start:function(){if(o)return;const d=n,s=[];let c=!1;const l={active:()=>!o&&!c&&n===l,own(e){if(c){const n=t([e]);n.failed&&i(n.failure)}else s.push(e)},dispose(){if(c)return;c=!0,n===l&&(n=void 0);const e=t(s.splice(0).reverse());e.failed&&i(e.failure)},fail(e){l.active()&&(l.dispose(),i(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(i){l.fail(i)}},publish(n,o){if(!l.active())return;if(!n)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(n);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{e({url:d,...o})}catch(c){r===d&&(r=a.has(s)?s:void 0);const e=t([()=>u(d)]);throw e.failed&&i(e.failure),c}u(s)}};return n=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)return;o=!0;const e=t([d,...[...a].map(e=>()=>u(e))]);r=void 0,e.failed&&i(e.failure)},get closed(){return o}}}(e=>{n.thumbnails=e},r),a=[],u=()=>{const t=o.start();t&&t.guard(()=>{const r=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(i,()=>n.option.url);t.active()&&e(t,r)})()},d=()=>{const e=a.splice(0),i=t([o.destroy,...e]);i.failed&&r(i.failure)};try{for(const[e,t]of[["destroy",d],["restart",o.cancel],["video:loadedmetadata",u]]){if(o.closed)break;a.push(()=>n.off(e,t)),n.on(e,t),o.closed&&n.off(e,t)}}catch(s){throw d(),s}return{name:"artplayerPluginAutoThumbnail"}}}}); diff --git a/docs/compiled/artplayer-plugin-auto-thumbnail.legacy.js b/docs/compiled/artplayer-plugin-auto-thumbnail.legacy.js index efa10b587..18a135348 100644 --- a/docs/compiled/artplayer-plugin-auto-thumbnail.legacy.js +++ b/docs/compiled/artplayer-plugin-auto-thumbnail.legacy.js @@ -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,r=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable,i=(t,r,n)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[r]=n;function o(e,t){const r=document.createElement("video");e.own(()=>r.load()),e.own(()=>r.removeAttribute("src")),e.own(()=>r.pause());for(const n of["onloadedmetadata","onseeked","onerror"])e.own(()=>{r[n]=null});e.active()&&(r.crossOrigin="anonymous",r.onerror=e.guard(()=>{throw r.error||new Error("Auto-thumbnail media failed to load")}),r.onloadedmetadata=e.guard(()=>{r.onloadedmetadata=null;const n=r.duration,{height:i,canvasWidth:o,canvasHeight:a}=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 r=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),i=Math.trunc(r*Math.ceil(e.number/10));if(![r,n,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:r,canvasWidth:n,canvasHeight:i}}(t,{duration:n,videoHeight:r.videoHeight,videoWidth:r.videoWidth});if(!e.active())return;const u=document.createElement("canvas");if(!e.active())return;u.width=o,u.height=a;const d=u.getContext("2d");if(!d)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let c=0;const l=e.guard(()=>{c>=t.number?e.dispose():(r.onseeked=e.guard(()=>{if(r.onseeked=null,d.drawImage(r,c%10*t.width,Math.floor(c/10)*i,t.width,i),!e.active())return;let n=!1;u.toBlob(e.guard(r=>{n||(n=!0,e.publish(r,{height:i,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(c+=1,l()))}),"image/jpeg")}),e.active()&&(r.currentTime=n*c/t.number))});l()}),e.active()&&(r.src=t.url))}function a(e){let t,r=!1;for(const i of e)try{i()}catch(n){r||(r=!0,t=n)}return{failed:r,failure:t}}function u(e,o){let u,d,c=!1;const l=new Set;function s(e){l.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(c)return;const f=u,h=[];let m=!1;const v={active:()=>!c&&!m&&u===v,own(e){if(m){const t=a([e]);t.failed&&o(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=a(h.splice(0).reverse());e.failed&&o(e.failure)},fail(e){v.active()&&(v.dispose(),o(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(r){v.fail(r)}},publish(u,c){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(l.add(f),!v.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))r.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))n.call(o,a)&&i(e,a,o[a]);return e})({url:f},c))}catch(m){d===f&&(d=l.has(h)?h:void 0);const e=a([()=>s(f)]);throw e.failed&&o(e.failure),m}s(h)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(c)return;c=!0;const e=a([f,...[...l].map(e=>()=>s(e))]);d=void 0,e.failed&&o(e.failure)},get closed(){return c}}}return function(e){return t=>{return r=null,n=null,i=function*(){const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),n=u(e=>{t.thumbnails=e},r),i=[],d=()=>{const r=n.start();r&&r.guard(()=>{const n=function(e,t){const r={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(r.width))||r.width<=0||!Number.isFinite(Number(r.number))||r.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return r}(e,()=>t.option.url);r.active()&&o(r,n)})()},c=()=>{const e=i.splice(0),t=a([n.destroy,...e]);t.failed&&r(t.failure)};try{for(const[e,r]of[["destroy",c],["restart",n.cancel],["video:loadedmetadata",d]]){if(n.closed)break;i.push(()=>t.off(e,r)),t.on(e,r),n.closed&&t.off(e,r)}}catch(l){throw c(),l}return{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var o=e=>{try{u(i.next(e))}catch(r){t(r)}},a=e=>{try{u(i.throw(e))}catch(r){t(r)}},u=t=>t.done?e(t.value):Promise.resolve(t.value).then(o,a);u((i=i.apply(r,n)).next())});var r,n,i}}}); +!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,i=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable,r=(t,i,n)=>i in t?e(t,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[i]=n;function o(e,t){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 i of["onloadedmetadata","onseeked","onerror"])e.own(()=>{t[i]=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 n=i.duration,r=i.videoHeight,o=i.videoWidth,{height:a,canvasWidth:u,canvasHeight:d}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:r,videoWidth:o});if(!e.active())return;i.width=o,i.height=r,i.style.width=`${o}px`,i.style.height=`${r}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=u,c.height=d;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let s=0;const h=e.guard(()=>{if(s>=t.number)return void e.dispose();const r=n*s/t.number;let o=0;i.onseeked=e.guard(()=>{if(i.seeking)return;const n=i.currentTime;if(!e.active())return;if(!Number.isFinite(n)||Math.abs(n-r)>.05){if(++o>3)throw new Error("Auto-thumbnail seek did not reach the requested time");return void(i.currentTime=r)}if(i.onseeked=null,l.drawImage(i,s%10*t.width,Math.floor(s/10)*a,t.width,a),!e.active())return;let u=!1;c.toBlob(e.guard(i=>{u||(u=!0,e.publish(i,{height:a,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(s+=1,h()))}),"image/jpeg")}),e.active()&&(i.currentTime=r)});h()}),e.active()&&(i.src=t.url))}function a(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}function u(e,o){let u,d,c=!1;const l=new Set;function s(e){l.delete(e)&&URL.revokeObjectURL(e)}function h(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(c)return;const h=u,f=[];let m=!1;const v={active:()=>!c&&!m&&u===v,own(e){if(m){const t=a([e]);t.failed&&o(t.failure)}else f.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=a(f.splice(0).reverse());e.failed&&o(e.failure)},fail(e){v.active()&&(v.dispose(),o(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(i){v.fail(i)}},publish(u,c){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const h=URL.createObjectURL(u);if(l.add(h),!v.active())return void s(h);const f=d;d=h;try{e(((e,o)=>{for(var a in o||(o={}))i.call(o,a)&&r(e,a,o[a]);if(t)for(var a of t(o))n.call(o,a)&&r(e,a,o[a]);return e})({url:h},c))}catch(m){d===h&&(d=l.has(f)?f:void 0);const e=a([()=>s(h)]);throw e.failed&&o(e.failure),m}s(f)}};return u=v,null==h||h.dispose(),v},cancel:h,destroy:function(){if(c)return;c=!0;const e=a([h,...[...l].map(e=>()=>s(e))]);d=void 0,e.failed&&o(e.failure)},get closed(){return c}}}return function(e){return t=>{return i=null,n=null,r=function*(){const i=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),n=u(e=>{t.thumbnails=e},i),r=[],d=()=>{const i=n.start();i&&i.guard(()=>{const n=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(e,()=>t.option.url);i.active()&&o(i,n)})()},c=()=>{const e=r.splice(0),t=a([n.destroy,...e]);t.failed&&i(t.failure)};try{for(const[e,i]of[["destroy",c],["restart",n.cancel],["video:loadedmetadata",d]]){if(n.closed)break;r.push(()=>t.off(e,i)),t.on(e,i),n.closed&&t.off(e,i)}}catch(l){throw c(),l}return{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var o=e=>{try{u(r.next(e))}catch(i){t(i)}},a=e=>{try{u(r.throw(e))}catch(i){t(i)}},u=t=>t.done?e(t.value):Promise.resolve(t.value).then(o,a);u((r=r.apply(i,n)).next())});var i,n,r}}}); diff --git a/docs/compiled/artplayer-plugin-auto-thumbnail.mjs b/docs/compiled/artplayer-plugin-auto-thumbnail.mjs index bee9c380f..a3c006446 100644 --- a/docs/compiled/artplayer-plugin-auto-thumbnail.mjs +++ b/docs/compiled/artplayer-plugin-auto-thumbnail.mjs @@ -25,8 +25,9 @@ function sheetSize(config, video) { throw new RangeError("Auto-thumbnail canvas dimensions are invalid"); return { height, canvasWidth, canvasHeight }; } -function extract(job, config) { +function createVideo(job) { const video = document.createElement("video"); + job.own(() => video.remove()); job.own(() => video.load()); job.own(() => video.removeAttribute("src")); job.own(() => video.pause()); @@ -35,21 +36,41 @@ function extract(job, config) { video[property] = null; }); if (!job.active()) - return; + return video; video.crossOrigin = "anonymous"; + video.muted = true; + video.playsInline = true; + video.tabIndex = -1; + video.setAttribute("aria-hidden", "true"); + video.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(video); + if (!job.active()) + video.remove(); + return video; +} +function extract(job, config) { + const video = createVideo(job); + if (!job.active()) + return; video.onerror = job.guard(() => { throw video.error || new Error("Auto-thumbnail media failed to load"); }); video.onloadedmetadata = job.guard(() => { video.onloadedmetadata = null; const duration = video.duration; + const videoHeight = video.videoHeight; + const videoWidth = video.videoWidth; const { height, canvasWidth, canvasHeight } = sheetSize(config, { duration, - videoHeight: video.videoHeight, - videoWidth: video.videoWidth + videoHeight, + videoWidth }); if (!job.active()) return; + video.width = videoWidth; + video.height = videoHeight; + video.style.width = `${videoWidth}px`; + video.style.height = `${videoHeight}px`; const canvas = document.createElement("canvas"); if (!job.active()) return; @@ -66,7 +87,20 @@ function extract(job, config) { job.dispose(); return; } + const target = duration * index / config.number; + let retries = 0; video.onseeked = job.guard(() => { + if (video.seeking) + return; + const time = video.currentTime; + if (!job.active()) + return; + if (!Number.isFinite(time) || Math.abs(time - target) > 0.05) { + if (++retries > 3) + throw new Error("Auto-thumbnail seek did not reach the requested time"); + video.currentTime = target; + return; + } video.onseeked = null; ctx.drawImage(video, index % 10 * config.width, Math.floor(index / 10) * height, config.width, height); if (!job.active()) @@ -84,7 +118,7 @@ function extract(job, config) { }), "image/jpeg"); }); if (job.active()) - video.currentTime = duration * index / config.number; + video.currentTime = target; }); seek(); }); diff --git a/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md b/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md index d5243747e..f987a109d 100644 --- a/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md +++ b/packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md @@ -24,9 +24,16 @@ for video processing. 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 + 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. 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 @@ -39,6 +46,13 @@ Duration and sheet dimensions are captured at metadata time; later duration chan do not move the remaining samples within the current sheet. The old `height` option remains ignored at runtime. +A `seeked` callback is ignored while another seek is pending. Before drawing, +extraction checks that the media time is finite and within 50ms of the requested +sample; a mismatch retries that same target at most three times, then fails with +cleanup and retains any previous preview. This prevents observed stale seek +events from advancing the sheet, but does not prove frame presentation accuracy: +the current time can match even when the drawable first frame is stale. + The previous empty first encode is removed. Encoding is serial, duplicate native callbacks are consumed once, and source replacement/destruction invalidates old metadata, seek and Blob callbacks. Failure does not revoke an earlier usable @@ -57,6 +71,7 @@ Use the root Yarn toolchain: ```sh yarn test:auto-thumbnail 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 ``` @@ -66,11 +81,21 @@ Historical contract/failure tests remain separate and continue to reproduce old defects; their passing status does not mean those defects should remain. This is an intermediate `PKG-AUTO-THUMB-03` implementation. Native lifecycle -validation does not prove correct pixels: the detached decoder path still needs -the recorded Windows WebKit frame/rendering fix (`AUTO-THUMB-PIXEL-01`). Hidden -rendering must retain source detail; a 1x1 element producing an averaged pixel is -not a correct fix. Frame timing, additional reentry/cleanup boundaries and resource -budgets still need the remaining task03 work. +validation does not prove correct pixels. The attached renderer now has native +pixel checks for cells 2-4 (zero-based) on a five-frame sheet, including real black +content, changing colors and spatial detail. Cells 0-1 remain diagnostic only: +initial transparent/stale draws and WebKit frame-time offsets are unresolved +(`AUTO-THUMB-PIXEL-01`). Merely waiting for `seeked`, adding two animation frames, +or seeking away and back did not consistently repair the first frame. Do not +close this risk based on the later-cell assertions or replace it with a nonblack +test; legitimate black frames have opaque pixels. Frame timing, additional +reentry/cleanup boundaries and resource budgets still need the remaining task03 work. + +The frozen eight-second timeline has one unique purple first frame followed by +red, black, blue and yellow sections. Its command and fingerprint are in +`refactor/baselines/auto-thumbnail-timeline-media.json`. Reproduce into a new +directory with `ARTPLAYER_FFMPEG` and `node scripts/generate-auto-thumbnail-fixture.mjs +`; 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 diff --git a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.js b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.js index 8b86f9ee5..92ad75057 100644 --- a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.js +++ b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.js @@ -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,t){const i=document.createElement("video");e.own(()=>i.load()),e.own(()=>i.removeAttribute("src")),e.own(()=>i.pause());for(const n of["onloadedmetadata","onseeked","onerror"])e.own(()=>{i[n]=null});e.active()&&(i.crossOrigin="anonymous",i.onerror=e.guard(()=>{throw i.error||new Error("Auto-thumbnail media failed to load")}),i.onloadedmetadata=e.guard(()=>{i.onloadedmetadata=null;const n=i.duration,{height:r,canvasWidth:o,canvasHeight:a}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:i.videoHeight,videoWidth:i.videoWidth});if(!e.active())return;const u=document.createElement("canvas");if(!e.active())return;u.width=o,u.height=a;const d=u.getContext("2d");if(!d)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let c=0;const s=e.guard(()=>{c>=t.number?e.dispose():(i.onseeked=e.guard(()=>{if(i.onseeked=null,d.drawImage(i,c%10*t.width,Math.floor(c/10)*r,t.width,r),!e.active())return;let n=!1;u.toBlob(e.guard(i=>{n||(n=!0,e.publish(i,{height:r,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(c+=1,s()))}),"image/jpeg")}),e.active()&&(i.currentTime=n*c/t.number))});s()}),e.active()&&(i.src=t.url))}function t(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}return function(i){return async n=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(e,i){let n,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=n;n=void 0,e?.dispose()}return{start:function(){if(o)return;const d=n,c=[];let s=!1;const l={active:()=>!o&&!s&&n===l,own(e){if(s){const n=t([e]);n.failed&&i(n.failure)}else c.push(e)},dispose(){if(s)return;s=!0,n===l&&(n=void 0);const e=t(c.splice(0).reverse());e.failed&&i(e.failure)},fail(e){l.active()&&(l.dispose(),i(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(i){l.fail(i)}},publish(n,o){if(!l.active())return;if(!n)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(n);if(a.add(d),!l.active())return void u(d);const c=r;r=d;try{e({url:d,...o})}catch(s){r===d&&(r=a.has(c)?c:void 0);const e=t([()=>u(d)]);throw e.failed&&i(e.failure),s}u(c)}};return n=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)return;o=!0;const e=t([d,...[...a].map(e=>()=>u(e))]);r=void 0,e.failed&&i(e.failure)},get closed(){return o}}}(e=>{n.thumbnails=e},r),a=[],u=()=>{const t=o.start();t&&t.guard(()=>{const r=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(i,()=>n.option.url);t.active()&&e(t,r)})()},d=()=>{const e=a.splice(0),i=t([o.destroy,...e]);i.failed&&r(i.failure)};try{for(const[e,t]of[["destroy",d],["restart",o.cancel],["video:loadedmetadata",u]]){if(o.closed)break;a.push(()=>n.off(e,t)),n.on(e,t),o.closed&&n.off(e,t)}}catch(c){throw d(),c}return{name:"artplayerPluginAutoThumbnail"}}}}); +!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,t){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 i of["onloadedmetadata","onseeked","onerror"])e.own(()=>{t[i]=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 n=i.duration,r=i.videoHeight,o=i.videoWidth,{height:a,canvasWidth:u,canvasHeight:d}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:r,videoWidth:o});if(!e.active())return;i.width=o,i.height=r,i.style.width=`${o}px`,i.style.height=`${r}px`;const s=document.createElement("canvas");if(!e.active())return;s.width=u,s.height=d;const c=s.getContext("2d");if(!c)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let l=0;const h=e.guard(()=>{if(l>=t.number)return void e.dispose();const r=n*l/t.number;let o=0;i.onseeked=e.guard(()=>{if(i.seeking)return;const n=i.currentTime;if(!e.active())return;if(!Number.isFinite(n)||Math.abs(n-r)>.05){if(++o>3)throw new Error("Auto-thumbnail seek did not reach the requested time");return void(i.currentTime=r)}if(i.onseeked=null,c.drawImage(i,l%10*t.width,Math.floor(l/10)*a,t.width,a),!e.active())return;let u=!1;s.toBlob(e.guard(i=>{u||(u=!0,e.publish(i,{height:a,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(l+=1,h()))}),"image/jpeg")}),e.active()&&(i.currentTime=r)});h()}),e.active()&&(i.src=t.url))}function t(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}return function(i){return async n=>{const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),o=function(e,i){let n,r,o=!1;const a=new Set;function u(e){a.delete(e)&&URL.revokeObjectURL(e)}function d(){const e=n;n=void 0,e?.dispose()}return{start:function(){if(o)return;const d=n,s=[];let c=!1;const l={active:()=>!o&&!c&&n===l,own(e){if(c){const n=t([e]);n.failed&&i(n.failure)}else s.push(e)},dispose(){if(c)return;c=!0,n===l&&(n=void 0);const e=t(s.splice(0).reverse());e.failed&&i(e.failure)},fail(e){l.active()&&(l.dispose(),i(e))},guard:e=>(...t)=>{if(l.active())try{return e(...t)}catch(i){l.fail(i)}},publish(n,o){if(!l.active())return;if(!n)throw new Error("Auto-thumbnail encoding returned no Blob");const d=URL.createObjectURL(n);if(a.add(d),!l.active())return void u(d);const s=r;r=d;try{e({url:d,...o})}catch(c){r===d&&(r=a.has(s)?s:void 0);const e=t([()=>u(d)]);throw e.failed&&i(e.failure),c}u(s)}};return n=l,d?.dispose(),l},cancel:d,destroy:function(){if(o)return;o=!0;const e=t([d,...[...a].map(e=>()=>u(e))]);r=void 0,e.failed&&i(e.failure)},get closed(){return o}}}(e=>{n.thumbnails=e},r),a=[],u=()=>{const t=o.start();t&&t.guard(()=>{const r=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(i,()=>n.option.url);t.active()&&e(t,r)})()},d=()=>{const e=a.splice(0),i=t([o.destroy,...e]);i.failed&&r(i.failure)};try{for(const[e,t]of[["destroy",d],["restart",o.cancel],["video:loadedmetadata",u]]){if(o.closed)break;a.push(()=>n.off(e,t)),n.on(e,t),o.closed&&n.off(e,t)}}catch(s){throw d(),s}return{name:"artplayerPluginAutoThumbnail"}}}}); diff --git a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.legacy.js b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.legacy.js index efa10b587..18a135348 100644 --- a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.legacy.js +++ b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.legacy.js @@ -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,r=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable,i=(t,r,n)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[r]=n;function o(e,t){const r=document.createElement("video");e.own(()=>r.load()),e.own(()=>r.removeAttribute("src")),e.own(()=>r.pause());for(const n of["onloadedmetadata","onseeked","onerror"])e.own(()=>{r[n]=null});e.active()&&(r.crossOrigin="anonymous",r.onerror=e.guard(()=>{throw r.error||new Error("Auto-thumbnail media failed to load")}),r.onloadedmetadata=e.guard(()=>{r.onloadedmetadata=null;const n=r.duration,{height:i,canvasWidth:o,canvasHeight:a}=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 r=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),i=Math.trunc(r*Math.ceil(e.number/10));if(![r,n,i].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:r,canvasWidth:n,canvasHeight:i}}(t,{duration:n,videoHeight:r.videoHeight,videoWidth:r.videoWidth});if(!e.active())return;const u=document.createElement("canvas");if(!e.active())return;u.width=o,u.height=a;const d=u.getContext("2d");if(!d)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let c=0;const l=e.guard(()=>{c>=t.number?e.dispose():(r.onseeked=e.guard(()=>{if(r.onseeked=null,d.drawImage(r,c%10*t.width,Math.floor(c/10)*i,t.width,i),!e.active())return;let n=!1;u.toBlob(e.guard(r=>{n||(n=!0,e.publish(r,{height:i,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(c+=1,l()))}),"image/jpeg")}),e.active()&&(r.currentTime=n*c/t.number))});l()}),e.active()&&(r.src=t.url))}function a(e){let t,r=!1;for(const i of e)try{i()}catch(n){r||(r=!0,t=n)}return{failed:r,failure:t}}function u(e,o){let u,d,c=!1;const l=new Set;function s(e){l.delete(e)&&URL.revokeObjectURL(e)}function f(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(c)return;const f=u,h=[];let m=!1;const v={active:()=>!c&&!m&&u===v,own(e){if(m){const t=a([e]);t.failed&&o(t.failure)}else h.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=a(h.splice(0).reverse());e.failed&&o(e.failure)},fail(e){v.active()&&(v.dispose(),o(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(r){v.fail(r)}},publish(u,c){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const f=URL.createObjectURL(u);if(l.add(f),!v.active())return void s(f);const h=d;d=f;try{e(((e,o)=>{for(var a in o||(o={}))r.call(o,a)&&i(e,a,o[a]);if(t)for(var a of t(o))n.call(o,a)&&i(e,a,o[a]);return e})({url:f},c))}catch(m){d===f&&(d=l.has(h)?h:void 0);const e=a([()=>s(f)]);throw e.failed&&o(e.failure),m}s(h)}};return u=v,null==f||f.dispose(),v},cancel:f,destroy:function(){if(c)return;c=!0;const e=a([f,...[...l].map(e=>()=>s(e))]);d=void 0,e.failed&&o(e.failure)},get closed(){return c}}}return function(e){return t=>{return r=null,n=null,i=function*(){const r=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),n=u(e=>{t.thumbnails=e},r),i=[],d=()=>{const r=n.start();r&&r.guard(()=>{const n=function(e,t){const r={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(r.width))||r.width<=0||!Number.isFinite(Number(r.number))||r.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return r}(e,()=>t.option.url);r.active()&&o(r,n)})()},c=()=>{const e=i.splice(0),t=a([n.destroy,...e]);t.failed&&r(t.failure)};try{for(const[e,r]of[["destroy",c],["restart",n.cancel],["video:loadedmetadata",d]]){if(n.closed)break;i.push(()=>t.off(e,r)),t.on(e,r),n.closed&&t.off(e,r)}}catch(l){throw c(),l}return{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var o=e=>{try{u(i.next(e))}catch(r){t(r)}},a=e=>{try{u(i.throw(e))}catch(r){t(r)}},u=t=>t.done?e(t.value):Promise.resolve(t.value).then(o,a);u((i=i.apply(r,n)).next())});var r,n,i}}}); +!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,i=Object.prototype.hasOwnProperty,n=Object.prototype.propertyIsEnumerable,r=(t,i,n)=>i in t?e(t,i,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[i]=n;function o(e,t){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 i of["onloadedmetadata","onseeked","onerror"])e.own(()=>{t[i]=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 n=i.duration,r=i.videoHeight,o=i.videoWidth,{height:a,canvasWidth:u,canvasHeight:d}=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 i=Math.floor(e.width*t.videoHeight/t.videoWidth),n=Math.trunc(10*e.width),r=Math.trunc(i*Math.ceil(e.number/10));if(![i,n,r].every(e=>Number.isSafeInteger(e)&&e>0&&e<=4294967295))throw new RangeError("Auto-thumbnail canvas dimensions are invalid");return{height:i,canvasWidth:n,canvasHeight:r}}(t,{duration:n,videoHeight:r,videoWidth:o});if(!e.active())return;i.width=o,i.height=r,i.style.width=`${o}px`,i.style.height=`${r}px`;const c=document.createElement("canvas");if(!e.active())return;c.width=u,c.height=d;const l=c.getContext("2d");if(!l)throw new Error("Auto-thumbnail canvas context is unavailable");if(!e.active())return;let s=0;const h=e.guard(()=>{if(s>=t.number)return void e.dispose();const r=n*s/t.number;let o=0;i.onseeked=e.guard(()=>{if(i.seeking)return;const n=i.currentTime;if(!e.active())return;if(!Number.isFinite(n)||Math.abs(n-r)>.05){if(++o>3)throw new Error("Auto-thumbnail seek did not reach the requested time");return void(i.currentTime=r)}if(i.onseeked=null,l.drawImage(i,s%10*t.width,Math.floor(s/10)*a,t.width,a),!e.active())return;let u=!1;c.toBlob(e.guard(i=>{u||(u=!0,e.publish(i,{height:a,column:10,number:t.number,width:t.width,scale:t.scale}),e.active()&&(s+=1,h()))}),"image/jpeg")}),e.active()&&(i.currentTime=r)});h()}),e.active()&&(i.src=t.url))}function a(e){let t,i=!1;for(const r of e)try{r()}catch(n){i||(i=!0,t=n)}return{failed:i,failure:t}}function u(e,o){let u,d,c=!1;const l=new Set;function s(e){l.delete(e)&&URL.revokeObjectURL(e)}function h(){const e=u;u=void 0,null==e||e.dispose()}return{start:function(){if(c)return;const h=u,f=[];let m=!1;const v={active:()=>!c&&!m&&u===v,own(e){if(m){const t=a([e]);t.failed&&o(t.failure)}else f.push(e)},dispose(){if(m)return;m=!0,u===v&&(u=void 0);const e=a(f.splice(0).reverse());e.failed&&o(e.failure)},fail(e){v.active()&&(v.dispose(),o(e))},guard:e=>(...t)=>{if(v.active())try{return e(...t)}catch(i){v.fail(i)}},publish(u,c){if(!v.active())return;if(!u)throw new Error("Auto-thumbnail encoding returned no Blob");const h=URL.createObjectURL(u);if(l.add(h),!v.active())return void s(h);const f=d;d=h;try{e(((e,o)=>{for(var a in o||(o={}))i.call(o,a)&&r(e,a,o[a]);if(t)for(var a of t(o))n.call(o,a)&&r(e,a,o[a]);return e})({url:h},c))}catch(m){d===h&&(d=l.has(f)?f:void 0);const e=a([()=>s(h)]);throw e.failed&&o(e.failure),m}s(f)}};return u=v,null==h||h.dispose(),v},cancel:h,destroy:function(){if(c)return;c=!0;const e=a([h,...[...l].map(e=>()=>s(e))]);d=void 0,e.failed&&o(e.failure)},get closed(){return c}}}return function(e){return t=>{return i=null,n=null,r=function*(){const i=e=>console.warn("ArtPlayer auto-thumbnail failed:",e),n=u(e=>{t.thumbnails=e},i),r=[],d=()=>{const i=n.start();i&&i.guard(()=>{const n=function(e,t){const i={url:e.url||t(),width:e.width||160,number:e.number||100,scale:e.scale||1};if(!Number.isFinite(Number(i.width))||i.width<=0||!Number.isFinite(Number(i.number))||i.number<=0)throw new TypeError("Auto-thumbnail width and number must be finite positive numbers");return i}(e,()=>t.option.url);i.active()&&o(i,n)})()},c=()=>{const e=r.splice(0),t=a([n.destroy,...e]);t.failed&&i(t.failure)};try{for(const[e,i]of[["destroy",c],["restart",n.cancel],["video:loadedmetadata",d]]){if(n.closed)break;r.push(()=>t.off(e,i)),t.on(e,i),n.closed&&t.off(e,i)}}catch(l){throw c(),l}return{name:"artplayerPluginAutoThumbnail"}},new Promise((e,t)=>{var o=e=>{try{u(r.next(e))}catch(i){t(i)}},a=e=>{try{u(r.throw(e))}catch(i){t(i)}},u=t=>t.done?e(t.value):Promise.resolve(t.value).then(o,a);u((r=r.apply(i,n)).next())});var i,n,r}}}); diff --git a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.mjs b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.mjs index bee9c380f..a3c006446 100644 --- a/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.mjs +++ b/packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.mjs @@ -25,8 +25,9 @@ function sheetSize(config, video) { throw new RangeError("Auto-thumbnail canvas dimensions are invalid"); return { height, canvasWidth, canvasHeight }; } -function extract(job, config) { +function createVideo(job) { const video = document.createElement("video"); + job.own(() => video.remove()); job.own(() => video.load()); job.own(() => video.removeAttribute("src")); job.own(() => video.pause()); @@ -35,21 +36,41 @@ function extract(job, config) { video[property] = null; }); if (!job.active()) - return; + return video; video.crossOrigin = "anonymous"; + video.muted = true; + video.playsInline = true; + video.tabIndex = -1; + video.setAttribute("aria-hidden", "true"); + video.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(video); + if (!job.active()) + video.remove(); + return video; +} +function extract(job, config) { + const video = createVideo(job); + if (!job.active()) + return; video.onerror = job.guard(() => { throw video.error || new Error("Auto-thumbnail media failed to load"); }); video.onloadedmetadata = job.guard(() => { video.onloadedmetadata = null; const duration = video.duration; + const videoHeight = video.videoHeight; + const videoWidth = video.videoWidth; const { height, canvasWidth, canvasHeight } = sheetSize(config, { duration, - videoHeight: video.videoHeight, - videoWidth: video.videoWidth + videoHeight, + videoWidth }); if (!job.active()) return; + video.width = videoWidth; + video.height = videoHeight; + video.style.width = `${videoWidth}px`; + video.style.height = `${videoHeight}px`; const canvas = document.createElement("canvas"); if (!job.active()) return; @@ -66,7 +87,20 @@ function extract(job, config) { job.dispose(); return; } + const target = duration * index / config.number; + let retries = 0; video.onseeked = job.guard(() => { + if (video.seeking) + return; + const time = video.currentTime; + if (!job.active()) + return; + if (!Number.isFinite(time) || Math.abs(time - target) > 0.05) { + if (++retries > 3) + throw new Error("Auto-thumbnail seek did not reach the requested time"); + video.currentTime = target; + return; + } video.onseeked = null; ctx.drawImage(video, index % 10 * config.width, Math.floor(index / 10) * height, config.width, height); if (!job.active()) @@ -84,7 +118,7 @@ function extract(job, config) { }), "image/jpeg"); }); if (job.active()) - video.currentTime = duration * index / config.number; + video.currentTime = target; }); seek(); }); diff --git a/packages/artplayer-plugin-auto-thumbnail/src/extraction.js b/packages/artplayer-plugin-auto-thumbnail/src/extraction.js index 5ace488e2..a2825b8c4 100644 --- a/packages/artplayer-plugin-auto-thumbnail/src/extraction.js +++ b/packages/artplayer-plugin-auto-thumbnail/src/extraction.js @@ -1,28 +1,29 @@ import { sheetSize } from './options' +import createVideo from './video' export default function extract(job, config) { - const video = document.createElement('video') - job.own(() => video.load()) - job.own(() => video.removeAttribute('src')) - job.own(() => video.pause()) - for (const property of ['onloadedmetadata', 'onseeked', 'onerror']) - job.own(() => { video[property] = null }) + const video = createVideo(job) if (!job.active()) return - video.crossOrigin = 'anonymous' video.onerror = job.guard(() => { throw video.error || new Error('Auto-thumbnail media failed to load') }) video.onloadedmetadata = job.guard(() => { video.onloadedmetadata = null const duration = video.duration + const videoHeight = video.videoHeight + const videoWidth = video.videoWidth const { height, canvasWidth, canvasHeight } = sheetSize(config, { duration, - videoHeight: video.videoHeight, - videoWidth: video.videoWidth, + videoHeight, + videoWidth, }) if (!job.active()) return + video.width = videoWidth + video.height = videoHeight + video.style.width = `${videoWidth}px` + video.style.height = `${videoHeight}px` const canvas = document.createElement('canvas') if (!job.active()) return @@ -39,7 +40,20 @@ export default function extract(job, config) { job.dispose() return } + const target = duration * index / config.number + let retries = 0 video.onseeked = job.guard(() => { + if (video.seeking) + return + const time = video.currentTime + if (!job.active()) + return + if (!Number.isFinite(time) || Math.abs(time - target) > 0.05) { + if (++retries > 3) + throw new Error('Auto-thumbnail seek did not reach the requested time') + video.currentTime = target + return + } video.onseeked = null ctx.drawImage(video, (index % 10) * config.width, Math.floor(index / 10) * height, config.width, height) if (!job.active()) @@ -57,7 +71,7 @@ export default function extract(job, config) { }), 'image/jpeg') }) if (job.active()) - video.currentTime = duration * index / config.number + video.currentTime = target }) seek() }) diff --git a/packages/artplayer-plugin-auto-thumbnail/src/video.js b/packages/artplayer-plugin-auto-thumbnail/src/video.js new file mode 100644 index 000000000..b9498fc4c --- /dev/null +++ b/packages/artplayer-plugin-auto-thumbnail/src/video.js @@ -0,0 +1,22 @@ +export default function createVideo(job) { + 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', 'onseeked', 'onerror']) + job.own(() => { video[property] = null }) + if (!job.active()) + return video + video.crossOrigin = 'anonymous' + video.muted = true + video.playsInline = true + video.tabIndex = -1 + video.setAttribute('aria-hidden', 'true') + // WebKit needs a rendered box; display:none and a 1px box lose decoded pixels. + video.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(video) + if (!job.active()) + video.remove() + return video +} diff --git a/refactor/baselines/auto-thumbnail-hidden-renderer.json b/refactor/baselines/auto-thumbnail-hidden-renderer.json new file mode 100644 index 000000000..327a38544 --- /dev/null +++ b/refactor/baselines/auto-thumbnail-hidden-renderer.json @@ -0,0 +1,11592 @@ +{ + "task": "PKG-AUTO-THUMB-03", + "status": "doing", + "date": "2026-09-12T23:19:22.843Z", + "previousCommit": "84721f19ed77b9e5134605b522036a78375c8e45", + "scope": "Attached hidden intrinsic-sized decoder ownership and bounded stale-seek retries. Native pixel assertions cover cells 2-4 of five only; initial presentation remains unresolved. No completion or release claim.", + "unit": [ + { + "variant": "before", + "tests": 33, + "pass": 25, + "fail": 8, + "log": "refactor/.cache/auto-thumbnail03-render-unit-timing-before.log", + "sha256": "92685ea1a76e2ecb6706b41928ca5bc726fe77adb832bff090730e47b6629447" + }, + { + "variant": "source", + "tests": 33, + "pass": 33, + "fail": 0, + "log": "refactor/.cache/auto-thumbnail03-render-unit-timing-source.log", + "sha256": "7e321fca74b1d6fe90d584a58feb7eeaf52e29a7a630957832c38e4c13ca7d68" + }, + { + "variant": "main", + "tests": 33, + "pass": 33, + "fail": 0, + "log": "refactor/.cache/auto-thumbnail03-render-unit-timing-main.log", + "sha256": "ec83ba11b048b26ce8444bc148084c9d21c1c3f78aa8334653136dd724496f03" + }, + { + "variant": "legacy", + "tests": 33, + "pass": 33, + "fail": 0, + "log": "refactor/.cache/auto-thumbnail03-render-unit-timing-legacy.log", + "sha256": "11d4165767fb449a94a0591ab9ae06e988a3972caddd9a104f4084ad114cbf8b" + } + ], + "native": [ + { + "variant": "source", + "tests": 45, + "retries": 0, + "skipped": 0, + "report": "refactor/.cache/auto-thumbnail03-render-browser-timing-source.json", + "sha256": "4b81314b5c078f90bf48c0cd539afded3eb896278ea4d4ab59c7a1b3f930dfcf", + "results": "refactor/.cache/auto-thumbnail03-render-browser-timing-source-results", + "measurements": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + }, + { + "type": "image/jpeg", + "bytes": 4226 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + }, + { + "type": "image/jpeg", + "bytes": 4226 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + }, + { + "type": "image/jpeg", + "bytes": 4226 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + }, + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + }, + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + }, + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + }, + { + "type": "image/jpeg", + "bytes": 4215 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + }, + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + }, + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 126, + 0, + 126, + 255 + ], + [ + 254, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 1, + 252, + 255 + ], + [ + 255, + 255, + 1, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 127, + 0, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 254, + 0, + 0, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 255, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 15, + 13, + 138, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 14, + 15, + 141, + 255 + ], + [ + 213, + 61, + 47, + 255 + ] + ], + "spatial": [ + [ + 244, + 1, + 0, + 255 + ], + [ + 5, + 251, + 2, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 255, + 0, + 253, + 255 + ], + [ + 2, + 255, + 253, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 253, + 52, + 0, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 126, + 0, + 126, + 255 + ], + [ + 254, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 1, + 252, + 255 + ], + [ + 255, + 255, + 1, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 127, + 0, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 254, + 0, + 0, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 255, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 15, + 13, + 138, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 14, + 15, + 141, + 255 + ], + [ + 213, + 61, + 47, + 255 + ] + ], + "spatial": [ + [ + 244, + 1, + 0, + 255 + ], + [ + 5, + 251, + 2, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 255, + 0, + 253, + 255 + ], + [ + 2, + 255, + 253, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 253, + 52, + 0, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 126, + 0, + 126, + 255 + ], + [ + 254, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 1, + 252, + 255 + ], + [ + 255, + 255, + 1, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 127, + 0, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 254, + 0, + 0, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 255, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 15, + 13, + 138, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 14, + 15, + 141, + 255 + ], + [ + 213, + 61, + 47, + 255 + ] + ], + "spatial": [ + [ + 244, + 1, + 0, + 255 + ], + [ + 5, + 251, + 2, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 255, + 0, + 253, + 255 + ], + [ + 2, + 255, + 253, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 253, + 52, + 0, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 136, + 19, + 126, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 254, + 241, + 2, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 137, + 19, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 241, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 5, + 15, + 250, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 247, + 64, + 0, + 255 + ] + ], + "spatial": [ + [ + 255, + 22, + 9, + 255 + ], + [ + 0, + 216, + 3, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 255, + 36, + 254, + 255 + ], + [ + 1, + 229, + 254, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 69, + 1, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 136, + 19, + 126, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 254, + 241, + 2, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 137, + 19, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 241, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 5, + 15, + 250, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 247, + 64, + 0, + 255 + ] + ], + "spatial": [ + [ + 255, + 22, + 9, + 255 + ], + [ + 0, + 216, + 3, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 255, + 36, + 254, + 255 + ], + [ + 1, + 229, + 254, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 69, + 1, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 136, + 19, + 126, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 254, + 241, + 2, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 137, + 19, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 241, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 5, + 15, + 250, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 247, + 64, + 0, + 255 + ] + ], + "spatial": [ + [ + 255, + 22, + 9, + 255 + ], + [ + 0, + 216, + 3, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 255, + 36, + 254, + 255 + ], + [ + 1, + 229, + 254, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 69, + 1, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 238, + 14, + 14, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 15, + 239, + 255 + ], + [ + 235, + 236, + 12, + 255 + ] + ], + "spatial": [ + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6019152, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 238, + 14, + 14, + 255 + ] + }, + { + "time": 3.2025442, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 16, + 16, + 255 + ] + }, + { + "time": 4.8007987, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.400963, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 235, + 236, + 12, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 217, + 65, + 51, + 255 + ] + ], + "spatial": [ + [ + 238, + 14, + 15, + 255 + ], + [ + 14, + 238, + 14, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 238, + 13, + 237, + 255 + ], + [ + 14, + 237, + 237, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6006694, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 3.2019709, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 4.8012503, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4032397, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 239, + 62, + 14, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 238, + 14, + 14, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 15, + 239, + 255 + ], + [ + 235, + 236, + 12, + 255 + ] + ], + "spatial": [ + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ] + ], + "draws": [ + { + "time": 0.0015006, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6009459, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 238, + 14, + 14, + 255 + ] + }, + { + "time": 3.2005912, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 16, + 16, + 255 + ] + }, + { + "time": 4.8016489, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4029758, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 235, + 236, + 12, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 217, + 65, + 51, + 255 + ] + ], + "spatial": [ + [ + 238, + 14, + 15, + 255 + ], + [ + 14, + 238, + 14, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 238, + 13, + 237, + 255 + ], + [ + 14, + 237, + 237, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6018154, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 3.2019216, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 4.8019528, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4032085, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 239, + 62, + 14, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 238, + 14, + 14, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 15, + 239, + 255 + ], + [ + 235, + 236, + 12, + 255 + ] + ], + "spatial": [ + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6018602, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 238, + 14, + 14, + 255 + ] + }, + { + "time": 3.2009135, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 16, + 16, + 255 + ] + }, + { + "time": 4.8015943, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4024989, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 235, + 236, + 12, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d86c51814028db5030b06c5e63a3236e0ddd573449c35fec632f42165b03c034", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 217, + 65, + 51, + 255 + ] + ], + "spatial": [ + [ + 238, + 14, + 15, + 255 + ], + [ + 14, + 238, + 14, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 238, + 13, + 237, + 255 + ], + [ + 14, + 237, + 237, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6019339, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 3.2010852, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 4.8010224, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4028233, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 239, + 62, + 14, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + } + ] + }, + { + "variant": "main", + "tests": 15, + "retries": 0, + "skipped": 0, + "report": "refactor/.cache/auto-thumbnail03-render-browser-timing-main.json", + "sha256": "60ae5f0007ff4359aff2fe9b10748a72b7923f24323b09cc07972c82fdbbf4cf", + "results": "refactor/.cache/auto-thumbnail03-render-browser-timing-main-results", + "measurements": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + }, + { + "type": "image/jpeg", + "bytes": 4226 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + }, + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + }, + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 126, + 0, + 126, + 255 + ], + [ + 254, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 1, + 252, + 255 + ], + [ + 255, + 255, + 1, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 127, + 0, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 254, + 0, + 0, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 255, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 15, + 13, + 138, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 14, + 15, + 141, + 255 + ], + [ + 213, + 61, + 47, + 255 + ] + ], + "spatial": [ + [ + 244, + 1, + 0, + 255 + ], + [ + 5, + 251, + 2, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 255, + 0, + 253, + 255 + ], + [ + 2, + 255, + 253, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 253, + 52, + 0, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 136, + 19, + 126, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 254, + 241, + 2, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 137, + 19, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 241, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 5, + 15, + 250, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 247, + 64, + 0, + 255 + ] + ], + "spatial": [ + [ + 255, + 22, + 9, + 255 + ], + [ + 0, + 216, + 3, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 255, + 36, + 254, + 255 + ], + [ + 1, + 229, + 254, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 69, + 1, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 238, + 14, + 14, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 15, + 239, + 255 + ], + [ + 235, + 236, + 12, + 255 + ] + ], + "spatial": [ + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6016184, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 238, + 14, + 14, + 255 + ] + }, + { + "time": 3.2026037, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 16, + 16, + 255 + ] + }, + { + "time": 4.8017984, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4018786, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 235, + 236, + 12, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 217, + 65, + 51, + 255 + ] + ], + "spatial": [ + [ + 238, + 14, + 14, + 255 + ], + [ + 14, + 238, + 14, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 239, + 13, + 237, + 255 + ], + [ + 14, + 237, + 237, + 255 + ] + ], + "draws": [ + { + "time": 0.000913, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6019995, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 3.2005722, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 4.8013164, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.401676, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 239, + 62, + 14, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + } + ] + }, + { + "variant": "legacy", + "tests": 15, + "retries": 0, + "skipped": 0, + "report": "refactor/.cache/auto-thumbnail03-render-browser-timing-legacy.json", + "sha256": "0411850df3f67a444ba5f231088953756dcfd4dff76498ec2069904b1560c874", + "results": "refactor/.cache/auto-thumbnail03-render-browser-timing-legacy-results", + "measurements": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 2635 + }, + { + "type": "image/jpeg", + "bytes": 4226 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 4076 + }, + { + "type": "image/jpeg", + "bytes": 4076 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native destroy owns decoder and encoded URLs", + "scenario": "destroy", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native restart owns decoder and encoded URLs", + "scenario": "restart", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 0, + "updates": 0 + }, + "after": { + "urls": 0, + "updates": 0 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 0 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate native complete owns decoder and encoded URLs", + "scenario": "complete", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual HTTP decoding/seek/JPEG lifecycle with a stub player host. This checkpoint does not establish accurate extracted pixels; AUTO-THUMB-PIXEL-01 remains open.", + "before": { + "urls": 1, + "updates": 2 + }, + "after": { + "urls": 1, + "updates": 2 + }, + "video": { + "connected": false, + "src": null, + "readyState": 0, + "paused": true, + "handlers": [ + true, + true, + true + ] + }, + "final": { + "urls": 0, + "listeners": 0, + "updates": 2 + }, + "blobs": [ + { + "type": "image/jpeg", + "bytes": 983 + }, + { + "type": "image/jpeg", + "bytes": 4215 + } + ], + "result": { + "name": "artplayerPluginAutoThumbnail" + } + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 126, + 0, + 126, + 255 + ], + [ + 254, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 1, + 252, + 255 + ], + [ + 255, + 255, + 1, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 127, + 0, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 254, + 0, + 0, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 255, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 15, + 13, + 138, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 14, + 15, + 141, + 255 + ], + [ + 213, + 61, + 47, + 255 + ] + ], + "spatial": [ + [ + 244, + 1, + 0, + 255 + ], + [ + 5, + 251, + 2, + 255 + ], + [ + 15, + 15, + 139, + 255 + ], + [ + 255, + 0, + 253, + 255 + ], + [ + 2, + 255, + 253, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 253, + 52, + 0, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 136, + 19, + 126, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 254, + 241, + 2, + 255 + ] + ], + "spatial": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 0, + 0, + 0, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 137, + 19, + 126, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 241, + 2, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "firefox", + "version": "155.0", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 5, + 15, + 250, + 255 + ], + [ + 0, + 0, + 0, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 247, + 64, + 0, + 255 + ] + ], + "spatial": [ + [ + 255, + 22, + 9, + 255 + ], + [ + 0, + 216, + 3, + 255 + ], + [ + 1, + 14, + 253, + 255 + ], + [ + 255, + 36, + 254, + 255 + ], + [ + 1, + 229, + 254, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 1.6, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 3.2, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 4.8, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 14, + 253, + 255 + ] + }, + { + "time": 6.4, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 255, + 69, + 1, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 auto-thumbnail-timeline pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "auto-thumbnail-timeline", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 238, + 14, + 14, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 15, + 239, + 255 + ], + [ + 235, + 236, + 12, + 255 + ] + ], + "spatial": [ + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ], + [ + 16, + 16, + 16, + 255 + ] + ], + "draws": [ + { + "time": 0, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6028348, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 238, + 14, + 14, + 255 + ] + }, + { + "time": 3.2022605, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 16, + 16, + 255 + ] + }, + { + "time": 4.8021543, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.4009858, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 235, + 236, + 12, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + }, + { + "browser": "webkit", + "version": "26.6", + "title": "Auto-thumbnail candidate retains cells 2-4 pattern pixels in a hidden decoder", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "media": "pattern", + "scope": "Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.", + "cells": [ + [ + 0, + 0, + 0, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 217, + 65, + 51, + 255 + ] + ], + "spatial": [ + [ + 238, + 14, + 15, + 255 + ], + [ + 14, + 238, + 14, + 255 + ], + [ + 28, + 28, + 140, + 255 + ], + [ + 238, + 13, + 237, + 255 + ], + [ + 14, + 237, + 237, + 255 + ] + ], + "draws": [ + { + "time": 0.0011813, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 0, + 0, + 0, + 0 + ] + }, + { + "time": 1.6027213, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 3.2025537, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 4.8014865, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 16, + 15, + 239, + 255 + ] + }, + { + "time": 6.402929, + "duration": 8, + "connected": true, + "visibility": "hidden", + "display": "block", + "width": 320, + "height": 180, + "raw": [ + 239, + 62, + 14, + 255 + ] + } + ], + "final": [ + { + "connected": false, + "src": null, + "paused": true + } + ], + "playing": 0, + "warnings": [] + } + ] + } + ], + "fullCI": { + "status": "passed", + "command": "yarn ci:check", + "unit": 1553, + "engineering": 14, + "baseline": 232, + "total": 1799, + "strictProductionTypeScriptFiles": 339, + "scope": "Auto-thumbnail remains JavaScript in this task03 checkpoint.", + "log": "refactor/.cache/auto-thumbnail03-render-ci.log", + "sha256": "1fb9c7a232c66bbabacdea3728bec21026be2925bc3a51cb1ad668a2ec0a806d" + }, + "limits": [ + "AUTO-THUMB-PIXEL-01 remains open: initial transparent/stale pixels and frame-presentation precision are not fixed by currentTime validation.", + "Cells 0-1 are diagnostic only. Stable later cells do not establish correct whole-sheet extraction.", + "Three retries and a 50ms media-time tolerance bound observed wrong-time events; seeked/currentTime do not guarantee drawable frame identity.", + "Real browser tests use a minimal host, not a core integration. Windows WebKit is not physical Safari.", + "Resource budgets, remaining frame scheduling and reentry boundaries remain task03; strict TypeScript/public declarations remain task04." + ], + "failuresRetained": [ + { + "report": "refactor/.cache/auto-thumbnail03-render-browser-before.json", + "expected": 0, + "unexpected": 6, + "meaning": "Previous checkpoint has no attached renderer; Windows WebKit recorded detached black cells. Other browsers also fail the new attachment requirement, not necessarily the same pixel defect.", + "sha256": "604d9e2acff1ea55b1ef4c738dc08bf829fa2821b91e0016a0054fa50f8740dd", + "results": "refactor/.cache/auto-thumbnail03-render-browser-before-results" + }, + { + "report": "refactor/.cache/auto-thumbnail03-render-browser-source-initial.json", + "expected": 10, + "unexpected": 5, + "meaning": "Initial broad pixel experiment exposed transparent early draws and wrong-time events; pattern JPEG center assertions also incorrectly assumed all cells pure blue. Retained as diagnostic failure, never acceptance.", + "sha256": "e64515e7d414c173a619ff217bca31ae7d63b162dccdf1d020aab9c85b67cf1c", + "results": "refactor/.cache/auto-thumbnail03-render-browser-source-initial-results" + }, + { + "report": "refactor/.cache/auto-thumbnail03-render-browser-verified-main.json", + "expected": 14, + "unexpected": 1, + "meaning": "A later WebKit cell had currentTime about 1.6 seconds from target. Fixed by bounded time validation/retry before drawing, then new source/main/legacy runs.", + "sha256": "3e06b8603637d2d69695920e6d4d9a1ad3bf9ec1ef0d1ea2abb90f64275dd91b", + "results": "refactor/.cache/auto-thumbnail03-render-browser-verified-main-results" + } + ], + "experiments": [ + { + "file": "refactor/.cache/auto-thumbnail-colors-metadata-probe.json", + "sha256": "b2fe4a379633a09ebddf72b8f7af225484c9bc57cd0ed6bf86c7f5e1dd18b38f", + "observations": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 2.5, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.5, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.5, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 2.0015379, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 2.0015379, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5007641, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5007641, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5027166, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5027166, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5005583, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5005583, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0017167, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0017167, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5017896, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5017896, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5017259, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5017259, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5019455, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5019455, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 2.001663, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 2.001663, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5013006, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5013006, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5019302, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5019302, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5011835, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5011835, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + } + ] + }, + { + "file": "refactor/.cache/auto-thumbnail-colors-paint-probe.json", + "sha256": "9db9ace8d0cf3b1531f27baa37072db078bcb153827a47a75c5a3575e10a7d6e", + "observations": [ + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0022076, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0022076, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5018151, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5018151, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5027098, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5027098, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5006556, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5006556, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0006381, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0006381, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5013392, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5013392, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5013332, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5013332, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5021428, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5021428, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0013027, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0013027, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5028165, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5028165, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5027205, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5027205, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5008908, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5008908, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0016829, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0016829, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5022282, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5022282, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5021594, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5021594, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5004614, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5004614, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0017984, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0017984, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5018179, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5018179, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5021986, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5021986, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5017615, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5017615, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0018873, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0018873, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.50242, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.50242, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5016017, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5016017, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5012096, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5012096, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0011129, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0011129, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5025352, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5025352, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5004349, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5004349, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.500437, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.500437, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0018748, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0018748, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5004897, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5004897, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.50267, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.50267, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5017197, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5017197, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0015825, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0015825, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5006792, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5006792, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5016085, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5016085, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5019578, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5019578, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0019491, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0019491, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5021505, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5021505, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5026759, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5026759, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.501186, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.501186, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + } + ] + }, + { + "file": "refactor/.cache/auto-thumbnail-colors-seek-probe.json", + "sha256": "6ff6b5bb34cfc3bfbc0dfeab64cb4727b5ecea1d08dbe3cf1a5946cebdb7e9d2", + "observations": [ + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0006804, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0006804, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0044552, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0044552, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0119901, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0119901, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.0411372, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0411372, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.101364, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.101364, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0031435, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0031435, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0018733, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0018733, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0108777, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0108777, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.043022, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.043022, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1011221, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.1011221, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-plain", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0018633, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0.0018633, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0118288, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0.0118288, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.0430059, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0430059, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1005022, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.1005022, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + } + ] + }, + { + "file": "refactor/.cache/auto-thumbnail-colors-first-probe.json", + "sha256": "81051f284ba7e2b3c3e3a47ca45f30cd15f46712511b5a9a5b782da8e1d15563", + "observations": [ + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-fast", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.501597, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.501597, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5009251, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5009251, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5021267, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5021267, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0012247, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 0.0012247, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-play", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0164757, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0.0164757, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5171151, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5171151, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5161717, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5161717, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5171654, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5171654, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0168014, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 0.0168014, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime-play", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0167322, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0167322, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 2.5, + "immediate": { + "time": 2.5172422, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 2.5172422, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 4.5, + "immediate": { + "time": 4.5171296, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + }, + "afterPaint": { + "time": 4.5171296, + "readyState": 4, + "rgba": [ + 16, + 15, + 239, + 255 + ] + } + }, + { + "target": 6.5, + "immediate": { + "time": 6.5181475, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 6.5181475, + "readyState": 3, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0161152, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + }, + "afterPaint": { + "time": 0.0161152, + "readyState": 4, + "rgba": [ + 235, + 236, + 12, + 255 + ] + } + } + ] + } + ] + }, + { + "file": "refactor/.cache/auto-thumbnail-unique-first-probe.json", + "sha256": "db9d74287244e939d0516beccaf42865de4aa8941dfcfa01ecf374ee30fd813f", + "observations": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-plain", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-plain", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0.01, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.04, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 0.1, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0027184, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0027184, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0006203, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0006203, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0115399, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.0115399, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.0410149, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + }, + "afterPaint": { + "time": 0.0410149, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1010477, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.1010477, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-prime", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0.0013223, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0013223, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0021425, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0021425, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0115562, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + }, + "afterPaint": { + "time": 0.0115562, + "readyState": 4, + "rgba": [ + 16, + 16, + 16, + 255 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.0427947, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + }, + "afterPaint": { + "time": 0.0427947, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1021376, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.1021376, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-plain", + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0, + "immediate": { + "time": 0.0023575, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0.0023575, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0.01, + "immediate": { + "time": 0.0124145, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + }, + "afterPaint": { + "time": 0.0124145, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 0 + ] + } + }, + { + "target": 0.04, + "immediate": { + "time": 0.0416324, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + }, + "afterPaint": { + "time": 0.0416324, + "readyState": 4, + "rgba": [ + 127, + 14, + 127, + 255 + ] + } + }, + { + "target": 0.1, + "immediate": { + "time": 0.1018848, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + }, + "afterPaint": { + "time": 0.1018848, + "readyState": 4, + "rgba": [ + 238, + 14, + 14, + 255 + ] + } + } + ] + } + ] + } + ], + "artifacts": [ + { + "file": "packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.js", + "copy": "docs/compiled/artplayer-plugin-auto-thumbnail.js", + "bytes": 4800, + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "copiedBytesEqual": true + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.legacy.js", + "copy": "docs/compiled/artplayer-plugin-auto-thumbnail.legacy.js", + "bytes": 5380, + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "copiedBytesEqual": true + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/dist/artplayer-plugin-auto-thumbnail.mjs", + "copy": "docs/compiled/artplayer-plugin-auto-thumbnail.mjs", + "bytes": 8722, + "sha256": "e4497e133cdd7ffc89e829afa1bd8f9350ae710efbc8e5f5619491e5916b8932", + "copiedBytesEqual": true + } + ], + "fixture": { + "kind": "generated-auto-thumbnail-timeline", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "args": [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "color=c=purple:s=320x180:r=30:d=0.033333333", + "-f", + "lavfi", + "-i", + "color=c=red:s=320x180:r=30:d=1.966666667", + "-f", + "lavfi", + "-i", + "color=c=black:s=320x180:r=30:d=2", + "-f", + "lavfi", + "-i", + "color=c=blue:s=320x180:r=30:d=2", + "-f", + "lavfi", + "-i", + "color=c=yellow:s=320x180:r=30:d=2", + "-filter_complex", + "[0:v][1:v][2:v][3:v][4:v]concat=n=5:v=1:a=0[v]", + "-map", + "[v]", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-g", + "30", + "-movflags", + "+faststart", + "auto-thumbnail-timeline.mp4" + ], + "width": 320, + "height": 180, + "fps": 30, + "duration": 8, + "segments": [ + [ + "purple", + "0.033333333" + ], + [ + "red", + "1.966666667" + ], + [ + "black", + "2" + ], + [ + "blue", + "2" + ], + [ + "yellow", + "2" + ] + ], + "purpose": "Unique purple first frame, then red/black/blue/yellow timeline; distinguish missing transparent pixels, legitimate black frames and stale first frames.", + "file": { + "name": "auto-thumbnail-timeline.mp4", + "bytes": 8602, + "sha256": "10370156cffada462d3ea00aae0caadd62752369cd6538cc55248b3ddd7bf994" + }, + "regeneratedBytesEqual": true + }, + "inputs": [ + { + "file": "packages/artplayer-plugin-auto-thumbnail/ARCHITECTURE.md", + "sha256LF": "dc293f225ed6d0faab55c4b7dbb0cfe9c9145aa96bedb8dae73ebb0f5bf40c08" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/src/index.js", + "sha256LF": "6ecc757ac74d961fb0bda13d58582f0845e29b62f10e351a267b67adb7b684b8" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/src/options.js", + "sha256LF": "11c88fe9682d0736d28a128b352f34832a8ed2a7a82fb6e92e44fc85b7458056" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/src/session.js", + "sha256LF": "14b69480a829d15c9a74995fc398296ad10983bd3a177aa1ddc0205273afa6ec" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/src/extraction.js", + "sha256LF": "bd7c11c8093130163f86ce805b8a7251a06ba12aa7f2a3a5b7cedb10ab2a0915" + }, + { + "file": "packages/artplayer-plugin-auto-thumbnail/src/video.js", + "sha256LF": "06c610423e055cfb2c96dc665595405e61d7c4fc5ded97c38038ab36f16ec1fd" + }, + { + "file": "test/helpers/auto-thumbnail.js", + "sha256LF": "fab8541f1a03329824c9bd7e8d670c7d4dec398640f12a08064b7b5c9f61411d" + }, + { + "file": "test/auto-thumbnail-lifecycle.test.js", + "sha256LF": "f184ff44d0e3d679463407e4e52a32e4c67308625876eb1bc7f96cb2e4fabc02" + }, + { + "file": "test/browser/auto-thumbnail-lifecycle.spec.js", + "sha256LF": "ca4fe5600a3c894bd59d8861aaa9266147bb9f94236ab95f6c407fc9a03dce28" + }, + { + "file": "test/browser/auto-thumbnail-pixels.spec.js", + "sha256LF": "56dfcf3910d344504f46f8619322fc28b8e753d191a208effce2f6154a72094f" + }, + { + "file": "test/browser/server.mjs", + "sha256LF": "5f2cad96de00af41049edbc27a128d32dea4b04a2ef57c870d7cfa838438de4e" + }, + { + "file": "scripts/generate-auto-thumbnail-fixture.mjs", + "sha256LF": "f7ed5804a021eb9a4ac9f7112126ddf8a7b32ac67b2fe2382f5f7204bc34f49c" + } + ], + "actualEntries": [ + { + "name": "main-require", + "entry": "./dist/artplayer-plugin-auto-thumbnail.js", + "result": "pass", + "sha256": "d2ddb67be36e83fcda49aa4de625a4a019e840d1d3f37b2106a6e0aefe323b25", + "scope": "Actual built entry and registration without DOM access; not an installed tarball test." + }, + { + "name": "legacy-require", + "entry": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "result": "pass", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual built entry and registration without DOM access; not an installed tarball test." + }, + { + "name": "legacy-import", + "entry": "./dist/artplayer-plugin-auto-thumbnail.legacy.js", + "result": "pass", + "sha256": "4d67323bc1dc3923ee5336eeeaf2744e94b8d1f850b5ec7af2f3a9438642cf8e", + "scope": "Actual built entry and registration without DOM access; not an installed tarball test." + }, + { + "name": "module-import", + "entry": "./dist/artplayer-plugin-auto-thumbnail.mjs", + "result": "pass", + "sha256": "e4497e133cdd7ffc89e829afa1bd8f9350ae710efbc8e5f5619491e5916b8932", + "scope": "Actual built entry and registration without DOM access; not an installed tarball test." + } + ], + "followUpExperiment": { + "file": "refactor/.cache/auto-thumbnail-frame-callback-probe.json", + "sha256": "44b29870f0e4c301e144c9287fcac2c84df7b9e534b5768c9fc77f8564cf2f37", + "results": [ + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-hidden-callback", + "initial": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "frame": 6.4, + "beforeSeek": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 1.6, + "immediate": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 3.2, + "immediate": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.8, + "immediate": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + } + }, + { + "target": 6.4, + "immediate": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + } + } + ], + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 1 + }, + { + "event": "seeked", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 1.6, + "readyState": 4 + }, + { + "event": "canplay", + "time": 1.6, + "readyState": 4 + }, + { + "event": "seeked", + "time": 3.2, + "readyState": 4 + }, + { + "event": "canplay", + "time": 3.2, + "readyState": 4 + }, + { + "event": "seeked", + "time": 4.8, + "readyState": 4 + }, + { + "event": "canplay", + "time": 4.8, + "readyState": 4 + }, + { + "event": "seeked", + "time": 6.4, + "readyState": 4 + }, + { + "event": "canplay", + "time": 6.4, + "readyState": 4 + } + ] + }, + { + "browser": "chromium", + "version": "153.0.8010.12", + "mode": "attached-callback", + "initial": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "frame": 6.4, + "beforeSeek": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 127, + 0, + 126, + 255 + ] + } + }, + { + "target": 1.6, + "immediate": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 254, + 0, + 0, + 255 + ] + } + }, + { + "target": 3.2, + "immediate": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.8, + "immediate": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 0, + 253, + 255 + ] + } + }, + { + "target": 6.4, + "immediate": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 255, + 2, + 255 + ] + } + } + ], + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 1 + }, + { + "event": "seeked", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 1.6, + "readyState": 4 + }, + { + "event": "canplay", + "time": 1.6, + "readyState": 4 + }, + { + "event": "seeked", + "time": 3.2, + "readyState": 4 + }, + { + "event": "canplay", + "time": 3.2, + "readyState": 4 + }, + { + "event": "seeked", + "time": 4.8, + "readyState": 4 + }, + { + "event": "canplay", + "time": 4.8, + "readyState": 4 + }, + { + "event": "seeked", + "time": 6.4, + "readyState": 4 + }, + { + "event": "canplay", + "time": 6.4, + "readyState": 4 + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-hidden-callback", + "initial": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "frame": 6.4, + "beforeSeek": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 1.6, + "immediate": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 3.2, + "immediate": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.8, + "immediate": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + } + }, + { + "target": 6.4, + "immediate": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + } + } + ], + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 1.6, + "readyState": 4 + }, + { + "event": "canplay", + "time": 1.6, + "readyState": 4 + }, + { + "event": "seeked", + "time": 3.2, + "readyState": 4 + }, + { + "event": "canplay", + "time": 3.2, + "readyState": 4 + }, + { + "event": "seeked", + "time": 4.8, + "readyState": 4 + }, + { + "event": "canplay", + "time": 4.8, + "readyState": 4 + }, + { + "event": "seeked", + "time": 6.4, + "readyState": 4 + }, + { + "event": "canplay", + "time": 6.4, + "readyState": 4 + } + ] + }, + { + "browser": "firefox", + "version": "155.0", + "mode": "attached-callback", + "initial": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "frame": 6.4, + "beforeSeek": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "frames": [ + { + "target": 0, + "immediate": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + }, + "afterPaint": { + "time": 0, + "readyState": 4, + "rgba": [ + 137, + 19, + 126, + 255 + ] + } + }, + { + "target": 1.6, + "immediate": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + }, + "afterPaint": { + "time": 1.6, + "readyState": 4, + "rgba": [ + 255, + 24, + 0, + 255 + ] + } + }, + { + "target": 3.2, + "immediate": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + }, + "afterPaint": { + "time": 3.2, + "readyState": 4, + "rgba": [ + 0, + 0, + 0, + 255 + ] + } + }, + { + "target": 4.8, + "immediate": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + }, + "afterPaint": { + "time": 4.8, + "readyState": 4, + "rgba": [ + 0, + 14, + 253, + 255 + ] + } + }, + { + "target": 6.4, + "immediate": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + }, + "afterPaint": { + "time": 6.4, + "readyState": 4, + "rgba": [ + 255, + 241, + 2, + 255 + ] + } + } + ], + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 1.6, + "readyState": 4 + }, + { + "event": "canplay", + "time": 1.6, + "readyState": 4 + }, + { + "event": "seeked", + "time": 3.2, + "readyState": 4 + }, + { + "event": "canplay", + "time": 3.2, + "readyState": 4 + }, + { + "event": "seeked", + "time": 4.8, + "readyState": 4 + }, + { + "event": "canplay", + "time": 4.8, + "readyState": 4 + }, + { + "event": "seeked", + "time": 6.4, + "readyState": 4 + }, + { + "event": "canplay", + "time": 6.4, + "readyState": 4 + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-hidden-callback", + "error": "No frame callback", + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 4 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 0.0014992, + "readyState": 4 + } + ] + }, + { + "browser": "webkit", + "version": "26.6", + "mode": "attached-callback", + "error": "No frame callback", + "transitions": [ + { + "event": "loadedmetadata", + "time": 0, + "readyState": 4 + }, + { + "event": "loadeddata", + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "time": 0, + "readyState": 4 + }, + { + "event": "seeked", + "time": 0, + "readyState": 4 + } + ] + } + ], + "scope": "Exploration only, not current production code or acceptance. Awaiting native frame presentation after loadeddata/seek yielded all five intended colors on Chromium/Firefox; this Windows WebKit has no requestVideoFrameCallback. Cancellation/duplicate/stale frame callbacks and a validated fallback are still required." + }, + "validatedAt": "2026-09-12T23:23:26.840Z" +} diff --git a/refactor/baselines/auto-thumbnail-timeline-media.json b/refactor/baselines/auto-thumbnail-timeline-media.json new file mode 100644 index 000000000..ee8856fb5 --- /dev/null +++ b/refactor/baselines/auto-thumbnail-timeline-media.json @@ -0,0 +1,75 @@ +{ + "kind": "generated-auto-thumbnail-timeline", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "args": [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "color=c=purple:s=320x180:r=30:d=0.033333333", + "-f", + "lavfi", + "-i", + "color=c=red:s=320x180:r=30:d=1.966666667", + "-f", + "lavfi", + "-i", + "color=c=black:s=320x180:r=30:d=2", + "-f", + "lavfi", + "-i", + "color=c=blue:s=320x180:r=30:d=2", + "-f", + "lavfi", + "-i", + "color=c=yellow:s=320x180:r=30:d=2", + "-filter_complex", + "[0:v][1:v][2:v][3:v][4:v]concat=n=5:v=1:a=0[v]", + "-map", + "[v]", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-g", + "30", + "-movflags", + "+faststart", + "auto-thumbnail-timeline.mp4" + ], + "width": 320, + "height": 180, + "fps": 30, + "duration": 8, + "segments": [ + [ + "purple", + "0.033333333" + ], + [ + "red", + "1.966666667" + ], + [ + "black", + "2" + ], + [ + "blue", + "2" + ], + [ + "yellow", + "2" + ] + ], + "purpose": "Unique purple first frame, then red/black/blue/yellow timeline; distinguish missing transparent pixels, legitimate black frames and stale first frames.", + "file": { + "name": "auto-thumbnail-timeline.mp4", + "bytes": 8602, + "sha256": "10370156cffada462d3ea00aae0caadd62752369cd6538cc55248b3ddd7bf994" + } +} diff --git a/refactor/changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md b/refactor/changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md new file mode 100644 index 000000000..1e7bc1248 --- /dev/null +++ b/refactor/changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md @@ -0,0 +1,50 @@ +# PKG-AUTO-THUMB-03 隐藏解码元素检查点(doing) + +新增video.js,独立拥有内部video的挂载、静音、可访问性和移除。使用固定定位、 +visibility:hidden及metadata时锁定的原始尺寸;不调用play,不用display:none或1px缩放。 +extraction继续拥有原来的起点采样公式和串行编码。普通全局video样式不会把内部解码 +元素缩成1px;初始化取消、插入前后同步重入、插入失败及load/pause异常也回收DOM。 +公开参数、结果、Promise时序和声明未改。正常构建再生dist和docs副本。 + +构建main产物的验证又复现一次后续格偏移约1.6秒,失败报告独立保留为 +auto-thumbnail03-render-browser-verified-main.json(该文件名虽含verified,结果仍是 +14通过/1失败)。因此继续修复seeked归属:仍在seeking时忽略旧事件,绘制前检查有限 +currentTime及目标50ms容差;偏离只重试原目标最多3次,再失败清理。新增4项回归覆盖 +错时重试、重试界限/旧预览保留、seeking旧事件和时间getter销毁重入。最终证据使用 +browser-timing及unit-timing文件,不把这次失败当成通过或靠重复运行覆盖。 + +新增5项单元边界:此前检查点运行29项为25通过/4失败,新实现29通过。第五项load抛错 +本来就能通过,此次加强其DOM所有权断言。不能将29项都称为本次新修复。 + +真实浏览器新增两种像素样本:时间颜色片段及空间颜色图案。时间片段8秒/30fps,首帧 +独立紫色,随后红、黑、蓝、黄;生成脚本、FFmpeg版本、参数、SHA256保存在媒体清单。 +重新生成字节完全一致。解码前raw alpha区分“没有画出来”和合法黑画面,实际JPEG解码 +验证颜色及空间差异,记录采样时间。9项原生生命周期还增加DOM脱离断言。 + +**这是局部修复,03和AUTO-THUMB-PIXEL-01保持未完成。** 新的像素验收只覆盖五格中的 +第2-4格(从0编号);前两格完整记录为诊断数据,不能当成通过。初次广泛断言的报告 +保留在auto-thumbnail03-render-browser-source-initial.json:发现Firefox早期draw可能 +透明,Windows WebKit的早期seeked可能时间回退。pattern样本的JPEG中心在色块交界处 +存在色度混合,末段本身也改变颜色,因此不能错误地要求每一格中心始终纯蓝。 +当前像素断言使用已知阶段的颜色优势和空间差异;这不意味着早期帧问题被修复。 + +独立诊断还证明:WebKit跳回0秒可能保留上一张图;两次rAF、先跳远再返回、fastSeek及 +playing后立即pause均未稳定解决。唯一紫色首帧在Chromium/Firefox的0秒出现,而本机 +WebKit可能在约0.04秒才读到;不能简单把所有浏览器偏移0.04秒,也不能用均匀红色片段 +掩盖一帧的时间错误。相关原始实验摘要保存在本检查点验证记录,物理Safari仍未验证。 + +后续继续首帧和早期frame-ready调度,保持任务取消及URL归属,再完成资源预算/其余 +边界;04转严格TS,05/06做核心组合、设备、真实安装与demo/editor。没有新依赖、 +发布、推送或任务完成数变化。提交仅是可回退的03检查点。 + +见[验证记录](../baselines/auto-thumbnail-hidden-renderer.json)。 + +最终33项候选回归:此前检查点25通过/8失败,源码/main/legacy各33通过。最终源码原生 +连续三轮45项,main/legacy各15项,共75项通过,无重试/跳过/未处理页面错误。完整CI1799项 +(1553单元+14工程+232基线)及339生产TS通过;另核对4种实际bundle入口与无DOM异步 +注册,尚不代表安装tarball。三份产物与docs副本逐字节相等,03仍doing,像素风险仍open。 + +后续实验auto-thumbnail-frame-callback-probe在loadeddata后对每次seek等待原生帧回调, +Chromium/Firefox隐藏和普通元素都能读到五格预期颜色,包括独立紫色首帧;本机WebKit +没有requestVideoFrameCallback。这尚未接入生产,下一步要处理回调归属/取消/失效/ +超时及无该API浏览器的可靠路径,不能把实验结果提前标为修复。 diff --git a/refactor/plan.md b/refactor/plan.md index b8baf94b2..5592c7d1e 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -496,7 +496,7 @@ - PKG-AUDIO-05: [记录](changes/2026-09-12-PKG-AUDIO-05-combinations.md) [记录](baselines/audio-combinations-first.json) [记录](baselines/audio-combinations-checkpoint.json) [记录](audio-validation.md) - PKG-AUTO-THUMB-01: [记录](baselines/auto-thumbnail-release.json) [记录](baselines/auto-thumbnail-contract.md) [记录](changes/2026-09-13-PKG-AUTO-THUMB-01-contract.md) [记录](baselines/auto-thumbnail-contract-validation.json) - PKG-AUTO-THUMB-02: [记录](baselines/auto-thumbnail-failures.md) [记录](baselines/auto-thumbnail-failures-validation.json) [记录](changes/2026-09-13-PKG-AUTO-THUMB-02-failures.md) -- PKG-AUTO-THUMB-03: [记录](changes/2026-09-13-PKG-AUTO-THUMB-03-lifecycle-checkpoint.md) [记录](baselines/auto-thumbnail-lifecycle-checkpoint.json) +- PKG-AUTO-THUMB-03: [记录](changes/2026-09-13-PKG-AUTO-THUMB-03-lifecycle-checkpoint.md) [记录](baselines/auto-thumbnail-lifecycle-checkpoint.json) [记录](changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md) [记录](baselines/auto-thumbnail-hidden-renderer.json) [记录](baselines/auto-thumbnail-timeline-media.json) - PKG-HLS-01: [记录](baselines/hls-control-contract.md) [记录](baselines/hls-control-release.json) [记录](changes/2026-09-11-PKG-HLS-01-contract.md) - PKG-HLS-02: [记录](hls-validation.md) [记录](baselines/hls-sdk.json) [记录](baselines/hls-validation.json) [记录](changes/2026-09-11-PKG-HLS-02-tests.md) - PKG-HLS-03: [记录](changes/2026-09-12-PKG-HLS-03-modules.md) [记录](baselines/hls-modules-validation.json) [记录](hls-validation.md) diff --git a/refactor/progress.md b/refactor/progress.md index 6bdd93d8b..4fc649b85 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,18 @@ # 进度与证据 +## PKG-AUTO-THUMB-03 隐藏解码与错时seek重试检查点(doing) + +新增video模块,挂载隐藏且保持实际尺寸的解码元素,完善DOM回收及插入/清理重入。 +真实产物测试发现seeked可能停留在前一格,已增加绘制前时间核对及最多3次原目标重试。 +33项候选单元在此前检查点25通过/8失败,新源码/main/legacy各33通过。 +最终原生源码连续三轮45项、main/legacy各15项通过,共75项;其中仅第2-4格有像素 +验收,前两格及首帧精度保持open。保留先前真实失败,不把重复通过当作全流程完成。 +新增可再生时间颜色夹具及脚本,严格TS仍属于04,无依赖或版本改动。 +完整CI1799项、339生产TS通过,4种实际bundle入口通过;见[验证](baselines/auto-thumbnail-hidden-renderer.json), +[变更](changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md)解释修复和剩余边界。 +222项:114 done、12 doing、96 todo;本次是03检查点,任务完成数未增加。 + + ## PKG-AUTO-THUMB-03 源码任务与资源所有权检查点(doing) 生产源码拆为index/options/session/extraction,保持异步公开注册与原有效配置语义。 diff --git a/refactor/risks.json b/refactor/risks.json index 3af50a0eb..066b5c3fb 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -4110,10 +4110,14 @@ "evidence": [ "test/browser/auto-thumbnail.spec.js", "refactor/baselines/auto-thumbnail-failures.md", - "refactor/baselines/auto-thumbnail-failures-validation.json" + "refactor/baselines/auto-thumbnail-failures-validation.json", + "test/browser/auto-thumbnail-pixels.spec.js", + "refactor/baselines/auto-thumbnail-hidden-renderer.json", + "refactor/baselines/auto-thumbnail-timeline-media.json" ], "compatibleResolution": "Establish actual decoded-frame readiness for the existing timeline/grid and preserve silent independent extraction; do not waive colored pixel checks as unsupported media.", - "closureCriteria": "Candidate source and artifacts generate usable sampled pixels on native browser controls with lifecycle checks; supported Safari and core combinations remain explicit final gates." + "closureCriteria": "Candidate source and artifacts generate usable sampled pixels on native browser controls with lifecycle checks; supported Safari and core combinations remain explicit final gates.", + "workspaceState": "Hidden intrinsic-sized attached decoder mitigates detached WebKit black later frames. Source 45 repeated native cases plus main/legacy 15 each verify lifecycle and cells 2-4 only. Initial cells 0-1 remain diagnostic: transparent/stale draws and Windows WebKit first-frame timing remain unresolved. Bounded retries now reject wrong-time seeked events before drawing. Do not close this risk or task03 based on partial pixel acceptance." } ] } diff --git a/refactor/tasks.json b/refactor/tasks.json index 90345da58..62113cb56 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1783,7 +1783,10 @@ "acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过", "evidence": [ "changes/2026-09-13-PKG-AUTO-THUMB-03-lifecycle-checkpoint.md", - "baselines/auto-thumbnail-lifecycle-checkpoint.json" + "baselines/auto-thumbnail-lifecycle-checkpoint.json", + "changes/2026-09-13-PKG-AUTO-THUMB-03-hidden-renderer.md", + "baselines/auto-thumbnail-hidden-renderer.json", + "baselines/auto-thumbnail-timeline-media.json" ] }, { diff --git a/scripts/generate-auto-thumbnail-fixture.mjs b/scripts/generate-auto-thumbnail-fixture.mjs new file mode 100644 index 000000000..672c30bc2 --- /dev/null +++ b/scripts/generate-auto-thumbnail-fixture.mjs @@ -0,0 +1,48 @@ +import assert from 'node:assert/strict' +import { execFileSync } from 'node:child_process' +import fs from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import { hash } from '../refactor/scripts/releases.mjs' + +const output = path.resolve(process.argv[2] || 'refactor/.cache/auto-thumbnail-fixture') +assert(!fs.existsSync(output), 'Use a new directory; never overwrite frozen media') +const ffmpeg = process.env.ARTPLAYER_FFMPEG || 'ffmpeg' +const version = execFileSync(ffmpeg, ['-version'], { encoding: 'utf8' }).split(/\r?\n/)[0] +fs.mkdirSync(output, { recursive: true }) +const segments = [['purple', '0.033333333'], ['red', '1.966666667'], ['black', '2'], ['blue', '2'], ['yellow', '2']] +const args = [ + '-hide_banner', + '-loglevel', + 'error', + '-n', + ...segments.flatMap(([color, duration]) => ['-f', 'lavfi', '-i', `color=c=${color}:s=320x180:r=30:d=${duration}`]), + '-filter_complex', + '[0:v][1:v][2:v][3:v][4:v]concat=n=5:v=1:a=0[v]', + '-map', + '[v]', + '-c:v', + 'libx264', + '-pix_fmt', + 'yuv420p', + '-g', + '30', + '-movflags', + '+faststart', + 'auto-thumbnail-timeline.mp4', +] +execFileSync(ffmpeg, args, { cwd: output, stdio: 'pipe', timeout: 120000 }) +const bytes = fs.readFileSync(path.join(output, 'auto-thumbnail-timeline.mp4')) +fs.writeFileSync(path.join(output, 'manifest.json'), `${JSON.stringify({ + kind: 'generated-auto-thumbnail-timeline', + version, + args, + width: 320, + height: 180, + fps: 30, + duration: 8, + segments, + purpose: 'Unique purple first frame, then red/black/blue/yellow timeline; distinguish missing transparent pixels, legitimate black frames and stale first frames.', + file: { name: 'auto-thumbnail-timeline.mp4', bytes: bytes.length, sha256: hash(bytes) }, +}, null, 2)}\n`) +console.log(`Generated auto-thumbnail timeline in ${output}`) diff --git a/test/auto-thumbnail-lifecycle.test.js b/test/auto-thumbnail-lifecycle.test.js index 7136409c8..e9a085bf4 100644 --- a/test/auto-thumbnail-lifecycle.test.js +++ b/test/auto-thumbnail-lifecycle.test.js @@ -13,6 +13,7 @@ async function setup(option = { width: 80, number: 2 }) { return env } function assertClosed(env, video = env.videos[0]) { + assert.equal(env.attached.has(video), false) assert.equal(video.src, undefined) for (const key of ['onloadedmetadata', 'onseeked', 'onerror']) assert.equal(video[key], null) assert(env.operations.some(item => item.name === 'pause' && item.video === video)) @@ -329,3 +330,119 @@ test('Auto-thumbnail candidate keeps the metadata duration snapshot for frame ti assert.deepEqual(env.operations.filter(item => item.name === 'seek').map(item => item.value), [0, 60]) env.art.emit('destroy') }) + +test('Auto-thumbnail candidate hides an attached decoder at intrinsic dimensions without playback', async () => { + const env = await setup() + const video = env.videos[0] + assert.equal(env.attached.has(video), true) + assert.equal(video['aria-hidden'], 'true') + assert.equal(video.tabIndex, -1) + assert.equal(video.muted, true) + assert.match(video.style.cssText, /visibility:hidden/) + assert.doesNotMatch(video.style.cssText, /display:none|width:1px|height:1px/) + env.metadata() + assert.equal(video.width, 1920) + assert.equal(video.height, 1080) + assert.equal(video.style.width, '1920px') + assert.equal(video.style.height, '1080px') + env.art.emit('destroy') + assertClosed(env) +}) + +for (const phase of ['beforeAppend', 'afterAppend']) { + test(`Auto-thumbnail candidate ${phase} reentry cannot leave an attached decoder`, async () => { + const env = autoThumbnailEnvironment(implementation) + await env.factory({})(env.art) + env.controls[phase] = () => env.art.emit('destroy') + env.art.emit('video:loadedmetadata') + assert.equal(env.attached.size, 0) + assert.equal(env.videos[0].src, undefined) + assertClosed(env) + assert.equal(env.warnings.length, 0) + }) +} + +test('Auto-thumbnail candidate failed insertion removes a partially attached decoder', async () => { + const env = autoThumbnailEnvironment(implementation) + const failure = new Error('Insertion observer failed') + env.controls.afterAppend = () => { + throw failure + } + await env.factory({})(env.art) + env.art.emit('video:loadedmetadata') + assert.equal(env.attached.size, 0) + assert.equal(env.videos[0].src, undefined) + assert.equal(env.warnings[0][1], failure) + assertClosed(env) + env.art.emit('destroy') +}) + +test('Auto-thumbnail candidate decoder removal still runs after load throws', async () => { + const env = await setup() + const failure = new Error('Decoder reset failed') + env.videos[0].load = () => { + throw failure + } + env.art.emit('destroy') + assert.equal(env.attached.size, 0) + assert.equal(env.videos[0].src, undefined) + assert.equal(env.warnings[0][1], failure) + assert([...env.listeners.values()].every(set => set.size === 0)) +}) + +test('Auto-thumbnail candidate ignores a stale seeked event while a new seek is in progress', async () => { + const env = await setup() + env.metadata() + env.videos[0].seeking = true + env.seeked() + assert.equal(env.blobs.length, 0) + env.videos[0].seeking = false + env.seeked() + assert.equal(env.blobs.length, 1) + env.art.emit('destroy') + assertClosed(env) +}) + +test('Auto-thumbnail candidate retries a completed seek at the wrong time before drawing', async () => { + const env = await setup() + env.metadata() + env.videos[0].timeOffset = 1 + env.seeked() + assert.equal(env.blobs.length, 0) + assert.deepEqual(env.operations.filter(item => item.name === 'seek').map(item => item.value), [0, 0]) + env.videos[0].timeOffset = 0 + env.seeked() + assert.equal(env.blobs.length, 1) + env.art.emit('destroy') + assertClosed(env) +}) + +test('Auto-thumbnail candidate bounds incorrect seek retries and preserves its last usable preview', async () => { + const env = await setup() + env.metadata() + env.seeked() + env.finish() + const previous = env.art.thumbnails + env.videos[0].timeOffset = -60 + for (let index = 0; index < 5; index++) env.seeked() + assert.equal(env.blobs.length, 1) + assert.equal(env.art.thumbnails, previous) + assert.equal(env.urls.size, 1) + assert.equal(env.operations.filter(item => item.name === 'seek').length, 5) + assert.equal(env.warnings.length, 1) + assertClosed(env) + env.art.emit('destroy') + assert.equal(env.urls.size, 0) +}) + +test('Auto-thumbnail candidate seek-time getters cannot draw after synchronous destruction', async () => { + const env = await setup() + env.metadata() + Object.defineProperty(env.videos[0], 'timeOffset', { get() { + env.art.emit('destroy') + return 0 + } }) + env.seeked() + assert.equal(env.blobs.length, 0) + assertClosed(env) +}) diff --git a/test/browser/auto-thumbnail-lifecycle.spec.js b/test/browser/auto-thumbnail-lifecycle.spec.js index 8750ce4cc..bbbcf7833 100644 --- a/test/browser/auto-thumbnail-lifecycle.spec.js +++ b/test/browser/auto-thumbnail-lifecycle.spec.js @@ -75,7 +75,7 @@ for (const scenario of ['destroy', 'restart', 'complete']) { } const after = { urls: probe.urls.size, updates: probe.updates.length } const decoder = probe.videos[0] - const video = { src: decoder.getAttribute('src'), readyState: decoder.readyState, paused: decoder.paused, handlers: ['onloadedmetadata', 'onseeked', 'onerror'].map(key => decoder[key] === null) } + const video = { connected: decoder.isConnected, src: decoder.getAttribute('src'), readyState: decoder.readyState, paused: decoder.paused, handlers: ['onloadedmetadata', 'onseeked', 'onerror'].map(key => decoder[key] === null) } probe.art.emit('destroy') probe.art.emit('destroy') const final = { urls: probe.urls.size, listeners: [...probe.listeners.values()].reduce((sum, set) => sum + set.size, 0), updates: probe.updates.length } @@ -87,7 +87,7 @@ for (const scenario of ['destroy', 'restart', 'complete']) { expect(state.result).toEqual({ name: 'artplayerPluginAutoThumbnail' }) expect(state.before).toEqual(scenario === 'complete' ? { urls: 1, updates: 2 } : { urls: 0, updates: 0 }) expect(state.after).toEqual(state.before) - expect(state.video).toEqual({ src: null, readyState: 0, paused: true, handlers: [true, true, true] }) + expect(state.video).toEqual({ connected: false, src: null, readyState: 0, paused: true, handlers: [true, true, true] }) expect(state.final).toEqual({ urls: 0, listeners: 0, updates: scenario === 'complete' ? 2 : 0 }) expect(state.blobs.every(blob => blob.type === 'image/jpeg' && blob.bytes > 0)).toBe(true) }) diff --git a/test/browser/auto-thumbnail-pixels.spec.js b/test/browser/auto-thumbnail-pixels.spec.js new file mode 100644 index 000000000..ba3fb66df --- /dev/null +++ b/test/browser/auto-thumbnail-pixels.spec.js @@ -0,0 +1,122 @@ +import { hash } from '../../refactor/scripts/releases.mjs' +import { autoThumbnailCandidate } from '../helpers/auto-thumbnail.js' +import { expect, test } from './fixtures.js' + +const implementation = await autoThumbnailCandidate() + +for (const media of ['auto-thumbnail-timeline', 'pattern']) { + test(`Auto-thumbnail candidate retains cells 2-4 ${media} pixels in a hidden decoder`, async ({ page, browserName }, testInfo) => { + await page.goto('/test/player.html?core=published') + await page.setContent('') + await page.addScriptTag({ content: implementation.code }) + await page.evaluate(async (media) => { + const createElement = document.createElement.bind(document) + const drawImage = CanvasRenderingContext2D.prototype.drawImage + const probe = window.probe = { videos: [], updates: [], draws: [], playing: 0, warnings: [] } + const warn = console.warn + console.warn = (...args) => probe.warnings.push(args.map(String)) + document.createElement = function (tag, ...args) { + const element = createElement(tag, ...args) + if (tag === 'video') { + probe.videos.push(element) + element.addEventListener('playing', () => probe.playing++) + } + return element + } + CanvasRenderingContext2D.prototype.drawImage = function (source, ...args) { + const result = drawImage.call(this, source, ...args) + if (source instanceof HTMLVideoElement) { + const [x, y, width, height] = args + const style = getComputedStyle(source) + const box = source.getBoundingClientRect() + probe.draws.push({ + time: source.currentTime, + duration: source.duration, + connected: source.isConnected, + visibility: style.visibility, + display: style.display, + width: box.width, + height: box.height, + raw: [...this.getImageData(x + Math.floor(width / 2), y + Math.floor(height / 2), 1, 1).data], + }) + } + return result + } + const listeners = new Map() + probe.art = { + option: { url: `/test/${media}.mp4` }, + on(name, callback) { + if (!listeners.has(name)) + listeners.set(name, new Set()) + listeners.get(name).add(callback) + }, + off(name, callback) { listeners.get(name)?.delete(callback) }, + emit(name) { for (const callback of [...(listeners.get(name) || [])]) callback() }, + get thumbnails() { return probe.updates.at(-1) }, + set thumbnails(value) { probe.updates.push(value) }, + } + probe.restore = () => { + document.createElement = createElement + CanvasRenderingContext2D.prototype.drawImage = drawImage + console.warn = warn + } + await window.artplayerPluginAutoThumbnail({ width: 80, number: 5 })(probe.art) + probe.art.emit('video:loadedmetadata') + }, media) + await expect.poll(() => page.evaluate(() => window.probe.updates.length)).toBe(5) + const state = await page.evaluate(async () => { + const probe = window.probe + const image = document.createElement('img') + image.src = probe.updates.at(-1).url + await image.decode() + const canvas = document.createElement('canvas') + canvas.width = image.naturalWidth + canvas.height = image.naturalHeight + const ctx = canvas.getContext('2d') + ctx.drawImage(image, 0, 0) + const cells = Array.from({ length: 5 }, (_, index) => [...ctx.getImageData(index * 80 + 40, 22, 1, 1).data]) + const spatial = [10, 20, 40, 60, 70].map(x => [...ctx.getImageData(160 + x, 22, 1, 1).data]) + const final = probe.videos.map(video => ({ connected: video.isConnected, src: video.getAttribute('src'), paused: video.paused })) + probe.art.emit('destroy') + probe.restore() + return { cells, spatial, draws: probe.draws, final, playing: probe.playing, warnings: probe.warnings } + }) + await testInfo.attach('auto-thumbnail-candidate-hidden-pixels', { contentType: 'application/json', body: JSON.stringify({ + sha256: hash(implementation.code), + media, + scope: 'Native decoding and JPEG pixels for cells 2-4, hidden intrinsic-sized rendering and cleanup. Cells 0-1 are diagnostic only: initial drawing/readiness/timestamp behavior remains open under AUTO-THUMB-PIXEL-01. Stub player host, not a core integration.', + ...state, + }) }) + testInfo.annotations.push({ type: 'remaining-initial-frame-risk', description: `${browserName}: cells 0-1 are evidence only; this test cannot close AUTO-THUMB-PIXEL-01 or PKG-AUTO-THUMB-03.` }) + expect(state.warnings).toEqual([]) + expect(state.playing).toBe(0) + expect(state.final).toEqual([{ connected: false, src: null, paused: true }]) + expect(state.draws).toHaveLength(5) + for (const [index, draw] of state.draws.entries()) { + expect(draw.connected).toBe(true) + expect(draw.visibility).toBe('hidden') + expect(draw.display).toBe('block') + expect(draw.width).toBeGreaterThanOrEqual(80) + expect(draw.height).toBeGreaterThanOrEqual(45) + if (index > 1) { + expect(Math.abs(draw.time - draw.duration * index / 5)).toBeLessThan(0.05) + expect(draw.raw[3]).toBe(255) + } + } + if (media === 'auto-thumbnail-timeline') { + const [black, blue, yellow] = state.cells.slice(2) + expect(Math.max(...black.slice(0, 3))).toBeLessThan(30) + expect(blue[2]).toBeGreaterThan(200) + expect(Math.max(blue[0], blue[1])).toBeLessThan(40) + expect(Math.min(yellow[0], yellow[1])).toBeGreaterThan(200) + expect(yellow[2]).toBeLessThan(40) + } + else { + for (const pixel of state.cells.slice(2, 4)) { + expect(pixel[2] - Math.max(pixel[0], pixel[1])).toBeGreaterThan(80) + } + expect(state.cells[4][0] - Math.max(state.cells[4][1], state.cells[4][2])).toBeGreaterThan(80) + expect(new Set(state.spatial.map(pixel => pixel.slice(0, 3).join(','))).size).toBeGreaterThan(2) + } + }) +} diff --git a/test/browser/media/auto-thumbnail-timeline.mp4 b/test/browser/media/auto-thumbnail-timeline.mp4 new file mode 100644 index 000000000..643aeb919 Binary files /dev/null and b/test/browser/media/auto-thumbnail-timeline.mp4 differ diff --git a/test/browser/server.mjs b/test/browser/server.mjs index 2a9cbcd9a..61f2f6885 100644 --- a/test/browser/server.mjs +++ b/test/browser/server.mjs @@ -76,6 +76,7 @@ assert.equal(hash(iframeCoreBytes), iframeCore.files[iframeCoreMember], 'Histori add('/published-4.5.9/artplayer.js', iframeCoreBytes, { kind: 'npm-release', version: iframeCore.version, integrity: iframeCore.integrity, member: iframeCoreMember }) add('/test/audio-tone.m4a', fs.readFileSync(path.join(workspace, 'test/browser/media/audio-tone.m4a')), { kind: 'generated-media', file: 'test/browser/media/audio-tone.m4a' }) add('/test/thumbnail-pattern.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/thumbnail-pattern.mp4')), { kind: 'generated-media', file: 'test/browser/media/thumbnail-pattern.mp4' }) +add('/test/auto-thumbnail-timeline.mp4', fs.readFileSync(path.join(workspace, 'test/browser/media/auto-thumbnail-timeline.mp4')), { kind: 'generated-media', file: 'test/browser/media/auto-thumbnail-timeline.mp4' }) const mime = { '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.json': 'application/json', '.css': 'text/css', '.mp4': 'video/mp4', '.m4a': 'audio/mp4', '.webm': 'video/webm', '.vtt': 'text/vtt', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg' } add('/test/declaration-cues.vtt', fs.readFileSync(path.join(workspace, 'test/browser/media/declaration-cues.vtt')), { kind: 'test-subtitles', file: 'test/browser/media/declaration-cues.vtt' }) diff --git a/test/helpers/auto-thumbnail.js b/test/helpers/auto-thumbnail.js index ebd3cf7b5..6a61c277a 100644 --- a/test/helpers/auto-thumbnail.js +++ b/test/helpers/auto-thumbnail.js @@ -42,12 +42,29 @@ export function autoThumbnailEnvironment(implementation, { script = false } = {} const updates = [] const warnings = [] let nextUrl = 0 - const controls = { nullContext: false, drawError: null, encodeError: null, updateError: null, onUpdate: null } + const controls = { nullContext: false, drawError: null, encodeError: null, updateError: null, onUpdate: null, beforeAppend: null, afterAppend: null } + const attached = new Set() const document = { + documentElement: { + appendChild(video) { + controls.beforeAppend?.(video) + attached.add(video) + controls.afterAppend?.(video) + return video + }, + }, createElement(tag) { if (tag === 'video') { const video = { + style: {}, + setAttribute(name, value) { this[name] = value }, + remove() { + attached.delete(this) + operations.push({ name: 'remove', video: this }) + }, duration: 120, + timeOffset: 0, + seeking: false, videoWidth: 1920, videoHeight: 1080, onloadedmetadata: null, @@ -62,7 +79,7 @@ export function autoThumbnailEnvironment(implementation, { script = false } = {} } let time = 0 Object.defineProperty(video, 'currentTime', { - get: () => time, + get: () => time + video.timeOffset, set(value) { time = value operations.push({ name: 'seek', value, handlerInstalled: typeof video.onseeked === 'function', video }) @@ -158,6 +175,7 @@ export function autoThumbnailEnvironment(implementation, { script = false } = {} updates, warnings, controls, + attached, metadata(video = videos.at(-1)) { video.onloadedmetadata?.() }, seeked(video = videos.at(-1)) { video.onseeked?.() }, finish(index = 0, blob = { type: 'image/jpeg' }) { blobs[index].callback(blob) },