mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-16 09:36:16 -08:00
refactor(vast): [PKG-VAST-03] isolate lifecycle ownership checkpoint
This commit is contained in:
1 parent
d5e1feadf5
commit
4f324a8438
30 files changed
+1453
-383
No files matched your search
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var v={};v.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,E,y,A=v.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function v(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var f={};f.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,y,E,A=f.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,v(this,m)[m]=t,v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=v(this,m)[m])&&t.paused||(v(this,b)[b]=null==(e=v(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;v(this,g)[g]||(null==(t=v(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.addEventListener("timeupdate",this.t),v(this,g)[g]=!0)},e.disable=function(){var t,e,i;v(this,g)[g]&&(null==(t=v(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.removeEventListener("timeupdate",this.t),v(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=v(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=v(this,m)[m])||t.pause()},e.reset=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.disable(),v(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return v(this,g)[g]}},{key:"currentTime",get:function(){return v(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
@@ -98,15 +98,15 @@ function w(t2, i2) {
|
||||
return t2;
|
||||
}
|
||||
var m = {};
|
||||
m.CustomEvent = "function" == typeof CustomEvent ? CustomEvent : (function(t2) {
|
||||
m.CustomEvent = "function" == typeof CustomEvent ? CustomEvent : function(t2) {
|
||||
return i2[t2] = new i2("").constructor[t2], i2;
|
||||
function i2(t3, i3) {
|
||||
i3 || (i3 = {});
|
||||
var e2 = document.createEvent("CustomEvent");
|
||||
return e2.initCustomEvent(t3, !!i3.bubbles, !!i3.cancelable, i3.detail), e2;
|
||||
}
|
||||
})("prototype");
|
||||
var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b("enabled"), k = (function() {
|
||||
}("prototype");
|
||||
var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b("enabled"), k = function() {
|
||||
function t2(t3) {
|
||||
Object.defineProperty(this, j, { writable: true, value: void 0 }), Object.defineProperty(this, g, { writable: true, value: void 0 }), Object.defineProperty(this, A, { writable: true, value: void 0 }), this.seeking = void 0, w(this, j)[j] = t3, w(this, g)[g] = 0, w(this, A)[A] = false, this.seeking = false, this.t = this.t.bind(this), this.i = this.i.bind(this), this.h = this.h.bind(this), this.enable();
|
||||
}
|
||||
@@ -151,7 +151,7 @@ var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b(
|
||||
var t3;
|
||||
return null == (t3 = w(this, j)[j]) ? void 0 : t3.volume;
|
||||
} }]), t2;
|
||||
})(), C = (function() {
|
||||
}(), C = function() {
|
||||
function t2() {
|
||||
this.delegate = document.createDocumentFragment();
|
||||
}
|
||||
@@ -163,23 +163,23 @@ var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b(
|
||||
}, i2.removeEventListener = function() {
|
||||
return this.delegate.removeEventListener.apply(this.delegate, [].slice.call(arguments));
|
||||
}, t2;
|
||||
})(), P = ["abort", "canplay", "canplaythrough", "durationchange", "emptied", "ended", "error", "loadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing", "progress", "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate", "volumechange", "waiting"];
|
||||
!(function(t2) {
|
||||
}(), P = ["abort", "canplay", "canplaythrough", "durationchange", "emptied", "ended", "error", "loadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing", "progress", "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate", "volumechange", "waiting"];
|
||||
!function(t2) {
|
||||
t2.MEDIA_START = "MediaStart", t2.MEDIA_IMPRESSION = "MediaImpression", t2.MEDIA_STOP = "MediaStop", t2.MEDIA_CUE_POINTS_CHANGE = "MediaCuePointsChange", t2.MEDIA_RESUMED = "MediaResumed";
|
||||
})(p || (p = {})), (function(t2) {
|
||||
}(p || (p = {})), function(t2) {
|
||||
t2.AD_ERROR = "AdError", t2.AD_BUFFERING = "AdBuffering", t2.LOADED = "AdLoaded", t2.IMPRESSION = "AdImpression", t2.STARTED = "AdStarted", t2.FIRST_QUARTILE = "AdFirstQuartile", t2.MIDPOINT = "AdMidpoint", t2.THIRD_QUARTILE = "AdThirdQuartile", t2.AD_PROGRESS = "AdProgress", t2.COMPLETE = "AdComplete", t2.CLICK = "AdClick", t2.PAUSED = "AdPaused", t2.RESUMED = "AdResumed", t2.SKIPPED = "AdSkipped", t2.SKIPPABLE_STATE_CHANGED = "AdSkippableStateChanged", t2.VOLUME_CHANGED = "AdVolumeChanged", t2.VOLUME_MUTED = "AdMuted", t2.AD_METADATA = "AdMetadata", t2.AD_BREAK_READY = "AdBreakReady", t2.CONTENT_PAUSE_REQUESTED = "AdContentPauseRequested", t2.CONTENT_RESUME_REQUESTED = "AdContentResumeRequested", t2.ALL_ADS_COMPLETED = "AdAllAdsCompleted", t2.DURATION_CHANGE = "AdDurationChange", t2.INTERACTION = "AdInteraction", t2.LINEAR_CHANGED = "AdLinearChanged", t2.LOG = "AdLog", t2.USER_CLOSE = "AdUserClose", t2.AD_CAN_PLAY = "AdCanPlay", t2.EXPANDED_CHANGED = "AdExpandedChanged", t2.VIEWABLE_IMPRESSION = "AdViewableImpression";
|
||||
})(y || (y = {}));
|
||||
}(y || (y = {}));
|
||||
var R = h({}, y, p), E = function() {
|
||||
this.disableCustomPlaybackForIOS10Plus = false, this.autoResize = true, this.clickTrackingElement = void 0;
|
||||
}, T = (function(t2) {
|
||||
}, T = function(t2) {
|
||||
function i2() {
|
||||
var i3;
|
||||
return (i3 = t2.call.apply(t2, [this].concat([].slice.call(arguments))) || this).errorCode = void 0, i3.innerError = void 0, i3.type = void 0, i3.vastErrorCode = void 0, i3;
|
||||
}
|
||||
return r(i2, t2), i2;
|
||||
})(d(Error));
|
||||
}(d(Error));
|
||||
T.ERROR_CODE_ADS_MANAGER_LOADED_TIMEOUT = 9e3, T.ERROR_CODE_REQUEST_ADS_TIMEOUT = 9001;
|
||||
var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("adsRenderingSettings"), B = b("ima"), L = b("adDisplayContainer"), D = b("adsManager"), W = b("width"), _ = b("height"), q = b("adsLoader"), F = b("playerOptions"), N = b("resizeObserver"), V = b("currentAd"), G = b("loadedAd"), Q = b("mediaStartTriggered"), U = b("mediaImpressionTriggered"), z = b("mediaInActivation"), Z = b("customPlaybackTimeAdjustedOnEnded"), $ = b("cuePoints"), H = b("adCurrentTime"), J = b("adDuration"), K = b("startAdCallback"), X = b("adsManagerLoadedTimeout"), Y = b("requestAdsTimeout"), tt = b("wasExternallyPaused"), it = b("lastNonZeroAdVolume"), et = b("activatePromise"), nt = (function(t2) {
|
||||
var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("adsRenderingSettings"), B = b("ima"), L = b("adDisplayContainer"), D = b("adsManager"), W = b("width"), _ = b("height"), q = b("adsLoader"), F = b("playerOptions"), N = b("resizeObserver"), V = b("currentAd"), G = b("loadedAd"), Q = b("mediaStartTriggered"), U = b("mediaImpressionTriggered"), z = b("mediaInActivation"), Z = b("customPlaybackTimeAdjustedOnEnded"), $ = b("cuePoints"), H = b("adCurrentTime"), J = b("adDuration"), K = b("startAdCallback"), X = b("adsManagerLoadedTimeout"), Y = b("requestAdsTimeout"), tt = b("wasExternallyPaused"), it = b("lastNonZeroAdVolume"), et = b("activatePromise"), nt = function(t2) {
|
||||
function i2(i3, e3, n2, s2, h2) {
|
||||
var r2;
|
||||
void 0 === s2 && (s2 = new i3.AdsRenderingSettings()), void 0 === h2 && (h2 = new E()), r2 = t2.call(this) || this, Object.defineProperty(l(r2), S, { writable: true, value: void 0 }), Object.defineProperty(l(r2), M, { writable: true, value: void 0 }), Object.defineProperty(l(r2), x, { writable: true, value: void 0 }), Object.defineProperty(l(r2), I, { writable: true, value: void 0 }), Object.defineProperty(l(r2), B, { writable: true, value: void 0 }), Object.defineProperty(l(r2), L, { writable: true, value: void 0 }), Object.defineProperty(l(r2), D, { writable: true, value: void 0 }), Object.defineProperty(l(r2), W, { writable: true, value: void 0 }), Object.defineProperty(l(r2), _, { writable: true, value: void 0 }), Object.defineProperty(l(r2), q, { writable: true, value: void 0 }), Object.defineProperty(l(r2), F, { writable: true, value: void 0 }), Object.defineProperty(l(r2), N, { writable: true, value: void 0 }), Object.defineProperty(l(r2), V, { writable: true, value: void 0 }), Object.defineProperty(l(r2), G, { writable: true, value: void 0 }), Object.defineProperty(l(r2), Q, { writable: true, value: false }), Object.defineProperty(l(r2), U, { writable: true, value: false }), Object.defineProperty(l(r2), z, { writable: true, value: false }), Object.defineProperty(l(r2), Z, { writable: true, value: false }), Object.defineProperty(l(r2), $, { writable: true, value: [] }), Object.defineProperty(l(r2), H, { writable: true, value: void 0 }), Object.defineProperty(l(r2), J, { writable: true, value: void 0 }), Object.defineProperty(l(r2), K, { writable: true, value: void 0 }), Object.defineProperty(l(r2), X, { writable: true, value: void 0 }), Object.defineProperty(l(r2), Y, { writable: true, value: void 0 }), Object.defineProperty(l(r2), tt, { writable: true, value: false }), Object.defineProperty(l(r2), it, { writable: true, value: 1 }), Object.defineProperty(l(r2), et, { writable: true, value: Promise.resolve() }), w(l(r2), S)[S] = e3, w(l(r2), M)[M] = n2, w(l(r2), B)[B] = i3, w(l(r2), F)[F] = h2, w(l(r2), I)[I] = s2, w(l(r2), I)[I].restoreCustomPlaybackStateOnAdBreakComplete = true, h2.disableCustomPlaybackForIOS10Plus && !w(l(r2), S)[S].hasAttribute("playsinline") && w(l(r2), S)[S].setAttribute("playsinline", ""), w(l(r2), B)[B].settings.setDisableCustomPlaybackForIOS10Plus(h2.disableCustomPlaybackForIOS10Plus), w(l(r2), x)[x] = new k(w(l(r2), S)[S]), r2.o = r2.o.bind(l(r2)), P.forEach(function(t3) {
|
||||
@@ -373,16 +373,16 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
w(t3, U)[U] = false, w(t3, Q)[Q] = false, w(t3, Z)[Z] = false, t3.dispatchEvent(new O(R.MEDIA_STOP));
|
||||
}, 1);
|
||||
}, e2.v = function(t3) {
|
||||
for (var i3, e3 = (function(t4, i4) {
|
||||
for (var i3, e3 = function(t4, i4) {
|
||||
var e4 = "undefined" != typeof Symbol && t4[Symbol.iterator] || t4["@@iterator"];
|
||||
if (e4) return (e4 = e4.call(t4)).next.bind(e4);
|
||||
if (Array.isArray(t4) || (e4 = (function(t5, i5) {
|
||||
if (Array.isArray(t4) || (e4 = function(t5, i5) {
|
||||
if (t5) {
|
||||
if ("string" == typeof t5) return f(t5, i5);
|
||||
var e5 = Object.prototype.toString.call(t5).slice(8, -1);
|
||||
return "Object" === e5 && t5.constructor && (e5 = t5.constructor.name), "Map" === e5 || "Set" === e5 ? Array.from(t5) : "Arguments" === e5 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e5) ? f(t5, i5) : void 0;
|
||||
}
|
||||
})(t4))) {
|
||||
}(t4))) {
|
||||
e4 && (t4 = e4);
|
||||
var n3 = 0;
|
||||
return function() {
|
||||
@@ -390,7 +390,7 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
};
|
||||
}
|
||||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
})(t3); !(i3 = e3()).done; ) {
|
||||
}(t3); !(i3 = e3()).done; ) {
|
||||
var n2 = i3.value;
|
||||
n2.contentBoxSize && 1 === n2.contentBoxSize.length ? (w(this, W)[W] = n2.contentBoxSize[0].inlineSize, w(this, _)[_] = n2.contentBoxSize[0].blockSize) : n2.contentBoxSize && n2.contentBoxSize.inlineSize ? (w(this, W)[W] = n2.contentBoxSize.inlineSize, w(this, _)[_] = n2.contentBoxSize.blockSize) : (w(this, W)[W] = n2.contentRect.width, w(this, _)[_] = n2.contentRect.height);
|
||||
}
|
||||
@@ -435,116 +435,216 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
} }, { key: "cuePoints", get: function() {
|
||||
return [].concat(w(this, $)[$]);
|
||||
} }]), i2;
|
||||
})(C);
|
||||
}(C);
|
||||
function createRequest(ima, field, value, config) {
|
||||
const request = new ima.AdsRequest();
|
||||
request[field] = value;
|
||||
const fields = request;
|
||||
for (const key in config)
|
||||
fields[key] = config[key];
|
||||
return request;
|
||||
}
|
||||
let nextId = 0;
|
||||
function createContainer(utils) {
|
||||
const container = utils.createElement("div");
|
||||
container.id = `art-vast-${Date.now()}-${++nextId}`;
|
||||
utils.setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
backgroundColor: "black",
|
||||
display: "none",
|
||||
pointerEvents: "auto"
|
||||
});
|
||||
return container;
|
||||
}
|
||||
function createSession(art, ima, utils, closed) {
|
||||
const { $video, $player } = art.template;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
||||
adsRenderingSettings.enablePreloading = true;
|
||||
const playerOptions = new E();
|
||||
let current = null;
|
||||
let initializing = false;
|
||||
let releasing = 0;
|
||||
const live = (owner) => current === owner && !owner.released && !closed();
|
||||
function release(owner) {
|
||||
if (current === owner)
|
||||
current = null;
|
||||
owner.released = true;
|
||||
owner.playing = false;
|
||||
const player = owner.player;
|
||||
owner.player = null;
|
||||
const listeners = owner.listeners.splice(0);
|
||||
let failed = false;
|
||||
let failure;
|
||||
const attempt = (cleanup) => {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
} else {
|
||||
console.error("VAST cleanup error:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
releasing++;
|
||||
try {
|
||||
if (player) {
|
||||
for (const [name, callback] of listeners)
|
||||
attempt(() => player.removeEventListener(name, callback));
|
||||
attempt(() => player.destroy());
|
||||
}
|
||||
attempt(() => {
|
||||
if (owner.container.parentNode)
|
||||
owner.container.parentNode.removeChild(owner.container);
|
||||
});
|
||||
} finally {
|
||||
releasing--;
|
||||
}
|
||||
if (failed)
|
||||
throw failure;
|
||||
}
|
||||
function init() {
|
||||
if (closed() || releasing)
|
||||
return null;
|
||||
if (initializing)
|
||||
throw new Error("VAST initialization is already in progress");
|
||||
if (current?.player)
|
||||
return current.player;
|
||||
initializing = true;
|
||||
let owner;
|
||||
try {
|
||||
owner = { container: createContainer(utils), player: null, listeners: [], playing: false, released: false };
|
||||
current = owner;
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
$player.appendChild(owner.container);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
owner.player = new nt(ima, $video, owner.container, adsRenderingSettings, playerOptions);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
const allocated = owner;
|
||||
for (const [name, playing] of [
|
||||
["AdContentPauseRequested", true],
|
||||
["AdContentResumeRequested", false],
|
||||
["AdStarted", true],
|
||||
["AdError", false]
|
||||
]) {
|
||||
const callback = (event) => {
|
||||
if (!live(allocated))
|
||||
return;
|
||||
if (name === "AdError")
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
allocated.playing = playing;
|
||||
allocated.container.style.display = playing ? "block" : "none";
|
||||
};
|
||||
owner.listeners.push([name, callback]);
|
||||
owner.player.addEventListener(name, callback);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return owner.player;
|
||||
} catch (error) {
|
||||
if (owner) {
|
||||
try {
|
||||
release(owner);
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
initializing = false;
|
||||
}
|
||||
}
|
||||
function play(field, value, config) {
|
||||
if (closed() || current?.playing)
|
||||
return;
|
||||
const player = init();
|
||||
const owner = current;
|
||||
if (!player || !owner)
|
||||
return;
|
||||
const request = createRequest(ima, field, value, config);
|
||||
if (live(owner) && owner.player === player)
|
||||
player.playAds(request);
|
||||
}
|
||||
function destroy() {
|
||||
if (current)
|
||||
release(current);
|
||||
}
|
||||
const context = {
|
||||
art,
|
||||
playUrl: (url, config = {}) => play("adTagUrl", url, config),
|
||||
playRes: (response, config = {}) => play("adsResponse", response, config),
|
||||
init,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return current?.player || null;
|
||||
},
|
||||
get container() {
|
||||
return current?.container || null;
|
||||
}
|
||||
};
|
||||
return { context, destroy };
|
||||
}
|
||||
function artplayerPluginVast(callback) {
|
||||
return async (art) => {
|
||||
const { template, constructor } = art;
|
||||
const { createElement, setStyles } = constructor.utils;
|
||||
const { $video, $player } = template;
|
||||
await e();
|
||||
const google = window.google;
|
||||
const ima = google.ima;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
||||
adsRenderingSettings.enablePreloading = true;
|
||||
const playerOptions = new E();
|
||||
let isAdPlaying = false;
|
||||
let imaPlayer = null;
|
||||
let $container = null;
|
||||
function createContainer() {
|
||||
const container = createElement("div");
|
||||
const id = `art-vast-${Date.now()}`;
|
||||
container.id = id;
|
||||
setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
backgroundColor: "black",
|
||||
display: "none",
|
||||
pointerEvents: "auto"
|
||||
});
|
||||
return container;
|
||||
}
|
||||
function initPlayer() {
|
||||
if (imaPlayer)
|
||||
return imaPlayer;
|
||||
$container = createContainer();
|
||||
$player.appendChild($container);
|
||||
imaPlayer = new nt(ima, $video, $container, adsRenderingSettings, playerOptions);
|
||||
imaPlayer.addEventListener("AdContentPauseRequested", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdContentResumeRequested", () => {
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
imaPlayer.addEventListener("AdStarted", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdError", (event) => {
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
return imaPlayer;
|
||||
}
|
||||
function destroyPlayer() {
|
||||
if (imaPlayer?.destroy)
|
||||
imaPlayer.destroy();
|
||||
if ($container?.parentNode)
|
||||
$container.parentNode.removeChild($container);
|
||||
$container = null;
|
||||
imaPlayer = null;
|
||||
}
|
||||
function playUrl(url, config = {}) {
|
||||
if (isAdPlaying)
|
||||
let disposed = false;
|
||||
let session;
|
||||
const closed = () => disposed || art.isDestroy;
|
||||
const result = { name: "artplayerPluginVast", destroy: () => session?.destroy() };
|
||||
function dispose() {
|
||||
if (disposed)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adTagUrl = url;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
disposed = true;
|
||||
try {
|
||||
art.off("destroy", dispose);
|
||||
} finally {
|
||||
session?.destroy();
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
}
|
||||
function playRes(res, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adsResponse = res;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
if (closed())
|
||||
return result;
|
||||
art.on("destroy", dispose);
|
||||
try {
|
||||
if (closed())
|
||||
return result;
|
||||
const ima = await e();
|
||||
if (closed())
|
||||
return result;
|
||||
const utils = art.constructor.utils;
|
||||
session = createSession(art, ima, utils, closed);
|
||||
if (closed()) {
|
||||
dispose();
|
||||
return result;
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
if (typeof callback === "function")
|
||||
await callback(session.context);
|
||||
return result;
|
||||
} catch (error) {
|
||||
try {
|
||||
dispose();
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (typeof callback === "function") {
|
||||
await callback({
|
||||
art,
|
||||
playUrl,
|
||||
playRes,
|
||||
init: initPlayer,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return imaPlayer;
|
||||
},
|
||||
get container() {
|
||||
return $container;
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
name: "artplayerPluginVast",
|
||||
destroy: destroyPlayer
|
||||
};
|
||||
};
|
||||
}
|
||||
export {
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@
|
||||
"ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports",
|
||||
"test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js",
|
||||
"typecheck": "node scripts/typecheck.mjs",
|
||||
"test:unit": "node --test test/vast.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js",
|
||||
"test:unit": "node --test test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js",
|
||||
"test:coverage": "node --test test/coverage.test.js && node scripts/coverage.mjs",
|
||||
"test": "yarn test:node && yarn test:baseline",
|
||||
"test:browser": "playwright test",
|
||||
@@ -65,7 +65,7 @@
|
||||
"test:dash-types-package": "node refactor/scripts/dash-package-types.mjs",
|
||||
"test:ads-types-package": "node refactor/scripts/ads-package-types.mjs",
|
||||
"test:ads-native-visibility": "node refactor/scripts/ads-native-visibility.mjs",
|
||||
"test:vast": "node --test test/vast.test.js"
|
||||
"test:vast": "node --test test/vast.test.js test/vast-lifecycle.test.js"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# VAST implementation and maintenance
|
||||
|
||||
This is the PKG-VAST-03 implementation checkpoint. The published-versus-workspace
|
||||
initialization conflict remains open; this checkpoint is not release acceptance.
|
||||
|
||||
## Module map
|
||||
|
||||
- `src/index.ts` owns the core destroy subscription before SDK loading begins,
|
||||
awaits SDK loading and the user callback, and preserves original rejection values.
|
||||
- `src/sdk.ts` is the only runtime Glomex import boundary. It also constructs IMA
|
||||
requests, preserving own/inherited configuration fields and primary-field overrides.
|
||||
- `src/session.ts` owns one current SDK/container pair, the four ad-event subscriptions,
|
||||
active-ad request suppression, initialization rollback and explicit recreation.
|
||||
- `src/view.ts` creates the existing overlay styles and distinct per-module container
|
||||
IDs, including multiple instances initialized in the same millisecond.
|
||||
- `src/types.ts` describes the implementation context and SDK boundary. Public legacy
|
||||
declarations in `types/` remain separate pending PKG-VAST-04 reconciliation.
|
||||
|
||||
Dependency direction is entry -> session -> SDK/view/types. The session passes the
|
||||
original `art` through the callback for compatibility; only template elements are
|
||||
used for SDK allocation. Constructor utility access is narrowed once at the entry.
|
||||
|
||||
## Lifetime and errors
|
||||
|
||||
The entry subscribes before awaiting the shared SDK loader. Core destruction makes
|
||||
that attachment terminal, removes the subscription and releases the current session.
|
||||
It does not cancel the shared IMA script load for other instances. A late completion
|
||||
does not invoke the callback or allocate a player. SDK failures still reject with
|
||||
their original value. Callback failure closes the attachment and releases resources;
|
||||
secondary cleanup failures are logged without replacing the original error.
|
||||
|
||||
Explicit plugin `destroy()` releases the current ad session, resets active-ad state,
|
||||
and permits a later `init`/`playUrl`/`playRes` while the core remains alive. Core destroy
|
||||
and failed attachment are terminal: request methods are inert and `init()` returns
|
||||
null. Public declaration accuracy for this invalid-lifetime case belongs to04.
|
||||
|
||||
Each session has an owner identity. Its callbacks verify that identity and core
|
||||
liveness before changing visibility. Cleanup detaches the current owner and clears
|
||||
references before invoking SDK code, removes each subscription, destroys the SDK and
|
||||
removes the container even when another cleanup operation throws. A cleanup exception
|
||||
is observable, but cannot leave the wrapper pointing at a half-destroyed player.
|
||||
|
||||
Initialization is guarded against reentrancy. Constructor/subscription failure rolls
|
||||
back; destruction reentered during constructor completion releases the late player.
|
||||
Config accessors can execute user code, so request dispatch verifies owner identity
|
||||
again after request construction. Cleanup itself prevents reentrant recreation until
|
||||
it finishes. SDK content pause/resume behavior is not duplicated in this wrapper.
|
||||
|
||||
## Compatibility and remaining work
|
||||
|
||||
The checkpoint retains the workspace callback order, lazy initialization, mutable
|
||||
settings/options identities, default flags, void request methods, and asynchronous
|
||||
outer attachment. The historical namespace export, `id`/`$container` aliases, eager
|
||||
published initialization and contradictory public return types are not yet reconciled.
|
||||
See [the explicit decision](../../refactor/vast-compatibility-decision.md).
|
||||
|
||||
The former timestamp-only overlay ID now has a monotonic suffix to avoid same-tick
|
||||
collisions; the existing `art-vast-` prefix and CSS styles remain. IDs are internal
|
||||
in the workspace context; published ID compatibility is tracked with the above decision.
|
||||
|
||||
`@alugha/ima@2.1.0` is a direct pinned dependency because Glomex declarations import its
|
||||
types while Glomex lists it only as a development dependency. Runtime imports continue
|
||||
to use Glomex1.21.2. No new direct remote loader or SDK major upgrade was introduced.
|
||||
|
||||
## Validation
|
||||
|
||||
Run `yarn test:vast`, `yarn typecheck`, `yarn build artplayer-plugin-vast`, and
|
||||
`yarn test:browser vast.spec.js` using the repository pinned toolchain. The node and
|
||||
browser wrapper tests substitute only the Glomex SDK boundary. They cover current and
|
||||
frozen historical sources, real core5.1.7/5.4.1/candidate registration, real DOM and
|
||||
main-video decoding; they do not certify Google IMA ads or final npm distribution.
|
||||
|
||||
For state or cleanup changes start in session, for callback timing in entry, and for
|
||||
SDK request fields in sdk. Keep Node candidate assertions, historical observations,
|
||||
browser counterparts and [test maintenance](../../refactor/vast-validation.md) aligned.
|
||||
Actual IMA/media/device validation remains05, public types04, and full distribution06.
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
VAST plugin for ArtPlayer
|
||||
|
||||
## Maintenance
|
||||
|
||||
Implementation modules, lifecycle ownership, test commands and pending compatibility
|
||||
decisions are documented in [ARCHITECTURE.md](ARCHITECTURE.md).
|
||||
|
||||
## Demo
|
||||
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vast/index.js&example=vast)
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var v={};v.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,E,y,A=v.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
@@ -4,4 +4,4 @@
|
||||
* (c) 2017-2026 Harvey Zhao
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function s(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function r(t){return(r=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var s=new(Function.bind.apply(t,n));return i&&o(s,i.prototype),s}).apply(null,arguments)}function d(t){var e="function"==typeof Map?new Map:void 0;return d=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,r(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},d(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function u(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function v(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var f={};f.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var p,y,E,A=f.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,v(this,m)[m]=t,v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=v(this,m)[m])&&t.paused||(v(this,b)[b]=null==(e=v(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;v(this,g)[g]||(null==(t=v(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.addEventListener("timeupdate",this.t),v(this,g)[g]=!0)},e.disable=function(){var t,e,i;v(this,g)[g]&&(null==(t=v(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=v(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=v(this,m)[m])||i.removeEventListener("timeupdate",this.t),v(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=v(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=v(this,m)[m])||t.pause()},e.reset=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){v(this,b)[b]=0,v(this,g)[g]=!1,this.seeking=!1,this.disable(),v(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return v(this,g)[g]}},{key:"currentTime",get:function(){return v(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=v(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.artplayerPluginVast=e(),define(function(){return t.artplayerPluginVast})):(t="undefined"!==typeof globalThis?globalThis:t||self).artplayerPluginVast=e()}(this,function(){"use strict";var t=null,e=function(){t=null};function i(t,e,i){return e&&function(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}(t.prototype,e),t}function n(){return n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t},n.apply(this,arguments)}function r(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,o(t,e)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function o(t,e){return(o=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e,i){return(a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}()?Reflect.construct:function(t,e,i){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return i&&o(r,i.prototype),r}).apply(null,arguments)}function u(t){var e="function"==typeof Map?new Map:void 0;return u=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,i)}function i(){return a(t,arguments,s(this).constructor)}return i.prototype=Object.create(t.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),o(i,t)},u(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function d(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i<e;i++)n[i]=t[i];return n}var l=0;function c(t){return"__private_"+l+++"_"+t}function f(t,e){if(!Object.prototype.hasOwnProperty.call(t,e))throw new TypeError("attempted to use private field on non-instance");return t}var p={};p.CustomEvent="function"==typeof CustomEvent?CustomEvent:function(t){return e[t]=new e("").constructor[t],e;function e(t,e){e||(e={});var i=document.createEvent("CustomEvent");return i.initCustomEvent(t,!!e.bubbles,!!e.cancelable,e.detail),i}}("prototype");var v,y,E,A=p.CustomEvent,m=c("mediaElement"),b=c("currentTime"),g=c("enabled"),O=function(){function t(t){Object.defineProperty(this,m,{writable:!0,value:void 0}),Object.defineProperty(this,b,{writable:!0,value:void 0}),Object.defineProperty(this,g,{writable:!0,value:void 0}),this.seeking=void 0,f(this,m)[m]=t,f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.t=this.t.bind(this),this.i=this.i.bind(this),this.h=this.h.bind(this),this.enable()}var e=t.prototype;return e.i=function(){this.seeking=!0},e.h=function(){this.seeking=!1},e.t=function(){var t,e;this.seeking||null!=(t=f(this,m)[m])&&t.paused||(f(this,b)[b]=null==(e=f(this,m)[m])?void 0:e.currentTime)},e.enable=function(){var t,e,i;f(this,g)[g]||(null==(t=f(this,m)[m])||t.addEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.addEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.addEventListener("timeupdate",this.t),f(this,g)[g]=!0)},e.disable=function(){var t,e,i;f(this,g)[g]&&(null==(t=f(this,m)[m])||t.removeEventListener("seeking",this.i),null==(e=f(this,m)[m])||e.removeEventListener("seeked",this.h),null==(i=f(this,m)[m])||i.removeEventListener("timeupdate",this.t),f(this,g)[g]=!1)},e.play=function(){var t=this;return new Promise(function(e){var i;e(null==(i=f(t,m)[m])?void 0:i.play())})},e.pause=function(){var t;null==(t=f(this,m)[m])||t.pause()},e.reset=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.enable()},e.destroy=function(){f(this,b)[b]=0,f(this,g)[g]=!1,this.seeking=!1,this.disable(),f(this,m)[m]=void 0},i(t,[{key:"enabled",get:function(){return f(this,g)[g]}},{key:"currentTime",get:function(){return f(this,b)[b]}},{key:"duration",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.duration}},{key:"muted",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.muted}},{key:"volume",get:function(){var t;return null==(t=f(this,m)[m])?void 0:t.volume}}]),t}(),w=function(){function t(){this.delegate=document.createDocumentFragment()}var e=t.prototype;return e.addEventListener=function(){this.delegate.addEventListener.apply(this.delegate,[].slice.call(arguments))},e.dispatchEvent=function(){return this.delegate.dispatchEvent.apply(this.delegate,[].slice.call(arguments))},e.removeEventListener=function(){return this.delegate.removeEventListener.apply(this.delegate,[].slicLine truncated
|
||||
+218
-118
@@ -98,15 +98,15 @@ function w(t2, i2) {
|
||||
return t2;
|
||||
}
|
||||
var m = {};
|
||||
m.CustomEvent = "function" == typeof CustomEvent ? CustomEvent : (function(t2) {
|
||||
m.CustomEvent = "function" == typeof CustomEvent ? CustomEvent : function(t2) {
|
||||
return i2[t2] = new i2("").constructor[t2], i2;
|
||||
function i2(t3, i3) {
|
||||
i3 || (i3 = {});
|
||||
var e2 = document.createEvent("CustomEvent");
|
||||
return e2.initCustomEvent(t3, !!i3.bubbles, !!i3.cancelable, i3.detail), e2;
|
||||
}
|
||||
})("prototype");
|
||||
var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b("enabled"), k = (function() {
|
||||
}("prototype");
|
||||
var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b("enabled"), k = function() {
|
||||
function t2(t3) {
|
||||
Object.defineProperty(this, j, { writable: true, value: void 0 }), Object.defineProperty(this, g, { writable: true, value: void 0 }), Object.defineProperty(this, A, { writable: true, value: void 0 }), this.seeking = void 0, w(this, j)[j] = t3, w(this, g)[g] = 0, w(this, A)[A] = false, this.seeking = false, this.t = this.t.bind(this), this.i = this.i.bind(this), this.h = this.h.bind(this), this.enable();
|
||||
}
|
||||
@@ -151,7 +151,7 @@ var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b(
|
||||
var t3;
|
||||
return null == (t3 = w(this, j)[j]) ? void 0 : t3.volume;
|
||||
} }]), t2;
|
||||
})(), C = (function() {
|
||||
}(), C = function() {
|
||||
function t2() {
|
||||
this.delegate = document.createDocumentFragment();
|
||||
}
|
||||
@@ -163,23 +163,23 @@ var p, y, O = m.CustomEvent, j = b("mediaElement"), g = b("currentTime"), A = b(
|
||||
}, i2.removeEventListener = function() {
|
||||
return this.delegate.removeEventListener.apply(this.delegate, [].slice.call(arguments));
|
||||
}, t2;
|
||||
})(), P = ["abort", "canplay", "canplaythrough", "durationchange", "emptied", "ended", "error", "loadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing", "progress", "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate", "volumechange", "waiting"];
|
||||
!(function(t2) {
|
||||
}(), P = ["abort", "canplay", "canplaythrough", "durationchange", "emptied", "ended", "error", "loadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing", "progress", "ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate", "volumechange", "waiting"];
|
||||
!function(t2) {
|
||||
t2.MEDIA_START = "MediaStart", t2.MEDIA_IMPRESSION = "MediaImpression", t2.MEDIA_STOP = "MediaStop", t2.MEDIA_CUE_POINTS_CHANGE = "MediaCuePointsChange", t2.MEDIA_RESUMED = "MediaResumed";
|
||||
})(p || (p = {})), (function(t2) {
|
||||
}(p || (p = {})), function(t2) {
|
||||
t2.AD_ERROR = "AdError", t2.AD_BUFFERING = "AdBuffering", t2.LOADED = "AdLoaded", t2.IMPRESSION = "AdImpression", t2.STARTED = "AdStarted", t2.FIRST_QUARTILE = "AdFirstQuartile", t2.MIDPOINT = "AdMidpoint", t2.THIRD_QUARTILE = "AdThirdQuartile", t2.AD_PROGRESS = "AdProgress", t2.COMPLETE = "AdComplete", t2.CLICK = "AdClick", t2.PAUSED = "AdPaused", t2.RESUMED = "AdResumed", t2.SKIPPED = "AdSkipped", t2.SKIPPABLE_STATE_CHANGED = "AdSkippableStateChanged", t2.VOLUME_CHANGED = "AdVolumeChanged", t2.VOLUME_MUTED = "AdMuted", t2.AD_METADATA = "AdMetadata", t2.AD_BREAK_READY = "AdBreakReady", t2.CONTENT_PAUSE_REQUESTED = "AdContentPauseRequested", t2.CONTENT_RESUME_REQUESTED = "AdContentResumeRequested", t2.ALL_ADS_COMPLETED = "AdAllAdsCompleted", t2.DURATION_CHANGE = "AdDurationChange", t2.INTERACTION = "AdInteraction", t2.LINEAR_CHANGED = "AdLinearChanged", t2.LOG = "AdLog", t2.USER_CLOSE = "AdUserClose", t2.AD_CAN_PLAY = "AdCanPlay", t2.EXPANDED_CHANGED = "AdExpandedChanged", t2.VIEWABLE_IMPRESSION = "AdViewableImpression";
|
||||
})(y || (y = {}));
|
||||
}(y || (y = {}));
|
||||
var R = h({}, y, p), E = function() {
|
||||
this.disableCustomPlaybackForIOS10Plus = false, this.autoResize = true, this.clickTrackingElement = void 0;
|
||||
}, T = (function(t2) {
|
||||
}, T = function(t2) {
|
||||
function i2() {
|
||||
var i3;
|
||||
return (i3 = t2.call.apply(t2, [this].concat([].slice.call(arguments))) || this).errorCode = void 0, i3.innerError = void 0, i3.type = void 0, i3.vastErrorCode = void 0, i3;
|
||||
}
|
||||
return r(i2, t2), i2;
|
||||
})(d(Error));
|
||||
}(d(Error));
|
||||
T.ERROR_CODE_ADS_MANAGER_LOADED_TIMEOUT = 9e3, T.ERROR_CODE_REQUEST_ADS_TIMEOUT = 9001;
|
||||
var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("adsRenderingSettings"), B = b("ima"), L = b("adDisplayContainer"), D = b("adsManager"), W = b("width"), _ = b("height"), q = b("adsLoader"), F = b("playerOptions"), N = b("resizeObserver"), V = b("currentAd"), G = b("loadedAd"), Q = b("mediaStartTriggered"), U = b("mediaImpressionTriggered"), z = b("mediaInActivation"), Z = b("customPlaybackTimeAdjustedOnEnded"), $ = b("cuePoints"), H = b("adCurrentTime"), J = b("adDuration"), K = b("startAdCallback"), X = b("adsManagerLoadedTimeout"), Y = b("requestAdsTimeout"), tt = b("wasExternallyPaused"), it = b("lastNonZeroAdVolume"), et = b("activatePromise"), nt = (function(t2) {
|
||||
var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("adsRenderingSettings"), B = b("ima"), L = b("adDisplayContainer"), D = b("adsManager"), W = b("width"), _ = b("height"), q = b("adsLoader"), F = b("playerOptions"), N = b("resizeObserver"), V = b("currentAd"), G = b("loadedAd"), Q = b("mediaStartTriggered"), U = b("mediaImpressionTriggered"), z = b("mediaInActivation"), Z = b("customPlaybackTimeAdjustedOnEnded"), $ = b("cuePoints"), H = b("adCurrentTime"), J = b("adDuration"), K = b("startAdCallback"), X = b("adsManagerLoadedTimeout"), Y = b("requestAdsTimeout"), tt = b("wasExternallyPaused"), it = b("lastNonZeroAdVolume"), et = b("activatePromise"), nt = function(t2) {
|
||||
function i2(i3, e3, n2, s2, h2) {
|
||||
var r2;
|
||||
void 0 === s2 && (s2 = new i3.AdsRenderingSettings()), void 0 === h2 && (h2 = new E()), r2 = t2.call(this) || this, Object.defineProperty(l(r2), S, { writable: true, value: void 0 }), Object.defineProperty(l(r2), M, { writable: true, value: void 0 }), Object.defineProperty(l(r2), x, { writable: true, value: void 0 }), Object.defineProperty(l(r2), I, { writable: true, value: void 0 }), Object.defineProperty(l(r2), B, { writable: true, value: void 0 }), Object.defineProperty(l(r2), L, { writable: true, value: void 0 }), Object.defineProperty(l(r2), D, { writable: true, value: void 0 }), Object.defineProperty(l(r2), W, { writable: true, value: void 0 }), Object.defineProperty(l(r2), _, { writable: true, value: void 0 }), Object.defineProperty(l(r2), q, { writable: true, value: void 0 }), Object.defineProperty(l(r2), F, { writable: true, value: void 0 }), Object.defineProperty(l(r2), N, { writable: true, value: void 0 }), Object.defineProperty(l(r2), V, { writable: true, value: void 0 }), Object.defineProperty(l(r2), G, { writable: true, value: void 0 }), Object.defineProperty(l(r2), Q, { writable: true, value: false }), Object.defineProperty(l(r2), U, { writable: true, value: false }), Object.defineProperty(l(r2), z, { writable: true, value: false }), Object.defineProperty(l(r2), Z, { writable: true, value: false }), Object.defineProperty(l(r2), $, { writable: true, value: [] }), Object.defineProperty(l(r2), H, { writable: true, value: void 0 }), Object.defineProperty(l(r2), J, { writable: true, value: void 0 }), Object.defineProperty(l(r2), K, { writable: true, value: void 0 }), Object.defineProperty(l(r2), X, { writable: true, value: void 0 }), Object.defineProperty(l(r2), Y, { writable: true, value: void 0 }), Object.defineProperty(l(r2), tt, { writable: true, value: false }), Object.defineProperty(l(r2), it, { writable: true, value: 1 }), Object.defineProperty(l(r2), et, { writable: true, value: Promise.resolve() }), w(l(r2), S)[S] = e3, w(l(r2), M)[M] = n2, w(l(r2), B)[B] = i3, w(l(r2), F)[F] = h2, w(l(r2), I)[I] = s2, w(l(r2), I)[I].restoreCustomPlaybackStateOnAdBreakComplete = true, h2.disableCustomPlaybackForIOS10Plus && !w(l(r2), S)[S].hasAttribute("playsinline") && w(l(r2), S)[S].setAttribute("playsinline", ""), w(l(r2), B)[B].settings.setDisableCustomPlaybackForIOS10Plus(h2.disableCustomPlaybackForIOS10Plus), w(l(r2), x)[x] = new k(w(l(r2), S)[S]), r2.o = r2.o.bind(l(r2)), P.forEach(function(t3) {
|
||||
@@ -373,16 +373,16 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
w(t3, U)[U] = false, w(t3, Q)[Q] = false, w(t3, Z)[Z] = false, t3.dispatchEvent(new O(R.MEDIA_STOP));
|
||||
}, 1);
|
||||
}, e2.v = function(t3) {
|
||||
for (var i3, e3 = (function(t4, i4) {
|
||||
for (var i3, e3 = function(t4, i4) {
|
||||
var e4 = "undefined" != typeof Symbol && t4[Symbol.iterator] || t4["@@iterator"];
|
||||
if (e4) return (e4 = e4.call(t4)).next.bind(e4);
|
||||
if (Array.isArray(t4) || (e4 = (function(t5, i5) {
|
||||
if (Array.isArray(t4) || (e4 = function(t5, i5) {
|
||||
if (t5) {
|
||||
if ("string" == typeof t5) return f(t5, i5);
|
||||
var e5 = Object.prototype.toString.call(t5).slice(8, -1);
|
||||
return "Object" === e5 && t5.constructor && (e5 = t5.constructor.name), "Map" === e5 || "Set" === e5 ? Array.from(t5) : "Arguments" === e5 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e5) ? f(t5, i5) : void 0;
|
||||
}
|
||||
})(t4))) {
|
||||
}(t4))) {
|
||||
e4 && (t4 = e4);
|
||||
var n3 = 0;
|
||||
return function() {
|
||||
@@ -390,7 +390,7 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
};
|
||||
}
|
||||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
})(t3); !(i3 = e3()).done; ) {
|
||||
}(t3); !(i3 = e3()).done; ) {
|
||||
var n2 = i3.value;
|
||||
n2.contentBoxSize && 1 === n2.contentBoxSize.length ? (w(this, W)[W] = n2.contentBoxSize[0].inlineSize, w(this, _)[_] = n2.contentBoxSize[0].blockSize) : n2.contentBoxSize && n2.contentBoxSize.inlineSize ? (w(this, W)[W] = n2.contentBoxSize.inlineSize, w(this, _)[_] = n2.contentBoxSize.blockSize) : (w(this, W)[W] = n2.contentRect.width, w(this, _)[_] = n2.contentRect.height);
|
||||
}
|
||||
@@ -435,116 +435,216 @@ var S = b("mediaElement"), M = b("adElement"), x = b("customPlayhead"), I = b("a
|
||||
} }, { key: "cuePoints", get: function() {
|
||||
return [].concat(w(this, $)[$]);
|
||||
} }]), i2;
|
||||
})(C);
|
||||
}(C);
|
||||
function createRequest(ima, field, value, config) {
|
||||
const request = new ima.AdsRequest();
|
||||
request[field] = value;
|
||||
const fields = request;
|
||||
for (const key in config)
|
||||
fields[key] = config[key];
|
||||
return request;
|
||||
}
|
||||
let nextId = 0;
|
||||
function createContainer(utils) {
|
||||
const container = utils.createElement("div");
|
||||
container.id = `art-vast-${Date.now()}-${++nextId}`;
|
||||
utils.setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
backgroundColor: "black",
|
||||
display: "none",
|
||||
pointerEvents: "auto"
|
||||
});
|
||||
return container;
|
||||
}
|
||||
function createSession(art, ima, utils, closed) {
|
||||
const { $video, $player } = art.template;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
||||
adsRenderingSettings.enablePreloading = true;
|
||||
const playerOptions = new E();
|
||||
let current = null;
|
||||
let initializing = false;
|
||||
let releasing = 0;
|
||||
const live = (owner) => current === owner && !owner.released && !closed();
|
||||
function release(owner) {
|
||||
if (current === owner)
|
||||
current = null;
|
||||
owner.released = true;
|
||||
owner.playing = false;
|
||||
const player = owner.player;
|
||||
owner.player = null;
|
||||
const listeners = owner.listeners.splice(0);
|
||||
let failed = false;
|
||||
let failure;
|
||||
const attempt = (cleanup) => {
|
||||
try {
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
if (!failed) {
|
||||
failed = true;
|
||||
failure = error;
|
||||
} else {
|
||||
console.error("VAST cleanup error:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
releasing++;
|
||||
try {
|
||||
if (player) {
|
||||
for (const [name, callback] of listeners)
|
||||
attempt(() => player.removeEventListener(name, callback));
|
||||
attempt(() => player.destroy());
|
||||
}
|
||||
attempt(() => {
|
||||
if (owner.container.parentNode)
|
||||
owner.container.parentNode.removeChild(owner.container);
|
||||
});
|
||||
} finally {
|
||||
releasing--;
|
||||
}
|
||||
if (failed)
|
||||
throw failure;
|
||||
}
|
||||
function init() {
|
||||
if (closed() || releasing)
|
||||
return null;
|
||||
if (initializing)
|
||||
throw new Error("VAST initialization is already in progress");
|
||||
if (current?.player)
|
||||
return current.player;
|
||||
initializing = true;
|
||||
let owner;
|
||||
try {
|
||||
owner = { container: createContainer(utils), player: null, listeners: [], playing: false, released: false };
|
||||
current = owner;
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
$player.appendChild(owner.container);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
owner.player = new nt(ima, $video, owner.container, adsRenderingSettings, playerOptions);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
const allocated = owner;
|
||||
for (const [name, playing] of [
|
||||
["AdContentPauseRequested", true],
|
||||
["AdContentResumeRequested", false],
|
||||
["AdStarted", true],
|
||||
["AdError", false]
|
||||
]) {
|
||||
const callback = (event) => {
|
||||
if (!live(allocated))
|
||||
return;
|
||||
if (name === "AdError")
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
allocated.playing = playing;
|
||||
allocated.container.style.display = playing ? "block" : "none";
|
||||
};
|
||||
owner.listeners.push([name, callback]);
|
||||
owner.player.addEventListener(name, callback);
|
||||
if (!live(owner)) {
|
||||
release(owner);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return owner.player;
|
||||
} catch (error) {
|
||||
if (owner) {
|
||||
try {
|
||||
release(owner);
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
initializing = false;
|
||||
}
|
||||
}
|
||||
function play(field, value, config) {
|
||||
if (closed() || current?.playing)
|
||||
return;
|
||||
const player = init();
|
||||
const owner = current;
|
||||
if (!player || !owner)
|
||||
return;
|
||||
const request = createRequest(ima, field, value, config);
|
||||
if (live(owner) && owner.player === player)
|
||||
player.playAds(request);
|
||||
}
|
||||
function destroy() {
|
||||
if (current)
|
||||
release(current);
|
||||
}
|
||||
const context = {
|
||||
art,
|
||||
playUrl: (url, config = {}) => play("adTagUrl", url, config),
|
||||
playRes: (response, config = {}) => play("adsResponse", response, config),
|
||||
init,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return current?.player || null;
|
||||
},
|
||||
get container() {
|
||||
return current?.container || null;
|
||||
}
|
||||
};
|
||||
return { context, destroy };
|
||||
}
|
||||
function artplayerPluginVast(callback) {
|
||||
return async (art) => {
|
||||
const { template, constructor } = art;
|
||||
const { createElement, setStyles } = constructor.utils;
|
||||
const { $video, $player } = template;
|
||||
await e();
|
||||
const google = window.google;
|
||||
const ima = google.ima;
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
|
||||
adsRenderingSettings.enablePreloading = true;
|
||||
const playerOptions = new E();
|
||||
let isAdPlaying = false;
|
||||
let imaPlayer = null;
|
||||
let $container = null;
|
||||
function createContainer() {
|
||||
const container = createElement("div");
|
||||
const id = `art-vast-${Date.now()}`;
|
||||
container.id = id;
|
||||
setStyles(container, {
|
||||
position: "absolute",
|
||||
inset: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
zIndex: "150",
|
||||
backgroundColor: "black",
|
||||
display: "none",
|
||||
pointerEvents: "auto"
|
||||
});
|
||||
return container;
|
||||
}
|
||||
function initPlayer() {
|
||||
if (imaPlayer)
|
||||
return imaPlayer;
|
||||
$container = createContainer();
|
||||
$player.appendChild($container);
|
||||
imaPlayer = new nt(ima, $video, $container, adsRenderingSettings, playerOptions);
|
||||
imaPlayer.addEventListener("AdContentPauseRequested", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdContentResumeRequested", () => {
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
imaPlayer.addEventListener("AdStarted", () => {
|
||||
isAdPlaying = true;
|
||||
$container.style.display = "block";
|
||||
});
|
||||
imaPlayer.addEventListener("AdError", (event) => {
|
||||
console.error("VAST Ad Error:", event.detail);
|
||||
isAdPlaying = false;
|
||||
$container.style.display = "none";
|
||||
});
|
||||
return imaPlayer;
|
||||
}
|
||||
function destroyPlayer() {
|
||||
if (imaPlayer?.destroy)
|
||||
imaPlayer.destroy();
|
||||
if ($container?.parentNode)
|
||||
$container.parentNode.removeChild($container);
|
||||
$container = null;
|
||||
imaPlayer = null;
|
||||
}
|
||||
function playUrl(url, config = {}) {
|
||||
if (isAdPlaying)
|
||||
let disposed = false;
|
||||
let session;
|
||||
const closed = () => disposed || art.isDestroy;
|
||||
const result = { name: "artplayerPluginVast", destroy: () => session?.destroy() };
|
||||
function dispose() {
|
||||
if (disposed)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adTagUrl = url;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
disposed = true;
|
||||
try {
|
||||
art.off("destroy", dispose);
|
||||
} finally {
|
||||
session?.destroy();
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
}
|
||||
function playRes(res, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return;
|
||||
if (!imaPlayer)
|
||||
initPlayer();
|
||||
const request = new ima.AdsRequest();
|
||||
request.adsResponse = res;
|
||||
for (const key in config) {
|
||||
request[key] = config[key];
|
||||
if (closed())
|
||||
return result;
|
||||
art.on("destroy", dispose);
|
||||
try {
|
||||
if (closed())
|
||||
return result;
|
||||
const ima = await e();
|
||||
if (closed())
|
||||
return result;
|
||||
const utils = art.constructor.utils;
|
||||
session = createSession(art, ima, utils, closed);
|
||||
if (closed()) {
|
||||
dispose();
|
||||
return result;
|
||||
}
|
||||
imaPlayer.playAds(request);
|
||||
if (typeof callback === "function")
|
||||
await callback(session.context);
|
||||
return result;
|
||||
} catch (error) {
|
||||
try {
|
||||
dispose();
|
||||
} catch (cleanupError) {
|
||||
console.error("VAST cleanup error:", cleanupError);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (typeof callback === "function") {
|
||||
await callback({
|
||||
art,
|
||||
playUrl,
|
||||
playRes,
|
||||
init: initPlayer,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return imaPlayer;
|
||||
},
|
||||
get container() {
|
||||
return $container;
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
name: "artplayerPluginVast",
|
||||
destroy: destroyPlayer
|
||||
};
|
||||
};
|
||||
}
|
||||
export {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"legacy": "./dist/artplayer-plugin-vast.legacy.js",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"dependencies": {
|
||||
"@alugha/ima": "2.1.0",
|
||||
"@glomex/vast-ima-player": "^1.21.2"
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
import { loadImaSdk, Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||
|
||||
export default function artplayerPluginVast(callback) {
|
||||
return async (art) => {
|
||||
const { template, constructor } = art
|
||||
const { createElement, setStyles } = constructor.utils
|
||||
const { $video, $player } = template
|
||||
|
||||
await loadImaSdk()
|
||||
const google = window.google
|
||||
const ima = google.ima
|
||||
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings()
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
|
||||
adsRenderingSettings.enablePreloading = true
|
||||
|
||||
const playerOptions = new PlayerOptions()
|
||||
let isAdPlaying = false
|
||||
let imaPlayer = null
|
||||
let $container = null
|
||||
|
||||
function createContainer() {
|
||||
const container = createElement('div')
|
||||
const id = `art-vast-${Date.now()}`
|
||||
container.id = id
|
||||
setStyles(container, {
|
||||
position: 'absolute',
|
||||
inset: '0',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: '150',
|
||||
backgroundColor: 'black',
|
||||
display: 'none',
|
||||
pointerEvents: 'auto',
|
||||
})
|
||||
return container
|
||||
}
|
||||
|
||||
function initPlayer() {
|
||||
if (imaPlayer)
|
||||
return imaPlayer
|
||||
|
||||
$container = createContainer()
|
||||
$player.appendChild($container)
|
||||
|
||||
imaPlayer = new Player(ima, $video, $container, adsRenderingSettings, playerOptions)
|
||||
|
||||
imaPlayer.addEventListener('AdContentPauseRequested', () => {
|
||||
isAdPlaying = true
|
||||
$container.style.display = 'block'
|
||||
})
|
||||
|
||||
imaPlayer.addEventListener('AdContentResumeRequested', () => {
|
||||
isAdPlaying = false
|
||||
$container.style.display = 'none'
|
||||
})
|
||||
|
||||
imaPlayer.addEventListener('AdStarted', () => {
|
||||
isAdPlaying = true
|
||||
$container.style.display = 'block'
|
||||
})
|
||||
|
||||
imaPlayer.addEventListener('AdError', (event) => {
|
||||
console.error('VAST Ad Error:', event.detail)
|
||||
isAdPlaying = false
|
||||
$container.style.display = 'none'
|
||||
})
|
||||
|
||||
return imaPlayer
|
||||
}
|
||||
|
||||
function destroyPlayer() {
|
||||
if (imaPlayer?.destroy)
|
||||
imaPlayer.destroy()
|
||||
if ($container?.parentNode)
|
||||
$container.parentNode.removeChild($container)
|
||||
$container = null
|
||||
imaPlayer = null
|
||||
}
|
||||
|
||||
function playUrl(url, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return
|
||||
if (!imaPlayer)
|
||||
initPlayer()
|
||||
const request = new ima.AdsRequest()
|
||||
request.adTagUrl = url
|
||||
for (const key in config) {
|
||||
request[key] = config[key]
|
||||
}
|
||||
imaPlayer.playAds(request)
|
||||
}
|
||||
|
||||
function playRes(res, config = {}) {
|
||||
if (isAdPlaying)
|
||||
return
|
||||
if (!imaPlayer)
|
||||
initPlayer()
|
||||
const request = new ima.AdsRequest()
|
||||
request.adsResponse = res
|
||||
for (const key in config) {
|
||||
request[key] = config[key]
|
||||
}
|
||||
imaPlayer.playAds(request)
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
await callback({
|
||||
art,
|
||||
playUrl,
|
||||
playRes,
|
||||
init: initPlayer,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() {
|
||||
return imaPlayer
|
||||
},
|
||||
get container() {
|
||||
return $container
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'artplayerPluginVast',
|
||||
destroy: destroyPlayer,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Callback, Result } from './types'
|
||||
import { loadImaSdk } from './sdk'
|
||||
import { createSession } from './session'
|
||||
|
||||
export default function artplayerPluginVast(callback?: Callback) {
|
||||
return async (art: Artplayer): Promise<Result> => {
|
||||
let disposed = false
|
||||
let session: ReturnType<typeof createSession> | undefined
|
||||
const closed = () => disposed || art.isDestroy
|
||||
const result: Result = { name: 'artplayerPluginVast', destroy: () => session?.destroy() }
|
||||
function dispose(): void {
|
||||
if (disposed)
|
||||
return
|
||||
disposed = true
|
||||
try {
|
||||
art.off('destroy', dispose)
|
||||
}
|
||||
finally { session?.destroy() }
|
||||
}
|
||||
if (closed())
|
||||
return result
|
||||
art.on('destroy', dispose)
|
||||
try {
|
||||
if (closed())
|
||||
return result
|
||||
const ima = await loadImaSdk()
|
||||
if (closed())
|
||||
return result
|
||||
const utils = (art.constructor as typeof Artplayer).utils
|
||||
session = createSession(art, ima, utils, closed)
|
||||
if (closed()) {
|
||||
dispose()
|
||||
return result
|
||||
}
|
||||
if (typeof callback === 'function')
|
||||
await callback(session.context)
|
||||
return result
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
dispose()
|
||||
}
|
||||
catch (cleanupError) { console.error('VAST cleanup error:', cleanupError) }
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { ImaSdk } from '@alugha/ima'
|
||||
import type { RequestConfig } from './types'
|
||||
|
||||
export { loadImaSdk, Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||
|
||||
export function createRequest(ima: ImaSdk, field: 'adTagUrl' | 'adsResponse', value: string, config: RequestConfig) {
|
||||
const request = new ima.AdsRequest()
|
||||
request[field] = value
|
||||
// Preserve the historical SDK extension surface, including inherited config fields.
|
||||
const fields = request as unknown as Record<string, unknown>
|
||||
for (const key in config)
|
||||
fields[key] = config[key]
|
||||
return request
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import type { ImaSdk } from '@alugha/ima'
|
||||
import type Artplayer from 'artplayer'
|
||||
import type { Context, RequestConfig, Utilities } from './types'
|
||||
import { createRequest, Player, PlayerOptions } from './sdk'
|
||||
import { createContainer } from './view'
|
||||
|
||||
interface Owner {
|
||||
container: HTMLDivElement
|
||||
player: Player | null
|
||||
listeners: [string, EventListener][]
|
||||
playing: boolean
|
||||
released: boolean
|
||||
}
|
||||
|
||||
export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, closed: () => boolean) {
|
||||
const { $video, $player } = art.template
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings()
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
|
||||
adsRenderingSettings.enablePreloading = true
|
||||
const playerOptions = new PlayerOptions()
|
||||
let current: Owner | null = null
|
||||
let initializing = false
|
||||
let releasing = 0
|
||||
|
||||
const live = (owner: Owner) => current === owner && !owner.released && !closed()
|
||||
|
||||
function release(owner: Owner): void {
|
||||
if (current === owner)
|
||||
current = null
|
||||
owner.released = true
|
||||
owner.playing = false
|
||||
const player = owner.player
|
||||
owner.player = null
|
||||
const listeners = owner.listeners.splice(0)
|
||||
let failed = false
|
||||
let failure: unknown
|
||||
const attempt = (cleanup: () => void) => {
|
||||
try {
|
||||
cleanup()
|
||||
}
|
||||
catch (error) {
|
||||
if (!failed) {
|
||||
failed = true
|
||||
failure = error
|
||||
}
|
||||
else {
|
||||
console.error('VAST cleanup error:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
releasing++
|
||||
try {
|
||||
if (player) {
|
||||
for (const [name, callback] of listeners)
|
||||
attempt(() => player.removeEventListener(name, callback))
|
||||
attempt(() => player.destroy())
|
||||
}
|
||||
attempt(() => {
|
||||
if (owner.container.parentNode)
|
||||
owner.container.parentNode.removeChild(owner.container)
|
||||
})
|
||||
}
|
||||
finally {
|
||||
releasing--
|
||||
}
|
||||
if (failed)
|
||||
throw failure
|
||||
}
|
||||
|
||||
function init(): Player | null {
|
||||
if (closed() || releasing)
|
||||
return null
|
||||
if (initializing)
|
||||
throw new Error('VAST initialization is already in progress')
|
||||
if (current?.player)
|
||||
return current.player
|
||||
initializing = true
|
||||
let owner: Owner | undefined
|
||||
try {
|
||||
owner = { container: createContainer(utils), player: null, listeners: [], playing: false, released: false }
|
||||
current = owner
|
||||
if (!live(owner)) {
|
||||
release(owner)
|
||||
return null
|
||||
}
|
||||
$player.appendChild(owner.container)
|
||||
if (!live(owner)) {
|
||||
release(owner)
|
||||
return null
|
||||
}
|
||||
owner.player = new Player(ima, $video, owner.container, adsRenderingSettings, playerOptions)
|
||||
if (!live(owner)) {
|
||||
release(owner)
|
||||
return null
|
||||
}
|
||||
const allocated = owner
|
||||
for (const [name, playing] of [
|
||||
['AdContentPauseRequested', true],
|
||||
['AdContentResumeRequested', false],
|
||||
['AdStarted', true],
|
||||
['AdError', false],
|
||||
] as const) {
|
||||
const callback: EventListener = (event) => {
|
||||
if (!live(allocated))
|
||||
return
|
||||
if (name === 'AdError')
|
||||
console.error('VAST Ad Error:', (event as CustomEvent<unknown>).detail)
|
||||
allocated.playing = playing
|
||||
allocated.container.style.display = playing ? 'block' : 'none'
|
||||
}
|
||||
owner.listeners.push([name, callback])
|
||||
owner.player.addEventListener(name, callback)
|
||||
if (!live(owner)) {
|
||||
release(owner)
|
||||
return null
|
||||
}
|
||||
}
|
||||
return owner.player
|
||||
}
|
||||
catch (error) {
|
||||
if (owner) {
|
||||
try {
|
||||
release(owner)
|
||||
}
|
||||
catch (cleanupError) { console.error('VAST cleanup error:', cleanupError) }
|
||||
}
|
||||
throw error
|
||||
}
|
||||
finally {
|
||||
initializing = false
|
||||
}
|
||||
}
|
||||
|
||||
function play(field: 'adTagUrl' | 'adsResponse', value: string, config: RequestConfig): void {
|
||||
if (closed() || current?.playing)
|
||||
return
|
||||
const player = init()
|
||||
const owner = current
|
||||
if (!player || !owner)
|
||||
return
|
||||
const request = createRequest(ima, field, value, config)
|
||||
// Request constructors and config accessors may synchronously destroy or replace the session.
|
||||
if (live(owner) && owner.player === player)
|
||||
player.playAds(request)
|
||||
}
|
||||
|
||||
function destroy(): void {
|
||||
if (current)
|
||||
release(current)
|
||||
}
|
||||
|
||||
const context: Context = {
|
||||
art,
|
||||
playUrl: (url, config = {}) => play('adTagUrl', url, config),
|
||||
playRes: (response, config = {}) => play('adsResponse', response, config),
|
||||
init,
|
||||
ima,
|
||||
adsRenderingSettings,
|
||||
playerOptions,
|
||||
get imaPlayer() { return current?.player || null },
|
||||
get container() { return current?.container || null },
|
||||
}
|
||||
return { context, destroy }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { google, ImaSdk } from '@alugha/ima'
|
||||
import type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||
import type Artplayer from 'artplayer'
|
||||
|
||||
export type Utilities = Pick<typeof Artplayer.utils, 'createElement' | 'setStyles'>
|
||||
export type RequestConfig = Record<string, unknown>
|
||||
|
||||
export interface Context {
|
||||
art: Artplayer
|
||||
playUrl: (url: string, config?: RequestConfig) => void
|
||||
playRes: (response: string, config?: RequestConfig) => void
|
||||
init: () => Player | null
|
||||
ima: ImaSdk
|
||||
adsRenderingSettings: google.ima.AdsRenderingSettings
|
||||
playerOptions: PlayerOptions
|
||||
readonly imaPlayer: Player | null
|
||||
readonly container: HTMLDivElement | null
|
||||
}
|
||||
|
||||
export type Callback = (context: Context) => unknown
|
||||
export interface Result {
|
||||
name: 'artplayerPluginVast'
|
||||
destroy: () => void
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Utilities } from './types'
|
||||
|
||||
let nextId = 0
|
||||
|
||||
export function createContainer(utils: Utilities): HTMLDivElement {
|
||||
const container = utils.createElement('div')
|
||||
container.id = `art-vast-${Date.now()}-${++nextId}`
|
||||
utils.setStyles(container, {
|
||||
position: 'absolute',
|
||||
inset: '0',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: '150',
|
||||
backgroundColor: 'black',
|
||||
display: 'none',
|
||||
pointerEvents: 'auto',
|
||||
})
|
||||
return container
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": { "allowJs": false },
|
||||
"include": ["src/**/*.ts", "types/**/*.d.ts"]
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "PKG-VAST-03",
|
||||
"status": "doing",
|
||||
"sourceCommit": "d5e1fead",
|
||||
"checks": [
|
||||
{
|
||||
"command": "node --test refactor/.cache/vast03-before.test.mjs",
|
||||
"result": "15 expected failures on frozen workspace source; identical candidate assertions",
|
||||
"tests": 15,
|
||||
"failed": 15,
|
||||
"passed": 0,
|
||||
"log": {
|
||||
"file": "refactor/.cache/vast03-before.log",
|
||||
"sha256": "05bddd211578ae5086ce5b974d7598a1d0024bda69794026d730f8da02149058"
|
||||
},
|
||||
"fixture": {
|
||||
"file": "refactor/.cache/vast03-before.test.mjs",
|
||||
"sha256": "505d9a87e16138283ec2823b394eac6f0e640718a6cbf50af8a2dcfb3d611f49"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "node --test test/vast.test.js test/vast-lifecycle.test.js",
|
||||
"result": "pass",
|
||||
"tests": 60,
|
||||
"candidateLifecycle": 15,
|
||||
"log": {
|
||||
"file": "refactor/.cache/vast03-lifecycle-node-final.log",
|
||||
"sha256": "b1a22029079b702954cce52fc63a57203baa38bcfefbb0b7d60c4a7dc4c43408"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "yarn build artplayer-plugin-vast",
|
||||
"result": "pass",
|
||||
"formats": [
|
||||
"main",
|
||||
"legacy",
|
||||
"esm"
|
||||
],
|
||||
"log": {
|
||||
"file": "refactor/.cache/vast03-build.log",
|
||||
"sha256": "c32e975b99fdf2d88397ec528c2d4b954dab4cfdaedbf83c0f0f8f38672a9e65"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "yarn test:browser vast.spec.js",
|
||||
"result": "pass",
|
||||
"tests": 117,
|
||||
"stats": {
|
||||
"startTime": "2026-09-12T01:27:19.631Z",
|
||||
"duration": 49123.307,
|
||||
"expected": 117,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"scope": "Actual core 5.1.7/5.4.1/candidate, actual DOM/main media, controlled Glomex boundary in wrapper source builds. Not final bundled SDK runtime acceptance.",
|
||||
"log": {
|
||||
"file": "refactor/.cache/vast03-browser.log",
|
||||
"sha256": "848ea969ac9f30776817284eb488fdf9d660ae98bcd01d32dbaf8f70e04fdfb5"
|
||||
},
|
||||
"report": {
|
||||
"file": "refactor/.cache/vast03-browser-report.json",
|
||||
"sha256": "fd58f0b1ebcd1d2ec209bfd94e29f7387ef55d9ffdba8e145d7a22f72fbb079c"
|
||||
},
|
||||
"results": "refactor/.cache/vast03-browser-results"
|
||||
},
|
||||
{
|
||||
"command": "yarn ci:check",
|
||||
"result": "pass",
|
||||
"tests": {
|
||||
"unit": 832,
|
||||
"engineering": 14,
|
||||
"baseline": 54,
|
||||
"total": 900
|
||||
},
|
||||
"sourceTS": 274,
|
||||
"coreDeclarations": 37,
|
||||
"log": {
|
||||
"file": "refactor/.cache/vast03-ci.log",
|
||||
"sha256": "5e6bb801f578792debcd88ff0341922dd053f358b9f78f2d51839063132c0deb"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pending": [
|
||||
"Published versus workspace initialization decision",
|
||||
"Published id/$container aliases",
|
||||
"Public declaration and CommonJS namespace reconciliation in04",
|
||||
"Real IMA and package distribution validation in05/06"
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"file": "package.json",
|
||||
"sha256LF": "fce3d3a49ba5bb24fd1ae2191e4e13b679395cf50df5d26b355904dd9b31caf2"
|
||||
},
|
||||
{
|
||||
"file": "yarn.lock",
|
||||
"sha256LF": "9bd01cf6394ece742aecb0ecc2a2aa563012de2c16f28141ed03dd37e17f8717"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/package.json",
|
||||
"sha256LF": "dd4c196a8c94b0037bc156e428300b030d40b6f015f3ad165ef48aa733149052"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/tsconfig.json",
|
||||
"sha256LF": "712a3fa32ed57692d16bf854a0e77ffaecd04236efa0f557905aab7291e0aef6"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/src/index.ts",
|
||||
"sha256LF": "c17455be188ecb23161729234faa1b4309a3b60f08465509e873fee2f1dd21d6"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/src/sdk.ts",
|
||||
"sha256LF": "aaff7c1e4a31ff99261b045648663caa46f66b5a25ad129e5fc929facaf1ff89"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/src/session.ts",
|
||||
"sha256LF": "472ad363276711dd79c375e5cdfe44cc42dd7f781a04974442f2599998c8cbc2"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/src/types.ts",
|
||||
"sha256LF": "0042303fd4206467724a7c5abda633436ac30a3d1139b24609e1a7dd1e890b23"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/src/view.ts",
|
||||
"sha256LF": "c36008cdf2e6b7818b166deb4842ce8d405272486e2c07b6226e8e2905640328"
|
||||
},
|
||||
{
|
||||
"file": "test/helpers/vast-sdk.js",
|
||||
"sha256LF": "f8bc792ef16da9396bafefaf89f1b53b6254bf263d0c3019b87ee188eac35bd1"
|
||||
},
|
||||
{
|
||||
"file": "test/helpers/vast.js",
|
||||
"sha256LF": "ea985ca97946645a8b6fc76c9d69ec4fc12f959ab175402cd34e93bc81c14ce9"
|
||||
},
|
||||
{
|
||||
"file": "test/vast.test.js",
|
||||
"sha256LF": "b02c12c0440540f4f13929bbdcb3607621a42fdc6f29debbc912189c3aa025a6"
|
||||
},
|
||||
{
|
||||
"file": "test/vast-lifecycle.test.js",
|
||||
"sha256LF": "5b6eb97ee038755046fdc31b4fa12e4a3e20903deafc208d6378f7e5de61dfbc"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/vast.spec.js",
|
||||
"sha256LF": "7cef5364837e3e0b4818ecfa954c1e4214ac6627be78ee85bd32cdb479b37f62"
|
||||
}
|
||||
],
|
||||
"artifacts": [
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.js",
|
||||
"sha256": "874803ec726f04649bb636c1376de9e038754310ab0016a22da44f189b7a5ce0"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.legacy.js",
|
||||
"sha256": "7d4e0fdb95e6881f6b6379a7c36599fb5087cf9122253718a955931077c9f420"
|
||||
},
|
||||
{
|
||||
"file": "packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.mjs",
|
||||
"sha256": "7650fb0d42e8bb7049d201859187d28f69b1868ac7e25539a7575ee50ae1b2d7"
|
||||
}
|
||||
],
|
||||
"dependency": {
|
||||
"package": "@alugha/ima",
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
"purpose": "Public Glomex SDK declaration dependency; runtime loader remains existing Glomex implementation",
|
||||
"installation": {
|
||||
"file": "refactor/.cache/vast03-dependency.log",
|
||||
"sha256": "ad5ace8a5a596d521f65ab454793d3e3d2cce9b774310ce9082e232fd8d1bf95"
|
||||
},
|
||||
"consumerTypes": {
|
||||
"source": "import vast from \"artplayer-plugin-vast\"; vast(({imaPlayer})=>{void imaPlayer});",
|
||||
"results": [
|
||||
{
|
||||
"compiler": "5.9.3",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": []
|
||||
},
|
||||
{
|
||||
"compiler": "4.3.5",
|
||||
"mode": "node10-commonjs",
|
||||
"diagnostics": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# PKG-VAST-03 生命周期实现检查点
|
||||
|
||||
起点d5e1fead。原index.js迁为5个严格TS模块:入口、SDK/request边界、session所有权、
|
||||
DOM视图及内部类型。实际职责/依赖/时序见
|
||||
[包内架构](../../packages/artplayer-plugin-vast/ARCHITECTURE.md)。
|
||||
|
||||
核心destroy在SDK加载前订阅;加载或callback完成后不会再创建终止实例的广告。
|
||||
session销毁时先使旧owner失效,再逐项释放监听/SDK/DOM,异常不阻断剩余清理;
|
||||
构造和事件注册失败回滚;旧事件不能污染新session;活动广告显式destroy后可重建。
|
||||
构造/订阅/销毁重入及request配置getter引发销毁/替换也有身份检查。
|
||||
|
||||
15项候选生命周期断言配合45项已有行为/历史观察,60项Node通过;另在冻结工作区
|
||||
执行同一候选断言记录修复前失败。三格式正式构建成功,117项真实浏览器测试通过,
|
||||
包含三核心/三引擎的新增终止、回调失败、旧事件与显式重建路径。SDK边界仍受控,
|
||||
不代表正式bundle中的实际IMA执行;该部分留给05/06。
|
||||
|
||||
直接固定依赖@alugha/ima2.1.0(MIT),补齐Glomex声明引用但未作为运行依赖提供的
|
||||
类型链;保持Glomex1.21.2与其实际SDK加载器,新增依赖没有直接运行时import。
|
||||
Yarn仅新增该依赖和相应锁条目;包的tsconfig纳入严格检查,未用skipLibCheck掩盖错误。
|
||||
初次lint发现单行try格式不符后修正,没有通过忽略整个文件避开检查。
|
||||
|
||||
**本任务仍doing**:[初始化决策](../vast-compatibility-decision.md) 展示npm发布版
|
||||
eager与未发布工作区lazy的不可同时满足条件。当前默认行为暂保持工作区,尚未恢复
|
||||
发布id/$container,因此不能声称03兼容验收完成。拟定方案默认保持npm1.0.0行为、
|
||||
另提供显式工作区兼容选择;尚未实现,等待用户确认。Ads批准不扩展到VAST。
|
||||
|
||||
公开类型同步误声明、历史CJS.default入口仍由04处理。新ID增加同毫秒区分后缀,保留
|
||||
workspace art-vast-前缀;发布ID规则与上面的初始化决策一起处理。SDK-07及VAST相关
|
||||
风险继续open,候选可控修复证据与实际供应商/发布验收分开记录。
|
||||
|
||||
执行结果、输入和产物指纹见 [验证记录](../baselines/vast-lifecycle-validation.json)。
|
||||
本批作为03未完成检查点独立本地提交;不push/tag/publish。回退该提交恢复旧VAST
|
||||
源码、依赖、构建输出和测试接入;01/02不可变基线与历史缺陷证据保留。
|
||||
|
||||
最终完整本地CI900项通过(832单元、14工程、54基线),274个生产TS检查,37份核心
|
||||
声明无漂移;15个候选断言在旧工作区均失败,修复后全部通过。TS5.9.3/4.3.5当前
|
||||
最小公开消费者的缺失类型错误均消除,但同步返回误声明仍开放。
|
||||
+3
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 217 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 132 / doing 5 / blocked 0 / done 80 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 131 / doing 6 / blocked 0 / done 80 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| PKG-VAST-01 | artplayer-plugin-vast<br>核对包契约与历史用法 | BASE-05 | 异步工厂、callback context、playUrl/playRes/init 与 SDK 版本;实际 npm 1.0.0 与未发布 1.2.0、SDK 1.21.0/1.21.2 的60成员归档和发布关联核心5.1.7 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||
| PKG-VAST-02 | artplayer-plugin-vast<br>建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态;发布 id/$container/eager 与工作区 lazy/config 覆盖、callback拒绝、加载中销毁、同毫秒多实例与晚到事件 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||
| PKG-VAST-03 | artplayer-plugin-vast<br>整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo |
|
||||
| PKG-VAST-03 | artplayer-plugin-vast<br>整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | doing |
|
||||
| PKG-VAST-04 | artplayer-plugin-vast<br>迁移自有源码和公开类型 | PKG-VAST-03, ENG-04, ENG-06, CORE-07 | IMA/context/Promise 真实类型,外部 SDK 动态对象限定边界;修复 @alugha/ima 声明依赖链,保留 export= 和 require.default 消费;同步错误声明的兼容决策单列 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
||||
| PKG-VAST-05 | artplayer-plugin-vast<br>验证新旧核心和组合 | PKG-VAST-04, CORE-22 | 官方测试广告或受控 SDK 环境,错误后主视频状态恢复;核验真实5.1.7/5.4.1/候选核心,VAST VPN外部脚本例外逐项记录,不将受控SDK当作实际IMA验收 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-VAST-06 | artplayer-plugin-vast<br>验证分发并同步文档 | PKG-VAST-05, ENG-07 | vast.js、SDK 资源、声明消费和独立版本记录;核验实际发布 namespace default、历史深路径、ESM和准确声明,版本按政策2.0.0由REL-09统一处理 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
@@ -491,3 +491,4 @@
|
||||
- PKG-ADS-05: [记录](changes/2026-09-12-PKG-ADS-05-browser.md) [记录](baselines/ads-ui-visibility-validation.json)
|
||||
- PKG-VAST-01: [记录](baselines/vast-contract.md) [记录](baselines/vast-release.json) [记录](changes/2026-09-12-PKG-VAST-01-contract.md) [记录](baselines/vast-contract-validation.json)
|
||||
- PKG-VAST-02: [记录](changes/2026-09-12-PKG-VAST-02-tests.md) [记录](baselines/vast-behavior-validation.json) [记录](baselines/vast-core.json) [记录](vast-validation.md)
|
||||
- PKG-VAST-03: [记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) [记录](baselines/vast-lifecycle-validation.json) [记录](vast-compatibility-decision.md)
|
||||
@@ -1,5 +1,17 @@
|
||||
# 进度与证据
|
||||
|
||||
## 当前实施:VAST-03 TS拆分与生命周期修复
|
||||
|
||||
原入口拆成5个严格TS模块,处理核心终止、显式广告重建、SDK/DOM回滚与晚到/重入回调。
|
||||
15项候选生命周期断言在旧工作区全部失败,修复后60项Node通过;三格式构建成功,
|
||||
117项三核心/三引擎浏览器wrapper测试通过。完整CI900项通过、274个生产TS严格检查。
|
||||
补齐@alugha/ima2.1.0类型依赖,两个编译器不再出现SDK缺失类型错误。
|
||||
初始化行为存在真实发布/工作区冲突,已给出 [具体取舍](vast-compatibility-decision.md),
|
||||
确认前仍保持工作区默认,03保持doing;Google IMA及公开类型/分发完整验收未完成。
|
||||
当前217项:80 done、6 doing、131 todo。此批独立提交未完成检查点,见
|
||||
[实施记录](changes/2026-09-12-PKG-VAST-03-lifecycle.md) 和
|
||||
[验证证据](baselines/vast-lifecycle-validation.json)。
|
||||
|
||||
## 最新完成:VAST-02 行为与生命周期回归
|
||||
|
||||
45项Node测试通过,覆盖当前源码及两套冻结历史源码;实际核心5.1.7的197成员已归档。
|
||||
|
||||
+12
-6
@@ -702,7 +702,7 @@
|
||||
"PKG-VAST-05"
|
||||
],
|
||||
"evidence": [
|
||||
"packages/artplayer-plugin-vast/src/index.js",
|
||||
"packages/artplayer-plugin-vast/src/sdk.ts",
|
||||
"refactor/baselines/vast-contract.md",
|
||||
"refactor/baselines/vast-release.json",
|
||||
"refactor/changes/2026-09-12-PKG-VAST-01-contract.md",
|
||||
@@ -3181,7 +3181,8 @@
|
||||
"refactor/baselines/vast-contract.md",
|
||||
"refactor/baselines/vast-release.json",
|
||||
"refactor/changes/2026-09-12-PKG-VAST-01-contract.md",
|
||||
"refactor/baselines/vast-contract-validation.json"
|
||||
"refactor/baselines/vast-contract-validation.json",
|
||||
"refactor/vast-compatibility-decision.md"
|
||||
],
|
||||
"compatibleResolution": "Restore published id/$container access and reconcile eager non-null Player with lazy workspace usage using explicit consumer evidence.",
|
||||
"closureCriteria": "Published and workspace consumer fixtures cover all callback fields and initialization timing; any irreconcilable behavior has a concrete decision rather than implicit waiver."
|
||||
@@ -3199,10 +3200,13 @@
|
||||
"refactor/baselines/vast-contract.md",
|
||||
"refactor/baselines/vast-release.json",
|
||||
"refactor/changes/2026-09-12-PKG-VAST-01-contract.md",
|
||||
"refactor/baselines/vast-contract-validation.json"
|
||||
"refactor/baselines/vast-contract-validation.json",
|
||||
"refactor/baselines/vast-lifecycle-validation.json",
|
||||
"refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md"
|
||||
],
|
||||
"compatibleResolution": "Provide accurate Promise/context/IMA types and a self-contained installed declaration chain while checking legacy export= and consumers.",
|
||||
"closureCriteria": "Strict isolated package consumers pass without skipLibCheck; synchronous Result inference differences are reproduced and resolved or separately approved. Ads approval does not apply."
|
||||
"closureCriteria": "Strict isolated package consumers pass without skipLibCheck; synchronous Result inference differences are reproduced and resolved or separately approved. Ads approval does not apply.",
|
||||
"workspaceState": "Direct @alugha/ima2.1.0 removes the two TS2307 diagnostics in TS5.9.3 and4.3.5; public synchronous Result mismatch and isolated packaged declaration validation remain04/06."
|
||||
},
|
||||
{
|
||||
"id": "VAST-LIFE-01",
|
||||
@@ -3222,11 +3226,13 @@
|
||||
"refactor/changes/2026-09-12-PKG-VAST-02-tests.md",
|
||||
"refactor/baselines/vast-behavior-validation.json",
|
||||
"refactor/baselines/vast-core.json",
|
||||
"refactor/vast-validation.md"
|
||||
"refactor/vast-validation.md",
|
||||
"refactor/baselines/vast-lifecycle-validation.json",
|
||||
"refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md"
|
||||
],
|
||||
"compatibleResolution": "Reproduce pending SDK/callback destruction, errors, duplicate IDs and stale ad events before adding compatible cleanup and state ownership.",
|
||||
"closureCriteria": "Tests prove cleanup during load/callback rejection/core destruction and distinguish explicit plugin recreation from terminal core destruction; vendor media restoration is separately verified.",
|
||||
"workspaceState": "45 Node tests include 16 frozen historical observations across 10 lifecycle/error categories. Real browser core destruction plus late SDK resolution leaves a newly allocated recorder in the detached player across 5.1.7/5.4.1/candidate. Google IMA allocation itself is not simulated as evidence; exact wrapper SDK boundary is controlled. All production fixes remain PKG-VAST-03 work."
|
||||
"workspaceState": "45 Node tests include 16 frozen historical observations across 10 lifecycle/error categories. Real browser core destruction plus late SDK resolution leaves a newly allocated recorder in the detached player across 5.1.7/5.4.1/candidate. Google IMA allocation itself is not simulated as evidence; exact wrapper SDK boundary is controlled. All production fixes remain PKG-VAST-03 work. PKG-VAST-03 checkpoint: 15 candidate lifecycle assertions fail on frozen workspace and pass after TS ownership changes; 117 real browser wrapper checks pass with controlled SDK. Risk stays open pending full compatibility and actual vendor acceptance."
|
||||
},
|
||||
{
|
||||
"id": "VAST-DIST-01",
|
||||
|
||||
+6
-2
@@ -2692,11 +2692,15 @@
|
||||
"CORE-10",
|
||||
"CORE-13"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "doing",
|
||||
"risk": "H",
|
||||
"deliverable": "SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分",
|
||||
"acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-12-PKG-VAST-03-lifecycle.md",
|
||||
"baselines/vast-lifecycle-validation.json",
|
||||
"vast-compatibility-decision.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-VAST-04",
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
{
|
||||
"name": "artplayer-plugin-vast",
|
||||
"declaredRuntimeDependencies": {
|
||||
"@alugha/ima": "2.1.0",
|
||||
"@glomex/vast-ima-player": "^1.21.2"
|
||||
},
|
||||
"resolvedRuntimeDependencies": [
|
||||
@@ -175,6 +176,14 @@
|
||||
"installedVersion": "1.21.2",
|
||||
"manifestLicense": "Apache-2.0",
|
||||
"licenseEvidence": "Installed package manifest claim; bundled notice and transitive/license review remain with the owning package."
|
||||
},
|
||||
{
|
||||
"name": "@alugha/ima",
|
||||
"range": "2.1.0",
|
||||
"lockedVersion": "2.1.0",
|
||||
"installedVersion": "2.1.0",
|
||||
"manifestLicense": "MIT",
|
||||
"licenseEvidence": "Installed package manifest and LICENSE.md; direct dependency supplies the public declaration chain referenced by Glomex."
|
||||
}
|
||||
],
|
||||
"developmentDependencies": {}
|
||||
@@ -1118,7 +1127,9 @@
|
||||
"PKG-VAST-05"
|
||||
],
|
||||
"sourceFiles": [
|
||||
"packages/artplayer-plugin-vast/src/index.js"
|
||||
"packages/artplayer-plugin-vast/src/index.ts",
|
||||
"packages/artplayer-plugin-vast/src/sdk.ts",
|
||||
"packages/artplayer-plugin-vast/src/session.ts"
|
||||
],
|
||||
"contract": "@glomex/vast-ima-player loadImaSdk loads external IMA; preserve event/content/ad state and teardown, do not equate mocks with vendor service acceptance.",
|
||||
"validationStatus": "Source integration observed; complete real SDK/service/device matrix not yet verified.",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# VAST 初始化兼容决策:待用户选择
|
||||
|
||||
来源:[真实发布契约](baselines/vast-contract.md);已可重跑的
|
||||
`vast-contract.test.mjs`及`test/vast.test.js`固定以下矛盾:
|
||||
|
||||
| 同一次 callback 开始时 | npm1.0.0 | 未发布工作区1.2.0 |
|
||||
| --- | --- | --- |
|
||||
| imaPlayer | 已构造、非null | null,直到init/playUrl/playRes |
|
||||
| DOM | 已挂载$container,并提供id | 不存在容器,container getter为null |
|
||||
| 设置 | IMA默认值 | 默认启用preloading及restoreCustomPlaybackStateOnAdBreakComplete |
|
||||
|
||||
实际发布用户可以直接写 `({ imaPlayer }) => imaPlayer.addEventListener(...)`。
|
||||
工作区用户可以先判断`context.imaPlayer === null`并修改`playerOptions`,然后等待
|
||||
用户操作调用`init()`。在同一默认调用中无法同时保留非null和null,以及相反初始化时机。
|
||||
添加别名或getter也无法同时满足两种值;按callback源码猜测用户版本不可取。
|
||||
|
||||
## 推荐的具体处置(尚未实现)
|
||||
|
||||
优先保持实际npm1.0.0默认行为:回调前初始化、提供id/$container,SDK默认设置保持
|
||||
发布语义;保留workspace新增的init/container/settings等字段作为扩展。
|
||||
|
||||
确实依赖未发布1.2.0惰性行为的代码,拟通过新的可选第二参数明确选择该兼容模式:
|
||||
|
||||
```js
|
||||
// npm旧用法保持原样
|
||||
artplayerPluginVast(({ imaPlayer, $container, id }) => {
|
||||
imaPlayer.addEventListener('AdStarted', onAdStarted)
|
||||
})
|
||||
|
||||
// 未发布工作区1.2.0的初始化时机与默认设置保留在显式模式
|
||||
artplayerPluginVast((context) => {
|
||||
context.playerOptions.autoResize = false
|
||||
button.onclick = () => context.playUrl(adTag)
|
||||
}, { compatibility: 'workspace-1.2' })
|
||||
```
|
||||
|
||||
这意味着依赖未发布1.2.0默认惰性的代码需要增加一个参数。普通npm1.0.0用户保持
|
||||
原调用;这不是声称两种相反语义完全兼容。第二参数仅为待确认方案,当前生产代码
|
||||
尚未新增它;类型误声明、CJS.default和分发路径仍各自单独验证。
|
||||
|
||||
## 当前检查点
|
||||
|
||||
生命周期与资源修复不依赖该选择,已经推进;默认初始化暂保持工作区行为,不把
|
||||
PKG-VAST-03或VAST-CONTEXT-01标完成。用户针对Ads的类型推导批准不适用于本决策。
|
||||
需要用户确认是否按推荐方案优先实际发布默认行为;也可指定其他取舍。
|
||||
@@ -4,6 +4,14 @@
|
||||
[实际契约](baselines/vast-contract.md)、[VAST/SDK归档](baselines/vast-release.json)
|
||||
和 [核心5.1.7归档](baselines/vast-core.json)。工作区1.2.0不是npm发布版本。
|
||||
|
||||
03检查点:新增`test/vast-lifecycle.test.js`的15项候选修复断言,冻结工作区全部失败、
|
||||
当前5个TS模块全部通过;现有测试共60项Node、117项浏览器通过。覆盖终止/回调失败、
|
||||
初始化回滚、活动广告重建、旧事件、配置getter和SDK同步重入;完整CI900项通过。
|
||||
该文件已纳入`yarn test:vast`和`test:unit`。实际资源所有权见
|
||||
[包内架构](../packages/artplayer-plugin-vast/ARCHITECTURE.md);
|
||||
[初始化冲突](vast-compatibility-decision.md)未决定,03仍doing。以下缺陷清单保留历史
|
||||
来源,不代表候选实现仍包含这些已获可控修复证据的问题;真实IMA验收仍待05。
|
||||
|
||||
## 文件与执行
|
||||
|
||||
- `test/helpers/vast-sdk.js`:可在Node和浏览器使用的SDK记录器,控制加载、构造、
|
||||
|
||||
@@ -165,5 +165,62 @@ for (const core of ['published-5.1.7', 'published', 'candidate']) {
|
||||
}))).toEqual({ calls: 1, players: 1, destroys: 0, connected: false, url: '/late.xml' })
|
||||
})
|
||||
}
|
||||
else {
|
||||
test(`${label}: candidate suppresses late SDK initialization after real core destruction`, async ({ page }, testInfo) => {
|
||||
await setup(page, core, implementation, testInfo, true)
|
||||
const state = await page.evaluate(async () => {
|
||||
let calls = 0
|
||||
const registration = window.art.plugins.add(window.artplayerPluginVast(() => calls++))
|
||||
window.art.destroy()
|
||||
window.vastSdk.resolveLoad()
|
||||
await registration
|
||||
return { calls, players: window.vastSdk.state.players.length }
|
||||
})
|
||||
expect(state).toEqual({ calls: 0, players: 0 })
|
||||
})
|
||||
|
||||
test(`${label}: candidate isolates stale events and terminates recreated ads on core destroy`, async ({ page }, testInfo) => {
|
||||
await setup(page, core, implementation, testInfo)
|
||||
await page.evaluate(async () => {
|
||||
await window.art.plugins.add(window.artplayerPluginVast((context) => {
|
||||
window.vastContext = context
|
||||
}))
|
||||
window.vastContext.playUrl('/one.xml')
|
||||
const first = window.vastContext.imaPlayer
|
||||
window.lateVastEvents = [...first.listeners.values()].flatMap(values => [...values])
|
||||
first.emit('AdStarted')
|
||||
})
|
||||
const container = page.locator('[id^="art-vast-"]')
|
||||
await expect(container).toBeVisible()
|
||||
await page.evaluate(() => {
|
||||
window.art.plugins.artplayerPluginVast.destroy()
|
||||
window.vastContext.playUrl('/two.xml')
|
||||
for (const callback of window.lateVastEvents) callback({ detail: 'late' })
|
||||
})
|
||||
await expect(container).toBeHidden()
|
||||
expect(await page.evaluate(() => window.vastSdk.state.players.map(player => player.requests.length))).toEqual([1, 1])
|
||||
await page.evaluate(() => {
|
||||
window.art.destroy()
|
||||
window.vastContext.playUrl('/after-core-destroy.xml')
|
||||
})
|
||||
expect(await page.evaluate(() => window.vastContext.init())).toBe(null)
|
||||
expect(await page.evaluate(() => window.vastSdk.state.players.map(player => player.destroyCalls))).toEqual([1, 1])
|
||||
await expect(container).toHaveCount(0)
|
||||
})
|
||||
|
||||
test(`${label}: candidate callback rejection cleans allocated SDK and DOM without destroying the core`, async ({ page }, testInfo) => {
|
||||
await setup(page, core, implementation, testInfo)
|
||||
const result = await page.evaluate(async () => {
|
||||
const failure = new Error('callback rejected')
|
||||
const registration = window.art.plugins.add(window.artplayerPluginVast((context) => {
|
||||
context.init()
|
||||
return Promise.reject(failure)
|
||||
}))
|
||||
return { sameError: await registration.catch(error => error === failure), destroys: window.vastSdk.state.players[0].destroyCalls, coreDestroyed: window.art.isDestroy }
|
||||
})
|
||||
expect(result).toEqual({ sameError: true, destroys: 1, coreDestroyed: false })
|
||||
await expect(page.locator('[id^="art-vast-"]')).toHaveCount(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ export function createVastSdk(options = {}) {
|
||||
this.listeners = new Map()
|
||||
this.destroyCalls = 0
|
||||
state.players.push(this)
|
||||
state.onConstruct?.(this)
|
||||
}
|
||||
|
||||
addEventListener(name, callback) {
|
||||
@@ -32,6 +33,7 @@ export function createVastSdk(options = {}) {
|
||||
if (!this.listeners.has(name))
|
||||
this.listeners.set(name, new Set())
|
||||
this.listeners.get(name).add(callback)
|
||||
state.onListen?.(this)
|
||||
}
|
||||
|
||||
removeEventListener(name, callback) {
|
||||
@@ -52,6 +54,7 @@ export function createVastSdk(options = {}) {
|
||||
this.destroyCalls++
|
||||
if (state.destroyError)
|
||||
throw state.destroyError
|
||||
state.onDestroy?.(this)
|
||||
this.listeners.clear()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
import assert from 'node:assert/strict'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Candidate SDK lifecycle acceptance uses Node's runner.
|
||||
import test from 'node:test'
|
||||
import { deferred, vastEnvironment, vastImplementations } from './helpers/vast.js'
|
||||
|
||||
const candidates = (await vastImplementations()).filter(item => !item.historical)
|
||||
|
||||
for (const implementation of candidates) {
|
||||
const { name } = implementation
|
||||
test(`${name}: core destruction releases SDK and makes escaped methods inert`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
const host = env.host()
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
value.playUrl('/first.xml')
|
||||
})(host.art)
|
||||
const player = context.imaPlayer
|
||||
host.art.destroy()
|
||||
result.destroy()
|
||||
assert.equal(context.init(), null)
|
||||
context.playUrl('/late.xml')
|
||||
context.playRes('late response')
|
||||
assert.equal(player.destroyCalls, 1)
|
||||
assert.equal(player.requests.length, 1)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
assert.equal(context.imaPlayer, null)
|
||||
assert.equal(context.container, null)
|
||||
})
|
||||
|
||||
test(`${name}: destruction while SDK is loading suppresses callback and allocation`, async () => {
|
||||
const env = vastEnvironment(implementation, { deferLoad: true })
|
||||
const host = env.host()
|
||||
let calls = 0
|
||||
const attaching = env.factory(() => calls++)(host.art)
|
||||
assert.equal(host.listeners.get('destroy').size, 1)
|
||||
host.art.destroy()
|
||||
env.resolveLoad()
|
||||
const result = await attaching
|
||||
result.destroy()
|
||||
assert.equal(calls, 0)
|
||||
assert.equal(env.state.players.length, 0)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
})
|
||||
|
||||
test(`${name}: already destroyed hosts do not load SDK or subscribe`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
const host = env.host()
|
||||
host.art.destroy()
|
||||
await env.factory(() => assert.fail('Unexpected callback'))(host.art)
|
||||
assert.equal(env.state.loads, 0)
|
||||
assert.equal(host.listeners.size, 0)
|
||||
})
|
||||
|
||||
test(`${name}: SDK rejection unregisters the pending core listener`, async () => {
|
||||
const env = vastEnvironment(implementation, { deferLoad: true })
|
||||
const host = env.host()
|
||||
const attaching = env.factory()(host.art)
|
||||
const failure = new Error('load failure')
|
||||
const rejected = assert.rejects(attaching, error => error === failure)
|
||||
env.rejectLoad(failure)
|
||||
await rejected
|
||||
assert.equal(host.listeners.get('destroy').size, 0)
|
||||
})
|
||||
|
||||
test(`${name}: callback rejection reclaims its SDK and preserves the original error over cleanup failure`, async () => {
|
||||
const failure = new Error('callback failure')
|
||||
for (const destroyError of [null, new Error('cleanup failure')]) {
|
||||
const env = vastEnvironment(implementation, { destroyError })
|
||||
const host = env.host()
|
||||
let context
|
||||
await assert.rejects(env.factory((value) => {
|
||||
context = value
|
||||
context.init()
|
||||
throw failure
|
||||
})(host.art), error => error === failure)
|
||||
assert.equal(env.state.players[0].destroyCalls, 1)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
assert.equal(host.listeners.get('destroy').size, 0)
|
||||
assert.equal(context.init(), null)
|
||||
if (destroyError)
|
||||
assert.equal(env.state.errors[0][1], destroyError)
|
||||
}
|
||||
})
|
||||
|
||||
test(`${name}: a callback resumed after core destroy cannot request or recreate ads`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
const host = env.host()
|
||||
const started = deferred()
|
||||
const finish = deferred()
|
||||
const attaching = env.factory(async (context) => {
|
||||
context.init()
|
||||
started.resolve()
|
||||
await finish.promise
|
||||
context.playUrl('/late.xml')
|
||||
assert.equal(context.init(), null)
|
||||
})(host.art)
|
||||
await started.promise
|
||||
host.art.destroy()
|
||||
finish.resolve()
|
||||
await attaching
|
||||
assert.equal(env.state.players.length, 1)
|
||||
assert.equal(env.state.players[0].destroyCalls, 1)
|
||||
assert.equal(env.state.players[0].requests.length, 0)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
})
|
||||
|
||||
test(`${name}: constructor and event-registration failures roll back and allow explicit retry`, async () => {
|
||||
for (const field of ['constructError', 'listenError']) {
|
||||
const failure = new Error(field)
|
||||
const env = vastEnvironment(implementation, { [field]: failure })
|
||||
const host = env.host()
|
||||
let context
|
||||
await env.factory((value) => {
|
||||
context = value
|
||||
})(host.art)
|
||||
assert.throws(() => context.init(), error => error === failure)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
assert.equal(context.imaPlayer, null)
|
||||
assert.equal(context.container, null)
|
||||
if (field === 'listenError')
|
||||
assert.equal(env.state.players[0].destroyCalls, 1)
|
||||
env.state[field] = null
|
||||
const player = context.init()
|
||||
assert.equal(player.listeners.size, 4)
|
||||
assert.equal(host.parent.children.length, 1)
|
||||
}
|
||||
})
|
||||
|
||||
test(`${name}: same-millisecond instances use distinct IDs and clean up independently`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
const contexts = []
|
||||
const attach = env.factory((context) => {
|
||||
context.init()
|
||||
contexts.push(context)
|
||||
})
|
||||
const one = env.host()
|
||||
const two = env.host()
|
||||
const [result] = await Promise.all([attach(one.art), attach(two.art)])
|
||||
assert.notEqual(contexts[0].container.id, contexts[1].container.id)
|
||||
result.destroy()
|
||||
assert.equal(one.parent.children.length, 0)
|
||||
assert.equal(two.parent.children.length, 1)
|
||||
contexts[1].playUrl('/other.xml')
|
||||
assert.equal(contexts[1].imaPlayer.requests.length, 1)
|
||||
})
|
||||
|
||||
test(`${name}: explicit destroy during an active ad clears suppression for a new session`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
})(env.host().art)
|
||||
context.playUrl('/first.xml')
|
||||
context.imaPlayer.emit('AdStarted')
|
||||
result.destroy()
|
||||
context.playUrl('/second.xml')
|
||||
assert.equal(env.state.players.length, 2)
|
||||
assert.equal(context.imaPlayer.requests[0].adTagUrl, '/second.xml')
|
||||
})
|
||||
|
||||
test(`${name}: saved old SDK callbacks are inert both after cleanup and after recreation`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
})(env.host().art)
|
||||
const first = context.init()
|
||||
const late = [...first.listeners.values()].flatMap(listeners => [...listeners])
|
||||
result.destroy()
|
||||
for (const callback of late) assert.doesNotThrow(() => callback({ detail: 'late' }))
|
||||
context.init()
|
||||
for (const callback of late) callback({ detail: 'late' })
|
||||
assert.equal(context.container.style.display, 'none')
|
||||
context.playUrl('/fresh.xml')
|
||||
assert.equal(context.imaPlayer.requests.length, 1)
|
||||
assert.equal(env.state.errors.length, 0)
|
||||
})
|
||||
|
||||
test(`${name}: SDK destroy failure still clears references and DOM and is not retried accidentally`, async () => {
|
||||
const failure = new Error('destroy failure')
|
||||
const env = vastEnvironment(implementation, { destroyError: failure })
|
||||
const host = env.host()
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
})(host.art)
|
||||
const player = context.init()
|
||||
assert.throws(() => result.destroy(), error => error === failure)
|
||||
assert.equal(context.container, null)
|
||||
assert.equal(context.imaPlayer, null)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
assert.doesNotThrow(() => result.destroy())
|
||||
assert.equal(player.destroyCalls, 1)
|
||||
env.state.destroyError = null
|
||||
assert.notEqual(context.init(), player)
|
||||
})
|
||||
|
||||
test(`${name}: a request config accessor destroying the core prevents playAds`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
const host = env.host()
|
||||
let context
|
||||
await env.factory((value) => {
|
||||
context = value
|
||||
})(host.art)
|
||||
context.playUrl('/cancelled.xml', { get extra() {
|
||||
host.art.destroy()
|
||||
return 1
|
||||
} })
|
||||
assert.equal(env.state.players[0].requests.length, 0)
|
||||
assert.equal(env.state.players[0].destroyCalls, 1)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
})
|
||||
|
||||
test(`${name}: a request accessor replacing the session cannot dispatch through its stale player`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
})(env.host().art)
|
||||
context.playUrl('/stale.xml', { get extra() {
|
||||
result.destroy()
|
||||
context.init()
|
||||
return 1
|
||||
} })
|
||||
assert.equal(env.state.players.length, 2)
|
||||
assert.equal(env.state.players[0].requests.length, 0)
|
||||
assert.equal(env.state.players[1].requests.length, 0)
|
||||
context.playUrl('/fresh.xml')
|
||||
assert.equal(env.state.players[1].requests[0].adTagUrl, '/fresh.xml')
|
||||
})
|
||||
|
||||
test(`${name}: destruction reentered from SDK construction or subscription reclaims late resources`, async () => {
|
||||
for (const hook of ['onConstruct', 'onListen']) {
|
||||
const env = vastEnvironment(implementation)
|
||||
const host = env.host()
|
||||
let context
|
||||
await env.factory((value) => {
|
||||
context = value
|
||||
})(host.art)
|
||||
env.state[hook] = () => host.art.destroy()
|
||||
assert.equal(context.init(), null)
|
||||
assert.equal(env.state.players[0].destroyCalls, 1)
|
||||
assert.equal(host.parent.children.length, 0)
|
||||
assert.equal(context.imaPlayer, null)
|
||||
}
|
||||
})
|
||||
|
||||
test(`${name}: SDK destroy reentrancy cannot create a replacement until cleanup finishes`, async () => {
|
||||
const env = vastEnvironment(implementation)
|
||||
let context
|
||||
const result = await env.factory((value) => {
|
||||
context = value
|
||||
})(env.host().art)
|
||||
context.init()
|
||||
env.state.onDestroy = () => {
|
||||
assert.equal(context.init(), null)
|
||||
context.playUrl('/during-cleanup.xml')
|
||||
}
|
||||
result.destroy()
|
||||
assert.equal(env.state.players.length, 1)
|
||||
env.state.onDestroy = null
|
||||
context.playUrl('/after-cleanup.xml')
|
||||
assert.equal(env.state.players.length, 2)
|
||||
assert.equal(context.imaPlayer.requests.length, 1)
|
||||
})
|
||||
}
|
||||
@@ -155,6 +155,11 @@
|
||||
dependencies:
|
||||
"@algolia/client-common" "5.48.0"
|
||||
|
||||
"@alugha/ima@2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@alugha/ima/-/ima-2.1.0.tgz#f9569fe6b955be7f2472df195527d63b210d34a1"
|
||||
integrity sha512-gGMWR9QlSJQR4G8p8nYRR/NHSzCCSLq7Q82Xr0BK154nNCfhykpjqr/hGVZdpFaPecyxEMDP3aSp2dzM421KRA==
|
||||
|
||||
"@antfu/eslint-config@5.4.1":
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@antfu/eslint-config/-/eslint-config-5.4.1.tgz#1a2897a0d3c89f6a73e08d54ba92c2b456b1fd11"
|
||||
|
||||
Reference in new issue
Block a user