diff --git a/docs/compiled/artplayer-plugin-vast.js b/docs/compiled/artplayer-plugin-vast.js index b86279484..78add96cd 100644 --- a/docs/compiled/artplayer-plugin-vast.js +++ b/docs/compiled/artplayer-plugin-vast.js @@ -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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,q)[q].splice(e,1),this.g(f(this,q)[q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,q)[q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,s=this;this.reset(!0),f(this,C)[C].destroy(),R.forEach(function(t){f(s,D)[D].removeEventListener(t,s.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,z)[z])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,x)[x]=void 0,f(this,Q)[Q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(T.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(T.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,q)[q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,B)[B].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],s=n.offsetHeight,r=n.offsetWidth;f(this,j)[j]=r,f(this,N)[N]=s,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,q)[q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var s=f(this,x)[x]=t.getAd();s.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),s.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=s.getDuration(),f(this,Q)[Q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,x)[x])&&-1!==f(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,x)[x]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,x)[x]&&this.A(f(this,x)[x].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,x)[x].getDuration(),f(this,Q)[Q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var r=Boolean(f(this,x)[x]);if(r){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),r&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,q)[q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,Q)[Q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var d=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):d.adError&&!f(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,s=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var r=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){r.addEventListener(n.Type[t],function(i){if(e.S(i),T[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(T[t],{detail:{ad:i.getAd()||f(e,x)[x],adData:n?i.getAdData():{}}}))}})}),r.addEventListener(s,function(t){return e.j(e.B(t))});try{var o;r.init(f(this,j)[j],f(this,N)[N],this.k()),r.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(T.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(T.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return u(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?u(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,B)[B].autoResize&&f(this,M)[M]){var t=f(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(T.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(T.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,Q)[Q]?f(this,Q)[Q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,q)[q])}}]),e}(w);return function(i){return async n=>{const{template:s,constructor:r}=n,{createElement:o,setStyles:a}=r.utils,{$video:d,$player:h}=s;await function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();const u=window.google.ima,l=new u.AdsRenderingSettings;l.restoreCustomPlaybackStateOnAdBreakComplete=!0,l.enablePreloading=!0;const c=new P;let f=!1,v=null,p=null;function E(){return v||(p=function(){const t=o("div"),e=`art-vast-${Date.now()}`;return t.id=e,a(t,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),t}(),h.appendChild(p),v=new et(u,d,p,l,c),v.addEventListener("AdContentPauseRequested",()=>{f=!0,p.style.display="block"}),v.addEventListener("AdContentResumeRequested",()=>{f=!1,p.style.display="none"}),v.addEventListener("AdStarted",()=>{f=!0,p.style.display="block"}),v.addEventListener("AdError",t=>{console.error("VAST Ad Error:",t.detail),f=!1,p.style.display="none"}),v)}return"function"===typeof i&&await i({art:n,playUrl:function(t,e={}){if(f)return;v||E();const i=new u.AdsRequest;i.adTagUrl=t;for(const n in e)i[n]=e[n];v.playAds(i)},playRes:function(t,e={}){if(f)return;v||E();const i=new u.AdsRequest;i.adsResponse=t;for(const n in e)i[n]=e[n];v.playAds(i)},init:E,ima:u,adsRenderingSettings:l,playerOptions:c,get imaPlayer(){return v},get container(){return p}}),{name:"artplayerPluginVast",destroy:function(){v?.destroy&&v.destroy(),p?.parentNode&&p.parentNode.removeChild(p),p=null,v=null}}}}}); +!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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,Q)[Q].splice(e,1),this.g(f(this,Q)[Q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,Q)[Q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,r=this;this.reset(!0),f(this,C)[C].destroy(),T.forEach(function(t){f(r,D)[D].removeEventListener(t,r.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,B)[B])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,V)[V]=void 0,f(this,q)[q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(R.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(R.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,Q)[Q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,z)[z].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],r=n.offsetHeight,s=n.offsetWidth;f(this,j)[j]=s,f(this,N)[N]=r,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,Q)[Q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,x)[x]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,x)[x],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,x)[x]=void 0):this.M();break;case i.Type.STARTED:var r=f(this,V)[V]=t.getAd();r.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),r.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=r.getDuration(),f(this,q)[q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,V)[V])&&-1!==f(this,V)[V].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,V)[V]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,V)[V]&&this.A(f(this,V)[V].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,V)[V].getDuration(),f(this,q)[q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var s=Boolean(f(this,V)[V]);if(s){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),s&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,Q)[Q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,q)[q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var u=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):u.adError&&!f(this,V)[V]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,r=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var s=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){s.addEventListener(n.Type[t],function(i){if(e.S(i),R[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(R[t],{detail:{ad:i.getAd()||f(e,V)[V],adData:n?i.getAdData():{}}}))}})}),s.addEventListener(r,function(t){return e.j(e.B(t))});try{var o;s.init(f(this,j)[j],f(this,N)[N],this.k()),s.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(R.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(R.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return d(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?d(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,z)[z].autoResize&&f(this,M)[M]){var t=f(this,V)[V],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(R.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(R.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,q)[q]?f(this,q)[q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,Q)[Q])}}]),e}(w);let it=0;function nt(t){const e=t.createElement("div");return e.id=`art-vast-${Date.now()}-${++it}`,t.setStyles(e,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),e}return function(i){return async n=>{let r,s=!1;const o=()=>s||n.isDestroy,a={name:"artplayerPluginVast",destroy:()=>r?.destroy()};function u(){if(!s){s=!0;try{n.off("destroy",u)}finally{r?.destroy()}}}if(o())return a;n.on("destroy",u);try{if(o())return a;const s=await function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();if(o())return a;const h=n.constructor.utils;return r=function(t,e,i,n){const{$video:r,$player:s}=t.template,o=new e.AdsRenderingSettings;o.restoreCustomPlaybackStateOnAdBreakComplete=!0,o.enablePreloading=!0;const a=new P;let u=null,h=!1,d=0;const l=t=>u===t&&!t.released&&!n();function c(t){u===t&&(u=null),t.released=!0,t.playing=!1;const e=t.player;t.player=null;const i=t.listeners.splice(0);let n,r=!1;const s=t=>{try{t()}catch(e){r?console.error("VAST cleanup error:",e):(r=!0,n=e)}};d++;try{if(e){for(const[t,n]of i)s(()=>e.removeEventListener(t,n));s(()=>e.destroy())}s(()=>{t.container.parentNode&&t.container.parentNode.removeChild(t.container)})}finally{d--}if(r)throw n}function f(){if(n()||d)return null;if(h)throw new Error("VAST initialization is already in progress");if(u?.player)return u.player;let t;h=!0;try{if(t={container:nt(i),player:null,listeners:[],playing:!1,released:!1},u=t,!l(t))return c(t),null;if(s.appendChild(t.container),!l(t))return c(t),null;if(t.player=new et(e,r,t.container,o,a),!l(t))return c(t),null;const n=t;for(const[e,i]of[["AdContentPauseRequested",!0],["AdContentResumeRequested",!1],["AdStarted",!0],["AdError",!1]]){const r=t=>{l(n)&&("AdError"===e&&console.error("VAST Ad Error:",t.detail),n.playing=i,n.container.style.display=i?"block":"none")};if(t.listeners.push([e,r]),t.player.addEventListener(e,r),!l(t))return c(t),null}return t.player}catch(f){if(t)try{c(t)}catch(p){console.error("VAST cleanup error:",p)}throw f}finally{h=!1}}function p(t,i,r){if(n()||u?.playing)return;const s=f(),o=u;if(!s||!o)return;const a=function(t,e,i,n){const r=new t.AdsRequest;r[e]=i;const s=r;for(const o in n)s[o]=n[o];return r}(e,t,i,r);l(o)&&o.player===s&&s.playAds(a)}return{context:{art:t,playUrl:(t,e={})=>p("adTagUrl",t,e),playRes:(t,e={})=>p("adsResponse",t,e),init:f,ima:e,adsRenderingSettings:o,playerOptions:a,get imaPlayer(){return u?.player||null},get container(){return u?.container||null}},destroy:function(){u&&c(u)}}}(n,s,h,o),o()?(u(),a):("function"===typeof i&&await i(r.context),a)}catch(h){try{u()}catch(d){console.error("VAST cleanup error:",d)}throw h}}}}); diff --git a/docs/compiled/artplayer-plugin-vast.legacy.js b/docs/compiled/artplayer-plugin-vast.legacy.js index 104963dd7..08711d88e 100644 --- a/docs/compiled/artplayer-plugin-vast.legacy.js +++ b/docs/compiled/artplayer-plugin-vast.legacy.js @@ -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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(v(this,q)[q].splice(e,1),this.g(v(this,q)[q]))},n.resizeAd=function(t,e){v(this,j)[j]=t,v(this,N)[N]=e,v(this,M)[M]&&v(this,M)[M].resize(t,e,this.k()),v(this,_)[_].style.width=t+"px",v(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(v(this,F)[F]=!1,v(this,G)[G]=!1,v(this,W)[W]=!1),this.C(),v(this,q)[q]=[],v(this,Z)[Z]=!1,v(this,$)[$]=void 0,v(this,M)[M]&&v(this,M)[M].destroy(),v(this,M)[M]=void 0,v(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),v(this,_)[_].style.display="none"},n.P=function(){v(this,U)[U]&&(v(this,U)[U].removeEventListener(v(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),v(this,U)[U].removeEventListener(v(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),v(this,U)[U].destroy()),v(this,L)[L]&&v(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,s=this;this.reset(!0),v(this,C)[C].destroy(),P.forEach(function(t){v(s,D)[D].removeEventListener(t,s.o)}),null==(t=v(this,U)[U])||t.removeEventListener(v(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=v(this,L)[L])||e.destroy(),null==(i=v(this,U)[U])||i.destroy(),v(this,F)[F]=!1,v(this,W)[W]=!1,v(this,G)[G]=!1,null==(n=v(this,z)[z])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===v(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!v(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(v(this,Y)[Y]),window.clearTimeout(v(this,X)[X]),v(this,Y)[Y]=void 0,v(this,X)[X]=void 0,v(this,x)[x]=void 0,v(this,Q)[Q]=void 0,v(this,K)[K]=void 0,v(this,_)[_].style.display="none",v(this,_)[_].classList.remove("nonlinear"),v(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(v(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(v(this,M)[M]){var i=v(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(R.MEDIA_IMPRESSION)),v(this,F)[F]=!0)}if("play"!==t.type||v(this,G)[G]||v(this,H)[H]||(this.dispatchEvent(new A(R.MEDIA_START)),v(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&v(this,D)[D].currentTime===v(this,D)[D].duration&&v(this,q)[q].indexOf(-1)>-1&&(v(this,D)[D].currentTime=v(this,D)[D].duration-1e-5,v(this,W)[W]=!0),v(this,U)[U].contentComplete(),v(this,M)[M]||this.T()),!window.ResizeObserver&&v(this,B)[B].autoResize&&"loadedmetadata"===t.type){var n=v(this,D)[D],s=n.offsetHeight,r=n.offsetWidth;v(this,j)[j]=r,v(this,N)[N]=s,this.R()}v(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=v(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();v(this,$)[$]&&0===v(this,q)[q].length?v(this,$)[$]({ad:n,start:function(){e.M(),v(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):v(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),v(this,$)[$]?(v(this,$)[$]({ad:v(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),v(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),v(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var s=v(this,x)[x]=t.getAd();s.getAdPodInfo().getAdPosition()>1&&v(this,M)[M].setVolume(v(this,M)[M].getVolume()),v(this,_)[_].classList.remove("nonlinear"),this.R(),s.isLinear()?(v(this,C)[C].disable(),v(this,K)[K]=s.getDuration(),v(this,Q)[Q]=0):(v(this,_)[_].classList.add("nonlinear"),this.I()),v(this,_)[_].style.display="",v(this,Z)[Z]&&(v(this,Z)[Z]=!1,v(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(v(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(v(this,x)[x])&&-1!==v(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),v(this,x)[x]=t.getAd(),v(this,_)[_].style.display="",v(this,D)[D].pause(),this.R(),v(this,x)[x]&&this.A(v(this,x)[x].getAdPodInfo().getTimeOffset()),v(this,M)[M].setVolume(v(this,D)[D].muted?0:v(this,D)[D].volume),v(this,C)[C].disable(),v(this,K)[K]=v(this,x)[x].getDuration(),v(this,Q)[Q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var r=Boolean(v(this,x)[x]);if(r){var o=v(this,M)[M].getVolume();v(this,D)[D].muted=0===o,v(this,D)[D].volume=v(this,J)[J]}v(this,W)[W]&&(v(this,D)[D].currentTime=v(this,D)[D].duration+1,v(this,W)[W]=!1),v(this,D)[D].ended?(this.reset(),this.T()):this.C(),r&&(v(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(v(this,M)[M].getCuePoints()),-1===v(this,q)[q].indexOf(0)&&(v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();v(this,Q)[Q]=a.currentTime,v(this,K)[K]=a.duration;break;case i.Type.LOG:var d=t.getAdData();v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):d.adError&&!v(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=v(this,M)[M].getVolume();h>0&&(v(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=v(this,I)[I],n=i.AdEvent,s=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(v(this,Y)[Y]);var r=v(this,M)[M]=t.getAdsManager(v(this,C)[C],v(this,k)[k]);Object.keys(n.Type).forEach(function(t){r.addEventListener(n.Type[t],function(i){if(e.S(i),R[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(R[t],{detail:{ad:i.getAd()||v(e,x)[x],adData:n?i.getAdData():{}}}))}})}),r.addEventListener(s,function(t){return e.j(e.B(t))});try{var o;r.init(v(this,j)[j],v(this,N)[N],this.k()),r.setVolume(v(this,D)[D].muted?0:v(this,D)[D].volume),null==(o=v(this,L)[L])||o.initialize(),v(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(v(this,G)[G]||(this.dispatchEvent(new A(R.MEDIA_START)),v(this,G)[G]=!0),v(this,M)[M])try{v(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){v(t,F)[F]=!1,v(t,G)[G]=!1,v(t,W)[W]=!1,t.dispatchEvent(new A(R.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return u(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?u(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(v(this,j)[j]=n.contentBoxSize[0].inlineSize,v(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(v(this,j)[j]=n.contentBoxSize.inlineSize,v(this,N)[N]=n.contentBoxSize.blockSize):(v(this,j)[j]=n.contentRect.width,v(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(v(this,B)[B].autoResize&&v(this,M)[M]){var t=v(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>v(this,j)[j]||t.getHeight()>v(this,N)[N]?this.resizeAd(v(this,j)[j],v(this,N)[N]):(v(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),v(this,_)[_].style.width=t.getWidth()+"px",v(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(v(this,j)[j],v(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||v(this,D)[D].webkitDisplayingFullscreen?v(this,I)[I].ViewMode.FULLSCREEN:v(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;v(this,_)[_].style.display="none",v(this,D)[D].ended||(v(this,C)[C].enable(),v(this,Z)[Z]?(v(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(R.MEDIA_RESUMED))),v(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(R.AD_ERROR,{detail:{error:t}})),this.C(),v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!v(this,C)[C].enabled&&v(this,M)[M]?v(this,M)[M].getVolume():v(this,D)[D].volume},set:function(t){!v(this,C)[C].enabled&&v(this,M)[M]&&v(this,M)[M].setVolume(t),v(this,D)[D].volume=t}},{key:"muted",get:function(){return!v(this,C)[C].enabled&&v(this,M)[M]?0===v(this,M)[M].getVolume():v(this,D)[D].muted},set:function(t){!v(this,C)[C].enabled&&v(this,M)[M]&&v(this,M)[M].setVolume(t?0:v(this,J)[J]),v(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==v(this,Q)[Q]?v(this,Q)[Q]:v(this,D)[D].currentTime},set:function(t){v(this,C)[C].enabled&&(v(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==v(this,K)[K]?v(this,K)[K]:v(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(v(this,q)[q])}}]),e}(w);return function(i){return n=>{return s=null,r=null,o=function*(){const{template:s,constructor:r}=n,{createElement:o,setStyles:a}=r.utils,{$video:d,$player:h}=s;yield function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();const u=window.google.ima,l=new u.AdsRenderingSettings;l.restoreCustomPlaybackStateOnAdBreakComplete=!0,l.enablePreloading=!0;const c=new T;let v=!1,f=null,p=null;function y(){return f||(p=function(){const t=o("div"),e=`art-vast-${Date.now()}`;return t.id=e,a(t,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),t}(),h.appendChild(p),f=new et(u,d,p,l,c),f.addEventListener("AdContentPauseRequested",()=>{v=!0,p.style.display="block"}),f.addEventListener("AdContentResumeRequested",()=>{v=!1,p.style.display="none"}),f.addEventListener("AdStarted",()=>{v=!0,p.style.display="block"}),f.addEventListener("AdError",t=>{console.error("VAST Ad Error:",t.detail),v=!1,p.style.display="none"}),f)}return"function"===typeof i&&(yield i({art:n,playUrl:function(t,e={}){if(v)return;f||y();const i=new u.AdsRequest;i.adTagUrl=t;for(const n in e)i[n]=e[n];f.playAds(i)},playRes:function(t,e={}){if(v)return;f||y();const i=new u.AdsRequest;i.adsResponse=t;for(const n in e)i[n]=e[n];f.playAds(i)},init:y,ima:u,adsRenderingSettings:l,playerOptions:c,get imaPlayer(){return f},get container(){return p}})),{name:"artplayerPluginVast",destroy:function(){(null==f?void 0:f.destroy)&&f.destroy(),(null==p?void 0:p.parentNode)&&p.parentNode.removeChild(p),p=null,f=null}}},new Promise((t,e)=>{var i=t=>{try{a(o.next(t))}catch(i){e(i)}},n=t=>{try{a(o.throw(t))}catch(i){e(i)}},a=e=>e.done?t(e.value):Promise.resolve(e.value).then(i,n);a((o=o.apply(s,r)).next())});var s,r,o}}}); +!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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,Q)[Q].splice(e,1),this.g(f(this,Q)[Q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,Q)[Q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,r=this;this.reset(!0),f(this,C)[C].destroy(),T.forEach(function(t){f(r,D)[D].removeEventListener(t,r.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,B)[B])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,x)[x]=void 0,f(this,q)[q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(P.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(P.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,Q)[Q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,z)[z].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],r=n.offsetHeight,s=n.offsetWidth;f(this,j)[j]=s,f(this,N)[N]=r,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,Q)[Q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var r=f(this,x)[x]=t.getAd();r.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),r.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=r.getDuration(),f(this,q)[q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,x)[x])&&-1!==f(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,x)[x]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,x)[x]&&this.A(f(this,x)[x].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,x)[x].getDuration(),f(this,q)[q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var s=Boolean(f(this,x)[x]);if(s){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),s&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,Q)[Q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,q)[q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var u=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):u.adError&&!f(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,r=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var s=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){s.addEventListener(n.Type[t],function(i){if(e.S(i),P[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(P[t],{detail:{ad:i.getAd()||f(e,x)[x],adData:n?i.getAdData():{}}}))}})}),s.addEventListener(r,function(t){return e.j(e.B(t))});try{var o;s.init(f(this,j)[j],f(this,N)[N],this.k()),s.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(P.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(P.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return d(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?d(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,z)[z].autoResize&&f(this,M)[M]){var t=f(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(P.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(P.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,q)[q]?f(this,q)[q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,Q)[Q])}}]),e}(w);let it=0;function nt(t){const e=t.createElement("div");return e.id=`art-vast-${Date.now()}-${++it}`,t.setStyles(e,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),e}return function(i){return n=>{return r=this,s=null,o=function*(){let r,s=!1;const o=()=>s||n.isDestroy,a={name:"artplayerPluginVast",destroy:()=>null==r?void 0:r.destroy()};function u(){if(!s){s=!0;try{n.off("destroy",u)}finally{null==r||r.destroy()}}}if(o())return a;n.on("destroy",u);try{if(o())return a;const s=yield function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();if(o())return a;const h=n.constructor.utils;return r=function(t,e,i,n){const{$video:r,$player:s}=t.template,o=new e.AdsRenderingSettings;o.restoreCustomPlaybackStateOnAdBreakComplete=!0,o.enablePreloading=!0;const a=new R;let u=null,h=!1,d=0;const l=t=>u===t&&!t.released&&!n();function c(t){u===t&&(u=null),t.released=!0,t.playing=!1;const e=t.player;t.player=null;const i=t.listeners.splice(0);let n,r=!1;const s=t=>{try{t()}catch(e){r?console.error("VAST cleanup error:",e):(r=!0,n=e)}};d++;try{if(e){for(const[t,n]of i)s(()=>e.removeEventListener(t,n));s(()=>e.destroy())}s(()=>{t.container.parentNode&&t.container.parentNode.removeChild(t.container)})}finally{d--}if(r)throw n}function f(){if(n()||d)return null;if(h)throw new Error("VAST initialization is already in progress");if(null==u?void 0:u.player)return u.player;let t;h=!0;try{if(t={container:nt(i),player:null,listeners:[],playing:!1,released:!1},u=t,!l(t))return c(t),null;if(s.appendChild(t.container),!l(t))return c(t),null;if(t.player=new et(e,r,t.container,o,a),!l(t))return c(t),null;const n=t;for(const[e,i]of[["AdContentPauseRequested",!0],["AdContentResumeRequested",!1],["AdStarted",!0],["AdError",!1]]){const r=t=>{l(n)&&("AdError"===e&&console.error("VAST Ad Error:",t.detail),n.playing=i,n.container.style.display=i?"block":"none")};if(t.listeners.push([e,r]),t.player.addEventListener(e,r),!l(t))return c(t),null}return t.player}catch(f){if(t)try{c(t)}catch(p){console.error("VAST cleanup error:",p)}throw f}finally{h=!1}}function p(t,i,r){if(n()||(null==u?void 0:u.playing))return;const s=f(),o=u;if(!s||!o)return;const a=function(t,e,i,n){const r=new t.AdsRequest;r[e]=i;const s=r;for(const o in n)s[o]=n[o];return r}(e,t,i,r);l(o)&&o.player===s&&s.playAds(a)}return{context:{art:t,playUrl:(t,e={})=>p("adTagUrl",t,e),playRes:(t,e={})=>p("adsResponse",t,e),init:f,ima:e,adsRenderingSettings:o,playerOptions:a,get imaPlayer(){return(null==u?void 0:u.player)||null},get container(){return(null==u?void 0:u.container)||null}},destroy:function(){u&&c(u)}}}(n,s,h,o),o()?(u(),a):("function"===typeof i&&(yield i(r.context)),a)}catch(h){try{u()}catch(d){console.error("VAST cleanup error:",d)}throw h}},new Promise((t,e)=>{var i=t=>{try{a(o.next(t))}catch(i){e(i)}},n=t=>{try{a(o.throw(t))}catch(i){e(i)}},a=e=>e.done?t(e.value):Promise.resolve(e.value).then(i,n);a((o=o.apply(r,s)).next())});var r,s,o}}}); diff --git a/docs/compiled/artplayer-plugin-vast.mjs b/docs/compiled/artplayer-plugin-vast.mjs index fb8194a22..df954611f 100644 --- a/docs/compiled/artplayer-plugin-vast.mjs +++ b/docs/compiled/artplayer-plugin-vast.mjs @@ -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 { diff --git a/package.json b/package.json index b4ba0d76d..c0c503e46 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/packages/artplayer-plugin-vast/ARCHITECTURE.md b/packages/artplayer-plugin-vast/ARCHITECTURE.md new file mode 100644 index 000000000..f38d29a3d --- /dev/null +++ b/packages/artplayer-plugin-vast/ARCHITECTURE.md @@ -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. diff --git a/packages/artplayer-plugin-vast/README.md b/packages/artplayer-plugin-vast/README.md index acf8ec25e..79b920774 100644 --- a/packages/artplayer-plugin-vast/README.md +++ b/packages/artplayer-plugin-vast/README.md @@ -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) diff --git a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.js b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.js index b86279484..78add96cd 100644 --- a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.js +++ b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.js @@ -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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,q)[q].splice(e,1),this.g(f(this,q)[q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,q)[q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,s=this;this.reset(!0),f(this,C)[C].destroy(),R.forEach(function(t){f(s,D)[D].removeEventListener(t,s.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,z)[z])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,x)[x]=void 0,f(this,Q)[Q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(T.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(T.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,q)[q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,B)[B].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],s=n.offsetHeight,r=n.offsetWidth;f(this,j)[j]=r,f(this,N)[N]=s,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,q)[q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var s=f(this,x)[x]=t.getAd();s.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),s.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=s.getDuration(),f(this,Q)[Q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,x)[x])&&-1!==f(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,x)[x]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,x)[x]&&this.A(f(this,x)[x].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,x)[x].getDuration(),f(this,Q)[Q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var r=Boolean(f(this,x)[x]);if(r){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),r&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,q)[q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,Q)[Q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var d=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):d.adError&&!f(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,s=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var r=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){r.addEventListener(n.Type[t],function(i){if(e.S(i),T[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(T[t],{detail:{ad:i.getAd()||f(e,x)[x],adData:n?i.getAdData():{}}}))}})}),r.addEventListener(s,function(t){return e.j(e.B(t))});try{var o;r.init(f(this,j)[j],f(this,N)[N],this.k()),r.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(T.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(T.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return u(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?u(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,B)[B].autoResize&&f(this,M)[M]){var t=f(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(T.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(T.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,Q)[Q]?f(this,Q)[Q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,q)[q])}}]),e}(w);return function(i){return async n=>{const{template:s,constructor:r}=n,{createElement:o,setStyles:a}=r.utils,{$video:d,$player:h}=s;await function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();const u=window.google.ima,l=new u.AdsRenderingSettings;l.restoreCustomPlaybackStateOnAdBreakComplete=!0,l.enablePreloading=!0;const c=new P;let f=!1,v=null,p=null;function E(){return v||(p=function(){const t=o("div"),e=`art-vast-${Date.now()}`;return t.id=e,a(t,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),t}(),h.appendChild(p),v=new et(u,d,p,l,c),v.addEventListener("AdContentPauseRequested",()=>{f=!0,p.style.display="block"}),v.addEventListener("AdContentResumeRequested",()=>{f=!1,p.style.display="none"}),v.addEventListener("AdStarted",()=>{f=!0,p.style.display="block"}),v.addEventListener("AdError",t=>{console.error("VAST Ad Error:",t.detail),f=!1,p.style.display="none"}),v)}return"function"===typeof i&&await i({art:n,playUrl:function(t,e={}){if(f)return;v||E();const i=new u.AdsRequest;i.adTagUrl=t;for(const n in e)i[n]=e[n];v.playAds(i)},playRes:function(t,e={}){if(f)return;v||E();const i=new u.AdsRequest;i.adsResponse=t;for(const n in e)i[n]=e[n];v.playAds(i)},init:E,ima:u,adsRenderingSettings:l,playerOptions:c,get imaPlayer(){return v},get container(){return p}}),{name:"artplayerPluginVast",destroy:function(){v?.destroy&&v.destroy(),p?.parentNode&&p.parentNode.removeChild(p),p=null,v=null}}}}}); +!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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,Q)[Q].splice(e,1),this.g(f(this,Q)[Q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,Q)[Q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,r=this;this.reset(!0),f(this,C)[C].destroy(),T.forEach(function(t){f(r,D)[D].removeEventListener(t,r.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,B)[B])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,V)[V]=void 0,f(this,q)[q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(R.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(R.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,Q)[Q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,z)[z].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],r=n.offsetHeight,s=n.offsetWidth;f(this,j)[j]=s,f(this,N)[N]=r,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,Q)[Q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,x)[x]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,x)[x],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,x)[x]=void 0):this.M();break;case i.Type.STARTED:var r=f(this,V)[V]=t.getAd();r.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),r.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=r.getDuration(),f(this,q)[q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,V)[V])&&-1!==f(this,V)[V].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,V)[V]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,V)[V]&&this.A(f(this,V)[V].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,V)[V].getDuration(),f(this,q)[q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var s=Boolean(f(this,V)[V]);if(s){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),s&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,Q)[Q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,q)[q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var u=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):u.adError&&!f(this,V)[V]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,r=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var s=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){s.addEventListener(n.Type[t],function(i){if(e.S(i),R[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(R[t],{detail:{ad:i.getAd()||f(e,V)[V],adData:n?i.getAdData():{}}}))}})}),s.addEventListener(r,function(t){return e.j(e.B(t))});try{var o;s.init(f(this,j)[j],f(this,N)[N],this.k()),s.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(R.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(R.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return d(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?d(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,z)[z].autoResize&&f(this,M)[M]){var t=f(this,V)[V],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(R.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(R.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,q)[q]?f(this,q)[q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,Q)[Q])}}]),e}(w);let it=0;function nt(t){const e=t.createElement("div");return e.id=`art-vast-${Date.now()}-${++it}`,t.setStyles(e,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),e}return function(i){return async n=>{let r,s=!1;const o=()=>s||n.isDestroy,a={name:"artplayerPluginVast",destroy:()=>r?.destroy()};function u(){if(!s){s=!0;try{n.off("destroy",u)}finally{r?.destroy()}}}if(o())return a;n.on("destroy",u);try{if(o())return a;const s=await function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();if(o())return a;const h=n.constructor.utils;return r=function(t,e,i,n){const{$video:r,$player:s}=t.template,o=new e.AdsRenderingSettings;o.restoreCustomPlaybackStateOnAdBreakComplete=!0,o.enablePreloading=!0;const a=new P;let u=null,h=!1,d=0;const l=t=>u===t&&!t.released&&!n();function c(t){u===t&&(u=null),t.released=!0,t.playing=!1;const e=t.player;t.player=null;const i=t.listeners.splice(0);let n,r=!1;const s=t=>{try{t()}catch(e){r?console.error("VAST cleanup error:",e):(r=!0,n=e)}};d++;try{if(e){for(const[t,n]of i)s(()=>e.removeEventListener(t,n));s(()=>e.destroy())}s(()=>{t.container.parentNode&&t.container.parentNode.removeChild(t.container)})}finally{d--}if(r)throw n}function f(){if(n()||d)return null;if(h)throw new Error("VAST initialization is already in progress");if(u?.player)return u.player;let t;h=!0;try{if(t={container:nt(i),player:null,listeners:[],playing:!1,released:!1},u=t,!l(t))return c(t),null;if(s.appendChild(t.container),!l(t))return c(t),null;if(t.player=new et(e,r,t.container,o,a),!l(t))return c(t),null;const n=t;for(const[e,i]of[["AdContentPauseRequested",!0],["AdContentResumeRequested",!1],["AdStarted",!0],["AdError",!1]]){const r=t=>{l(n)&&("AdError"===e&&console.error("VAST Ad Error:",t.detail),n.playing=i,n.container.style.display=i?"block":"none")};if(t.listeners.push([e,r]),t.player.addEventListener(e,r),!l(t))return c(t),null}return t.player}catch(f){if(t)try{c(t)}catch(p){console.error("VAST cleanup error:",p)}throw f}finally{h=!1}}function p(t,i,r){if(n()||u?.playing)return;const s=f(),o=u;if(!s||!o)return;const a=function(t,e,i,n){const r=new t.AdsRequest;r[e]=i;const s=r;for(const o in n)s[o]=n[o];return r}(e,t,i,r);l(o)&&o.player===s&&s.playAds(a)}return{context:{art:t,playUrl:(t,e={})=>p("adTagUrl",t,e),playRes:(t,e={})=>p("adsResponse",t,e),init:f,ima:e,adsRenderingSettings:o,playerOptions:a,get imaPlayer(){return u?.player||null},get container(){return u?.container||null}},destroy:function(){u&&c(u)}}}(n,s,h,o),o()?(u(),a):("function"===typeof i&&await i(r.context),a)}catch(h){try{u()}catch(d){console.error("VAST cleanup error:",d)}throw h}}}}); diff --git a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.legacy.js b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.legacy.js index 104963dd7..08711d88e 100644 --- a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.legacy.js +++ b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.legacy.js @@ -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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(v(this,q)[q].splice(e,1),this.g(v(this,q)[q]))},n.resizeAd=function(t,e){v(this,j)[j]=t,v(this,N)[N]=e,v(this,M)[M]&&v(this,M)[M].resize(t,e,this.k()),v(this,_)[_].style.width=t+"px",v(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(v(this,F)[F]=!1,v(this,G)[G]=!1,v(this,W)[W]=!1),this.C(),v(this,q)[q]=[],v(this,Z)[Z]=!1,v(this,$)[$]=void 0,v(this,M)[M]&&v(this,M)[M].destroy(),v(this,M)[M]=void 0,v(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),v(this,_)[_].style.display="none"},n.P=function(){v(this,U)[U]&&(v(this,U)[U].removeEventListener(v(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),v(this,U)[U].removeEventListener(v(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),v(this,U)[U].destroy()),v(this,L)[L]&&v(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,s=this;this.reset(!0),v(this,C)[C].destroy(),P.forEach(function(t){v(s,D)[D].removeEventListener(t,s.o)}),null==(t=v(this,U)[U])||t.removeEventListener(v(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=v(this,L)[L])||e.destroy(),null==(i=v(this,U)[U])||i.destroy(),v(this,F)[F]=!1,v(this,W)[W]=!1,v(this,G)[G]=!1,null==(n=v(this,z)[z])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===v(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!v(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(v(this,Y)[Y]),window.clearTimeout(v(this,X)[X]),v(this,Y)[Y]=void 0,v(this,X)[X]=void 0,v(this,x)[x]=void 0,v(this,Q)[Q]=void 0,v(this,K)[K]=void 0,v(this,_)[_].style.display="none",v(this,_)[_].classList.remove("nonlinear"),v(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(v(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(v(this,M)[M]){var i=v(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(R.MEDIA_IMPRESSION)),v(this,F)[F]=!0)}if("play"!==t.type||v(this,G)[G]||v(this,H)[H]||(this.dispatchEvent(new A(R.MEDIA_START)),v(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&v(this,D)[D].currentTime===v(this,D)[D].duration&&v(this,q)[q].indexOf(-1)>-1&&(v(this,D)[D].currentTime=v(this,D)[D].duration-1e-5,v(this,W)[W]=!0),v(this,U)[U].contentComplete(),v(this,M)[M]||this.T()),!window.ResizeObserver&&v(this,B)[B].autoResize&&"loadedmetadata"===t.type){var n=v(this,D)[D],s=n.offsetHeight,r=n.offsetWidth;v(this,j)[j]=r,v(this,N)[N]=s,this.R()}v(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=v(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();v(this,$)[$]&&0===v(this,q)[q].length?v(this,$)[$]({ad:n,start:function(){e.M(),v(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):v(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),v(this,$)[$]?(v(this,$)[$]({ad:v(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),v(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),v(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var s=v(this,x)[x]=t.getAd();s.getAdPodInfo().getAdPosition()>1&&v(this,M)[M].setVolume(v(this,M)[M].getVolume()),v(this,_)[_].classList.remove("nonlinear"),this.R(),s.isLinear()?(v(this,C)[C].disable(),v(this,K)[K]=s.getDuration(),v(this,Q)[Q]=0):(v(this,_)[_].classList.add("nonlinear"),this.I()),v(this,_)[_].style.display="",v(this,Z)[Z]&&(v(this,Z)[Z]=!1,v(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(v(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(v(this,x)[x])&&-1!==v(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),v(this,x)[x]=t.getAd(),v(this,_)[_].style.display="",v(this,D)[D].pause(),this.R(),v(this,x)[x]&&this.A(v(this,x)[x].getAdPodInfo().getTimeOffset()),v(this,M)[M].setVolume(v(this,D)[D].muted?0:v(this,D)[D].volume),v(this,C)[C].disable(),v(this,K)[K]=v(this,x)[x].getDuration(),v(this,Q)[Q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var r=Boolean(v(this,x)[x]);if(r){var o=v(this,M)[M].getVolume();v(this,D)[D].muted=0===o,v(this,D)[D].volume=v(this,J)[J]}v(this,W)[W]&&(v(this,D)[D].currentTime=v(this,D)[D].duration+1,v(this,W)[W]=!1),v(this,D)[D].ended?(this.reset(),this.T()):this.C(),r&&(v(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(v(this,M)[M].getCuePoints()),-1===v(this,q)[q].indexOf(0)&&(v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();v(this,Q)[Q]=a.currentTime,v(this,K)[K]=a.duration;break;case i.Type.LOG:var d=t.getAdData();v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):d.adError&&!v(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=v(this,M)[M].getVolume();h>0&&(v(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=v(this,I)[I],n=i.AdEvent,s=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(v(this,Y)[Y]);var r=v(this,M)[M]=t.getAdsManager(v(this,C)[C],v(this,k)[k]);Object.keys(n.Type).forEach(function(t){r.addEventListener(n.Type[t],function(i){if(e.S(i),R[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(R[t],{detail:{ad:i.getAd()||v(e,x)[x],adData:n?i.getAdData():{}}}))}})}),r.addEventListener(s,function(t){return e.j(e.B(t))});try{var o;r.init(v(this,j)[j],v(this,N)[N],this.k()),r.setVolume(v(this,D)[D].muted?0:v(this,D)[D].volume),null==(o=v(this,L)[L])||o.initialize(),v(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(v(this,G)[G]||(this.dispatchEvent(new A(R.MEDIA_START)),v(this,G)[G]=!0),v(this,M)[M])try{v(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){v(t,F)[F]=!1,v(t,G)[G]=!1,v(t,W)[W]=!1,t.dispatchEvent(new A(R.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return u(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?u(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(v(this,j)[j]=n.contentBoxSize[0].inlineSize,v(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(v(this,j)[j]=n.contentBoxSize.inlineSize,v(this,N)[N]=n.contentBoxSize.blockSize):(v(this,j)[j]=n.contentRect.width,v(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(v(this,B)[B].autoResize&&v(this,M)[M]){var t=v(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>v(this,j)[j]||t.getHeight()>v(this,N)[N]?this.resizeAd(v(this,j)[j],v(this,N)[N]):(v(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),v(this,_)[_].style.width=t.getWidth()+"px",v(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(v(this,j)[j],v(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||v(this,D)[D].webkitDisplayingFullscreen?v(this,I)[I].ViewMode.FULLSCREEN:v(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;v(this,_)[_].style.display="none",v(this,D)[D].ended||(v(this,C)[C].enable(),v(this,Z)[Z]?(v(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(R.MEDIA_RESUMED))),v(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(R.AD_ERROR,{detail:{error:t}})),this.C(),v(this,$)[$]?v(this,$)[$]({start:function(){e.I(),v(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!v(this,C)[C].enabled&&v(this,M)[M]?v(this,M)[M].getVolume():v(this,D)[D].volume},set:function(t){!v(this,C)[C].enabled&&v(this,M)[M]&&v(this,M)[M].setVolume(t),v(this,D)[D].volume=t}},{key:"muted",get:function(){return!v(this,C)[C].enabled&&v(this,M)[M]?0===v(this,M)[M].getVolume():v(this,D)[D].muted},set:function(t){!v(this,C)[C].enabled&&v(this,M)[M]&&v(this,M)[M].setVolume(t?0:v(this,J)[J]),v(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==v(this,Q)[Q]?v(this,Q)[Q]:v(this,D)[D].currentTime},set:function(t){v(this,C)[C].enabled&&(v(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==v(this,K)[K]?v(this,K)[K]:v(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(v(this,q)[q])}}]),e}(w);return function(i){return n=>{return s=null,r=null,o=function*(){const{template:s,constructor:r}=n,{createElement:o,setStyles:a}=r.utils,{$video:d,$player:h}=s;yield function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();const u=window.google.ima,l=new u.AdsRenderingSettings;l.restoreCustomPlaybackStateOnAdBreakComplete=!0,l.enablePreloading=!0;const c=new T;let v=!1,f=null,p=null;function y(){return f||(p=function(){const t=o("div"),e=`art-vast-${Date.now()}`;return t.id=e,a(t,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),t}(),h.appendChild(p),f=new et(u,d,p,l,c),f.addEventListener("AdContentPauseRequested",()=>{v=!0,p.style.display="block"}),f.addEventListener("AdContentResumeRequested",()=>{v=!1,p.style.display="none"}),f.addEventListener("AdStarted",()=>{v=!0,p.style.display="block"}),f.addEventListener("AdError",t=>{console.error("VAST Ad Error:",t.detail),v=!1,p.style.display="none"}),f)}return"function"===typeof i&&(yield i({art:n,playUrl:function(t,e={}){if(v)return;f||y();const i=new u.AdsRequest;i.adTagUrl=t;for(const n in e)i[n]=e[n];f.playAds(i)},playRes:function(t,e={}){if(v)return;f||y();const i=new u.AdsRequest;i.adsResponse=t;for(const n in e)i[n]=e[n];f.playAds(i)},init:y,ima:u,adsRenderingSettings:l,playerOptions:c,get imaPlayer(){return f},get container(){return p}})),{name:"artplayerPluginVast",destroy:function(){(null==f?void 0:f.destroy)&&f.destroy(),(null==p?void 0:p.parentNode)&&p.parentNode.removeChild(p),p=null,f=null}}},new Promise((t,e)=>{var i=t=>{try{a(o.next(t))}catch(i){e(i)}},n=t=>{try{a(o.throw(t))}catch(i){e(i)}},a=e=>e.done?t(e.value):Promise.resolve(e.value).then(i,n);a((o=o.apply(s,r)).next())});var s,r,o}}}); +!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;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i-1&&(f(this,Q)[Q].splice(e,1),this.g(f(this,Q)[Q]))},n.resizeAd=function(t,e){f(this,j)[j]=t,f(this,N)[N]=e,f(this,M)[M]&&f(this,M)[M].resize(t,e,this.k()),f(this,_)[_].style.width=t+"px",f(this,_)[_].style.height=e+"px"},n.reset=function(t){void 0===t&&(t=!1),t&&(f(this,F)[F]=!1,f(this,G)[G]=!1,f(this,W)[W]=!1),this.C(),f(this,Q)[Q]=[],f(this,Z)[Z]=!1,f(this,$)[$]=void 0,f(this,M)[M]&&f(this,M)[M].destroy(),f(this,M)[M]=void 0,f(this,I)[I].settings.setAutoPlayAdBreaks(!0),t&&this.P(),f(this,_)[_].style.display="none"},n.P=function(){f(this,U)[U]&&(f(this,U)[U].removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),f(this,U)[U].removeEventListener(f(this,I)[I].AdErrorEvent.Type.AD_ERROR,this.l,!1),f(this,U)[U].destroy()),f(this,L)[L]&&f(this,L)[L].destroy()},n.destroy=function(){var t,e,i,n,r=this;this.reset(!0),f(this,C)[C].destroy(),T.forEach(function(t){f(r,D)[D].removeEventListener(t,r.o)}),null==(t=f(this,U)[U])||t.removeEventListener(f(this,I)[I].AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,this.u,!1),null==(e=f(this,L)[L])||e.destroy(),null==(i=f(this,U)[U])||i.destroy(),f(this,F)[F]=!1,f(this,W)[W]=!1,f(this,G)[G]=!1,null==(n=f(this,B)[B])||n.disconnect()},n.isCustomPlaybackUsed=function(){return!1===f(this,I)[I].settings.getDisableCustomPlaybackForIOS10Plus()&&!f(this,_)[_].querySelector("video")},n.C=function(){window.clearTimeout(f(this,Y)[Y]),window.clearTimeout(f(this,X)[X]),f(this,Y)[Y]=void 0,f(this,X)[X]=void 0,f(this,x)[x]=void 0,f(this,q)[q]=void 0,f(this,K)[K]=void 0,f(this,_)[_].style.display="none",f(this,_)[_].classList.remove("nonlinear"),f(this,M)[M]&&this.R()},n.o=function(t){var e=this;if(f(this,C)[C].enabled||"volumechange"===t.type){if("timeupdate"===t.type){if(f(this,M)[M]){var i=f(this,M)[M].getCuePoints().filter(function(t){return t>=0&&t=.5&&(this.dispatchEvent(new A(P.MEDIA_IMPRESSION)),f(this,F)[F]=!0)}if("play"!==t.type||f(this,G)[G]||f(this,H)[H]||(this.dispatchEvent(new A(P.MEDIA_START)),f(this,G)[G]=!0),"ended"===t.type&&(this.isCustomPlaybackUsed()&&f(this,D)[D].currentTime===f(this,D)[D].duration&&f(this,Q)[Q].indexOf(-1)>-1&&(f(this,D)[D].currentTime=f(this,D)[D].duration-1e-5,f(this,W)[W]=!0),f(this,U)[U].contentComplete(),f(this,M)[M]||this.T()),!window.ResizeObserver&&f(this,z)[z].autoResize&&"loadedmetadata"===t.type){var n=f(this,D)[D],r=n.offsetHeight,s=n.offsetWidth;f(this,j)[j]=s,f(this,N)[N]=r,this.R()}f(this,H)[H]&&"volumechange"!==t.type||this.dispatchEvent(new A(t.type))}},n.S=function(t){var e=this,i=f(this,I)[I].AdEvent;switch(t.type){case i.Type.LOADED:var n=t.getAd();f(this,$)[$]&&0===f(this,Q)[Q].length?f(this,$)[$]({ad:n,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}):f(this,V)[V]=n;break;case i.Type.AD_BREAK_READY:this.C(),f(this,$)[$]?(f(this,$)[$]({ad:f(this,V)[V],adBreakTime:t.getAdData().adBreakTime,start:function(){e.M(),f(e,$)[$]=void 0},startWithoutReset:function(){e.M()}}),f(this,V)[V]=void 0):this.M();break;case i.Type.STARTED:var r=f(this,x)[x]=t.getAd();r.getAdPodInfo().getAdPosition()>1&&f(this,M)[M].setVolume(f(this,M)[M].getVolume()),f(this,_)[_].classList.remove("nonlinear"),this.R(),r.isLinear()?(f(this,C)[C].disable(),f(this,K)[K]=r.getDuration(),f(this,q)[q]=0):(f(this,_)[_].classList.add("nonlinear"),this.I()),f(this,_)[_].style.display="",f(this,Z)[Z]&&(f(this,Z)[Z]=!1,f(this,M)[M].pause());break;case i.Type.ALL_ADS_COMPLETED:if(f(this,W)[W])return;this.isCustomPlaybackUsed()&&Boolean(f(this,x)[x])&&-1!==f(this,x)[x].getAdPodInfo().getTimeOffset()&&this.I(),this.reset();break;case i.Type.CONTENT_PAUSE_REQUESTED:this.C(),f(this,x)[x]=t.getAd(),f(this,_)[_].style.display="",f(this,D)[D].pause(),this.R(),f(this,x)[x]&&this.A(f(this,x)[x].getAdPodInfo().getTimeOffset()),f(this,M)[M].setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),f(this,C)[C].disable(),f(this,K)[K]=f(this,x)[x].getDuration(),f(this,q)[q]=0;break;case i.Type.CONTENT_RESUME_REQUESTED:var s=Boolean(f(this,x)[x]);if(s){var o=f(this,M)[M].getVolume();f(this,D)[D].muted=0===o,f(this,D)[D].volume=f(this,J)[J]}f(this,W)[W]&&(f(this,D)[D].currentTime=f(this,D)[D].duration+1,f(this,W)[W]=!1),f(this,D)[D].ended?(this.reset(),this.T()):this.C(),s&&(f(this,Z)[Z]=!1,this.I());break;case i.Type.AD_METADATA:this.g(f(this,M)[M].getCuePoints()),-1===f(this,Q)[Q].indexOf(0)&&(f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I());break;case i.Type.AD_PROGRESS:var a=t.getAdData();f(this,q)[q]=a.currentTime,f(this,K)[K]=a.duration;break;case i.Type.LOG:var u=t.getAdData();f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):u.adError&&!f(this,x)[x]&&this.I();break;case i.Type.VOLUME_CHANGED:var h=f(this,M)[M].getVolume();h>0&&(f(this,J)[J]=h)}},n.l=function(t){this.j(this.B(t))},n.u=function(t){var e=this,i=f(this,I)[I],n=i.AdEvent,r=i.AdErrorEvent.Type.AD_ERROR;window.clearTimeout(f(this,Y)[Y]);var s=f(this,M)[M]=t.getAdsManager(f(this,C)[C],f(this,k)[k]);Object.keys(n.Type).forEach(function(t){s.addEventListener(n.Type[t],function(i){if(e.S(i),P[t]){var n=["LOG","AD_PROGRESS"].indexOf(t)>-1;e.dispatchEvent(new A(P[t],{detail:{ad:i.getAd()||f(e,x)[x],adData:n?i.getAdData():{}}}))}})}),s.addEventListener(r,function(t){return e.j(e.B(t))});try{var o;s.init(f(this,j)[j],f(this,N)[N],this.k()),s.setVolume(f(this,D)[D].muted?0:f(this,D)[D].volume),null==(o=f(this,L)[L])||o.initialize(),f(this,$)[$]||this.M()}catch(a){this.j(new S(a.message))}},n.M=function(){if(f(this,G)[G]||(this.dispatchEvent(new A(P.MEDIA_START)),f(this,G)[G]=!0),f(this,M)[M])try{f(this,M)[M].start()}catch(t){this.j(new S(t.message))}else this.I()},n.T=function(){var t=this;setTimeout(function(){f(t,F)[F]=!1,f(t,G)[G]=!1,f(t,W)[W]=!1,t.dispatchEvent(new A(P.MEDIA_STOP))},1)},n.v=function(t){for(var e,i=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,e){if(t){if("string"==typeof t)return d(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);return"Object"===i&&t.constructor&&(i=t.constructor.name),"Map"===i||"Set"===i?Array.from(t):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?d(t,e):void 0}}(t))){e&&(t=e);var i=0;return function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(t);!(e=i()).done;){var n=e.value;n.contentBoxSize&&1===n.contentBoxSize.length?(f(this,j)[j]=n.contentBoxSize[0].inlineSize,f(this,N)[N]=n.contentBoxSize[0].blockSize):n.contentBoxSize&&n.contentBoxSize.inlineSize?(f(this,j)[j]=n.contentBoxSize.inlineSize,f(this,N)[N]=n.contentBoxSize.blockSize):(f(this,j)[j]=n.contentRect.width,f(this,N)[N]=n.contentRect.height)}this.R()},n.R=function(){if(f(this,z)[z].autoResize&&f(this,M)[M]){var t=f(this,x)[x],e=this.k();t&&!t.isLinear()?t&&(t.getWidth()>f(this,j)[j]||t.getHeight()>f(this,N)[N]?this.resizeAd(f(this,j)[j],f(this,N)[N]):(f(this,M)[M].resize(t.getWidth(),t.getHeight()+20,e),f(this,_)[_].style.width=t.getWidth()+"px",f(this,_)[_].style.height=t.getHeight()+20+"px")):this.resizeAd(f(this,j)[j],f(this,N)[N])}},n.k=function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||f(this,D)[D].webkitDisplayingFullscreen?f(this,I)[I].ViewMode.FULLSCREEN:f(this,I)[I].ViewMode.NORMAL},n.I=function(){var t=this;f(this,_)[_].style.display="none",f(this,D)[D].ended||(f(this,C)[C].enable(),f(this,Z)[Z]?(f(this,D)[D].pause(),this.dispatchEvent(new A("pause"))):(this.p().then(function(){}).catch(function(){t.dispatchEvent(new A("pause"))}),this.dispatchEvent(new A("play")),this.dispatchEvent(new A(P.MEDIA_RESUMED))),f(this,Z)[Z]=!1)},n.B=function(t){var e=t.getError(),i=new S(e.getMessage());return i.type=e.getType(),i.errorCode=e.getErrorCode(),i.vastErrorCode=e.getVastErrorCode&&e.getVastErrorCode(),i.innerError=e.getInnerError(),i},n.j=function(t){var e=this;this.dispatchEvent(new A(P.AD_ERROR,{detail:{error:t}})),this.C(),f(this,$)[$]?f(this,$)[$]({start:function(){e.I(),f(e,$)[$]=void 0},startWithoutReset:function(){e.I()}}):this.I()},i(e,[{key:"volume",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?f(this,M)[M].getVolume():f(this,D)[D].volume},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t),f(this,D)[D].volume=t}},{key:"muted",get:function(){return!f(this,C)[C].enabled&&f(this,M)[M]?0===f(this,M)[M].getVolume():f(this,D)[D].muted},set:function(t){!f(this,C)[C].enabled&&f(this,M)[M]&&f(this,M)[M].setVolume(t?0:f(this,J)[J]),f(this,D)[D].muted=t}},{key:"currentTime",get:function(){return void 0!==f(this,q)[q]?f(this,q)[q]:f(this,D)[D].currentTime},set:function(t){f(this,C)[C].enabled&&(f(this,D)[D].currentTime=t)}},{key:"duration",get:function(){return void 0!==f(this,K)[K]?f(this,K)[K]:f(this,D)[D].duration}},{key:"cuePoints",get:function(){return[].concat(f(this,Q)[Q])}}]),e}(w);let it=0;function nt(t){const e=t.createElement("div");return e.id=`art-vast-${Date.now()}-${++it}`,t.setStyles(e,{position:"absolute",inset:"0",width:"100%",height:"100%",zIndex:"150",backgroundColor:"black",display:"none",pointerEvents:"auto"}),e}return function(i){return n=>{return r=this,s=null,o=function*(){let r,s=!1;const o=()=>s||n.isDestroy,a={name:"artplayerPluginVast",destroy:()=>null==r?void 0:r.destroy()};function u(){if(!s){s=!0;try{n.off("destroy",u)}finally{null==r||r.destroy()}}}if(o())return a;n.on("destroy",u);try{if(o())return a;const s=yield function(){var i=window;return i.google&&i.google.ima?Promise.resolve(i.google.ima):t||((t=new Promise(function(t,e){var i=document.createElement("script");i.async=!0,i.src="https://imasdk.googleapis.com/js/sdkloader/ima3.js",i.onload=t,i.onerror=e,document.body.appendChild(i)}).then(function(){return i.google.ima})).then(e).catch(e),t)}();if(o())return a;const h=n.constructor.utils;return r=function(t,e,i,n){const{$video:r,$player:s}=t.template,o=new e.AdsRenderingSettings;o.restoreCustomPlaybackStateOnAdBreakComplete=!0,o.enablePreloading=!0;const a=new R;let u=null,h=!1,d=0;const l=t=>u===t&&!t.released&&!n();function c(t){u===t&&(u=null),t.released=!0,t.playing=!1;const e=t.player;t.player=null;const i=t.listeners.splice(0);let n,r=!1;const s=t=>{try{t()}catch(e){r?console.error("VAST cleanup error:",e):(r=!0,n=e)}};d++;try{if(e){for(const[t,n]of i)s(()=>e.removeEventListener(t,n));s(()=>e.destroy())}s(()=>{t.container.parentNode&&t.container.parentNode.removeChild(t.container)})}finally{d--}if(r)throw n}function f(){if(n()||d)return null;if(h)throw new Error("VAST initialization is already in progress");if(null==u?void 0:u.player)return u.player;let t;h=!0;try{if(t={container:nt(i),player:null,listeners:[],playing:!1,released:!1},u=t,!l(t))return c(t),null;if(s.appendChild(t.container),!l(t))return c(t),null;if(t.player=new et(e,r,t.container,o,a),!l(t))return c(t),null;const n=t;for(const[e,i]of[["AdContentPauseRequested",!0],["AdContentResumeRequested",!1],["AdStarted",!0],["AdError",!1]]){const r=t=>{l(n)&&("AdError"===e&&console.error("VAST Ad Error:",t.detail),n.playing=i,n.container.style.display=i?"block":"none")};if(t.listeners.push([e,r]),t.player.addEventListener(e,r),!l(t))return c(t),null}return t.player}catch(f){if(t)try{c(t)}catch(p){console.error("VAST cleanup error:",p)}throw f}finally{h=!1}}function p(t,i,r){if(n()||(null==u?void 0:u.playing))return;const s=f(),o=u;if(!s||!o)return;const a=function(t,e,i,n){const r=new t.AdsRequest;r[e]=i;const s=r;for(const o in n)s[o]=n[o];return r}(e,t,i,r);l(o)&&o.player===s&&s.playAds(a)}return{context:{art:t,playUrl:(t,e={})=>p("adTagUrl",t,e),playRes:(t,e={})=>p("adsResponse",t,e),init:f,ima:e,adsRenderingSettings:o,playerOptions:a,get imaPlayer(){return(null==u?void 0:u.player)||null},get container(){return(null==u?void 0:u.container)||null}},destroy:function(){u&&c(u)}}}(n,s,h,o),o()?(u(),a):("function"===typeof i&&(yield i(r.context)),a)}catch(h){try{u()}catch(d){console.error("VAST cleanup error:",d)}throw h}},new Promise((t,e)=>{var i=t=>{try{a(o.next(t))}catch(i){e(i)}},n=t=>{try{a(o.throw(t))}catch(i){e(i)}},a=e=>e.done?t(e.value):Promise.resolve(e.value).then(i,n);a((o=o.apply(r,s)).next())});var r,s,o}}}); diff --git a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.mjs b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.mjs index fb8194a22..df954611f 100644 --- a/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.mjs +++ b/packages/artplayer-plugin-vast/dist/artplayer-plugin-vast.mjs @@ -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 { diff --git a/packages/artplayer-plugin-vast/package.json b/packages/artplayer-plugin-vast/package.json index b08c64150..dc421a960 100644 --- a/packages/artplayer-plugin-vast/package.json +++ b/packages/artplayer-plugin-vast/package.json @@ -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" } } diff --git a/packages/artplayer-plugin-vast/src/index.js b/packages/artplayer-plugin-vast/src/index.js deleted file mode 100644 index 7c3cc904c..000000000 --- a/packages/artplayer-plugin-vast/src/index.js +++ /dev/null @@ -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, - } - } -} diff --git a/packages/artplayer-plugin-vast/src/index.ts b/packages/artplayer-plugin-vast/src/index.ts new file mode 100644 index 000000000..9263a2de2 --- /dev/null +++ b/packages/artplayer-plugin-vast/src/index.ts @@ -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 => { + let disposed = false + let session: ReturnType | 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 + } + } +} diff --git a/packages/artplayer-plugin-vast/src/sdk.ts b/packages/artplayer-plugin-vast/src/sdk.ts new file mode 100644 index 000000000..2565d48e4 --- /dev/null +++ b/packages/artplayer-plugin-vast/src/sdk.ts @@ -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 + for (const key in config) + fields[key] = config[key] + return request +} diff --git a/packages/artplayer-plugin-vast/src/session.ts b/packages/artplayer-plugin-vast/src/session.ts new file mode 100644 index 000000000..0c8cf01d3 --- /dev/null +++ b/packages/artplayer-plugin-vast/src/session.ts @@ -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).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 } +} diff --git a/packages/artplayer-plugin-vast/src/types.ts b/packages/artplayer-plugin-vast/src/types.ts new file mode 100644 index 000000000..b7517788c --- /dev/null +++ b/packages/artplayer-plugin-vast/src/types.ts @@ -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 +export type RequestConfig = Record + +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 +} diff --git a/packages/artplayer-plugin-vast/src/view.ts b/packages/artplayer-plugin-vast/src/view.ts new file mode 100644 index 000000000..b62521a40 --- /dev/null +++ b/packages/artplayer-plugin-vast/src/view.ts @@ -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 +} diff --git a/packages/artplayer-plugin-vast/tsconfig.json b/packages/artplayer-plugin-vast/tsconfig.json new file mode 100644 index 000000000..285047f94 --- /dev/null +++ b/packages/artplayer-plugin-vast/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "allowJs": false }, + "include": ["src/**/*.ts", "types/**/*.d.ts"] +} diff --git a/refactor/baselines/vast-lifecycle-validation.json b/refactor/baselines/vast-lifecycle-validation.json new file mode 100644 index 000000000..3c6c80241 --- /dev/null +++ b/refactor/baselines/vast-lifecycle-validation.json @@ -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": [] + } + ] + } + } +} diff --git a/refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md b/refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md new file mode 100644 index 000000000..1ee0b29ce --- /dev/null +++ b/refactor/changes/2026-09-12-PKG-VAST-03-lifecycle.md @@ -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当前 +最小公开消费者的缺失类型错误均消除,但同步返回误声明仍开放。 diff --git a/refactor/plan.md b/refactor/plan.md index efa0dbff0..0c5447b19 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -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
核对包契约与历史用法 | 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
建立特有行为与错误测试 | PKG-VAST-01, ENG-03, ENG-05 | SDK 失败、重复初始化、广告事件、内容恢复和销毁竞态;发布 id/$container/eager 与工作区 lazy/config 覆盖、callback拒绝、加载中销毁、同毫秒多实例与晚到事件 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | -| PKG-VAST-03 | artplayer-plugin-vast
整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | +| PKG-VAST-03 | artplayer-plugin-vast
整理内部职责与资源 | PKG-VAST-02, CORE-10, CORE-13 | SDK loader、IMA adapter、广告状态和 DOM 清理分离;保持发布 callback 别名,明确初始化冲突;核心终止与显式 destroy 后重建区分 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | doing | | PKG-VAST-04 | artplayer-plugin-vast
迁移自有源码和公开类型 | 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
验证新旧核心和组合 | 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
验证分发并同步文档 | 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) diff --git a/refactor/progress.md b/refactor/progress.md index c90144dd1..9541d1e37 100644 --- a/refactor/progress.md +++ b/refactor/progress.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成员已归档。 diff --git a/refactor/risks.json b/refactor/risks.json index 222663318..f0d506811 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -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", diff --git a/refactor/tasks.json b/refactor/tasks.json index cc2bab517..5bd9bed14 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -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", diff --git a/refactor/third-party.json b/refactor/third-party.json index d174c1d67..95bab3c67 100644 --- a/refactor/third-party.json +++ b/refactor/third-party.json @@ -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.", diff --git a/refactor/vast-compatibility-decision.md b/refactor/vast-compatibility-decision.md new file mode 100644 index 000000000..5587405c4 --- /dev/null +++ b/refactor/vast-compatibility-decision.md @@ -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的类型推导批准不适用于本决策。 +需要用户确认是否按推荐方案优先实际发布默认行为;也可指定其他取舍。 diff --git a/refactor/vast-validation.md b/refactor/vast-validation.md index 710eb27cc..df2aa17d3 100644 --- a/refactor/vast-validation.md +++ b/refactor/vast-validation.md @@ -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记录器,控制加载、构造、 diff --git a/test/browser/vast.spec.js b/test/browser/vast.spec.js index ba926d541..b379aa09c 100644 --- a/test/browser/vast.spec.js +++ b/test/browser/vast.spec.js @@ -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) + }) + } } } diff --git a/test/helpers/vast-sdk.js b/test/helpers/vast-sdk.js index fa134511d..c0bd35eef 100644 --- a/test/helpers/vast-sdk.js +++ b/test/helpers/vast-sdk.js @@ -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() } }, diff --git a/test/vast-lifecycle.test.js b/test/vast-lifecycle.test.js new file mode 100644 index 000000000..98901c64f --- /dev/null +++ b/test/vast-lifecycle.test.js @@ -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) + }) +} diff --git a/yarn.lock b/yarn.lock index abd50ac77..2a997d8d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"