fix(vast): [PKG-VAST-03] preserve npm initialization with explicit workspace mode

This commit is contained in:
Harvey Zhao committed 2026-09-14 22:42:57 +08:00
1 parent 314a1c3163
commit c162d2b3b3
27 files changed
+13189 -191

No files matched your search

+43 -19
View File
@@ -1,19 +1,21 @@
# 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.
The runtime follows the accepted published-versus-workspace initialization decision.
Public declaration reconciliation and real IMA validation remain separate release gates.
## 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.
Its writable `.default` self-reference retains historical CommonJS default calls
It snapshots the optional compatibility mode at factory creation and initializes
the default session before the callback. Its writable `.default` self-reference retains historical CommonJS default calls
alongside the current direct factory. It does not wrap registration or load IMA.
- `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
- `src/session.ts` owns one current SDK/container pair, initialization rollback and
explicit recreation. Only workspace mode adds four ad-event subscriptions and
active-ad request suppression; default mode delegates those behaviors to the SDK.
- `src/view.ts` creates each mode's historical 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.
@@ -50,17 +52,34 @@ 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 old `require(...).default(...)` call is restored, while the
current callable export remains callable. This does not recreate the old namespace
object's reflection shape. The `id`/`$container` aliases, eager
published initialization and contradictory public return types are not yet reconciled.
See [the explicit decision](../../refactor/vast-compatibility-decision.md).
Calling `artplayerPluginVast(callback)` preserves npm1.0.0 behavior: the SDK and
container exist before the callback, including when no callback was supplied.
`imaPlayer`, `id` and `$container` are writable/enumerable/configurable data fields.
SDK settings retain their own defaults. The wrapper forwards each explicit request
and leaves ad visibility to the SDK, without adding workspace event listeners.
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.
Passing `{ compatibility: 'workspace-1.2' }` as the second argument retains unpublished
workspace behavior: no player/container until `init`, `playUrl` or `playRes`; callers
can mutate the original settings/options before initialization. Preloading and restore
custom playback state default to true. Four ad events control the black overlay and
active-ad suppression. Resource getters track the current session and become null
on release. The mode is captured once; an unknown value throws TypeError before loading.
Default data fields retain their last allocated values after destroy, as published
snapshots; `container` is a live getter and becomes null. Explicit recreation updates
the data fields to the new session. Public writes to these snapshots do not transfer
resource ownership. Never use a retained disposed SDK as an active session.
Both modes retain void request methods, async registration and SDK/callback rejection.
The old `require(...).default(...)` call and current callable export remain available;
this does not recreate the old namespace object's reflection shape. Contradictory
public return declarations and the new second-argument declaration remain task04.
See [the accepted decision](../../refactor/vast-compatibility-decision.md).
Overlay IDs use the historical `art-` default prefix or `art-vast-` workspace prefix,
with a monotonic suffix to fix same-millisecond collisions. Default styles do not add
workspace's black background or pointer-events rule. Container identity/ownership,
initial display:none and existing position/inset/size/z-index are preserved.
`@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
@@ -68,11 +87,16 @@ to use Glomex1.21.2. No new direct remote loader or SDK major upgrade was introd
## 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
Run `yarn test:vast`, `node node_modules/typescript/bin/tsc -p
packages/artplayer-plugin-vast/tsconfig.json --noEmit`, `yarn build artplayer-plugin-vast`,
and `yarn test:browser:source test/browser/vast.spec.js --workers=2` using the pinned
toolchain. Do not use the historical `tsc` binary alias for source checking. 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
frozen historical sources, real published core5.1.7/5.4.0 and candidate5.4.1 registration, real DOM and
main-video decoding; they do not certify Google IMA ads or final npm distribution.
Candidate default and explicit workspace cases execute identical compiled code with
different options; historical fixtures remain immutable. Compatibility tests compare
callback timing, data descriptors, defaults and request forwarding to actual npm source.
`test/vast-exports.test.js` exercises bundled CommonJS/global/AMD and native ESM
import, using an already destroyed host to verify registration without loading ads.
+26
View File
@@ -2,6 +2,32 @@
VAST plugin for ArtPlayer
## Initialization compatibility
Existing npm calls keep creating the SDK player before the callback:
```js
artplayerPluginVast(({ imaPlayer, playUrl }) => {
imaPlayer.addEventListener('AdStarted', onAdStarted)
playButton.onclick = () => playUrl(adTagUrl)
})
```
Code using the unpublished workspace 1.2 lazy initialization must select it explicitly:
```js
artplayerPluginVast((context) => {
context.playerOptions.autoResize = false
playButton.onclick = () => context.playUrl(adTagUrl)
}, { compatibility: 'workspace-1.2' })
```
The callback may be asynchronous. Core destruction releases the ad session and prevents
later requests or recreation. Explicit plugin `destroy()` allows a new ad session while
the core is alive. See the architecture guide for mode-specific fields and defaults.
Public TypeScript declarations for the second argument are still being reconciled in
PKG-VAST-04; these are JavaScript usage examples, not completed declaration acceptance.
## Maintenance
Implementation modules, lifecycle ownership, test commands and pending compatibility
@@ -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 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
!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 d(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function h(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 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
!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 l(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 h=0;function c(t){return"__private_"+h+++"_"+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
+55 -29
View File
@@ -445,30 +445,54 @@ function createRequest(ima, field, value, config) {
return request;
}
let nextId = 0;
function createContainer(utils) {
function createContainer(utils, workspaceMode) {
const container = utils.createElement("div");
container.id = `art-vast-${Date.now()}-${++nextId}`;
container.id = `${workspaceMode ? "art-vast-" : "art-"}${Date.now()}-${++nextId}`;
utils.setStyles(container, {
position: "absolute",
inset: "0",
width: "100%",
height: "100%",
zIndex: "150",
backgroundColor: "black",
display: "none",
pointerEvents: "auto"
display: "none"
});
if (workspaceMode)
utils.setStyles(container, { backgroundColor: "black", pointerEvents: "auto" });
return container;
}
function createSession(art, ima, utils, closed) {
function createSession(art, ima, utils, closed, workspaceMode) {
const { $video, $player } = art.template;
const adsRenderingSettings = new ima.AdsRenderingSettings();
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
adsRenderingSettings.enablePreloading = true;
if (workspaceMode) {
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
adsRenderingSettings.enablePreloading = true;
}
const playerOptions = new E();
let current = null;
let initializing = false;
let releasing = 0;
const context = {
art,
playUrl: (url, config = {}) => play("adTagUrl", url, config),
playRes: (response, config = {}) => play("adsResponse", response, config),
init,
ima,
adsRenderingSettings,
playerOptions,
imaPlayer: null,
id: null,
$container: null,
get container() {
return current?.container || null;
}
};
if (workspaceMode) {
Object.defineProperties(context, {
imaPlayer: { get: () => current?.player || null },
id: { get: () => current?.container.id || null },
$container: { get: () => current?.container || null }
});
}
const live = (owner) => current === owner && !owner.released && !closed();
function release(owner) {
if (current === owner)
@@ -519,7 +543,7 @@ function createSession(art, ima, utils, closed) {
initializing = true;
let owner;
try {
owner = { container: createContainer(utils), player: null, listeners: [], playing: false, released: false };
owner = { container: createContainer(utils, workspaceMode), player: null, listeners: [], playing: false, released: false };
current = owner;
if (!live(owner)) {
release(owner);
@@ -536,12 +560,13 @@ function createSession(art, ima, utils, closed) {
return null;
}
const allocated = owner;
for (const [name, playing] of [
const events = workspaceMode ? [
["AdContentPauseRequested", true],
["AdContentResumeRequested", false],
["AdStarted", true],
["AdError", false]
]) {
] : [];
for (const [name, playing] of events) {
const callback = (event) => {
if (!live(allocated))
return;
@@ -557,6 +582,13 @@ function createSession(art, ima, utils, closed) {
return null;
}
}
if (!workspaceMode) {
Object.defineProperties(context, {
imaPlayer: { value: owner.player },
id: { value: owner.container.id },
$container: { value: owner.container }
});
}
return owner.player;
} catch (error) {
if (owner) {
@@ -572,7 +604,7 @@ function createSession(art, ima, utils, closed) {
}
}
function play(field, value, config) {
if (closed() || current?.playing)
if (closed() || workspaceMode && current?.playing)
return;
const player = init();
const owner = current;
@@ -586,24 +618,13 @@ function createSession(art, ima, utils, closed) {
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) {
function artplayerPluginVast(callback, options = {}) {
const compatibility = options.compatibility;
if (compatibility !== void 0 && compatibility !== "workspace-1.2")
throw new TypeError("Unsupported VAST compatibility mode");
const workspaceMode = compatibility === "workspace-1.2";
return async (art) => {
let disposed = false;
let session;
@@ -629,11 +650,16 @@ function artplayerPluginVast(callback) {
if (closed())
return result;
const utils = art.constructor.utils;
session = createSession(art, ima, utils, closed);
session = createSession(art, ima, utils, closed, workspaceMode);
if (closed()) {
dispose();
return result;
}
if (!workspaceMode) {
session.context.init();
if (closed())
return result;
}
if (typeof callback === "function")
await callback(session.context);
return result;
+12 -3
View File
@@ -1,9 +1,13 @@
import type Artplayer from 'artplayer'
import type { Callback, Result } from './types'
import type { Callback, CompatibilityOptions, Result } from './types'
import { loadImaSdk } from './sdk'
import { createSession } from './session'
function artplayerPluginVast(callback?: Callback) {
function artplayerPluginVast(callback?: Callback, options: CompatibilityOptions = {}) {
const compatibility = options.compatibility
if (compatibility !== undefined && compatibility !== 'workspace-1.2')
throw new TypeError('Unsupported VAST compatibility mode')
const workspaceMode = compatibility === 'workspace-1.2'
return async (art: Artplayer): Promise<Result> => {
let disposed = false
let session: ReturnType<typeof createSession> | undefined
@@ -28,11 +32,16 @@ function artplayerPluginVast(callback?: Callback) {
if (closed())
return result
const utils = (art.constructor as typeof Artplayer).utils
session = createSession(art, ima, utils, closed)
session = createSession(art, ima, utils, closed, workspaceMode)
if (closed()) {
dispose()
return result
}
if (!workspaceMode) {
session.context.init()
if (closed())
return result
}
if (typeof callback === 'function')
await callback(session.context)
return result
+45 -22
View File
@@ -12,16 +12,39 @@ interface Owner {
released: boolean
}
export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, closed: () => boolean) {
export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, closed: () => boolean, workspaceMode: boolean) {
const { $video, $player } = art.template
const adsRenderingSettings = new ima.AdsRenderingSettings()
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
adsRenderingSettings.enablePreloading = true
if (workspaceMode) {
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
adsRenderingSettings.enablePreloading = true
}
const playerOptions = new PlayerOptions()
let current: Owner | null = null
let initializing = false
let releasing = 0
const context: Context = {
art,
playUrl: (url, config = {}) => play('adTagUrl', url, config),
playRes: (response, config = {}) => play('adsResponse', response, config),
init,
ima,
adsRenderingSettings,
playerOptions,
imaPlayer: null,
id: null,
$container: null,
get container() { return current?.container || null },
}
if (workspaceMode) {
Object.defineProperties(context, {
imaPlayer: { get: () => current?.player || null },
id: { get: () => current?.container.id || null },
$container: { get: () => current?.container || null },
})
}
const live = (owner: Owner) => current === owner && !owner.released && !closed()
function release(owner: Owner): void {
@@ -77,7 +100,7 @@ export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, clo
initializing = true
let owner: Owner | undefined
try {
owner = { container: createContainer(utils), player: null, listeners: [], playing: false, released: false }
owner = { container: createContainer(utils, workspaceMode), player: null, listeners: [], playing: false, released: false }
current = owner
if (!live(owner)) {
release(owner)
@@ -94,12 +117,15 @@ export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, clo
return null
}
const allocated = owner
for (const [name, playing] of [
['AdContentPauseRequested', true],
['AdContentResumeRequested', false],
['AdStarted', true],
['AdError', false],
] as const) {
const events = workspaceMode
? [
['AdContentPauseRequested', true],
['AdContentResumeRequested', false],
['AdStarted', true],
['AdError', false],
] as const
: []
for (const [name, playing] of events) {
const callback: EventListener = (event) => {
if (!live(allocated))
return
@@ -115,6 +141,14 @@ export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, clo
return null
}
}
if (!workspaceMode) {
// Published fields are writable data properties, not the workspace getters.
Object.defineProperties(context, {
imaPlayer: { value: owner.player },
id: { value: owner.container.id },
$container: { value: owner.container },
})
}
return owner.player
}
catch (error) {
@@ -132,7 +166,7 @@ export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, clo
}
function play(field: 'adTagUrl' | 'adsResponse', value: string, config: RequestConfig): void {
if (closed() || current?.playing)
if (closed() || (workspaceMode && current?.playing))
return
const player = init()
const owner = current
@@ -149,16 +183,5 @@ export function createSession(art: Artplayer, ima: ImaSdk, utils: Utilities, clo
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 }
}
@@ -5,6 +5,10 @@ import type Artplayer from 'artplayer'
export type Utilities = Pick<typeof Artplayer.utils, 'createElement' | 'setStyles'>
export type RequestConfig = Record<string, unknown>
export interface CompatibilityOptions {
compatibility?: 'workspace-1.2'
}
export interface Context {
art: Artplayer
playUrl: (url: string, config?: RequestConfig) => void
@@ -14,6 +18,8 @@ export interface Context {
adsRenderingSettings: google.ima.AdsRenderingSettings
playerOptions: PlayerOptions
readonly imaPlayer: Player | null
readonly id: string | null
readonly $container: HTMLDivElement | null
readonly container: HTMLDivElement | null
}
+4 -4
View File
@@ -2,18 +2,18 @@ import type { Utilities } from './types'
let nextId = 0
export function createContainer(utils: Utilities): HTMLDivElement {
export function createContainer(utils: Utilities, workspaceMode: boolean): HTMLDivElement {
const container = utils.createElement('div')
container.id = `art-vast-${Date.now()}-${++nextId}`
container.id = `${workspaceMode ? 'art-vast-' : 'art-'}${Date.now()}-${++nextId}`
utils.setStyles(container, {
position: 'absolute',
inset: '0',
width: '100%',
height: '100%',
zIndex: '150',
backgroundColor: 'black',
display: 'none',
pointerEvents: 'auto',
})
if (workspaceMode)
utils.setStyles(container, { backgroundColor: 'black', pointerEvents: 'auto' })
return container
}