diff --git a/docs/compiled/artplayer.js b/docs/compiled/artplayer.js index e86e16adf..4782ac7ff 100644 --- a/docs/compiled/artplayer.js +++ b/docs/compiled/artplayer.js @@ -67,4 +67,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var o=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function m(t,e=document){return e.querySelector(t)}function f(t,e=document){return Array.from(e.querySelectorAll(t))}function g(t,e){return t.classList.add(e)}function v(t,e){return t.classList.remove(e)}function y(t,e){return t.classList.contains(e)}function b(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function w(t){return t.parentNode.removeChild(t)}function x(t,e,r){return t.style[e]=r,t}function k(t,e){for(const r in e)x(t,r,e[r]);return t}function $(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function E(t,e){$(t).forEach(t=>v(t,e)),g(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),g(t,"hint--rounded"),g(t,`hint--${r}`))}function C(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function z(t,e){return R(t).includes(e)}function L(t,e){return e.parentNode.replaceChild(t,e),t}function S(t){return document.createElement(t)}function M(t="",e=""){const r=S("i");return g(r,"art-icon"),g(r,`art-icon-${t}`),b(r,e),r}function A(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function P(t){return t.getBoundingClientRect()}function I(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function N(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function D(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function F(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function H(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const W={"&":"&","<":"<",">":">","'":"'",'"':"""},j={"&":"&","<":"<",">":">","'":"'",""":'"'},U=/(&|<|>|'|")/g;function q(t){return t.replace(/[&<>'"]/g,t=>W[t]||t)}const X=Object.defineProperty,{hasOwnProperty:G}=Object.prototype;function K(t,e){return G.call(t,e)}function Z(t,e){return Object.getOwnPropertyDescriptor(t,e)}function J(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];let i;i=Array.isArray(a)&&Array.isArray(n)?a.concat(...n):e(a)&&e(n)?J(a,n):n,X(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function Q(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function tt(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function et(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,a="",n="",,,i=""]=o;return{start:r(a.trim()),end:r(n.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function rt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ot=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:g,append:b,assToVtt:et,capitalize:H,clamp:F,createElement:S,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:X,download:D,errorHandle:V,escape:q,get:Z,getComposedPath:R,getExt:N,getIcon:M,getRect:P,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:K,hasClass:y,includeFromEvent:z,inverseClass:E,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:C,isMobile:p,isSafari:l,loadImg:I,mergeDeep:J,query:m,queryAll:f,remove:w,removeClass:v,replaceElement:L,secondToTime:B,setStyle:x,setStyleText:u,setStyles:k,siblings:$,silencePromise:Y,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:Q,supportsFlex:A,throttle:rt,tooltip:T,unescape:function(t){return t.replace(U,t=>j[t]||t)},userAgent:s,vttToBlob:tt},Symbol.toStringTag,{value:"Module"})),at="array",nt="boolean",it="string",st="number",lt="object",ct="function";function dt(t,e,r){return V(e===it||e===st||t instanceof Element,`${r.join(".")} require '${it}' or 'Element' type`)}const pt={html:dt,disable:`?${nt}`,name:`?${it}`,index:`?${st}`,style:`?${lt}`,click:`?${ct}`,mounted:`?${ct}`,tooltip:`?${it}|${st}`,width:`?${st}`,selector:`?${at}`,onSelect:`?${ct}`,switch:`?${nt}`,onSwitch:`?${ct}`,range:`?${at}`,onRange:`?${ct}`,onChange:`?${ct}`},ht={id:it,container:dt,url:it,poster:it,type:it,theme:it,lang:it,volume:st,isLive:nt,muted:nt,autoplay:nt,autoSize:nt,autoMini:nt,loop:nt,flip:nt,playbackRate:nt,aspectRatio:nt,screenshot:nt,setting:nt,hotkey:nt,pip:nt,mutex:nt,backdrop:nt,fullscreen:nt,fullscreenWeb:nt,subtitleOffset:nt,miniProgressBar:nt,useSSR:nt,playsInline:nt,lock:nt,gesture:nt,fastForward:nt,autoPlayback:nt,autoOrientation:nt,airplay:nt,proxy:`?${ct}`,plugins:[ct],layers:[pt],contextmenu:[pt],settings:[pt],controls:[{...pt,position:(t,e,r)=>{const o=["top","left","right"];return V("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}}],quality:[{default:`?${nt}`,html:it,url:it}],highlight:[{time:st,text:it}],thumbnails:{url:it,number:st,column:st,width:st,height:st,scale:st},subtitle:{url:it,name:it,type:it,style:lt,escape:nt,encoding:it,onVttLoad:ct},moreVideoAttr:lt,i18n:lt,icons:lt,cssVar:lt,customType:lt};class ut{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return y(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?g(e,r):v(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",a(e,pt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=S("div");g(o,`art-${this.name}`),g(o,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));i?i.insertAdjacentElement("beforebegin",o):b(this.$parent,o),e.html&&b(o,e.html),e.style&&k(o,e.style),e.tooltip&&T(o,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,s),this[r]=o,this.cache.set(r,{$ref:o,events:s,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],w(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class mt extends ut{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=m('[data-value="1"]',t);r&&E(r,"art-current"),e.on("video:ratechange",()=>{const r=f("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&E(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=m('[data-value="default"]',t);r&&E(r,"art-current"),e.on("aspectRatio",e=>{const r=f("span",t).find(t=>t.dataset.value===e);r&&E(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(H(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=m('[data-value="normal"]',t);r&&E(r,"art-current"),e.on("flip",e=>{const r=f("span",t).find(t=>t.dataset.value===e);r&&E(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=P(r),{height:c,width:d}=P(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),k(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{z(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}class ft extends Error{constructor(t){super("Failed to release ArtPlayer resources"),this.errors=t,this.name="ResourceCleanupError"}}class gt{constructor(){this.cleanups=new Set,this.disposed=!1}get closed(){return this.disposed}add(t){let e=!0;const r=()=>{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new gt,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof ft?t.push(...e.errors):t.push(e)}if(t.length)throw new ft(t)}}const vt=new WeakMap,yt=new WeakMap;function bt(t){const e=vt.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function wt(t){return bt(t).scope}function xt(t){const e=bt(t);return e.destroying||e.scope.closed}function kt(t,e,r,o,a=!1){const n=bt(t);if(n.destroying||n.scope.closed)return;n.destroying=!0;const i=[],s=t=>{try{t()}catch(e){i.push(...e instanceof ft?e.errors:[e])}};o&&t.template?.$video&&s(()=>t.reset()),s(()=>n.scope.dispose()),s(()=>t.template?.destroy(r));const l=e.indexOf(t);-1!==l&&e.splice(l,1),t.isDestroy=!0,a||(n.releaseContainer?.(),n.releaseContainer=void 0),s(()=>t.emit("destroy")),a&&n.rollback&&s(n.rollback),n.rollback=void 0,n.releaseContainer?.(),n.releaseContainer=void 0;for(const c of i.slice(1))console.warn("Additional ArtPlayer cleanup failure:",c);if(i.length)throw i[0]}function $t(t,e,r){if(t.closed)return()=>{};let o=!0,a=()=>{};const n=setTimeout(()=>{o&&(a(),t.closed||e())},r);return a=t.add(()=>{o=!1,clearTimeout(n)}),a}function Et(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,a=()=>{};const n=setTimeout(()=>{o=!0,a(),r(!0)},e);a=t.add(()=>{clearTimeout(n),o||r(!1)})})}function Tt(t,e){const{$progress:r}=t.template,{left:o}=P(r),a=F((p?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:B(n),width:a,percentage:F(a/r.clientWidth,0,1)}}function Ct(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function zt(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=m(".art-progress-hover",t),d=m(".art-progress-loaded",t),h=m(".art-progress-played",t),u=m(".art-progress-highlight",t),f=m(".art-progress-indicator",t),y=m(".art-progress-tip",t);function w(r,o){const{width:a,time:n}=o||Tt(e,r);y.textContent=n||"00:00";const i=y.clientWidth;a<=i/2?x(y,"left",0):a>t.clientWidth-i/2?x(y,"left",t.clientWidth-i+"px"):x(y,"left",a-i/2+"px")}r.indicator?b(f,r.indicator):x(f,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&p;if("loaded"===r&&x(d,"width",100*o+"%"),"hover"===r&&(x(c,"width",100*o+"%"),z(a,u)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;y.textContent=a;const n=y.clientWidth;o<=n/2?x(y,"left",0):o>t.clientWidth-n/2?x(y,"left",t.clientWidth-n+"px"):x(y,"left",o-n/2+"px")}(a):w(a),0===o?v(n,"art-progress-hover"):g(n,"art-progress-hover")),"played"===r&&(x(h,"width",100*o+"%"),x(f,"left",100*o+"%")),i){g(n,"art-progress-hover");w(a,{width:t.clientWidth*o,time:B(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{v(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){u.textContent="";for(let t=0;t`;b(u,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(a(i,"click",t=>{t.target!==f&&Ct(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class Lt extends ut{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=z(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(v(r,"art-hide-cursor"),g(r,"art-hover"),this.timer=Date.now()):(g(r,"art-hide-cursor"),v(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(zt({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.play),i=b(t,o.pause);function s(){x(n,"display","flex"),x(i,"display","none")}function l(){x(n,"display","none"),x(i,"display","flex")}T(n,a.get("Play")),T(i,a.get("Pause")),r(n,"click",()=>{Y(e.play())}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:o}=e,a=b(t,o.volume),n=b(t,o.volumeClose),i=b(t,'
'),s=b(i,'
'),l=b(s,'
'),c=b(s,'
'),d=b(c,'
'),h=b(d,'
'),u=b(c,'
');function m(t){const{top:e,height:r}=P(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)x(a,"display","none"),x(n,"display","flex"),x(u,"top","100%"),x(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;x(a,"display","flex"),x(n,"display","none"),x(u,"top",100-t+"%"),x(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)x(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{e&&!wt(this.art).closed&&(this.art.quality=t.quality)}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;b(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;b(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;b(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;b(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.fullscreenWebOn),i=b(t,o.fullscreenWebOff);x(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,a.get("Exit Web Fullscreen")),x(n,"display","none"),x(i,"display","inline-flex")):(T(t,a.get("Web Fullscreen")),x(n,"display","inline-flex"),x(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.fullscreenOn),i=b(t,o.fullscreenOff);x(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,a.get("Exit Fullscreen")),x(n,"display","none"),x(i,"display","inline-flex")):(T(t,a.get("Fullscreen")),x(n,"display","inline-flex"),x(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),X(e,"$control_item",{get:()=>r}),X(e,"$control_value",{get:()=>a})}const i=o(n,"click",async e=>{const r=R(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=await t.onSelect.call(this.art,o,o.$control_item,e))});r.push(i)}}function St(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function Mt(t){if(t.constructor.USE_RAF){const e=wt(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const a=requestAnimationFrame(a=>{r&&(o(),t.closed||e(a))});return o=t.add(()=>{r=!1,cancelAnimationFrame(a)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const At=new WeakMap;class Pt{constructor(t){this.destroyEvents=new Set;const e=wt(t);At.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){z(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&a&&Y(t.toggle()):Y(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&Y(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{g(r,"art-hover"),t.emit("hover",!0,e)},e=>{v(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=wt(t);let n=()=>{};const i=()=>{n(),n=$t(a,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Ct(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=St(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=F((o-i)/t.width,-1,1),d=F((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=F(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",F(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=rt(()=>{t.emit("view",C(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{const o=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(o,r,e=>{t.emit(`window:${r}`,e)});a.push(s)})}n(),e.bindGlobalEvents=n}(t,this),Mt(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(At.get(this).closed)return()=>{};t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class It{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{Y(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Vt{constructor(t){const e={..._t,...t.option.icons};for(const r in e)X(this,r,{get:()=>M(r,e[r])})}}class Yt extends ut{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=()=>{};const i=f("[data-video]",r)||[];this.art.on("destroy",()=>n());const s=wt(this.art);!function t(){for(let e=0;e{x(a,"display","none"),x(n,"display",null)}),o.proxy(e.$state,"click",()=>Y(t.play()))}}class Ht{constructor(t){this.art=t,this.timer=null,wt(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(wt(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,g(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",v(r,"art-notice-show")},e.NOTICE_TIME)):v(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function Bt(t,e,r,o=!1){const a=e=>{xt(t)||r(e)};t[o?"once":"on"](e,a),wt(t).add(()=>{t.off(e,a)})}function Wt(t,e,r){for(const[o,a]of e){if(xt(t)||r&&!r())return;t[o].show=a}}const jt=new WeakMap,Ut=new WeakMap,qt=new WeakMap;function Xt(t){return qt.get(t)||wt(t)}function Gt(t){const e=jt.get(t),r=qt.get(t);return()=>jt.get(t)===e&&(!e||e.active())&&qt.get(t)===r&&(!r||!r.closed)}function Kt(t){const e=qt.get(t),r=wt(t).child(),o=r.child();qt.set(t,r),r.add(()=>{qt.get(t)===r&&qt.delete(t)});const a={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!xt(t)&&!o.closed&&jt.get(t)===a};return jt.set(t,a),o.add(()=>{jt.get(t)===a&&jt.delete(t),a.onAssigned=void 0,a.onError=void 0}),e?.dispose(),a}function Zt(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&e?.()}function Jt(t,e,r){Ut.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{Ut.get(t)===e&&(Ut.delete(t),Zt(e))}}function Qt(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function te(t){const{option:e,constructor:r,i18n:o,notice:a,template:{$player:n}}=t;let i,s=Xt(t),l=0;return{reset(){l=0,i?.dispose(),v(n,"art-error")},loadStart(){v(n,"art-error")},schedule(c){(async c=>{if(xt(t))return;const d=Xt(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const h=()=>!xt(t)&&!p.closed&&d===Xt(t),u=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ee(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{xt(t)||t.emit(`video:${e.type}`,e)})}(t);const e=te(t);!function(t,e){Bt(t,"video:canplay",()=>{e.reset(),Wt(t,[["loading",!1]])}),Bt(t,"video:canplay",()=>{Wt(t,[["loading",!1],["controls",!0],["mask",!0]]),xt(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;Bt(t,"video:ended",()=>{if(e.loop){const e=Gt(t);if(t.seek=0,xt(t)||!e())return;Y(t.play()),e()&&Wt(t,[["controls",!1],["mask",!1]],e)}else Wt(t,[["controls",!0],["mask",!0]])})}(t),Bt(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;Bt(t,"video:loadedmetadata",()=>{t.emit("resize"),p&&Wt(t,[["loading",!1],["controls",!0],["mask",!0]])}),Bt(t,"video:loadstart",()=>{e.loadStart(),Wt(t,[["loading",!0],["mask",!1],["controls",!0]])}),Bt(t,"video:pause",()=>{Wt(t,[["controls",!0],["mask",!0]])}),Bt(t,"video:play",()=>{Wt(t,[["mask",!1]]),xt(t)||x(r,"display","none")}),Bt(t,"video:playing",()=>Wt(t,[["mask",!1]])),Bt(t,"video:progress",()=>{t.playing&&Wt(t,[["loading",!1]])}),Bt(t,"video:seeked",()=>Wt(t,[["loading",!1],["mask",!0]])),Bt(t,"video:seeking",()=>Wt(t,[["loading",!0],["mask",!1]])),Bt(t,"video:timeupdate",()=>Wt(t,[["mask",!1]])),Bt(t,"video:waiting",()=>Wt(t,[["loading",!0],["mask",!1]]))}(t,e)}const re=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],oe=(()=>{if("undefined"===typeof document)return!1;const t=re[0],e={};for(const r of re){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),ae={change:oe.fullscreenchange,error:oe.fullscreenerror},ne={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{ne.off("change",a),r()};ne.on("change",a);const n=t[oe.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!ne.isFullscreen)return void t();const r=()=>{ne.off("change",r),t()};ne.on("change",r);const o=document[oe.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>ne.isFullscreen?ne.exit():ne.request(t,e),onchange(t){ne.on("change",t)},onerror(t){ne.on("error",t)},on(t,e){const r=ae[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=ae[t];r&&document.removeEventListener(r,e,!1)},raw:oe};function ie(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;t.once("video:loadedmetadata",()=>{var n;ne.isEnabled?(n=t,ne.on("change",()=>{n.emit("fullscreen",ne.isFullscreen),ne.isFullscreen?(n.state="fullscreen",g(a,"art-fullscreen")):v(a,"art-fullscreen"),n.emit("resize")}),ne.on("error",t=>{n.emit("fullscreenError",t)}),X(n,"fullscreen",{get:()=>ne.isFullscreen,async set(t){t?await ne.request(a):await ne.exit()}})):o.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),X(t,"fullscreen",{get:()=>document.fullscreenElement===o,set(e){e?(t.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})})(t):X(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),X(t,"fullscreen",Z(t,"fullscreen"))})}function se(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(v(a,"art-mini"),x(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(x(e,"display","none"),x(r,"display","flex")):(x(e,"display","flex"),x(r,"display","none"))}function p(){const{$mini:e}=t.template,r=P(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),x(e,"top",`${a}px`),x(e,"left",`${n}px`)}X(t,"mini",{get:()=>y(a,"art-mini"),set(h){if(h){t.state="mini",g(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return b(a,n),x(a,"display","flex");{const a=S("div");g(a,"art-mini-popup"),b(document.body,a),t.template.$mini=a,b(a,n);const p=b(a,'
');b(p,e.close),r(p,"click",c);const h=b(a,'
'),u=b(h,e.play),m=b(h,e.pause);return r(u,"click",()=>Y(t.play())),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){g(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;x(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,v(a,"art-mini-dragging");const t=P(a);o.set("left",t.left),o.set("top",t.top),x(a,"left",`${t.left}px`),x(a,"top",`${t.top}px`),x(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(x(h,"top",`${u}px`),x(h,"left",`${m}px`),C(h)||p()):p(),t.emit("mini",!0)}else c()}})}function le(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,X(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),X(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):X(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function ce(t,e,r,o,a=!0){let n,i=!1;const s=e=>{t.closed||i||(a&&(i=!0,n()),o(e))};return e[a?"once":"on"](r,s),n=t.add(()=>{e.off(r,s)}),s}function de(t,e,r){return new Promise((o,a)=>{if(xt(t)||e===t.url)return void o();const n=Kt(t),i=n.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,n.onError=void 0,n.onAssigned=void 0,i.dispose(),t?a(e):o(),t&&n.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&n.active(),d=t=>l(!0,t);n.onError=d;try{const{playing:o,aspectRatio:a,playbackRate:s}=t;if(t.pause(),!c())return;const p=i.child(),h={"video:error":d,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){d(e)}},"video:canplay":()=>{if(!c())return;p.dispose();(async()=>{if(t.playbackRate=s,c()&&(t.aspectRatio=a,c())){if(o)try{await t.play()}catch{}c()&&(t.notice.show="",l())}})().catch(d)}},u=i.child(),m=[],f=Object.keys(h);for(const e of f)ce(u,t,e,t=>{n.acceptingEvents&&m.push([e,t])},!1);if(Jt(t,n,e),!c())return;if(t.notice.show="",!c())return;const g=()=>{if(u.dispose(),!e)return void l();const r={};for(const e of f)r[e]=ce(p,t,e,h[e]);for(const[t,e]of m){if(!c()||p.closed)break;r[t](e)}m.length=0};n.assigned?g():n.onAssigned=g}catch(p){d(p)}})}function pe(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",async(a,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===a||"played"===a&&l&&p){if(i||n||(n=!0,i=await I(d,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-h/2?x(n,"left",r.clientWidth-h+"px"):x(n,"left",a-h/2+"px")}(a)}}),X(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}function he(t){const{option:e,template:{$video:r}}=t;X(t,"url",{get:()=>r.src,async set(o){if(xt(t))return;const a=function(t){const e=Ut.get(t);return Ut.delete(t),e||Kt(t)}(t);a.acceptingEvents=!1;try{if(!o)return void(await Et(a.scope)&&a.active()&&(t.loading.show=!0));const n=t.url,i=e.type||N(o),s=e.customType[i];if(i&&s){if(!(await Et(a.scope))||!a.active())return;t.loading.show=!0}if(!a.active())return;const l=a.scope.child();let c=!1,d=!1;ce(l,t,"video:canplay",()=>{c=!d}),ce(l,t,"video:error",()=>{d=!0});try{if(a.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>Qt(a,t))}else{if(n&&URL.revokeObjectURL(n),!a.active())return;r.src=o}}finally{l.dispose()}if(!a.active())return;if(n!==t.url&&(t.option.url=o,a.active()&&t.isReady&&n)){const e=()=>{a.active()&&t.emit("restart",o)};c?e():d||ce(a.scope,t,"video:canplay",e)}}catch(n){Qt(a,n)}finally{Zt(a)}}})}Object.defineProperties(ne,{isFullscreen:{get:()=>Boolean(document[oe.fullscreenElement])},element:{enumerable:!0,get:()=>document[oe.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[oe.fullscreenEnabled])}});class ue{constructor(t){he(t),function(t){const{template:{$video:e}}=t;X(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;X(t,"play",{async value(){const i=Gt(t),s=await n.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;X(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;X(t,"forward",{set(e){r.seek=t.currentTime+e}}),X(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;X(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=F(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&a.set("volume",e.volume)}}),X(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;X(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=F(o,0,t.duration))}})}(t),function(t){X(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>de(t,e,0);X(t,"switchQuality",{value:e=>de(t,e,t.currentTime)}),X(t,"switchUrl",{value:e}),X(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,a=t;X(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else a.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;X(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)x(o,"width",null),x(o,"height",null),x(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(x(o,"width",s*r+"px"),x(o,"height","100%"),x(o,"margin","0 auto")):(x(o,"width","100%"),x(o,"height",e/s+"px"),x(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=S("canvas");X(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),X(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),X(t,"screenshot",{value:async e=>{const o=await t.getDataURL();return D(o,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",o),o}})}(t),ie(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";X(t,"fullscreenWeb",{get:()=>y(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&b(document.body,o),t.state="fullscreenWeb",x(o,"width","100%"),x(o,"height","100%"),g(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&b(r,o),a&&(o.style.cssText=a,a=""),v(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),le(t),function(t){const{$video:e}=t.template,r=t;X(t,"loaded",{get:()=>r.loadedTime/e.duration}),X(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){X(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;X(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;X(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=P(e),l=a/n;if(i/s>l)x(r,"width",s*l/i*100+"%"),x(r,"height","100%");else{const t=i/l/s*100;x(r,"width","100%"),x(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;X(t,"rect",{get:()=>P(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[a]})}X(t,"x",{get:()=>e.left+window.pageXOffset}),X(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;X(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(H(a))}`,t.emit("flip",a)}})}(t),se(t),function(t){const{template:{$poster:e}}=t;X(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){x(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;X(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);x(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;X(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){X(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){X(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];X(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;oo.$track?.offset||0,set(a){const{cues:n}=t.subtitle;if(!o.$track||0===n.length)return;const i=F(a,-10,10);o.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,X(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){X(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),pe(t),ee(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=F(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=F(n,0,1)),e.poster&&x(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function me(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!y(o,n)&&function(){const e=O(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;x(o,"width",`${a}px`),x(o,"height",`${i}px`),x(o,"transform-origin","0 0"),x(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),g(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else y(o,n)&&(x(o,"width",""),x(o,"height",""),x(o,"transform-origin",""),x(o,"transform",""),v(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,g(o,i)}catch(a){s=!1,e.show=a}}else if(y(o,i)&&v(o,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return y(o,n)}}}function fe(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=m(".art-auto-playback-last",s),c=m(".art-auto-playback-jump",s),d=m(".art-auto-playback-close",s);b(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),x(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(x(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{x(s,"display","none")}),n(c,"click",()=>{t.seek=r,Y(t.play()),x(i,"display","none"),x(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{x(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function ge(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,v(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,g(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return y(o,"art-fast-forward")}}}function ve(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return y(o,"art-lock")}function n(){g(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){v(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=b(e,r.lock),a=b(e,r.unlock);x(o,"display","none"),t.on("lock",t=>{t?(x(o,"display","inline-flex"),x(a,"display","none")):(x(o,"display","none"),x(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function ye(t){return t.on("control",e=>{e?v(t.template.$player,"art-mini-progress-bar"):g(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class be{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){xt(t.art)||!e.miniProgressBar||e.isLive||t.add(ye),!xt(t.art)&&e.lock&&p&&t.add(ve),xt(t.art)||!e.autoPlayback||e.isLive||t.add(fe),!xt(t.art)&&e.autoOrientation&&p&&t.add(me),!xt(t.art)&&e.fastForward&&p&&!e.isLive&&t.add(ge)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){V(!xt(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(xt(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(xt(t.art))return t;let a=o;const n=K(t,a);if(xt(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return xt(t.art)||(V(!n,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(a=Reflect.ownKeys({[a]:void 0})[0]),xt(t.art)||X(t,a,{value:r})),t}(this,t,e)}}class we extends ut{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=z(t,r.setting),o=z(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(H(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&E(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),X(n,"$parents",{get:()=>r}),X(n,"$option",{get:()=>t});const o=[];X(n,"$events",{get:()=>o}),X(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:o,$setting:a}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=P(t.setting),{left:l,width:c}=P(o),d=i-l+s/2-n/2;if(x(a,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),x(a,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(x(a,"left",null),x(a,"right",null)):(x(a,"left",`${d}px`),x(a,"right","auto"))}}inactivate(t){for(let e=0;e'),s=S("div");g(s,"art-setting-item-left-icon"),b(s,o),b(i,s),b(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),b(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),o=t.$item;let a="selector";K(t,"switch")&&(a="switch"),K(t,"range")&&(a="range"),K(t,"onClick")&&(a="button");const{icons:n,proxy:i,constructor:s}=this.art,l=S("div");g(l,"art-setting-item"),x(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=b(l,'
'),d=b(l,'
'),p=S("div");switch(g(p,"art-setting-item-left-icon"),a){case"button":case"switch":case"range":b(p,t.icon||n.config);break;case"selector":t.selector?.length?b(p,t.icon||n.config):b(p,n.check)}b(c,p),X(t,"$icon",{configurable:!0,get:()=>p}),X(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",b(p,t)}});const h=S("div");g(h,"art-setting-item-left-text"),b(h,t.html||""),b(c,h),X(t,"$html",{configurable:!0,get:()=>h}),X(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",b(h,t)}});const u=S("div");switch(g(u,"art-setting-item-right-tooltip"),b(u,t.tooltip||""),b(d,u),X(t,"$tooltip",{configurable:!0,get:()=>u}),X(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",b(u,t)}}),a){case"switch":{const e=S("div");g(e,"art-setting-item-right-icon");const r=b(e,n.switchOn),o=b(e,n.switchOff);x(t.switch?o:r,"display","none"),b(d,e),X(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;X(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(x(o,"display","none"),x(r,"display",null)):(x(o,"display",null),x(r,"display","none"))}});break}case"range":{const e=S("div");g(e,"art-setting-item-right-icon");const r=b(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],g(r,"art-setting-range"),b(d,e),X(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];X(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=S("div");g(t,"art-setting-item-right-icon"),b(t,n.arrowRight),b(d,t)}}switch(a){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&g(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}X(t,"$item",{configurable:!0,get:()=>l}),e?L(l,o):b(r,l),t.mounted&&$t(wt(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){E(this.cache.get(t),"art-current")}else{const e=S("div");this.cache.set(t,e),g(e,"art-setting-panel"),b(this.$parent,e),E(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?k(r,t):x(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?q(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n={...a.subtitle,...e,url:t},i=await this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=S("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,w(i),b(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(a(t,ht.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||N(t.url)){case"srt":{const e=Q(r);return tt(t.onVttLoad(e))}case"ass":{const e=et(r);return tt(t.onVttLoad(e))}case"vtt":return tt(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}const Ee=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Te{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=m(e.container),V(this.$container,`No container element found by ${e.container}`)),V(A(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();V("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=yt.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const a=bt(t);a.rollback=r,yt.set(e,t),a.releaseContainer=()=>{yt.get(e)===t&&yt.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:a}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=a}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ee}query(t){return m(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Te.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){V(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),L(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&g(this.$player,"art-backdrop"),p&&g(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":g(this.$player,"art-destroy")}}const Ce=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class ze{on(t,e,r){const o=this.e||(this.e={});let a=Ce(o,t)?o[t]:void 0;return a||(a=[],Object.defineProperty(o,t,{value:a,enumerable:!0,configurable:!0,writable:!0})),a.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,a=e;let n=!1;function i(...e){n||(n=!0,o.off(t,i),a.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Ce(r,t)&&r[t]||[]).slice();for(const a of o)a.fn.apply(a.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Ce(r,t)?r[t]:void 0,a=[];if(o&&e)for(let n=0,i=o.length;ne.call(this,this)),Me.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Me.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=bt(t);return e.rollback=void 0,!e.scope.closed})(this)&&Se.push(this)}catch(o){try{kt(this,Se,!0,Me.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return Se}static get version(){return n}static get config(){return i}static get utils(){return ot}static get scheme(){return ht}static get Emitter(){return ze}static get validator(){return a}static get kindOf(){return a.kindOf}static get html(){return Te.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){kt(this,Se,t,Me.REMOVE_SRC_WHEN_DESTROY)}}return Me.STYLE=ke,Me.DEBUG=!1,Me.CONTEXTMENU=!0,Me.NOTICE_TIME=2e3,Me.SETTING_WIDTH=250,Me.SETTING_ITEM_WIDTH=200,Me.SETTING_ITEM_HEIGHT=35,Me.RESIZE_TIME=200,Me.SCROLL_TIME=200,Me.SCROLL_GAP=50,Me.AUTO_PLAYBACK_MAX=10,Me.AUTO_PLAYBACK_MIN=5,Me.AUTO_PLAYBACK_TIMEOUT=3e3,Me.RECONNECT_TIME_MAX=5,Me.RECONNECT_SLEEP_TIME=1e3,Me.CONTROL_HIDE_TIME=3e3,Me.DBCLICK_TIME=300,Me.DBCLICK_FULLSCREEN=!0,Me.MOBILE_DBCLICK_PLAY=!0,Me.MOBILE_CLICK_PLAY=!1,Me.AUTO_ORIENTATION_TIME=200,Me.INFO_LOOP_TIME=1e3,Me.FAST_FORWARD_VALUE=3,Me.FAST_FORWARD_TIME=1e3,Me.TOUCH_MOVE_RATIO=.5,Me.VOLUME_STEP=.1,Me.SEEK_STEP=5,Me.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Me.ASPECT_RATIO=["default","4:3","16:9"],Me.FLIP=["normal","horizontal","vertical"],Me.FULLSCREEN_WEB_IN_BODY=!0,Me.LOG_VERSION=!0,Me.USE_RAF=!1,Me.REMOVE_SRC_WHEN_DESTROY=!0,h&&(window.Artplayer=Me,u("artplayer-style",ke),setTimeout(()=>{Me.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Me.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Me}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var o=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new l,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof s?t.push(...e.errors):t.push(e)}if(t.length)throw new s(t)}}const c=new WeakMap,d=new WeakMap;function p(t){const e=c.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function h(t){return p(t).scope}function u(t){const e=p(t);return e.destroying||e.scope.closed}function f(t,e,r,o,n=!1){const a=p(t);if(a.destroying||a.scope.closed)return;a.destroying=!0;const i=[],l=t=>{try{t()}catch(e){i.push(...e instanceof s?e.errors:[e])}};o&&t.template?.$video&&l(()=>t.reset()),l(()=>a.scope.dispose()),l(()=>t.template?.destroy(r));const c=e.indexOf(t);-1!==c&&e.splice(c,1),t.isDestroy=!0,n||(a.releaseContainer?.(),a.releaseContainer=void 0),l(()=>t.emit("destroy")),n&&a.rollback&&l(a.rollback),a.rollback=void 0,a.releaseContainer?.(),a.releaseContainer=void 0;for(const s of i.slice(1))console.warn("Additional ArtPlayer cleanup failure:",s);if(i.length)throw i[0]}const m=new WeakMap;function g(t,e){const r=h(t).child();return m.set(e,r),r}function v(t){const e=m.get(t);if(!e)throw new Error("ArtPlayer component has not been registered");return e}function y(t){m.get(t)?.dispose()}function b(t,e){return{on:(r,o)=>{!function(t,e,r,o){const n=v(e);if(n.closed)return;const a=(...t)=>{if(!n.closed)return o(...t)};t.on(r,a),n.add(()=>{t.off(r,a)})}(t,e,r,o)},proxy:(r,o,n)=>function(t,e,r,o,n){const a=v(e);if(a.closed)return()=>{};const i=t.events.proxy(r,o,t=>{if(!a.closed)return n(t)});return a.add(()=>{t.events.remove(i)})}(t,e,r,o,n)}}const w=globalThis?.CUSTOM_USER_AGENT??("undefined"!==typeof navigator?navigator.userAgent:""),x=/^(?:(?!chrome|android).)*safari/i.test(w),k=/iPad|iPhone|iPod/i.test(w)&&!window.MSStream,$=k||w.includes("Macintosh")&&navigator.maxTouchPoints>=1,E=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(w)||$,T="undefined"!==typeof window&&"undefined"!==typeof document;function C(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function z(t,e=document){return e.querySelector(t)}function S(t,e=document){return Array.from(e.querySelectorAll(t))}function L(t,e){return t.classList.add(e)}function M(t,e){return t.classList.remove(e)}function A(t,e){return t.classList.contains(e)}function P(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function I(t){return t.parentNode.removeChild(t)}function O(t,e,r){return t.style[e]=r,t}function R(t,e){for(const r in e)O(t,r,e[r]);return t}function _(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function V(t,e){_(t).forEach(t=>M(t,e)),L(t,e)}function Y(t,e,r="top"){E||(t.setAttribute("aria-label",e),L(t,"hint--rounded"),L(t,`hint--${r}`))}function D(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function N(t,e){return U(t).includes(e)}function F(t,e){return e.parentNode.replaceChild(t,e),t}function H(t){return document.createElement(t)}function B(t="",e=""){const r=H("i");return L(r,"art-icon"),L(r,`art-icon-${t}`),P(r,e),r}function W(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function j(t){return t.getBoundingClientRect()}function q(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function U(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function X(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class G extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function K(t,e){if(!t)throw new G(e);return t}function Z(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function J(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function Q(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function tt(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function et(t){return t.charAt(0).toUpperCase()+t.slice(1)}function rt(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const ot={"&":"&","<":"<",">":">","'":"'",'"':"""},nt={"&":"&","<":"<",">":">","'":"'",""":'"'},at=/(&|<|>|'|")/g;function it(t){return t.replace(/[&<>'"]/g,t=>ot[t]||t)}const st=Object.defineProperty,{hasOwnProperty:lt}=Object.prototype;function ct(t,e){return lt.call(t,e)}function dt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function pt(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?pt(n,a):a,st(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function ht(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function ut(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function ft(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function mt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const gt=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:G,addClass:L,append:P,assToVtt:ft,capitalize:et,clamp:tt,createElement:H,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:st,download:Q,errorHandle:K,escape:it,get:dt,getComposedPath:U,getExt:J,getIcon:B,getRect:j,getSafeAreaInsets:X,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ct,hasClass:A,includeFromEvent:N,inverseClass:V,isBrowser:T,isIOS:k,isIOS13:$,isInViewport:D,isMobile:E,isSafari:x,loadImg:q,mergeDeep:pt,query:z,queryAll:S,remove:I,removeClass:M,replaceElement:F,secondToTime:rt,setStyle:O,setStyleText:C,setStyles:R,siblings:_,silencePromise:Z,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:ht,supportsFlex:W,throttle:mt,tooltip:Y,unescape:function(t){return t.replace(at,t=>nt[t]||t)},userAgent:w,vttToBlob:ut},Symbol.toStringTag,{value:"Module"}));function vt(t,e){return P(t,e)}function yt(t,e){return e.querySelector(t)}const bt="array",wt="boolean",xt="string",kt="number",$t="object",Et="function";function Tt(t,e,r){return K(e===xt||e===kt||t instanceof Element,`${r.join(".")} require '${xt}' or 'Element' type`)}const Ct={html:Tt,disable:`?${wt}`,name:`?${xt}`,index:`?${kt}`,style:`?${$t}`,click:`?${Et}`,mounted:`?${Et}`,tooltip:`?${xt}|${kt}`,width:`?${kt}`,selector:`?${bt}`,onSelect:`?${Et}`,switch:`?${wt}`,onSwitch:`?${Et}`,range:`?${bt}`,onRange:`?${Et}`,onChange:`?${Et}`},zt={id:xt,container:Tt,url:xt,poster:xt,type:xt,theme:xt,lang:xt,volume:kt,isLive:wt,muted:wt,autoplay:wt,autoSize:wt,autoMini:wt,loop:wt,flip:wt,playbackRate:wt,aspectRatio:wt,screenshot:wt,setting:wt,hotkey:wt,pip:wt,mutex:wt,backdrop:wt,fullscreen:wt,fullscreenWeb:wt,subtitleOffset:wt,miniProgressBar:wt,useSSR:wt,playsInline:wt,lock:wt,gesture:wt,fastForward:wt,autoPlayback:wt,autoOrientation:wt,airplay:wt,proxy:`?${Et}`,plugins:[Et],layers:[Ct],contextmenu:[Ct],settings:[Ct],controls:[{...Ct,position:(t,e,r)=>{const o=["top","left","right"];return K("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}}],quality:[{default:`?${wt}`,html:xt,url:xt}],highlight:[{time:kt,text:xt}],thumbnails:{url:xt,number:kt,column:kt,width:kt,height:kt,scale:kt},subtitle:{url:xt,name:xt,type:xt,style:$t,escape:wt,encoding:xt,onVttLoad:Et},moreVideoAttr:$t,i18n:$t,icons:$t,cssVar:$t,customType:$t},St=new WeakSet;class Lt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return A(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?L(e,r):M(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){if(u(this.art))return;const e="function"===typeof t?t(this.art):t;if(u(this.art))return;if(e.html=e.html||"",n(e,Ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`,o=this.cache;K(!o.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=document.createElement("div"),i=g(this.art,a),s=[],l=Object.getOwnPropertyDescriptor(this,r);let c=!1;i.add(()=>{for(const t of s)this.art.events.remove(t)});try{if(i.closed)return;if(function(t,e,r,o,n,a){L(t,`art-${r}`),L(t,`art-${r}-${o}`);const i=Array.from(e.children);t.dataset.index=String(a.index||n);const s=i.find(e=>Number(e.dataset.index)>=Number(t.dataset.index));s?s.insertAdjacentElement("beforebegin",t):P(e,t),a.html&&P(t,a.html),a.style&&R(t,a.style),a.tooltip&&Y(t,a.tooltip)}(a,this.$parent,this.name,r,this.id,e),i.closed)return;if(e.click){const t=this.art.events.proxy(a,"click",t=>{i.closed||(t.preventDefault(),e.click.call(this.art,this,t))});s.push(t)}if(e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),i.closed)return;return function(t,e,r){const o=t;"__proto__"===e?Object.defineProperty(o,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):o[e]=r}(this,r,a),c=!0,o.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}catch(d){try{y(a)}catch(p){console.warn("ArtPlayer component cleanup failed:",p)}throw o.get(r)?.$ref===a&&o.delete(r),c&&this[r]===a&&(l?Object.defineProperty(this,r,l):delete this[r]),a.remove(),d}}remove(t){K(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);if(!St.has(e)){St.add(e);try{e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);try{y(e.$ref)}finally{this.cache.get(t)===e&&(this.cache.delete(t),delete this[t]),e.$ref.remove()}}finally{St.delete(e)}}}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Mt extends Lt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,g(t,this.$parent),E||this.init()}init(){const{option:t,template:{$player:e,$contextmenu:r}}=this.art,{on:o,proxy:n}=b(this.art,r);t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="1"]',t);o&&V(o,"art-current"),r("video:ratechange",()=>{const r=Array.from(t.querySelectorAll("span")).find(t=>Number(t.dataset.value)===e.playbackRate);r&&V(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="default"]',t);o&&V(o,"art-current"),r("aspectRatio",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&V(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(et(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="normal"]',t);o&&V(o,"art-current"),r("flip",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&V(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return{...t,html:`ArtPlayer ${a}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const o=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=j(e),{height:c,width:d}=j(r);let p=o-s,h=n-l;o+d>s+i&&(p=i-d),n+c>l+a&&(h=a-c),R(r,{top:`${h}px`,left:`${p}px`})}),n(e,"click",t=>{N(t,r)||(this.show=!1)}),o("blur",()=>{this.show=!1})}}function At(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Pt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function It(t,e){const{$progress:r}=t.template,{left:o}=j(r),n=tt((E?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:rt(a),width:n,percentage:tt(n/r.clientWidth,0,1)}}function Ot(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=It(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Rt(t,e){const{icons:r,option:o}=t,{$player:n}=t.template,a=v(e),{on:i}=b(t,e);let s=()=>{};const l=yt(".art-progress-hover",e),c=yt(".art-progress-loaded",e),d=yt(".art-progress-played",e),p=yt(".art-progress-highlight",e),h=yt(".art-progress-indicator",e),u=yt(".art-progress-tip",e);function f(r,o){const{width:n,time:a}=o||It(t,r);u.textContent=a||"00:00";const i=u.clientWidth;n<=i/2?O(u,"left",0):n>e.clientWidth-i/2?O(u,"left",e.clientWidth-i+"px"):O(u,"left",n-i/2+"px")}r.indicator?P(h,r.indicator):O(h,"backgroundColor","var(--art-theme)"),i("setBar",function(r,o,i){const m="played"===r&&i&&E;if("loaded"===r&&O(c,"width",100*o+"%"),"hover"===r&&(O(l,"width",100*o+"%"),N(i,p)?function(r){const{width:o}=It(t,r),n=r.target instanceof HTMLElement?r.target.dataset.text:void 0;u.textContent=n??"";const a=u.clientWidth;o<=a/2?O(u,"left",0):o>e.clientWidth-a/2?O(u,"left",e.clientWidth-a+"px"):O(u,"left",o-a/2+"px")}(i):f(i),0===o?M(n,"art-progress-hover"):L(n,"art-progress-hover")),"played"===r&&(O(d,"width",100*o+"%"),O(h,"left",100*o+"%")),m){L(n,"art-progress-hover");f(i,{width:e.clientWidth*o,time:rt(o*t.duration)}),s(),s=At(a,()=>{M(n,"art-progress-hover")},500)}}),i("video:loadedmetadata",function(){p.textContent="";for(let e=0;e{t.emit("setBar","played",t.played),t.emit("setBar","loaded",t.loaded)}):(i("video:timeupdate",()=>{t.emit("setBar","played",t.played)}),i("video:progress",()=>{t.emit("setBar","loaded",t.loaded)}),i("video:ended",()=>{t.emit("setBar","played",1)})),t.emit("setBar","loaded",t.loaded||0)}function _t(t){return e=>({...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{Rt(e,t),function(t,e){const{$progress:r}=t.template,o=e.querySelector(".art-progress-indicator"),{on:n,proxy:a}=b(t,e);if(!E){let e=!1;a(r,"click",e=>{e.target!==o&&Ot(t,e)}),a(r,"mousemove",e=>{const{percentage:r}=It(t,e);t.emit("setBar","hover",r,e)}),a(r,"mouseleave",e=>{t.emit("setBar","hover",0,e)}),a(r,"mousedown",t=>{e=0===t.button}),n("document:mousemove",r=>{if(e){const{second:e,percentage:o}=It(t,r);t.emit("setBar","played",o,r),t.seek=e}}),n("document:mouseup",()=>{e&&(e=!1)})}}(e,t)}})}function Vt(t){const{option:e}=t.art;e.isLive||t.add(_t({name:"progress",position:"top",index:10})),t.add({name:"thumbnails",position:"top",index:20}),t.add(function(t){return e=>({...t,mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.play),s=vt(t,n.pause);function l(){O(i,"display","flex"),O(s,"display","none")}function c(){O(i,"display","none"),O(s,"display","flex")}Y(i,a.get("Play")),Y(s,a.get("Pause")),o(i,"click",()=>{Z(e.play())}),o(s,"click",()=>{e.pause()}),e.playing?c():l(),r("video:playing",()=>{c()}),r("video:pause",()=>{l()})}})}({name:"playAndPause",position:"left",index:10})),t.add(function(t){return e=>({...t,mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n}=e,a=vt(t,n.volume),i=vt(t,n.volumeClose),s=vt(t,'
'),l=vt(s,'
'),c=vt(l,'
'),d=vt(l,'
'),p=vt(d,'
'),h=vt(p,'
'),u=vt(d,'
');function f(t){const{top:e,height:r}=j(d);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)O(a,"display","none"),O(i,"display","flex"),O(u,"top","100%"),O(h,"top","100%"),c.textContent="0";else{const t=100*e.volume;O(a,"display","flex"),O(i,"display","none"),O(u,"top",100-t+"%"),O(h,"top",100-t+"%"),c.textContent=String(Math.floor(t))}}if(m(),r("video:volumechange",m),o(a,"click",()=>{e.muted=!0}),o(i,"click",()=>{e.muted=!1}),E)O(s,"display","none");else{let t=!1;o(d,"mousedown",r=>{t=0===r.button,e.volume=f(r)}),r("document:mousemove",r=>{t&&(e.muted=!1,e.volume=f(r))}),r("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),e.isLive||t.add(function(t){return e=>({...t,style:E?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{const{on:r}=b(e,t);function o(){const r=`${rt(e.currentTime)} / ${rt(e.duration)}`;r!==t.textContent&&(t.textContent=r)}o();const n=["video:loadedmetadata","video:timeupdate","video:progress"];for(let e=0;e{r&&!h(t.art).closed&&(t.art.quality=e.quality)}).catch(t=>{console.warn("ArtPlayer quality initialization failed:",t)}),e.screenshot&&!E&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r}=b(e,t),{icons:o}=e;vt(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),e.setting&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e;vt(t,n.setting),o(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),r("setting",e=>{Y(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),e.pip&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e;vt(t,n.pip),o(t,"click",()=>{e.pip=!e.pip}),r("pip",e=>{Y(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),e.airplay&&"WebKitPlaybackTargetAvailabilityEvent"in window&&window.WebKitPlaybackTargetAvailabilityEvent&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r}=b(e,t),{icons:o}=e;vt(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),e.fullscreenWeb&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.fullscreenWebOn),s=vt(t,n.fullscreenWebOff);O(s,"display","none"),o(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),r("fullscreenWeb",e=>{e?(Y(t,a.get("Exit Web Fullscreen")),O(i,"display","none"),O(s,"display","inline-flex")):(Y(t,a.get("Web Fullscreen")),O(i,"display","inline-flex"),O(s,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),e.fullscreen&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.fullscreenOn),s=vt(t,n.fullscreenOff);O(s,"display","none"),o(t,"click",()=>{e.fullscreen=!e.fullscreen}),r("fullscreen",e=>{e?(Y(t,a.get("Exit Fullscreen")),O(i,"display","none"),O(s,"display","inline-flex")):(Y(t,a.get("Fullscreen")),O(i,"display","inline-flex"),O(s,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let r=0;rDt.get(t).option.selector}),st(t,"$control_item",{get:()=>Dt.get(t).item}),st(t,"$control_value",{get:()=>Dt.get(t).value})),Dt.set(t,e)}function Ft(t,e){t.innerHTML=e}function Ht(t,e,r,o,n){const{proxy:a}=t.events,i=v(o),s=r.selector;L(o,"art-control-selector");const l=document.createElement("div");L(l,"art-selector-value"),P(l,r.html),o.textContent="",P(o,l);const c=vt(o,'
');for(let h=0;h{if(i.closed)return;const n=U(o),a=r.selector.find(t=>n.includes(t.$control_item));if(!a)return;const s=++d,c=()=>!i.closed&&s===d,p=i.add(function(t,e){return Yt.set(t,e),()=>{Yt.get(t)===e&&Yt.delete(t)}}(o,c));try{if(e(a),i.closed)return;if(r.onSelect){const e=await r.onSelect.call(t,a,a.$control_item,o);c()&&Ft(l,e)}}catch(h){console.warn("ArtPlayer selector failed:",h)}finally{p()}});n.push(p)}class Bt extends Lt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;g(t,o);const{on:n}=b(t,o);n("mousemove",()=>{E||(this.show=!0)}),n("click",()=>{E?this.toggle():this.show=!0}),n("document:mousemove",t=>{this.isHover=N(t,o)}),n("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),n("control",t=>{t?(M(r,"art-hide-cursor"),L(r,"art-hover"),this.timer=Date.now()):(L(r,"art-hide-cursor"),M(r,"art-hover"))}),this.init(),h(t).closed||function(t){const{$bottom:e,$controls:r,$player:o}=t.template,n=v(e),{on:a}=b(t,e),i=()=>{if(n.closed)return;const t=r.offsetHeight;t>0&&o.style.getPropertyValue("--art-controls-height")!==`${t}px`&&o.style.setProperty("--art-controls-height",`${t}px`)};if(a("resize",i),"undefined"!==typeof ResizeObserver){const t=new ResizeObserver(i);t.observe(r),n.add(()=>{t.disconnect()})}else if("undefined"!==typeof MutationObserver){const t=new MutationObserver(i);t.observe(r,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),n.add(()=>{t.disconnect()})}i()}(t)}init(){Vt(this)}add(t){if(u(this.art))return;const e="function"===typeof t?t(this.art):t,{$progress:r,$controlsLeft:o,$controlsRight:n}=this.art.template;switch(e.position){case"top":this.$parent=r;break;case"left":this.$parent=o;break;case"right":this.$parent=n;break;default:K(!1,"Control option.position must one of 'top', 'left', 'right'")}super.add(e)}check(t){!function(t){if(t){Ft(t.$control_value,t.html);for(let e=0;ethis.check(t),t,e,r)}}function Wt(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function jt(t){if(t.constructor.USE_RAF){const e=h(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const qt=new WeakMap;class Ut{constructor(t){this.destroyEvents=new Set;const e=h(t);qt.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){N(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),E?!t.isLock&&n&&Z(t.toggle()):Z(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),E?!t.isLock&&s&&Z(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{L(r,"art-hover"),t.emit("hover",!0,e)},e=>{M(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=h(t);let a=()=>{};const i=()=>{a(),a=At(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(E&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&Ot(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=Wt(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=tt((o-i)/t.width,-1,1),d=tt((a-s)/t.height,-1,1),p=t.isRotate?d:c,h=n===r?t.constructor.TOUCH_MOVE_RATIO:1,u=tt(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",tt(u/t.duration,0,1),e),t.notice.show=`${rt(u)} / ${rt(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=mt(()=>{t.emit("view",D(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{const o=a.window||i.ownerDocument?.defaultView||window,s=e.proxy(o,r,e=>{t.emit(`window:${r}`,e)});n.push(s)})}a(),e.bindGlobalEvents=a}(t,this),jt(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(qt.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Xt{constructor(t){this.art=t,this.keys={},E||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{Z(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Jt{constructor(t){const e={...Zt,...t.option.icons};for(const r in e)st(this,r,{get:()=>B(r,e[r])})}}class Qt extends Lt{constructor(t){super(t),this.name="info",E||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=S("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=h(this.art);!function t(){for(let e=0;e{O(n,"display","none"),O(a,"display",null)}),o.proxy(e.$state,"click",()=>Z(t.play()))}}class oe{constructor(t){this.art=t,this.timer=null,h(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(h(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,L(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",M(r,"art-notice-show")},e.NOTICE_TIME)):M(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function ne(t,e,r,o=!1){const n=e=>{u(t)||r(e)};t[o?"once":"on"](e,n),h(t).add(()=>{t.off(e,n)})}function ae(t,e,r){for(const[o,n]of e){if(u(t)||r&&!r())return;t[o].show=n}}const ie=new WeakMap,se=new WeakMap,le=new WeakMap;function ce(t){return le.get(t)||h(t)}function de(t){const e=ie.get(t),r=le.get(t);return()=>ie.get(t)===e&&(!e||e.active())&&le.get(t)===r&&(!r||!r.closed)}function pe(t){const e=le.get(t),r=h(t).child(),o=r.child();le.set(t,r),r.add(()=>{le.get(t)===r&&le.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!u(t)&&!o.closed&&ie.get(t)===n};return ie.set(t,n),o.add(()=>{ie.get(t)===n&&ie.delete(t),n.onAssigned=void 0,n.onError=void 0}),e?.dispose(),n}function he(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&e?.()}function ue(t,e,r){se.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{se.get(t)===e&&(se.delete(t),he(e))}}function fe(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function me(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=ce(t),l=0;return{reset(){l=0,i?.dispose(),M(a,"art-error")},loadStart(){M(a,"art-error")},schedule(c){(async c=>{if(u(t))return;const d=ce(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const h=()=>!u(t)&&!p.closed&&d===ce(t),f=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ge(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{u(t)||t.emit(`video:${e.type}`,e)})}(t);const e=me(t);!function(t,e){ne(t,"video:canplay",()=>{e.reset(),ae(t,[["loading",!1]])}),ne(t,"video:canplay",()=>{ae(t,[["loading",!1],["controls",!0],["mask",!0]]),u(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;ne(t,"video:ended",()=>{if(e.loop){const e=de(t);if(t.seek=0,u(t)||!e())return;Z(t.play()),e()&&ae(t,[["controls",!1],["mask",!1]],e)}else ae(t,[["controls",!0],["mask",!0]])})}(t),ne(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;ne(t,"video:loadedmetadata",()=>{t.emit("resize"),E&&ae(t,[["loading",!1],["controls",!0],["mask",!0]])}),ne(t,"video:loadstart",()=>{e.loadStart(),ae(t,[["loading",!0],["mask",!1],["controls",!0]])}),ne(t,"video:pause",()=>{ae(t,[["controls",!0],["mask",!0]])}),ne(t,"video:play",()=>{ae(t,[["mask",!1]]),u(t)||O(r,"display","none")}),ne(t,"video:playing",()=>ae(t,[["mask",!1]])),ne(t,"video:progress",()=>{t.playing&&ae(t,[["loading",!1]])}),ne(t,"video:seeked",()=>ae(t,[["loading",!1],["mask",!0]])),ne(t,"video:seeking",()=>ae(t,[["loading",!0],["mask",!1]])),ne(t,"video:timeupdate",()=>ae(t,[["mask",!1]])),ne(t,"video:waiting",()=>ae(t,[["loading",!0],["mask",!1]]))}(t,e)}const ve=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],ye=(()=>{if("undefined"===typeof document)return!1;const t=ve[0],e={};for(const r of ve){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),be={change:ye.fullscreenchange,error:ye.fullscreenerror},we={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{we.off("change",n),r()};we.on("change",n);const a=t[ye.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!we.isFullscreen)return void t();const r=()=>{we.off("change",r),t()};we.on("change",r);const o=document[ye.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>we.isFullscreen?we.exit():we.request(t,e),onchange(t){we.on("change",t)},onerror(t){we.on("error",t)},on(t,e){const r=be[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=be[t];r&&document.removeEventListener(r,e,!1)},raw:ye};function xe(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;t.once("video:loadedmetadata",()=>{var a;we.isEnabled?(a=t,we.on("change",()=>{a.emit("fullscreen",we.isFullscreen),we.isFullscreen?(a.state="fullscreen",L(n,"art-fullscreen")):M(n,"art-fullscreen"),a.emit("resize")}),we.on("error",t=>{a.emit("fullscreenError",t)}),st(a,"fullscreen",{get:()=>we.isFullscreen,async set(t){t?await we.request(n):await we.exit()}})):o.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),st(t,"fullscreen",{get:()=>document.fullscreenElement===o,set(e){e?(t.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})})(t):st(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),st(t,"fullscreen",dt(t,"fullscreen"))})}function ke(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(M(n,"art-mini"),O(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(O(e,"display","none"),O(r,"display","flex")):(O(e,"display","flex"),O(r,"display","none"))}function p(){const{$mini:e}=t.template,r=j(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),O(e,"top",`${n}px`),O(e,"left",`${a}px`)}st(t,"mini",{get:()=>A(n,"art-mini"),set(h){if(h){t.state="mini",L(n,"art-mini");const h=function(){const{$mini:n}=t.template;if(n)return P(n,a),O(n,"display","flex");{const n=H("div");L(n,"art-mini-popup"),P(document.body,n),t.template.$mini=n,P(n,a);const p=P(n,'
');P(p,e.close),r(p,"click",c);const h=P(n,'
'),u=P(h,e.play),f=P(h,e.pause);return r(u,"click",()=>Z(t.play())),r(f,"click",()=>t.pause()),d(u,f),t.on("video:playing",()=>d(u,f)),t.on("video:pause",()=>d(u,f)),t.on("video:timeupdate",()=>d(u,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){L(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;O(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,M(n,"art-mini-dragging");const t=j(n);o.set("left",t.left),o.set("top",t.top),O(n,"left",`${t.left}px`),O(n,"top",`${t.top}px`),O(n,"transform",null)}}),n}}(),u=o.get("top"),f=o.get("left");"number"===typeof u&&"number"===typeof f?(O(h,"top",`${u}px`),O(h,"left",`${f}px`),D(h)||p()):p(),t.emit("mini",!0)}else c()}})}function $e(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,st(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),st(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):st(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ee(t){st(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:a?.html||"",selector:e,async onSelect(e,r,a){const i=function(t){return t&&Yt.get(t)||(()=>!0)}(a);if(await t.switchQuality(e.url),!u(t)&&i()){const r=`${n.get("Switch Video")}: ${e.html}`;!u(t)&&i()&&(o.show=r)}return e.html}})}})}function Te(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function Ce(t,e,r){return new Promise((o,n)=>{if(u(t)||e===t.url)return void o();const a=pe(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),d=t=>l(!0,t);a.onError=d;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const p=i.child(),h={"video:error":d,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){d(e)}},"video:canplay":()=>{if(!c())return;p.dispose();(async()=>{if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{await t.play()}catch{}c()&&(t.notice.show="",l())}})().catch(d)}},u=i.child(),f=[],m=Object.keys(h);for(const e of m)Te(u,t,e,t=>{a.acceptingEvents&&f.push([e,t])},!1);if(ue(t,a,e),!c())return;if(t.notice.show="",!c())return;const g=()=>{if(u.dispose(),!e)return void l();const r={};for(const e of m)r[e]=Te(p,t,e,h[e]);for(const[t,e]of f){if(!c()||p.closed)break;r[t](e)}f.length=0};a.assigned?g():a.onAssigned=g}catch(p){d(p)}})}function ze(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",async(n,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:p}=e.thumbnails;if(!c||!d)return;if("hover"===n||"played"===n&&l&&E){if(i||a||(a=!0,i=await q(d,p),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?O(a,"left",r.clientWidth-h+"px"):O(a,"left",n-h/2+"px")}(n)}}),st(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function Se(t){const{option:e,template:{$video:r}}=t;st(t,"url",{get:()=>r.src,async set(o){if(u(t))return;const n=function(t){const e=se.get(t);return se.delete(t),e||pe(t)}(t);n.acceptingEvents=!1;try{if(!o)return void(await Pt(n.scope)&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||J(o),s=e.customType[i];if(i&&s){if(!(await Pt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;Te(l,t,"video:canplay",()=>{c=!d}),Te(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>fe(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||Te(n.scope,t,"video:canplay",e)}}catch(a){fe(n,a)}finally{he(n)}}})}Object.defineProperties(we,{isFullscreen:{get:()=>Boolean(document[ye.fullscreenElement])},element:{enumerable:!0,get:()=>document[ye.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[ye.fullscreenEnabled])}});class Le{constructor(t){Se(t),function(t){const{template:{$video:e}}=t;st(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;st(t,"play",{async value(){const i=de(t),s=await a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;st(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${rt(t.currentTime)} / ${rt(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;st(t,"forward",{set(e){r.seek=t.currentTime+e}}),st(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;st(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=tt(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),st(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;st(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=tt(o,0,t.duration))}})}(t),function(t){st(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>Ce(t,e,0);st(t,"switchQuality",{value:e=>Ce(t,e,t.currentTime)}),st(t,"switchUrl",{value:e}),st(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;st(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;st(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)O(o,"width",null),O(o,"height",null),O(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(O(o,"width",s*r+"px"),O(o,"height","100%"),O(o,"margin","0 auto")):(O(o,"width","100%"),O(o,"height",e/s+"px"),O(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=H("canvas");st(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),st(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),st(t,"screenshot",{value:async e=>{const o=await t.getDataURL();return Q(o,`${e||`artplayer_${rt(r.currentTime)}`}.png`),t.emit("screenshot",o),o}})}(t),xe(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";st(t,"fullscreenWeb",{get:()=>A(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&P(document.body,o),t.state="fullscreenWeb",O(o,"width","100%"),O(o,"height","100%"),L(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&P(r,o),n&&(o.style.cssText=n,n=""),M(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),$e(t),function(t){const{$video:e}=t.template,r=t;st(t,"loaded",{get:()=>r.loadedTime/e.duration}),st(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){st(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;st(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;st(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=j(e),l=n/a;if(i/s>l)O(r,"width",s*l/i*100+"%"),O(r,"height","100%");else{const t=i/l/s*100;O(r,"width","100%"),O(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;st(t,"rect",{get:()=>j(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}st(t,"x",{get:()=>e.left+window.pageXOffset}),st(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;st(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(et(n))}`,t.emit("flip",n)}})}(t),ke(t),function(t){const{template:{$poster:e}}=t;st(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){O(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;st(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);O(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;st(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){st(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){st(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];st(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;oo.$track?.offset||0,set(n){const{cues:a}=t.subtitle;if(!o.$track||0===a.length)return;const i=tt(n,-10,10);o.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,st(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),Ee(t),ze(t),ge(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=tt(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=tt(a,0,1)),e.poster&&O(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Me(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!A(o,a)&&function(){const e=X(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;O(o,"width",`${n}px`),O(o,"height",`${i}px`),O(o,"transform-origin","0 0"),O(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),L(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else A(o,a)&&(O(o,"width",""),O(o,"height",""),O(o,"transform-origin",""),O(o,"transform",""),M(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,L(o,i)}catch(n){s=!1,e.show=n}}else if(A(o,i)&&M(o,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return A(o,a)}}}function Ae(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=z(".art-auto-playback-last",s),c=z(".art-auto-playback-jump",s),d=z(".art-auto-playback-close",s);P(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),O(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(O(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${rt(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{O(s,"display","none")}),a(c,"click",()=>{t.seek=r,Z(t.play()),O(i,"display","none"),O(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{O(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Pe(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,M(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,L(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return A(o,"art-fast-forward")}}}function Ie(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return A(o,"art-lock")}function a(){L(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){M(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=P(e,r.lock),n=P(e,r.unlock);O(o,"display","none"),t.on("lock",t=>{t?(O(o,"display","inline-flex"),O(n,"display","none")):(O(o,"display","none"),O(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function Oe(t){return t.on("control",e=>{e?M(t.template.$player,"art-mini-progress-bar"):L(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Re{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){u(t.art)||!e.miniProgressBar||e.isLive||t.add(Oe),!u(t.art)&&e.lock&&E&&t.add(Ie),u(t.art)||!e.autoPlayback||e.isLive||t.add(Ae),!u(t.art)&&e.autoOrientation&&E&&t.add(Me),!u(t.art)&&e.fastForward&&E&&!e.isLive&&t.add(Pe)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){K(!u(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(u(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(u(t.art))return t;let n=o;const a=ct(t,n);if(u(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return u(t.art)||(K(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),u(t.art)||st(t,n,{value:r})),t}(this,t,e)}}class _e extends Lt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=N(t,r.setting),o=N(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(et(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&V(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),st(a,"$parents",{get:()=>r}),st(a,"$option",{get:()=>t});const o=[];st(a,"$events",{get:()=>o}),st(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:o,$setting:n}}=this.art;if(t.setting&&this.show){const a=this.active[0]?.$parent?.width||e,{left:i,width:s}=j(t.setting),{left:l,width:c}=j(o),d=i-l+s/2-a/2;if(O(n,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),O(n,"width",`${a}px`),this.art.isRotate||E)return;d+a>c?(O(n,"left",null),O(n,"right",null)):(O(n,"left",`${d}px`),O(n,"right","auto"))}}inactivate(t){for(let e=0;e'),s=H("div");L(s,"art-setting-item-left-icon"),P(s,o),P(i,s),P(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),P(e,a)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),o=t.$item;let n="selector";ct(t,"switch")&&(n="switch"),ct(t,"range")&&(n="range"),ct(t,"onClick")&&(n="button");const{icons:a,proxy:i,constructor:s}=this.art,l=H("div");L(l,"art-setting-item"),O(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=P(l,'
'),d=P(l,'
'),p=H("div");switch(L(p,"art-setting-item-left-icon"),n){case"button":case"switch":case"range":P(p,t.icon||a.config);break;case"selector":t.selector?.length?P(p,t.icon||a.config):P(p,a.check)}P(c,p),st(t,"$icon",{configurable:!0,get:()=>p}),st(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",P(p,t)}});const u=H("div");L(u,"art-setting-item-left-text"),P(u,t.html||""),P(c,u),st(t,"$html",{configurable:!0,get:()=>u}),st(t,"html",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",P(u,t)}});const f=H("div");switch(L(f,"art-setting-item-right-tooltip"),P(f,t.tooltip||""),P(d,f),st(t,"$tooltip",{configurable:!0,get:()=>f}),st(t,"tooltip",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",P(f,t)}}),n){case"switch":{const e=H("div");L(e,"art-setting-item-right-icon");const r=P(e,a.switchOn),o=P(e,a.switchOff);O(t.switch?o:r,"display","none"),P(d,e),st(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;st(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(O(o,"display","none"),O(r,"display",null)):(O(o,"display",null),O(r,"display","none"))}});break}case"range":{const e=H("div");L(e,"art-setting-item-right-icon");const r=P(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],L(r,"art-setting-range"),P(d,e),st(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];st(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=H("div");L(t,"art-setting-item-right-icon"),P(t,a.arrowRight),P(d,t)}}switch(n){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&L(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}st(t,"$item",{configurable:!0,get:()=>l}),e?F(l,o):P(r,l),t.mounted&&At(h(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){V(this.cache.get(t),"art-current")}else{const e=H("div");this.cache.set(t,e),L(e,"art-setting-panel"),P(this.$parent,e),V(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?R(r,t):O(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?it(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a={...n.subtitle,...e,url:t},i=await this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=H("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,I(i),P(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(n(t,zt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||J(t.url)){case"srt":{const e=ht(r);return ut(t.onVttLoad(e))}case"ass":{const e=ft(r);return ut(t.onVttLoad(e))}case"vtt":return ut(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}const Ne=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${a}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Fe{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=z(e.container),K(this.$container,`No container element found by ${e.container}`)),K(W(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();K("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),K(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=d.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=p(t);n.rollback=r,d.set(e,t),n.releaseContainer=()=>{d.get(e)===t&&d.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ne}query(t){return z(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Fe.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){K(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),F(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&L(this.$player,"art-backdrop"),E&&L(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":L(this.$player,"art-destroy")}}const He=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class Be{on(t,e,r){const o=this.e||(this.e={});let n=He(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(He(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=He(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),qe.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${qe.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=p(t);return e.rollback=void 0,!e.scope.closed})(this)&&je.push(this)}catch(o){try{f(this,je,!0,qe.REMOVE_SRC_WHEN_DESTROY,!0)}catch(a){console.warn("Failed to clean up ArtPlayer initialization:",a)}throw o}}static get instances(){return je}static get version(){return a}static get config(){return i}static get utils(){return gt}static get scheme(){return zt}static get Emitter(){return Be}static get validator(){return n}static get kindOf(){return n.kindOf}static get html(){return Fe.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:x?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){f(this,je,t,qe.REMOVE_SRC_WHEN_DESTROY)}}return qe.STYLE=Ye,qe.DEBUG=!1,qe.CONTEXTMENU=!0,qe.NOTICE_TIME=2e3,qe.SETTING_WIDTH=250,qe.SETTING_ITEM_WIDTH=200,qe.SETTING_ITEM_HEIGHT=35,qe.RESIZE_TIME=200,qe.SCROLL_TIME=200,qe.SCROLL_GAP=50,qe.AUTO_PLAYBACK_MAX=10,qe.AUTO_PLAYBACK_MIN=5,qe.AUTO_PLAYBACK_TIMEOUT=3e3,qe.RECONNECT_TIME_MAX=5,qe.RECONNECT_SLEEP_TIME=1e3,qe.CONTROL_HIDE_TIME=3e3,qe.DBCLICK_TIME=300,qe.DBCLICK_FULLSCREEN=!0,qe.MOBILE_DBCLICK_PLAY=!0,qe.MOBILE_CLICK_PLAY=!1,qe.AUTO_ORIENTATION_TIME=200,qe.INFO_LOOP_TIME=1e3,qe.FAST_FORWARD_VALUE=3,qe.FAST_FORWARD_TIME=1e3,qe.TOUCH_MOVE_RATIO=.5,qe.VOLUME_STEP=.1,qe.SEEK_STEP=5,qe.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],qe.ASPECT_RATIO=["default","4:3","16:9"],qe.FLIP=["normal","horizontal","vertical"],qe.FULLSCREEN_WEB_IN_BODY=!0,qe.LOG_VERSION=!0,qe.USE_RAF=!1,qe.REMOVE_SRC_WHEN_DESTROY=!0,T&&(window.Artplayer=qe,C("artplayer-style",Ye),setTimeout(()=>{qe.LOG_VERSION&&console.log(`%c ArtPlayer %c ${qe.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),qe}); diff --git a/docs/compiled/artplayer.legacy.js b/docs/compiled/artplayer.legacy.js index b151e2b4f..bd1b8d802 100644 --- a/docs/compiled/artplayer.legacy.js +++ b/docs/compiled/artplayer.legacy.js @@ -67,4 +67,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))a.call(e,r)&&s(t,r,e[r]);if(n)for(var r of n(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,n)=>{var a=t=>{try{s(r.next(t))}catch(e){n(e)}},i=t=>{try{s(r.throw(t))}catch(e){n(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(a,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var u,h={exports:{}};var f=(u||(u=1,h.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function E(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function T(t,e=document){return e.querySelector(t)}function C(t,e=document){return Array.from(e.querySelectorAll(t))}function z(t,e){return t.classList.add(e)}function L(t,e){return t.classList.remove(e)}function S(t,e){return t.classList.contains(e)}function M(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function A(t){return t.parentNode.removeChild(t)}function P(t,e,r){return t.style[e]=r,t}function I(t,e){for(const r in e)P(t,r,e[r]);return t}function O(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function R(t,e){O(t).forEach(t=>L(t,e)),z(t,e)}function _(t,e,r="top"){k||(t.setAttribute("aria-label",e),z(t,"hint--rounded"),z(t,`hint--${r}`))}function V(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function Y(t,e){return j(t).includes(e)}function D(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function F(t="",e=""){const r=N("i");return z(r,"art-icon"),z(r,`art-icon-${t}`),M(r,e),r}function H(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function B(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function K(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function Z(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function J(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function Q(t){return t.charAt(0).toUpperCase()+t.slice(1)}function tt(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const et={"&":"&","<":"<",">":">","'":"'",'"':"""},rt={"&":"&","<":"<",">":">","'":"'",""":'"'},ot=/(&|<|>|'|")/g;function nt(t){return t.replace(/[&<>'"]/g,t=>et[t]||t)}const at=Object.defineProperty,{hasOwnProperty:it}=Object.prototype;function st(t,e){return it.call(t,e)}function lt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function ct(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?ct(n,a):a,at(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function dt(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function pt(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function ut(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ht(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ft=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:z,append:M,assToVtt:ut,capitalize:Q,clamp:J,createElement:N,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:at,download:Z,errorHandle:X,escape:nt,get:lt,getComposedPath:j,getExt:K,getIcon:F,getRect:B,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:st,hasClass:S,includeFromEvent:Y,inverseClass:R,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:V,isMobile:k,isSafari:b,loadImg:W,mergeDeep:ct,query:T,queryAll:C,remove:A,removeClass:L,replaceElement:D,secondToTime:tt,setStyle:P,setStyleText:E,setStyles:I,siblings:O,silencePromise:G,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:dt,supportsFlex:H,throttle:ht,tooltip:_,unescape:function(t){return t.replace(ot,t=>rt[t]||t)},userAgent:y,vttToBlob:pt},Symbol.toStringTag,{value:"Module"})),mt="array",gt="boolean",vt="string",yt="number",bt="object",wt="function";function xt(t,e,r){return X(e===vt||e===yt||t instanceof Element,`${r.join(".")} require '${vt}' or 'Element' type`)}const kt={html:xt,disable:`?${gt}`,name:`?${vt}`,index:`?${yt}`,style:`?${bt}`,click:`?${wt}`,mounted:`?${wt}`,tooltip:`?${vt}|${yt}`,width:`?${yt}`,selector:`?${mt}`,onSelect:`?${wt}`,switch:`?${gt}`,onSwitch:`?${wt}`,range:`?${mt}`,onRange:`?${wt}`,onChange:`?${wt}`},$t={id:vt,container:xt,url:vt,poster:vt,type:vt,theme:vt,lang:vt,volume:yt,isLive:gt,muted:gt,autoplay:gt,autoSize:gt,autoMini:gt,loop:gt,flip:gt,playbackRate:gt,aspectRatio:gt,screenshot:gt,setting:gt,hotkey:gt,pip:gt,mutex:gt,backdrop:gt,fullscreen:gt,fullscreenWeb:gt,subtitleOffset:gt,miniProgressBar:gt,useSSR:gt,playsInline:gt,lock:gt,gesture:gt,fastForward:gt,autoPlayback:gt,autoOrientation:gt,airplay:gt,proxy:`?${wt}`,plugins:[wt],layers:[kt],contextmenu:[kt],settings:[kt],controls:[c(l({},kt),{position:(t,e,r)=>{const o=["top","left","right"];return X("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${gt}`,html:vt,url:vt}],highlight:[{time:yt,text:vt}],thumbnails:{url:vt,number:yt,column:yt,width:yt,height:yt,scale:yt},subtitle:{url:vt,name:vt,type:vt,style:bt,escape:gt,encoding:vt,onVttLoad:wt},moreVideoAttr:bt,i18n:bt,icons:bt,cssVar:bt,customType:bt};class Et{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return S(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?z(e,r):L(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",m(e,kt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");z(o,`art-${this.name}`),z(o,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const a=n.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));a?a.insertAdjacentElement("beforebegin",o):M(this.$parent,o),e.html&&M(o,e.html),e.style&&I(o,e.style),e.tooltip&&_(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],A(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Tt extends Et{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&R(r,"art-current"),e.on("video:ratechange",()=>{const r=C("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&R(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&R(r,"art-current"),e.on("aspectRatio",e=>{const r=C("span",t).find(t=>t.dataset.value===e);r&&R(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(Q(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&R(r,"art-current"),e.on("flip",e=>{const r=C("span",t).find(t=>t.dataset.value===e);r&&R(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let n=0;n{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=B(r),{height:c,width:d}=B(o);let p=e-s,u=n-l;e+d>s+i&&(p=i-d),n+c>l+a&&(u=a-c),I(o,{top:`${u}px`,left:`${p}px`})}),e(r,"click",t=>{Y(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}class Ct extends Error{constructor(t){super("Failed to release ArtPlayer resources"),this.errors=t,this.name="ResourceCleanupError"}}class zt{constructor(){this.cleanups=new Set,this.disposed=!1}get closed(){return this.disposed}add(t){let e=!0;const r=()=>{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new zt,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof Ct?t.push(...e.errors):t.push(e)}if(t.length)throw new Ct(t)}}const Lt=new WeakMap,St=new WeakMap;function Mt(t){const e=Lt.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function At(t){return Mt(t).scope}function Pt(t){const e=Mt(t);return e.destroying||e.scope.closed}function It(t,e,r,o,n=!1){var a,i,s;const l=Mt(t);if(l.destroying||l.scope.closed)return;l.destroying=!0;const c=[],d=t=>{try{t()}catch(e){c.push(...e instanceof Ct?e.errors:[e])}};o&&(null==(a=t.template)?void 0:a.$video)&&d(()=>t.reset()),d(()=>l.scope.dispose()),d(()=>{var e;return null==(e=t.template)?void 0:e.destroy(r)});const p=e.indexOf(t);-1!==p&&e.splice(p,1),t.isDestroy=!0,n||(null==(i=l.releaseContainer)||i.call(l),l.releaseContainer=void 0),d(()=>t.emit("destroy")),n&&l.rollback&&d(l.rollback),l.rollback=void 0,null==(s=l.releaseContainer)||s.call(l),l.releaseContainer=void 0;for(const u of c.slice(1))console.warn("Additional ArtPlayer cleanup failure:",u);if(c.length)throw c[0]}function Ot(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Rt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function _t(t,e){const{$progress:r}=t.template,{left:o}=B(r),n=J((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:tt(a),width:n,percentage:J(n/r.clientWidth,0,1)}}function Vt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=_t(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Yt(t){return e=>{const{icons:r,option:o,proxy:n}=e,{$player:a,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),u=T(".art-progress-highlight",t),h=T(".art-progress-indicator",t),f=T(".art-progress-tip",t);function m(r,o){const{width:n,time:a}=o||_t(e,r);f.textContent=a||"00:00";const i=f.clientWidth;n<=i/2?P(f,"left",0):n>t.clientWidth-i/2?P(f,"left",t.clientWidth-i+"px"):P(f,"left",n-i/2+"px")}r.indicator?M(h,r.indicator):P(h,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,n){const i="played"===r&&n&&k;if("loaded"===r&&P(d,"width",100*o+"%"),"hover"===r&&(P(c,"width",100*o+"%"),Y(n,u)?function(r){const{width:o}=_t(e,r),{text:n}=r.target.dataset;f.textContent=n;const a=f.clientWidth;o<=a/2?P(f,"left",0):o>t.clientWidth-a/2?P(f,"left",t.clientWidth-a+"px"):P(f,"left",o-a/2+"px")}(n):m(n),0===o?L(a,"art-progress-hover"):z(a,"art-progress-hover")),"played"===r&&(P(p,"width",100*o+"%"),P(h,"left",100*o+"%")),i){z(a,"art-progress-hover");m(n,{width:t.clientWidth*o,time:tt(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{L(a,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){u.textContent="";for(let t=0;t`;M(u,a)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(n(i,"click",t=>{t.target!==h&&Vt(e,t)}),n(i,"mousemove",t=>{const{percentage:r}=_t(e,t);e.emit("setBar","hover",r,t)}),n(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),n(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=_t(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class Dt extends Et{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=Y(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(L(r,"art-hide-cursor"),z(r,"art-hover"),this.timer=Date.now()):(z(r,"art-hide-cursor"),L(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Yt({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.play),i=M(t,o.pause);function s(){P(a,"display","flex"),P(i,"display","none")}function l(){P(a,"display","none"),P(i,"display","flex")}_(a,n.get("Play")),_(i,n.get("Pause")),r(a,"click",()=>{G(e.play())}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,n=M(t,o.volume),a=M(t,o.volumeClose),i=M(t,'
'),s=M(i,'
'),l=M(s,'
'),c=M(s,'
'),d=M(c,'
'),p=M(d,'
'),u=M(c,'
');function h(t){const{top:e,height:r}=B(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)P(n,"display","none"),P(a,"display","flex"),P(u,"top","100%"),P(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;P(n,"display","flex"),P(a,"display","none"),P(u,"top",100-t+"%"),P(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(n,"click",()=>{e.muted=!0}),r(a,"click",()=>{e.muted=!1}),k)P(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=h(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=h(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${tt(e.currentTime)} / ${tt(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let n=0;n{e&&!At(this.art).closed&&(this.art.quality=t.quality)}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;M(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e;M(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{_(t,n.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e;M(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{_(t,n.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;M(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.fullscreenWebOn),i=M(t,o.fullscreenWebOff);P(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(_(t,n.get("Exit Web Fullscreen")),P(a,"display","none"),P(i,"display","inline-flex")):(_(t,n.get("Web Fullscreen")),P(a,"display","inline-flex"),P(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.fullscreenOn),i=M(t,o.fullscreenOff);P(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(_(t,n.get("Exit Fullscreen")),P(a,"display","none"),P(i,"display","inline-flex")):(_(t,n.get("Fullscreen")),P(a,"display","inline-flex"),P(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),at(e,"$control_item",{get:()=>r}),at(e,"$control_value",{get:()=>n})}const i=o(a,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(n.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Nt(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function Ft(t){if(t.constructor.USE_RAF){const e=At(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const Ht=new WeakMap;class Bt{constructor(t){this.destroyEvents=new Set;const e=At(t);Ht.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){Y(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&n&&G(t.toggle()):G(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&G(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{z(r,"art-hover"),t.emit("hover",!0,e)},e=>{L(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=At(t);let a=()=>{};const i=()=>{a(),a=Ot(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&Vt(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=Nt(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=J((o-i)/t.width,-1,1),d=J((a-s)/t.height,-1,1),p=t.isRotate?d:c,u=n===r?t.constructor.TOUCH_MOVE_RATIO:1,h=J(l+t.duration*p*u,0,t.duration);t.seek=h,t.emit("setBar","played",J(h/t.duration,0,1),e),t.notice.show=`${tt(h)} / ${tt(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=ht(()=>{t.emit("view",V(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{var o;const s=a.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});n.push(l)})}a(),e.bindGlobalEvents=a}(t,this),Ft(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(Ht.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Wt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{G(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Xt{constructor(t){const e=l(l({},qt),t.option.icons);for(const r in e)at(this,r,{get:()=>F(r,e[r])})}}class Gt extends Et{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=C("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=At(this.art);!function t(){for(let e=0;e{P(n,"display","none"),P(a,"display",null)}),o.proxy(e.$state,"click",()=>G(t.play()))}}class Qt{constructor(t){this.art=t,this.timer=null,At(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(At(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,z(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",L(r,"art-notice-show")},e.NOTICE_TIME)):L(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function te(t,e,r,o=!1){const n=e=>{Pt(t)||r(e)};t[o?"once":"on"](e,n),At(t).add(()=>{t.off(e,n)})}function ee(t,e,r){for(const[o,n]of e){if(Pt(t)||r&&!r())return;t[o].show=n}}const re=new WeakMap,oe=new WeakMap,ne=new WeakMap;function ae(t){return ne.get(t)||At(t)}function ie(t){const e=re.get(t),r=ne.get(t);return()=>re.get(t)===e&&(!e||e.active())&&ne.get(t)===r&&(!r||!r.closed)}function se(t){const e=ne.get(t),r=At(t).child(),o=r.child();ne.set(t,r),r.add(()=>{ne.get(t)===r&&ne.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!Pt(t)&&!o.closed&&re.get(t)===n};return re.set(t,n),o.add(()=>{re.get(t)===n&&re.delete(t),n.onAssigned=void 0,n.onError=void 0}),null==e||e.dispose(),n}function le(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&(null==e||e())}function ce(t,e,r){oe.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{oe.get(t)===e&&(oe.delete(t),le(e))}}function de(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function pe(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=ae(t),l=0;return{reset(){l=0,null==i||i.dispose(),L(a,"art-error")},loadStart(){L(a,"art-error")},schedule(c){(c=>d(null,null,function*(){if(Pt(t))return;const d=ae(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const u=()=>!Pt(t)&&!p.closed&&d===ae(t),h=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ue(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{Pt(t)||t.emit(`video:${e.type}`,e)})}(t);const e=pe(t);!function(t,e){te(t,"video:canplay",()=>{e.reset(),ee(t,[["loading",!1]])}),te(t,"video:canplay",()=>{ee(t,[["loading",!1],["controls",!0],["mask",!0]]),Pt(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;te(t,"video:ended",()=>{if(e.loop){const e=ie(t);if(t.seek=0,Pt(t)||!e())return;G(t.play()),e()&&ee(t,[["controls",!1],["mask",!1]],e)}else ee(t,[["controls",!0],["mask",!0]])})}(t),te(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;te(t,"video:loadedmetadata",()=>{t.emit("resize"),k&&ee(t,[["loading",!1],["controls",!0],["mask",!0]])}),te(t,"video:loadstart",()=>{e.loadStart(),ee(t,[["loading",!0],["mask",!1],["controls",!0]])}),te(t,"video:pause",()=>{ee(t,[["controls",!0],["mask",!0]])}),te(t,"video:play",()=>{ee(t,[["mask",!1]]),Pt(t)||P(r,"display","none")}),te(t,"video:playing",()=>ee(t,[["mask",!1]])),te(t,"video:progress",()=>{t.playing&&ee(t,[["loading",!1]])}),te(t,"video:seeked",()=>ee(t,[["loading",!1],["mask",!0]])),te(t,"video:seeking",()=>ee(t,[["loading",!0],["mask",!1]])),te(t,"video:timeupdate",()=>ee(t,[["mask",!1]])),te(t,"video:waiting",()=>ee(t,[["loading",!0],["mask",!1]]))}(t,e)}const he=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],fe=(()=>{if("undefined"===typeof document)return!1;const t=he[0],e={};for(const r of he){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),me={change:fe.fullscreenchange,error:fe.fullscreenerror},ge={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{ge.off("change",n),r()};ge.on("change",n);const a=t[fe.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!ge.isFullscreen)return void t();const r=()=>{ge.off("change",r),t()};ge.on("change",r);const o=document[fe.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>ge.isFullscreen?ge.exit():ge.request(t,e),onchange(t){ge.on("change",t)},onerror(t){ge.on("error",t)},on(t,e){const r=me[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=me[t];r&&document.removeEventListener(r,e,!1)},raw:fe};function ve(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t,a=t=>{ge.on("change",()=>{t.emit("fullscreen",ge.isFullscreen),ge.isFullscreen?(t.state="fullscreen",z(n,"art-fullscreen")):L(n,"art-fullscreen"),t.emit("resize")}),ge.on("error",e=>{t.emit("fullscreenError",e)}),at(t,"fullscreen",{get:()=>ge.isFullscreen,set(t){return d(this,null,function*(){t?yield ge.request(n):yield ge.exit()})}})};t.once("video:loadedmetadata",()=>{var n;ge.isEnabled?a(t):o.webkitSupportsFullscreen?((n=t).on("document:webkitfullscreenchange",()=>{n.emit("fullscreen",n.fullscreen),n.emit("resize")}),at(n,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(n.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):at(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),at(t,"fullscreen",lt(t,"fullscreen"))})}function ye(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(L(n,"art-mini"),P(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(P(e,"display","none"),P(r,"display","flex")):(P(e,"display","flex"),P(r,"display","none"))}function p(){const{$mini:e}=t.template,r=B(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),P(e,"top",`${n}px`),P(e,"left",`${a}px`)}at(t,"mini",{get:()=>S(n,"art-mini"),set(u){if(u){t.state="mini",z(n,"art-mini");const u=function(){const{$mini:n}=t.template;if(n)return M(n,a),P(n,"display","flex");{const n=N("div");z(n,"art-mini-popup"),M(document.body,n),t.template.$mini=n,M(n,a);const p=M(n,'
');M(p,e.close),r(p,"click",c);const u=M(n,'
'),h=M(u,e.play),f=M(u,e.pause);return r(h,"click",()=>G(t.play())),r(f,"click",()=>t.pause()),d(h,f),t.on("video:playing",()=>d(h,f)),t.on("video:pause",()=>d(h,f)),t.on("video:timeupdate",()=>d(h,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){z(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;P(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,L(n,"art-mini-dragging");const t=B(n);o.set("left",t.left),o.set("top",t.top),P(n,"left",`${t.left}px`),P(n,"top",`${t.top}px`),P(n,"transform",null)}}),n}}(),h=o.get("top"),f=o.get("left");"number"===typeof h&&"number"===typeof f?(P(u,"top",`${h}px`),P(u,"left",`${f}px`),V(u)||p()):p(),t.emit("mini",!0)}else c()}})}function be(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,at(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),at(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):at(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function we(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function xe(t,e,r){return new Promise((o,n)=>{if(Pt(t)||e===t.url)return void o();const a=se(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),p=t=>l(!0,t);a.onError=p;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const u=i.child(),h={"video:error":p,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){p(e)}},"video:canplay":()=>{if(!c())return;u.dispose();d(null,null,function*(){if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{yield t.play()}catch(e){}c()&&(t.notice.show="",l())}}).catch(p)}},f=i.child(),m=[],g=Object.keys(h);for(const e of g)we(f,t,e,t=>{a.acceptingEvents&&m.push([e,t])},!1);if(ce(t,a,e),!c())return;if(t.notice.show="",!c())return;const v=()=>{if(f.dispose(),!e)return void l();const r={};for(const e of g)r[e]=we(u,t,e,h[e]);for(const[t,e]of m){if(!c()||u.closed)break;r[t](e)}m.length=0};a.assigned?v():a.onAssigned=v}catch(u){p(u)}})}function ke(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",(n,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:u}=e.thumbnails;if(!d||!p)return;if("hover"===n||"played"===n&&l&&k){if(i||a||(a=!0,i=yield W(p,u),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?P(s,"left",r.clientWidth-h+"px"):P(s,"left",n-h/2+"px")}(n)}})),at(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function $e(t){const{option:e,template:{$video:r}}=t;at(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(Pt(t))return;const n=function(t){const e=oe.get(t);return oe.delete(t),e||se(t)}(t);n.acceptingEvents=!1;try{if(!o)return void((yield Rt(n.scope))&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||K(o),s=e.customType[i];if(i&&s){if(!(yield Rt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;we(l,t,"video:canplay",()=>{c=!d}),we(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>de(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||we(n.scope,t,"video:canplay",e)}}catch(a){de(n,a)}finally{le(n)}})}})}Object.defineProperties(ge,{isFullscreen:{get:()=>Boolean(document[fe.fullscreenElement])},element:{enumerable:!0,get:()=>document[fe.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[fe.fullscreenEnabled])}});class Ee{constructor(t){$e(t),function(t){const{template:{$video:e}}=t;at(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;at(t,"play",{value(){return d(this,null,function*(){const i=ie(t),s=yield a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;at(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${tt(t.currentTime)} / ${tt(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;at(t,"forward",{set(e){r.seek=t.currentTime+e}}),at(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;at(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=J(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),at(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;at(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=J(o,0,t.duration))}})}(t),function(t){at(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>xe(t,e,0);at(t,"switchQuality",{value:e=>xe(t,e,t.currentTime)}),at(t,"switchUrl",{value:e}),at(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;at(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;at(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)P(o,"width",null),P(o,"height",null),P(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(P(o,"width",s*r+"px"),P(o,"height","100%"),P(o,"margin","0 auto")):(P(o,"width","100%"),P(o,"height",e/s+"px"),P(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");at(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),at(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),at(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return Z(o,`${e||`artplayer_${tt(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),ve(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";at(t,"fullscreenWeb",{get:()=>S(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&M(document.body,o),t.state="fullscreenWeb",P(o,"width","100%"),P(o,"height","100%"),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&M(r,o),n&&(o.style.cssText=n,n=""),L(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),be(t),function(t){const{$video:e}=t.template,r=t;at(t,"loaded",{get:()=>r.loadedTime/e.duration}),at(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){at(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;at(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;at(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=B(e),l=n/a;if(i/s>l)P(r,"width",s*l/i*100+"%"),P(r,"height","100%");else{const t=i/l/s*100;P(r,"width","100%"),P(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;at(t,"rect",{get:()=>B(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}at(t,"x",{get:()=>e.left+window.pageXOffset}),at(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;at(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(Q(n))}`,t.emit("flip",n)}})}(t),ye(t),function(t){const{template:{$poster:e}}=t;at(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){P(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;at(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);P(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;at(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){at(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){at(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];at(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,at(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){at(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==a?void 0:a.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${n.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),ke(t),ue(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=J(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=J(a,0,1)),e.poster&&P(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Te(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var n;if(e){if(l()){const e=Number(null!=(n=r.AUTO_ORIENTATION_TIME)?n:0);setTimeout(()=>{t.fullscreenWeb&&!S(o,a)&&function(){const e=U(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;P(o,"width",`${n}px`),P(o,"height",`${i}px`),P(o,"transform-origin","0 0"),P(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),z(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else S(o,a)&&(P(o,"width",""),P(o,"height",""),P(o,"transform-origin",""),P(o,"transform",""),L(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const n=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(n&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,z(o,i)}catch(a){s=!1,e.show=a}}else if(S(o,i)&&L(o,i),n&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return S(o,a)}}}function Ce(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);M(d,r.close);let p=null;function u(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),P(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(P(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${tt(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{P(s,"display","none")}),a(c,"click",()=>{t.seek=r,G(t.play()),P(i,"display","none"),P(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{P(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",u),t.on("restart",u),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function ze(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,L(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,z(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return S(o,"art-fast-forward")}}}function Le(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return S(o,"art-lock")}function a(){z(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){L(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=M(e,r.lock),n=M(e,r.unlock);P(o,"display","none"),t.on("lock",t=>{t?(P(o,"display","inline-flex"),P(n,"display","none")):(P(o,"display","none"),P(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function Se(t){return t.on("control",e=>{e?L(t.template.$player,"art-mini-progress-bar"):z(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Me{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){Pt(t.art)||!e.miniProgressBar||e.isLive||t.add(Se),!Pt(t.art)&&e.lock&&k&&t.add(Le),Pt(t.art)||!e.autoPlayback||e.isLive||t.add(Ce),!Pt(t.art)&&e.autoOrientation&&k&&t.add(Te),!Pt(t.art)&&e.fastForward&&k&&!e.isLive&&t.add(ze)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){X(!Pt(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(Pt(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(Pt(t.art))return t;let n=o;const a=st(t,n);if(Pt(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return Pt(t.art)||(X(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),Pt(t.art)||at(t,n,{value:r})),t}(this,t,e)}}class Ae extends Et{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=Y(t,r.setting),o=Y(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(Q(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&R(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),at(a,"$parents",{get:()=>r}),at(a,"$option",{get:()=>t});const o=[];at(a,"$events",{get:()=>o}),at(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:n},template:{$player:a,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=B(r.setting),{left:d,width:p}=B(a),u=l-d+c/2-s/2;if(P(i,"height",`${this.active===this.option?this.active.length*n:(this.active.length+1)*n}px`),P(i,"width",`${s}px`),this.art.isRotate||k)return;u+s>p?(P(i,"left",null),P(i,"right",null)):(P(i,"left",`${u}px`),P(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");z(s,"art-setting-item-left-icon"),M(s,o),M(i,s),M(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),M(e,a)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const n=this.cache.get(t.$option),a=t.$item;let i="selector";st(t,"switch")&&(i="switch"),st(t,"range")&&(i="range"),st(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");z(p,"art-setting-item"),P(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const u=M(p,'
'),h=M(p,'
'),f=N("div");switch(z(f,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":M(f,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?M(f,t.icon||s.config):M(f,s.check)}M(u,f),at(t,"$icon",{configurable:!0,get:()=>f}),at(t,"icon",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",M(f,t)}});const m=N("div");z(m,"art-setting-item-left-text"),M(m,t.html||""),M(u,m),at(t,"$html",{configurable:!0,get:()=>m}),at(t,"html",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",M(m,t)}});const g=N("div");switch(z(g,"art-setting-item-right-tooltip"),M(g,t.tooltip||""),M(h,g),at(t,"$tooltip",{configurable:!0,get:()=>g}),at(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",M(g,t)}}),i){case"switch":{const e=N("div");z(e,"art-setting-item-right-icon");const r=M(e,s.switchOn),o=M(e,s.switchOff);P(t.switch?o:r,"display","none"),M(h,e),at(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;at(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(P(o,"display","none"),P(r,"display",null)):(P(o,"display",null),P(r,"display","none"))}});break}case"range":{const e=N("div");z(e,"art-setting-item-right-icon");const r=M(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],z(r,"art-setting-range"),M(h,e),at(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];at(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");z(t,"art-setting-item-right-icon"),M(t,s.arrowRight),M(h,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&z(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}at(t,"$item",{configurable:!0,get:()=>p}),e?D(p,a):M(n,p),t.mounted&&Ot(At(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){R(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),z(r,"art-setting-panel"),M(this.$parent,r),R(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?I(r,t):P(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?nt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a=c(l(l({},n.subtitle),e),{url:t}),i=yield this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,A(i),M(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(m(t,$t.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||K(t.url)){case"srt":{const e=dt(r);return pt(t.onVttLoad(e))}case"ass":{const e=ut(r);return pt(t.onVttLoad(e))}case"vtt":return pt(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}const Re=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class _e{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(H(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=St.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=Mt(t);n.rollback=r,St.set(e,t),n.releaseContainer=()=>{St.get(e)===t&&St.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Re}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=_e.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){X(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),D(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&z(this.$player,"art-backdrop"),k&&z(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":z(this.$player,"art-destroy")}}const Ve=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class Ye{on(t,e,r){const o=this.e||(this.e={});let n=Ve(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Ve(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Ve(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),Fe.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Fe.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=Mt(t);return e.rollback=void 0,!e.scope.closed})(this)&&Ne.push(this)}catch(o){try{It(this,Ne,!0,Fe.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return Ne}static get version(){return g}static get config(){return v}static get utils(){return ft}static get scheme(){return $t}static get Emitter(){return Ye}static get validator(){return m}static get kindOf(){return m.kindOf}static get html(){return _e.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){It(this,Ne,t,Fe.REMOVE_SRC_WHEN_DESTROY)}}return Fe.STYLE=Ie,Fe.DEBUG=!1,Fe.CONTEXTMENU=!0,Fe.NOTICE_TIME=2e3,Fe.SETTING_WIDTH=250,Fe.SETTING_ITEM_WIDTH=200,Fe.SETTING_ITEM_HEIGHT=35,Fe.RESIZE_TIME=200,Fe.SCROLL_TIME=200,Fe.SCROLL_GAP=50,Fe.AUTO_PLAYBACK_MAX=10,Fe.AUTO_PLAYBACK_MIN=5,Fe.AUTO_PLAYBACK_TIMEOUT=3e3,Fe.RECONNECT_TIME_MAX=5,Fe.RECONNECT_SLEEP_TIME=1e3,Fe.CONTROL_HIDE_TIME=3e3,Fe.DBCLICK_TIME=300,Fe.DBCLICK_FULLSCREEN=!0,Fe.MOBILE_DBCLICK_PLAY=!0,Fe.MOBILE_CLICK_PLAY=!1,Fe.AUTO_ORIENTATION_TIME=200,Fe.INFO_LOOP_TIME=1e3,Fe.FAST_FORWARD_VALUE=3,Fe.FAST_FORWARD_TIME=1e3,Fe.TOUCH_MOVE_RATIO=.5,Fe.VOLUME_STEP=.1,Fe.SEEK_STEP=5,Fe.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Fe.ASPECT_RATIO=["default","4:3","16:9"],Fe.FLIP=["normal","horizontal","vertical"],Fe.FULLSCREEN_WEB_IN_BODY=!0,Fe.LOG_VERSION=!0,Fe.USE_RAF=!1,Fe.REMOVE_SRC_WHEN_DESTROY=!0,$&&(window.Artplayer=Fe,E("artplayer-style",Ie),setTimeout(()=>{Fe.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Fe.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Fe}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))a.call(e,r)&&s(t,r,e[r]);if(n)for(var r of n(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,n)=>{var a=t=>{try{s(r.next(t))}catch(e){n(e)}},i=t=>{try{s(r.throw(t))}catch(e){n(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(a,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var u,h={exports:{}};var f=(u||(u=1,h.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new b,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof y?t.push(...e.errors):t.push(e)}if(t.length)throw new y(t)}}const w=new WeakMap,x=new WeakMap;function k(t){const e=w.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function $(t){return k(t).scope}function E(t){const e=k(t);return e.destroying||e.scope.closed}function T(t,e,r,o,n=!1){var a,i,s;const l=k(t);if(l.destroying||l.scope.closed)return;l.destroying=!0;const c=[],d=t=>{try{t()}catch(e){c.push(...e instanceof y?e.errors:[e])}};o&&(null==(a=t.template)?void 0:a.$video)&&d(()=>t.reset()),d(()=>l.scope.dispose()),d(()=>{var e;return null==(e=t.template)?void 0:e.destroy(r)});const p=e.indexOf(t);-1!==p&&e.splice(p,1),t.isDestroy=!0,n||(null==(i=l.releaseContainer)||i.call(l),l.releaseContainer=void 0),d(()=>t.emit("destroy")),n&&l.rollback&&d(l.rollback),l.rollback=void 0,null==(s=l.releaseContainer)||s.call(l),l.releaseContainer=void 0;for(const u of c.slice(1))console.warn("Additional ArtPlayer cleanup failure:",u);if(c.length)throw c[0]}const C=new WeakMap;function z(t,e){const r=$(t).child();return C.set(e,r),r}function S(t){const e=C.get(t);if(!e)throw new Error("ArtPlayer component has not been registered");return e}function L(t){var e;null==(e=C.get(t))||e.dispose()}function M(t,e){return{on:(r,o)=>{!function(t,e,r,o){const n=S(e);if(n.closed)return;const a=(...t)=>{if(!n.closed)return o(...t)};t.on(r,a),n.add(()=>{t.off(r,a)})}(t,e,r,o)},proxy:(r,o,n)=>function(t,e,r,o,n){const a=S(e);if(a.closed)return()=>{};const i=t.events.proxy(r,o,t=>{if(!a.closed)return n(t)});return a.add(()=>{t.events.remove(i)})}(t,e,r,o,n)}}const A=null!=(t=null==globalThis?void 0:globalThis.CUSTOM_USER_AGENT)?t:"undefined"!==typeof navigator?navigator.userAgent:"",P=/^(?:(?!chrome|android).)*safari/i.test(A),O=/iPad|iPhone|iPod/i.test(A)&&!window.MSStream,I=O||A.includes("Macintosh")&&navigator.maxTouchPoints>=1,R=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(A)||I,_="undefined"!==typeof window&&"undefined"!==typeof document;function V(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function Y(t,e=document){return e.querySelector(t)}function D(t,e=document){return Array.from(e.querySelectorAll(t))}function N(t,e){return t.classList.add(e)}function F(t,e){return t.classList.remove(e)}function H(t,e){return t.classList.contains(e)}function B(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function W(t){return t.parentNode.removeChild(t)}function j(t,e,r){return t.style[e]=r,t}function q(t,e){for(const r in e)j(t,r,e[r]);return t}function U(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function X(t,e){U(t).forEach(t=>F(t,e)),N(t,e)}function G(t,e,r="top"){R||(t.setAttribute("aria-label",e),N(t,"hint--rounded"),N(t,`hint--${r}`))}function K(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function Z(t,e){return nt(t).includes(e)}function J(t,e){return e.parentNode.replaceChild(t,e),t}function Q(t){return document.createElement(t)}function tt(t="",e=""){const r=Q("i");return N(r,"art-icon"),N(r,`art-icon-${t}`),B(r,e),r}function et(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function rt(t){return t.getBoundingClientRect()}function ot(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function nt(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function at(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class it extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function st(t,e){if(!t)throw new it(e);return t}function lt(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function ct(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function dt(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function pt(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function ut(t){return t.charAt(0).toUpperCase()+t.slice(1)}function ht(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const ft={"&":"&","<":"<",">":">","'":"'",'"':"""},mt={"&":"&","<":"<",">":">","'":"'",""":'"'},gt=/(&|<|>|'|")/g;function vt(t){return t.replace(/[&<>'"]/g,t=>ft[t]||t)}const yt=Object.defineProperty,{hasOwnProperty:bt}=Object.prototype;function wt(t,e){return bt.call(t,e)}function xt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function kt(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?kt(n,a):a,yt(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function $t(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function Et(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Tt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function Ct(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const zt=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:it,addClass:N,append:B,assToVtt:Tt,capitalize:ut,clamp:pt,createElement:Q,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:yt,download:dt,errorHandle:st,escape:vt,get:xt,getComposedPath:nt,getExt:ct,getIcon:tt,getRect:rt,getSafeAreaInsets:at,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:wt,hasClass:H,includeFromEvent:Z,inverseClass:X,isBrowser:_,isIOS:O,isIOS13:I,isInViewport:K,isMobile:R,isSafari:P,loadImg:ot,mergeDeep:kt,query:Y,queryAll:D,remove:W,removeClass:F,replaceElement:J,secondToTime:ht,setStyle:j,setStyleText:V,setStyles:q,siblings:U,silencePromise:lt,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:$t,supportsFlex:et,throttle:Ct,tooltip:G,unescape:function(t){return t.replace(gt,t=>mt[t]||t)},userAgent:A,vttToBlob:Et},Symbol.toStringTag,{value:"Module"}));function St(t,e){return B(t,e)}function Lt(t,e){return e.querySelector(t)}const Mt="array",At="boolean",Pt="string",Ot="number",It="object",Rt="function";function _t(t,e,r){return st(e===Pt||e===Ot||t instanceof Element,`${r.join(".")} require '${Pt}' or 'Element' type`)}const Vt={html:_t,disable:`?${At}`,name:`?${Pt}`,index:`?${Ot}`,style:`?${It}`,click:`?${Rt}`,mounted:`?${Rt}`,tooltip:`?${Pt}|${Ot}`,width:`?${Ot}`,selector:`?${Mt}`,onSelect:`?${Rt}`,switch:`?${At}`,onSwitch:`?${Rt}`,range:`?${Mt}`,onRange:`?${Rt}`,onChange:`?${Rt}`},Yt={id:Pt,container:_t,url:Pt,poster:Pt,type:Pt,theme:Pt,lang:Pt,volume:Ot,isLive:At,muted:At,autoplay:At,autoSize:At,autoMini:At,loop:At,flip:At,playbackRate:At,aspectRatio:At,screenshot:At,setting:At,hotkey:At,pip:At,mutex:At,backdrop:At,fullscreen:At,fullscreenWeb:At,subtitleOffset:At,miniProgressBar:At,useSSR:At,playsInline:At,lock:At,gesture:At,fastForward:At,autoPlayback:At,autoOrientation:At,airplay:At,proxy:`?${Rt}`,plugins:[Rt],layers:[Vt],contextmenu:[Vt],settings:[Vt],controls:[c(l({},Vt),{position:(t,e,r)=>{const o=["top","left","right"];return st("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${At}`,html:Pt,url:Pt}],highlight:[{time:Ot,text:Pt}],thumbnails:{url:Pt,number:Ot,column:Ot,width:Ot,height:Ot,scale:Ot},subtitle:{url:Pt,name:Pt,type:Pt,style:It,escape:At,encoding:Pt,onVttLoad:Rt},moreVideoAttr:It,i18n:It,icons:It,cssVar:It,customType:It},Dt=new WeakSet;class Nt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return H(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?N(e,r):F(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){var e;if(E(this.art))return;const r="function"===typeof t?t(this.art):t;if(E(this.art))return;if(r.html=r.html||"",m(r,Vt),!this.$parent||!this.name||r.disable)return;const o=r.name||`${this.name}${this.id}`,n=this.cache;st(!n.has(o),`Can't add an existing [${o}] to the [${this.name}]`),this.id+=1;const a=document.createElement("div"),i=z(this.art,a),s=[],l=Object.getOwnPropertyDescriptor(this,o);let c=!1;i.add(()=>{for(const t of s)this.art.events.remove(t)});try{if(i.closed)return;if(function(t,e,r,o,n,a){N(t,`art-${r}`),N(t,`art-${r}-${o}`);const i=Array.from(e.children);t.dataset.index=String(a.index||n);const s=i.find(e=>Number(e.dataset.index)>=Number(t.dataset.index));s?s.insertAdjacentElement("beforebegin",t):B(e,t),a.html&&B(t,a.html),a.style&&q(t,a.style),a.tooltip&&G(t,a.tooltip)}(a,this.$parent,this.name,o,this.id,r),i.closed)return;if(r.click){const t=this.art.events.proxy(a,"click",t=>{i.closed||(t.preventDefault(),r.click.call(this.art,this,t))});s.push(t)}if(r.selector&&["left","right"].includes(r.position)&&this.selector(r,a,s),i.closed)return;return function(t,e,r){const o=t;"__proto__"===e?Object.defineProperty(o,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):o[e]=r}(this,o,a),c=!0,n.set(o,{$ref:a,events:s,option:r}),r.mounted&&r.mounted.call(this.art,a),a}catch(d){try{L(a)}catch(p){console.warn("ArtPlayer component cleanup failed:",p)}throw(null==(e=n.get(o))?void 0:e.$ref)===a&&n.delete(o),c&&this[o]===a&&(l?Object.defineProperty(this,o,l):delete this[o]),a.remove(),d}}remove(t){st(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);if(!Dt.has(e)){Dt.add(e);try{e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);try{L(e.$ref)}finally{this.cache.get(t)===e&&(this.cache.delete(t),delete this[t]),e.$ref.remove()}}finally{Dt.delete(e)}}}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Ft extends Nt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,z(t,this.$parent),R||this.init()}init(){const{option:t,template:{$player:e,$contextmenu:r}}=this.art,{on:o,proxy:n}=M(this.art,r);t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="1"]',t);o&&X(o,"art-current"),r("video:ratechange",()=>{const r=Array.from(t.querySelectorAll("span")).find(t=>Number(t.dataset.value)===e.playbackRate);r&&X(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="default"]',t);o&&X(o,"art-current"),r("aspectRatio",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&X(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(ut(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="normal"]',t);o&&X(o,"art-current"),r("flip",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&X(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const o=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=rt(e),{height:c,width:d}=rt(r);let p=o-s,u=n-l;o+d>s+i&&(p=i-d),n+c>l+a&&(u=a-c),q(r,{top:`${u}px`,left:`${p}px`})}),n(e,"click",t=>{Z(t,r)||(this.show=!1)}),o("blur",()=>{this.show=!1})}}function Ht(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Bt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function Wt(t,e){const{$progress:r}=t.template,{left:o}=rt(r),n=pt((R?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:ht(a),width:n,percentage:pt(n/r.clientWidth,0,1)}}function jt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Wt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function qt(t,e){const{icons:r,option:o}=t,{$player:n}=t.template,a=S(e),{on:i}=M(t,e);let s=()=>{};const l=Lt(".art-progress-hover",e),c=Lt(".art-progress-loaded",e),d=Lt(".art-progress-played",e),p=Lt(".art-progress-highlight",e),u=Lt(".art-progress-indicator",e),h=Lt(".art-progress-tip",e);function f(r,o){const{width:n,time:a}=o||Wt(t,r);h.textContent=a||"00:00";const i=h.clientWidth;n<=i/2?j(h,"left",0):n>e.clientWidth-i/2?j(h,"left",e.clientWidth-i+"px"):j(h,"left",n-i/2+"px")}r.indicator?B(u,r.indicator):j(u,"backgroundColor","var(--art-theme)"),i("setBar",function(r,o,i){const m="played"===r&&i&&R;if("loaded"===r&&j(c,"width",100*o+"%"),"hover"===r&&(j(l,"width",100*o+"%"),Z(i,p)?function(r){const{width:o}=Wt(t,r),n=r.target instanceof HTMLElement?r.target.dataset.text:void 0;h.textContent=null!=n?n:"";const a=h.clientWidth;o<=a/2?j(h,"left",0):o>e.clientWidth-a/2?j(h,"left",e.clientWidth-a+"px"):j(h,"left",o-a/2+"px")}(i):f(i),0===o?F(n,"art-progress-hover"):N(n,"art-progress-hover")),"played"===r&&(j(d,"width",100*o+"%"),j(u,"left",100*o+"%")),m){N(n,"art-progress-hover");f(i,{width:e.clientWidth*o,time:ht(o*t.duration)}),s(),s=Ht(a,()=>{F(n,"art-progress-hover")},500)}}),i("video:loadedmetadata",function(){p.textContent="";for(let e=0;e{t.emit("setBar","played",t.played),t.emit("setBar","loaded",t.loaded)}):(i("video:timeupdate",()=>{t.emit("setBar","played",t.played)}),i("video:progress",()=>{t.emit("setBar","loaded",t.loaded)}),i("video:ended",()=>{t.emit("setBar","played",1)})),t.emit("setBar","loaded",t.loaded||0)}function Ut(t){return e=>c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{qt(e,t),function(t,e){const{$progress:r}=t.template,o=e.querySelector(".art-progress-indicator"),{on:n,proxy:a}=M(t,e);if(!R){let e=!1;a(r,"click",e=>{e.target!==o&&jt(t,e)}),a(r,"mousemove",e=>{const{percentage:r}=Wt(t,e);t.emit("setBar","hover",r,e)}),a(r,"mouseleave",e=>{t.emit("setBar","hover",0,e)}),a(r,"mousedown",t=>{e=0===t.button}),n("document:mousemove",r=>{if(e){const{second:e,percentage:o}=Wt(t,r);t.emit("setBar","played",o,r),t.seek=e}}),n("document:mouseup",()=>{e&&(e=!1)})}}(e,t)}})}function Xt(t){const{option:e}=t.art;e.isLive||t.add(Ut({name:"progress",position:"top",index:10})),t.add({name:"thumbnails",position:"top",index:20}),t.add(function(t){return e=>c(l({},t),{mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.play),s=St(t,n.pause);function l(){j(i,"display","flex"),j(s,"display","none")}function c(){j(i,"display","none"),j(s,"display","flex")}G(i,a.get("Play")),G(s,a.get("Pause")),o(i,"click",()=>{lt(e.play())}),o(s,"click",()=>{e.pause()}),e.playing?c():l(),r("video:playing",()=>{c()}),r("video:pause",()=>{l()})}})}({name:"playAndPause",position:"left",index:10})),t.add(function(t){return e=>c(l({},t),{mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n}=e,a=St(t,n.volume),i=St(t,n.volumeClose),s=St(t,'
'),l=St(s,'
'),c=St(l,'
'),d=St(l,'
'),p=St(d,'
'),u=St(p,'
'),h=St(d,'
');function f(t){const{top:e,height:r}=rt(d);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)j(a,"display","none"),j(i,"display","flex"),j(h,"top","100%"),j(u,"top","100%"),c.textContent="0";else{const t=100*e.volume;j(a,"display","flex"),j(i,"display","none"),j(h,"top",100-t+"%"),j(u,"top",100-t+"%"),c.textContent=String(Math.floor(t))}}if(m(),r("video:volumechange",m),o(a,"click",()=>{e.muted=!0}),o(i,"click",()=>{e.muted=!1}),R)j(s,"display","none");else{let t=!1;o(d,"mousedown",r=>{t=0===r.button,e.volume=f(r)}),r("document:mousemove",r=>{t&&(e.muted=!1,e.volume=f(r))}),r("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),e.isLive||t.add(function(t){return e=>c(l({},t),{style:R?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{const{on:r}=M(e,t);function o(){const r=`${ht(e.currentTime)} / ${ht(e.duration)}`;r!==t.textContent&&(t.textContent=r)}o();const n=["video:loadedmetadata","video:timeupdate","video:progress"];for(let e=0;e{r&&!$(t.art).closed&&(t.art.quality=e.quality)}).catch(t=>{console.warn("ArtPlayer quality initialization failed:",t)}),e.screenshot&&!R&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r}=M(e,t),{icons:o}=e;St(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),e.setting&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e;St(t,n.setting),o(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),r("setting",e=>{G(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),e.pip&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e;St(t,n.pip),o(t,"click",()=>{e.pip=!e.pip}),r("pip",e=>{G(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),e.airplay&&"WebKitPlaybackTargetAvailabilityEvent"in window&&window.WebKitPlaybackTargetAvailabilityEvent&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r}=M(e,t),{icons:o}=e;St(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),e.fullscreenWeb&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.fullscreenWebOn),s=St(t,n.fullscreenWebOff);j(s,"display","none"),o(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),r("fullscreenWeb",e=>{e?(G(t,a.get("Exit Web Fullscreen")),j(i,"display","none"),j(s,"display","inline-flex")):(G(t,a.get("Web Fullscreen")),j(i,"display","inline-flex"),j(s,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),e.fullscreen&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.fullscreenOn),s=St(t,n.fullscreenOff);j(s,"display","none"),o(t,"click",()=>{e.fullscreen=!e.fullscreen}),r("fullscreen",e=>{e?(G(t,a.get("Exit Fullscreen")),j(i,"display","none"),j(s,"display","inline-flex")):(G(t,a.get("Fullscreen")),j(i,"display","inline-flex"),j(s,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let r=0;rKt.get(t).option.selector}),yt(t,"$control_item",{get:()=>Kt.get(t).item}),yt(t,"$control_value",{get:()=>Kt.get(t).value})),Kt.set(t,e)}function Jt(t,e){t.innerHTML=e}function Qt(t,e,r,o,n){const{proxy:a}=t.events,i=S(o),s=r.selector;N(o,"art-control-selector");const l=document.createElement("div");N(l,"art-selector-value"),B(l,r.html),o.textContent="",B(o,l);const c=St(o,'
');for(let d=0;dd(null,null,function*(){if(i.closed)return;const n=nt(o),a=r.selector.find(t=>n.includes(t.$control_item));if(!a)return;const s=++p,c=()=>!i.closed&&s===p,d=i.add(function(t,e){return Gt.set(t,e),()=>{Gt.get(t)===e&&Gt.delete(t)}}(o,c));try{if(e(a),i.closed)return;if(r.onSelect){const e=yield r.onSelect.call(t,a,a.$control_item,o);c()&&Jt(l,e)}}catch(u){console.warn("ArtPlayer selector failed:",u)}finally{d()}}));n.push(u)}class te extends Nt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;z(t,o);const{on:n}=M(t,o);n("mousemove",()=>{R||(this.show=!0)}),n("click",()=>{R?this.toggle():this.show=!0}),n("document:mousemove",t=>{this.isHover=Z(t,o)}),n("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),n("control",t=>{t?(F(r,"art-hide-cursor"),N(r,"art-hover"),this.timer=Date.now()):(N(r,"art-hide-cursor"),F(r,"art-hover"))}),this.init(),$(t).closed||function(t){const{$bottom:e,$controls:r,$player:o}=t.template,n=S(e),{on:a}=M(t,e),i=()=>{if(n.closed)return;const t=r.offsetHeight;t>0&&o.style.getPropertyValue("--art-controls-height")!==`${t}px`&&o.style.setProperty("--art-controls-height",`${t}px`)};if(a("resize",i),"undefined"!==typeof ResizeObserver){const t=new ResizeObserver(i);t.observe(r),n.add(()=>{t.disconnect()})}else if("undefined"!==typeof MutationObserver){const t=new MutationObserver(i);t.observe(r,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),n.add(()=>{t.disconnect()})}i()}(t)}init(){Xt(this)}add(t){if(E(this.art))return;const e="function"===typeof t?t(this.art):t,{$progress:r,$controlsLeft:o,$controlsRight:n}=this.art.template;switch(e.position){case"top":this.$parent=r;break;case"left":this.$parent=o;break;case"right":this.$parent=n;break;default:st(!1,"Control option.position must one of 'top', 'left', 'right'")}super.add(e)}check(t){!function(t){if(t){Jt(t.$control_value,t.html);for(let e=0;ethis.check(t),t,e,r)}}function ee(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function re(t){if(t.constructor.USE_RAF){const e=$(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const oe=new WeakMap;class ne{constructor(t){this.destroyEvents=new Set;const e=$(t);oe.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){Z(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),R?!t.isLock&&n&<(t.toggle()):lt(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),R?!t.isLock&&s&<(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{N(r,"art-hover"),t.emit("hover",!0,e)},e=>{F(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=$(t);let a=()=>{};const i=()=>{a(),a=Ht(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(R&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&jt(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=ee(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=pt((o-i)/t.width,-1,1),d=pt((a-s)/t.height,-1,1),p=t.isRotate?d:c,u=n===r?t.constructor.TOUCH_MOVE_RATIO:1,h=pt(l+t.duration*p*u,0,t.duration);t.seek=h,t.emit("setBar","played",pt(h/t.duration,0,1),e),t.notice.show=`${ht(h)} / ${ht(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=Ct(()=>{t.emit("view",K(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{var o;const s=a.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});n.push(l)})}a(),e.bindGlobalEvents=a}(t,this),re(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(oe.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class ae{constructor(t){this.art=t,this.keys={},R||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{lt(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class ce{constructor(t){const e=l(l({},le),t.option.icons);for(const r in e)yt(this,r,{get:()=>tt(r,e[r])})}}class de extends Nt{constructor(t){super(t),this.name="info",R||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=D("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=$(this.art);!function t(){for(let e=0;e{j(n,"display","none"),j(a,"display",null)}),o.proxy(e.$state,"click",()=>lt(t.play()))}}class fe{constructor(t){this.art=t,this.timer=null,$(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if($(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,N(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",F(r,"art-notice-show")},e.NOTICE_TIME)):F(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function me(t,e,r,o=!1){const n=e=>{E(t)||r(e)};t[o?"once":"on"](e,n),$(t).add(()=>{t.off(e,n)})}function ge(t,e,r){for(const[o,n]of e){if(E(t)||r&&!r())return;t[o].show=n}}const ve=new WeakMap,ye=new WeakMap,be=new WeakMap;function we(t){return be.get(t)||$(t)}function xe(t){const e=ve.get(t),r=be.get(t);return()=>ve.get(t)===e&&(!e||e.active())&&be.get(t)===r&&(!r||!r.closed)}function ke(t){const e=be.get(t),r=$(t).child(),o=r.child();be.set(t,r),r.add(()=>{be.get(t)===r&&be.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!E(t)&&!o.closed&&ve.get(t)===n};return ve.set(t,n),o.add(()=>{ve.get(t)===n&&ve.delete(t),n.onAssigned=void 0,n.onError=void 0}),null==e||e.dispose(),n}function $e(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&(null==e||e())}function Ee(t,e,r){ye.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{ye.get(t)===e&&(ye.delete(t),$e(e))}}function Te(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function Ce(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=we(t),l=0;return{reset(){l=0,null==i||i.dispose(),F(a,"art-error")},loadStart(){F(a,"art-error")},schedule(c){(c=>d(null,null,function*(){if(E(t))return;const d=we(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const u=()=>!E(t)&&!p.closed&&d===we(t),h=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ze(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{E(t)||t.emit(`video:${e.type}`,e)})}(t);const e=Ce(t);!function(t,e){me(t,"video:canplay",()=>{e.reset(),ge(t,[["loading",!1]])}),me(t,"video:canplay",()=>{ge(t,[["loading",!1],["controls",!0],["mask",!0]]),E(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;me(t,"video:ended",()=>{if(e.loop){const e=xe(t);if(t.seek=0,E(t)||!e())return;lt(t.play()),e()&&ge(t,[["controls",!1],["mask",!1]],e)}else ge(t,[["controls",!0],["mask",!0]])})}(t),me(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;me(t,"video:loadedmetadata",()=>{t.emit("resize"),R&&ge(t,[["loading",!1],["controls",!0],["mask",!0]])}),me(t,"video:loadstart",()=>{e.loadStart(),ge(t,[["loading",!0],["mask",!1],["controls",!0]])}),me(t,"video:pause",()=>{ge(t,[["controls",!0],["mask",!0]])}),me(t,"video:play",()=>{ge(t,[["mask",!1]]),E(t)||j(r,"display","none")}),me(t,"video:playing",()=>ge(t,[["mask",!1]])),me(t,"video:progress",()=>{t.playing&&ge(t,[["loading",!1]])}),me(t,"video:seeked",()=>ge(t,[["loading",!1],["mask",!0]])),me(t,"video:seeking",()=>ge(t,[["loading",!0],["mask",!1]])),me(t,"video:timeupdate",()=>ge(t,[["mask",!1]])),me(t,"video:waiting",()=>ge(t,[["loading",!0],["mask",!1]]))}(t,e)}const Se=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Le=(()=>{if("undefined"===typeof document)return!1;const t=Se[0],e={};for(const r of Se){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),Me={change:Le.fullscreenchange,error:Le.fullscreenerror},Ae={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{Ae.off("change",n),r()};Ae.on("change",n);const a=t[Le.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Ae.isFullscreen)return void t();const r=()=>{Ae.off("change",r),t()};Ae.on("change",r);const o=document[Le.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Ae.isFullscreen?Ae.exit():Ae.request(t,e),onchange(t){Ae.on("change",t)},onerror(t){Ae.on("error",t)},on(t,e){const r=Me[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Me[t];r&&document.removeEventListener(r,e,!1)},raw:Le};function Pe(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t,a=t=>{Ae.on("change",()=>{t.emit("fullscreen",Ae.isFullscreen),Ae.isFullscreen?(t.state="fullscreen",N(n,"art-fullscreen")):F(n,"art-fullscreen"),t.emit("resize")}),Ae.on("error",e=>{t.emit("fullscreenError",e)}),yt(t,"fullscreen",{get:()=>Ae.isFullscreen,set(t){return d(this,null,function*(){t?yield Ae.request(n):yield Ae.exit()})}})};t.once("video:loadedmetadata",()=>{var n;Ae.isEnabled?a(t):o.webkitSupportsFullscreen?((n=t).on("document:webkitfullscreenchange",()=>{n.emit("fullscreen",n.fullscreen),n.emit("resize")}),yt(n,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(n.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):yt(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),yt(t,"fullscreen",xt(t,"fullscreen"))})}function Oe(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(F(n,"art-mini"),j(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(j(e,"display","none"),j(r,"display","flex")):(j(e,"display","flex"),j(r,"display","none"))}function p(){const{$mini:e}=t.template,r=rt(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),j(e,"top",`${n}px`),j(e,"left",`${a}px`)}yt(t,"mini",{get:()=>H(n,"art-mini"),set(u){if(u){t.state="mini",N(n,"art-mini");const u=function(){const{$mini:n}=t.template;if(n)return B(n,a),j(n,"display","flex");{const n=Q("div");N(n,"art-mini-popup"),B(document.body,n),t.template.$mini=n,B(n,a);const p=B(n,'
');B(p,e.close),r(p,"click",c);const u=B(n,'
'),h=B(u,e.play),f=B(u,e.pause);return r(h,"click",()=>lt(t.play())),r(f,"click",()=>t.pause()),d(h,f),t.on("video:playing",()=>d(h,f)),t.on("video:pause",()=>d(h,f)),t.on("video:timeupdate",()=>d(h,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){N(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;j(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,F(n,"art-mini-dragging");const t=rt(n);o.set("left",t.left),o.set("top",t.top),j(n,"left",`${t.left}px`),j(n,"top",`${t.top}px`),j(n,"transform",null)}}),n}}(),h=o.get("top"),f=o.get("left");"number"===typeof h&&"number"===typeof f?(j(u,"top",`${h}px`),j(u,"left",`${f}px`),K(u)||p()):p(),t.emit("mini",!0)}else c()}})}function Ie(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,yt(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),yt(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):yt(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Re(t){yt(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==a?void 0:a.html)||"",selector:e,onSelect(e,r,a){return d(this,null,function*(){const r=function(t){return t&&Gt.get(t)||(()=>!0)}(a);if(yield t.switchQuality(e.url),!E(t)&&r()){const a=`${n.get("Switch Video")}: ${e.html}`;!E(t)&&r()&&(o.show=a)}return e.html})}})}})}function _e(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function Ve(t,e,r){return new Promise((o,n)=>{if(E(t)||e===t.url)return void o();const a=ke(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),p=t=>l(!0,t);a.onError=p;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const u=i.child(),h={"video:error":p,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){p(e)}},"video:canplay":()=>{if(!c())return;u.dispose();d(null,null,function*(){if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{yield t.play()}catch(e){}c()&&(t.notice.show="",l())}}).catch(p)}},f=i.child(),m=[],g=Object.keys(h);for(const e of g)_e(f,t,e,t=>{a.acceptingEvents&&m.push([e,t])},!1);if(Ee(t,a,e),!c())return;if(t.notice.show="",!c())return;const v=()=>{if(f.dispose(),!e)return void l();const r={};for(const e of g)r[e]=_e(u,t,e,h[e]);for(const[t,e]of m){if(!c()||u.closed)break;r[t](e)}m.length=0};a.assigned?v():a.onAssigned=v}catch(u){p(u)}})}function Ye(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",(n,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:u}=e.thumbnails;if(!d||!p)return;if("hover"===n||"played"===n&&l&&R){if(i||a||(a=!0,i=yield ot(p,u),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?j(s,"left",r.clientWidth-h+"px"):j(s,"left",n-h/2+"px")}(n)}})),yt(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function De(t){const{option:e,template:{$video:r}}=t;yt(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(E(t))return;const n=function(t){const e=ye.get(t);return ye.delete(t),e||ke(t)}(t);n.acceptingEvents=!1;try{if(!o)return void((yield Bt(n.scope))&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||ct(o),s=e.customType[i];if(i&&s){if(!(yield Bt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;_e(l,t,"video:canplay",()=>{c=!d}),_e(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>Te(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||_e(n.scope,t,"video:canplay",e)}}catch(a){Te(n,a)}finally{$e(n)}})}})}Object.defineProperties(Ae,{isFullscreen:{get:()=>Boolean(document[Le.fullscreenElement])},element:{enumerable:!0,get:()=>document[Le.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Le.fullscreenEnabled])}});class Ne{constructor(t){De(t),function(t){const{template:{$video:e}}=t;yt(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;yt(t,"play",{value(){return d(this,null,function*(){const i=xe(t),s=yield a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;yt(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${ht(t.currentTime)} / ${ht(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;yt(t,"forward",{set(e){r.seek=t.currentTime+e}}),yt(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;yt(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=pt(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),yt(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;yt(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=pt(o,0,t.duration))}})}(t),function(t){yt(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>Ve(t,e,0);yt(t,"switchQuality",{value:e=>Ve(t,e,t.currentTime)}),yt(t,"switchUrl",{value:e}),yt(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;yt(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;yt(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)j(o,"width",null),j(o,"height",null),j(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(j(o,"width",s*r+"px"),j(o,"height","100%"),j(o,"margin","0 auto")):(j(o,"width","100%"),j(o,"height",e/s+"px"),j(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=Q("canvas");yt(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),yt(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),yt(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return dt(o,`${e||`artplayer_${ht(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Pe(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";yt(t,"fullscreenWeb",{get:()=>H(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&B(document.body,o),t.state="fullscreenWeb",j(o,"width","100%"),j(o,"height","100%"),N(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&B(r,o),n&&(o.style.cssText=n,n=""),F(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Ie(t),function(t){const{$video:e}=t.template,r=t;yt(t,"loaded",{get:()=>r.loadedTime/e.duration}),yt(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){yt(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;yt(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;yt(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=rt(e),l=n/a;if(i/s>l)j(r,"width",s*l/i*100+"%"),j(r,"height","100%");else{const t=i/l/s*100;j(r,"width","100%"),j(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;yt(t,"rect",{get:()=>rt(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}yt(t,"x",{get:()=>e.left+window.pageXOffset}),yt(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;yt(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(ut(n))}`,t.emit("flip",n)}})}(t),Oe(t),function(t){const{template:{$poster:e}}=t;yt(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){j(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;yt(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);j(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;yt(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){yt(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){yt(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];yt(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,yt(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),Re(t),Ye(t),ze(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=pt(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=pt(a,0,1)),e.poster&&j(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Fe(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var n;if(e){if(l()){const e=Number(null!=(n=r.AUTO_ORIENTATION_TIME)?n:0);setTimeout(()=>{t.fullscreenWeb&&!H(o,a)&&function(){const e=at(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;j(o,"width",`${n}px`),j(o,"height",`${i}px`),j(o,"transform-origin","0 0"),j(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),N(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else H(o,a)&&(j(o,"width",""),j(o,"height",""),j(o,"transform-origin",""),j(o,"transform",""),F(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const n=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(n&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,N(o,i)}catch(a){s=!1,e.show=a}}else if(H(o,i)&&F(o,i),n&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return H(o,a)}}}function He(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=Y(".art-auto-playback-last",s),c=Y(".art-auto-playback-jump",s),d=Y(".art-auto-playback-close",s);B(d,r.close);let p=null;function u(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),j(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(j(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${ht(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{j(s,"display","none")}),a(c,"click",()=>{t.seek=r,lt(t.play()),j(i,"display","none"),j(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{j(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",u),t.on("restart",u),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Be(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,F(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,N(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return H(o,"art-fast-forward")}}}function We(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return H(o,"art-lock")}function a(){N(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){F(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=B(e,r.lock),n=B(e,r.unlock);j(o,"display","none"),t.on("lock",t=>{t?(j(o,"display","inline-flex"),j(n,"display","none")):(j(o,"display","none"),j(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function je(t){return t.on("control",e=>{e?F(t.template.$player,"art-mini-progress-bar"):N(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class qe{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){E(t.art)||!e.miniProgressBar||e.isLive||t.add(je),!E(t.art)&&e.lock&&R&&t.add(We),E(t.art)||!e.autoPlayback||e.isLive||t.add(He),!E(t.art)&&e.autoOrientation&&R&&t.add(Fe),!E(t.art)&&e.fastForward&&R&&!e.isLive&&t.add(Be)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){st(!E(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(E(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(E(t.art))return t;let n=o;const a=wt(t,n);if(E(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return E(t.art)||(st(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),E(t.art)||yt(t,n,{value:r})),t}(this,t,e)}}class Ue extends Nt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=Z(t,r.setting),o=Z(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(ut(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&X(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),yt(a,"$parents",{get:()=>r}),yt(a,"$option",{get:()=>t});const o=[];yt(a,"$events",{get:()=>o}),yt(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:n},template:{$player:a,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=rt(r.setting),{left:d,width:p}=rt(a),u=l-d+c/2-s/2;if(j(i,"height",`${this.active===this.option?this.active.length*n:(this.active.length+1)*n}px`),j(i,"width",`${s}px`),this.art.isRotate||R)return;u+s>p?(j(i,"left",null),j(i,"right",null)):(j(i,"left",`${u}px`),j(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=Q("div");N(s,"art-setting-item-left-icon"),B(s,o),B(i,s),B(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),B(e,a)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const n=this.cache.get(t.$option),a=t.$item;let i="selector";wt(t,"switch")&&(i="switch"),wt(t,"range")&&(i="range"),wt(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=Q("div");N(p,"art-setting-item"),j(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const u=B(p,'
'),h=B(p,'
'),f=Q("div");switch(N(f,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":B(f,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?B(f,t.icon||s.config):B(f,s.check)}B(u,f),yt(t,"$icon",{configurable:!0,get:()=>f}),yt(t,"icon",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",B(f,t)}});const m=Q("div");N(m,"art-setting-item-left-text"),B(m,t.html||""),B(u,m),yt(t,"$html",{configurable:!0,get:()=>m}),yt(t,"html",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",B(m,t)}});const g=Q("div");switch(N(g,"art-setting-item-right-tooltip"),B(g,t.tooltip||""),B(h,g),yt(t,"$tooltip",{configurable:!0,get:()=>g}),yt(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",B(g,t)}}),i){case"switch":{const e=Q("div");N(e,"art-setting-item-right-icon");const r=B(e,s.switchOn),o=B(e,s.switchOff);j(t.switch?o:r,"display","none"),B(h,e),yt(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;yt(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(j(o,"display","none"),j(r,"display",null)):(j(o,"display",null),j(r,"display","none"))}});break}case"range":{const e=Q("div");N(e,"art-setting-item-right-icon");const r=B(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],N(r,"art-setting-range"),B(h,e),yt(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];yt(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=Q("div");N(t,"art-setting-item-right-icon"),B(t,s.arrowRight),B(h,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&N(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}yt(t,"$item",{configurable:!0,get:()=>p}),e?J(p,a):B(n,p),t.mounted&&Ht($(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){X(this.cache.get(t),"art-current")}else{const r=Q("div");this.cache.set(t,r),N(r,"art-setting-panel"),B(this.$parent,r),X(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?q(r,t):j(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?vt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a=c(l(l({},n.subtitle),e),{url:t}),i=yield this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=Q("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,W(i),B(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(m(t,Yt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||ct(t.url)){case"srt":{const e=$t(r);return Et(t.onVttLoad(e))}case"ass":{const e=Tt(r);return Et(t.onVttLoad(e))}case"vtt":return Et(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}const Ze=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Je{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=Y(e.container),st(this.$container,`No container element found by ${e.container}`)),st(et(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();st("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),st(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=x.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=k(t);n.rollback=r,x.set(e,t),n.releaseContainer=()=>{x.get(e)===t&&x.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ze}query(t){return Y(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Je.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){st(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),J(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&N(this.$player,"art-backdrop"),R&&N(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":N(this.$player,"art-destroy")}}const Qe=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class tr{on(t,e,r){const o=this.e||(this.e={});let n=Qe(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Qe(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Qe(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),or.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${or.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=k(t);return e.rollback=void 0,!e.scope.closed})(this)&&rr.push(this)}catch(o){try{T(this,rr,!0,or.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return rr}static get version(){return g}static get config(){return v}static get utils(){return zt}static get scheme(){return Yt}static get Emitter(){return tr}static get validator(){return m}static get kindOf(){return m.kindOf}static get html(){return Je.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:P?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){T(this,rr,t,or.REMOVE_SRC_WHEN_DESTROY)}}return or.STYLE=Ge,or.DEBUG=!1,or.CONTEXTMENU=!0,or.NOTICE_TIME=2e3,or.SETTING_WIDTH=250,or.SETTING_ITEM_WIDTH=200,or.SETTING_ITEM_HEIGHT=35,or.RESIZE_TIME=200,or.SCROLL_TIME=200,or.SCROLL_GAP=50,or.AUTO_PLAYBACK_MAX=10,or.AUTO_PLAYBACK_MIN=5,or.AUTO_PLAYBACK_TIMEOUT=3e3,or.RECONNECT_TIME_MAX=5,or.RECONNECT_SLEEP_TIME=1e3,or.CONTROL_HIDE_TIME=3e3,or.DBCLICK_TIME=300,or.DBCLICK_FULLSCREEN=!0,or.MOBILE_DBCLICK_PLAY=!0,or.MOBILE_CLICK_PLAY=!1,or.AUTO_ORIENTATION_TIME=200,or.INFO_LOOP_TIME=1e3,or.FAST_FORWARD_VALUE=3,or.FAST_FORWARD_TIME=1e3,or.TOUCH_MOVE_RATIO=.5,or.VOLUME_STEP=.1,or.SEEK_STEP=5,or.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],or.ASPECT_RATIO=["default","4:3","16:9"],or.FLIP=["normal","horizontal","vertical"],or.FULLSCREEN_WEB_IN_BODY=!0,or.LOG_VERSION=!0,or.USE_RAF=!1,or.REMOVE_SRC_WHEN_DESTROY=!0,_&&(window.Artplayer=or,V("artplayer-style",Ge),setTimeout(()=>{or.LOG_VERSION&&console.log(`%c ArtPlayer %c ${or.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),or}); diff --git a/docs/compiled/artplayer.mjs b/docs/compiled/artplayer.mjs index aa5a19999..86665e924 100644 --- a/docs/compiled/artplayer.mjs +++ b/docs/compiled/artplayer.mjs @@ -302,6 +302,185 @@ const config$1 = { "webkitExitFullscreen" ] }; +class ResourceCleanupError extends Error { + constructor(errors) { + super("Failed to release ArtPlayer resources"); + this.errors = errors; + this.name = "ResourceCleanupError"; + } +} +class ResourceScope { + constructor() { + this.cleanups = /* @__PURE__ */ new Set(); + this.disposed = false; + } + get closed() { + return this.disposed; + } + add(cleanup) { + let active = true; + const release = () => { + if (!active) + return; + active = false; + this.cleanups.delete(release); + cleanup(); + }; + if (this.closed) + release(); + else + this.cleanups.add(release); + return release; + } + child() { + const child = new ResourceScope(); + const release = this.add(() => { + child.dispose(); + }); + child.add(() => { + release(); + }); + return child; + } + dispose() { + if (this.closed) + return; + this.disposed = true; + const errors = []; + for (const release of Array.from(this.cleanups).reverse()) { + try { + release(); + } catch (error2) { + if (error2 instanceof ResourceCleanupError) + errors.push(...error2.errors); + else + errors.push(error2); + } + } + if (errors.length) + throw new ResourceCleanupError(errors); + } +} +const states = /* @__PURE__ */ new WeakMap(); +const containers = /* @__PURE__ */ new WeakMap(); +function beginLifecycle(owner) { + states.set(owner, { scope: new ResourceScope(), destroying: false }); +} +function stateOf(owner) { + const state2 = states.get(owner); + if (!state2) + throw new Error("ArtPlayer lifecycle has not been initialized"); + return state2; +} +function getScope(owner) { + return stateOf(owner).scope; +} +function isClosing(owner) { + const state2 = stateOf(owner); + return state2.destroying || state2.scope.closed; +} +function ownContainer(owner, container, rollback) { + const current2 = containers.get(container); + if (current2 && current2 !== owner) + throw new Error("Cannot mount multiple instances on the same dom element"); + const state2 = stateOf(owner); + state2.rollback = rollback; + containers.set(container, owner); + state2.releaseContainer = () => { + if (containers.get(container) === owner) + containers.delete(container); + }; +} +function finishLifecycle(owner) { + const state2 = stateOf(owner); + state2.rollback = void 0; + return !state2.scope.closed; +} +function destroyInstance(owner, instances2, removeHtml, removeSource, failed = false) { + const state2 = stateOf(owner); + if (state2.destroying || state2.scope.closed) + return; + state2.destroying = true; + const errors = []; + const attempt = (cleanup) => { + try { + cleanup(); + } catch (error2) { + errors.push(...error2 instanceof ResourceCleanupError ? error2.errors : [error2]); + } + }; + if (removeSource && owner.template?.$video) + attempt(() => owner.reset()); + attempt(() => state2.scope.dispose()); + attempt(() => owner.template?.destroy(removeHtml)); + const index = instances2.indexOf(owner); + if (index !== -1) + instances2.splice(index, 1); + owner.isDestroy = true; + if (!failed) { + state2.releaseContainer?.(); + state2.releaseContainer = void 0; + } + attempt(() => owner.emit("destroy")); + if (failed && state2.rollback) + attempt(state2.rollback); + state2.rollback = void 0; + state2.releaseContainer?.(); + state2.releaseContainer = void 0; + for (const error2 of errors.slice(1)) + console.warn("Additional ArtPlayer cleanup failure:", error2); + if (errors.length) + throw errors[0]; +} +const scopes$1 = /* @__PURE__ */ new WeakMap(); +function ownEntry(art, element) { + const scope = getScope(art).child(); + scopes$1.set(element, scope); + return scope; +} +function entryScope(element) { + const scope = scopes$1.get(element); + if (!scope) + throw new Error("ArtPlayer component has not been registered"); + return scope; +} +function releaseEntry(element) { + scopes$1.get(element)?.dispose(); +} +function proxyEntry(art, element, target, name, callback) { + const scope = entryScope(element); + if (scope.closed) + return () => { + }; + const cleanup = art.events.proxy(target, name, (event) => { + if (!scope.closed) + return callback(event); + }); + return scope.add(() => { + art.events.remove(cleanup); + }); +} +function subscribeEntry(art, element, name, callback) { + const scope = entryScope(element); + if (scope.closed) + return; + const guarded = (...args) => { + if (!scope.closed) + return callback(...args); + }; + art.on(name, guarded); + scope.add(() => { + art.off(name, guarded); + }); +} +function controlEvents(art, element) { + return { + on: (name, callback) => { + subscribeEntry(art, element, name, callback); + }, + proxy: (target, name, callback) => proxyEntry(art, element, target, name, callback) + }; +} const userAgent = globalThis?.CUSTOM_USER_AGENT ?? (typeof navigator !== "undefined" ? navigator.userAgent : ""); const isSafari = /^(?:(?!chrome|android).)*safari/i.test(userAgent); const isIOS = /iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream; @@ -721,6 +900,29 @@ const utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert userAgent, vttToBlob }, Symbol.toStringTag, { value: "Module" })); +function renderEntry(element, parent, kind, name, id2, option) { + addClass(element, `art-${kind}`); + addClass(element, `art-${kind}-${name}`); + const children = Array.from(parent.children); + element.dataset.index = String(option.index || id2); + const next = children.find((child) => Number(child.dataset.index) >= Number(element.dataset.index)); + if (next) + next.insertAdjacentElement("beforebegin", element); + else + append(parent, element); + if (option.html) + append(element, option.html); + if (option.style) + setStyles(element, option.style); + if (option.tooltip) + tooltip(element, option.tooltip); +} +function appendElement(parent, child) { + return append(parent, child); +} +function queryElement(selector, parent) { + return parent.querySelector(selector); +} const a = "array"; const b = "boolean"; const s = "string"; @@ -840,6 +1042,7 @@ const scheme = { cssVar: o, customType: o }; +const removing = /* @__PURE__ */ new WeakSet(); class Component { constructor(art) { this.id = 0; @@ -855,75 +1058,102 @@ class Component { set show(value) { const { $player } = this.art.template; const className = `art-${this.name}-show`; - if (value) { + if (value) addClass($player, className); - } else { + else removeClass($player, className); - } this.art.emit(this.name, value); } toggle() { this.show = !this.show; } add(getOption) { + if (isClosing(this.art)) + return; const option = typeof getOption === "function" ? getOption(this.art) : getOption; + if (isClosing(this.art)) + return; option.html = option.html || ""; validator(option, ComponentOption); if (!this.$parent || !this.name || option.disable) return; const name = option.name || `${this.name}${this.id}`; - errorHandle(!this.cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`); + const cache = this.cache; + errorHandle(!cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`); this.id += 1; - const $ref = createElement("div"); - addClass($ref, `art-${this.name}`); - addClass($ref, `art-${this.name}-${name}`); - const childs = Array.from(this.$parent.children); - $ref.dataset.index = option.index || this.id; - const nextChild = childs.find((item) => Number(item.dataset.index) >= Number($ref.dataset.index)); - if (nextChild) { - nextChild.insertAdjacentElement("beforebegin", $ref); - } else { - append(this.$parent, $ref); - } - if (option.html) { - append($ref, option.html); - } - if (option.style) { - setStyles($ref, option.style); - } - if (option.tooltip) { - tooltip($ref, option.tooltip); - } + const $ref = document.createElement("div"); + const scope = ownEntry(this.art, $ref); const events = []; - if (option.click) { - const destroyEvent = this.art.events.proxy($ref, "click", (event) => { - event.preventDefault(); - option.click.call(this.art, this, event); - }); - events.push(destroyEvent); + const previous = Object.getOwnPropertyDescriptor(this, name); + let aliased = false; + scope.add(() => { + for (const event of events) + this.art.events.remove(event); + }); + try { + if (scope.closed) + return; + renderEntry($ref, this.$parent, this.name, name, this.id, option); + if (scope.closed) + return; + if (option.click) { + const cleanup = this.art.events.proxy($ref, "click", (event) => { + if (scope.closed) + return; + event.preventDefault(); + option.click.call(this.art, this, event); + }); + events.push(cleanup); + } + if (option.selector && ["left", "right"].includes(option.position)) + this.selector(option, $ref, events); + if (scope.closed) + return; + assignAlias(this, name, $ref); + aliased = true; + cache.set(name, { $ref, events, option }); + if (option.mounted) + option.mounted.call(this.art, $ref); + return $ref; + } catch (error2) { + try { + releaseEntry($ref); + } catch (cleanupError) { + console.warn("ArtPlayer component cleanup failed:", cleanupError); + } + if (cache.get(name)?.$ref === $ref) + cache.delete(name); + if (aliased && this[name] === $ref) { + if (previous) + Object.defineProperty(this, name, previous); + else + delete this[name]; + } + $ref.remove(); + throw error2; } - if (option.selector && ["left", "right"].includes(option.position)) { - this.selector(option, $ref, events); - } - this[name] = $ref; - this.cache.set(name, { $ref, events, option }); - if (option.mounted) { - option.mounted.call(this.art, $ref); - } - return $ref; } remove(name) { errorHandle(this.cache.has(name), `Can't find [${name}] from the [${this.name}]`); const item = this.cache.get(name); - if (item.option.beforeUnmount) { - item.option.beforeUnmount.call(this.art, item.$ref); + if (removing.has(item)) + return; + removing.add(item); + try { + if (item.option.beforeUnmount) + item.option.beforeUnmount.call(this.art, item.$ref); + try { + releaseEntry(item.$ref); + } finally { + if (this.cache.get(name) === item) { + this.cache.delete(name); + delete this[name]; + } + item.$ref.remove(); + } + } finally { + removing.delete(item); } - for (const event of item.events) { - this.art.events.remove(event); - } - this.cache.delete(name); - delete this[name]; - remove(item.$ref); } update(option) { if (this.cache.has(option.name)) { @@ -934,6 +1164,13 @@ class Component { return this.add(option); } } +function assignAlias(owner, name, value) { + const aliases = owner; + if (name === "__proto__") + Object.defineProperty(aliases, name, { value, enumerable: true, configurable: true, writable: true }); + else + aliases[name] = value; +} function aspectRatio$2(option) { return (art) => { const { @@ -947,19 +1184,20 @@ function aspectRatio$2(option) { ...option, html: `${i18n.get("Aspect Ratio")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.aspectRatio = value; contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="default"]', $panel); if ($default) { inverseClass($default, "art-current"); } - art.on("aspectRatio", (value) => { - const $current = queryAll("span", $panel).find((item) => item.dataset.value === value); + on("aspectRatio", (value) => { + const $current = Array.from($panel.querySelectorAll("span")).find((item) => item.dataset.value === value); if ($current) { inverseClass($current, "art-current"); } @@ -988,19 +1226,20 @@ function flip$2(option) { ...option, html: `${i18n.get("Video Flip")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.flip = value.toLowerCase(); contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="normal"]', $panel); if ($default) { inverseClass($default, "art-current"); } - art.on("flip", (value) => { - const $current = queryAll("span", $panel).find((item) => item.dataset.value === value); + on("flip", (value) => { + const $current = Array.from($panel.querySelectorAll("span")).find((item) => item.dataset.value === value); if ($current) { inverseClass($current, "art-current"); } @@ -1032,18 +1271,19 @@ function playbackRate$2(option) { ...option, html: `${i18n.get("Play Speed")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.playbackRate = Number(value); contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="1"]', $panel); if ($default) inverseClass($default, "art-current"); - art.on("video:ratechange", () => { - const $current = queryAll("span", $panel).find( + on("video:ratechange", () => { + const $current = Array.from($panel.querySelectorAll("span")).find( (item) => Number(item.dataset.value) === art.playbackRate ); if ($current) { @@ -1065,6 +1305,7 @@ class Contextmenu extends Component { super(art); this.name = "contextmenu"; this.$parent = art.template.$contextmenu; + ownEntry(art, this.$parent); if (!isMobile) { this.init(); } @@ -1072,9 +1313,9 @@ class Contextmenu extends Component { init() { const { option, - proxy, template: { $player, $contextmenu } } = this.art; + const { on, proxy } = controlEvents(this.art, $contextmenu); if (option.playbackRate) { this.add( playbackRate$2({ @@ -1147,141 +1388,11 @@ class Contextmenu extends Component { this.show = false; } }); - this.art.on("blur", () => { + on("blur", () => { this.show = false; }); } } -class ResourceCleanupError extends Error { - constructor(errors) { - super("Failed to release ArtPlayer resources"); - this.errors = errors; - this.name = "ResourceCleanupError"; - } -} -class ResourceScope { - constructor() { - this.cleanups = /* @__PURE__ */ new Set(); - this.disposed = false; - } - get closed() { - return this.disposed; - } - add(cleanup) { - let active = true; - const release = () => { - if (!active) - return; - active = false; - this.cleanups.delete(release); - cleanup(); - }; - if (this.closed) - release(); - else - this.cleanups.add(release); - return release; - } - child() { - const child = new ResourceScope(); - const release = this.add(() => { - child.dispose(); - }); - child.add(() => { - release(); - }); - return child; - } - dispose() { - if (this.closed) - return; - this.disposed = true; - const errors = []; - for (const release of Array.from(this.cleanups).reverse()) { - try { - release(); - } catch (error2) { - if (error2 instanceof ResourceCleanupError) - errors.push(...error2.errors); - else - errors.push(error2); - } - } - if (errors.length) - throw new ResourceCleanupError(errors); - } -} -const states = /* @__PURE__ */ new WeakMap(); -const containers = /* @__PURE__ */ new WeakMap(); -function beginLifecycle(owner) { - states.set(owner, { scope: new ResourceScope(), destroying: false }); -} -function stateOf(owner) { - const state2 = states.get(owner); - if (!state2) - throw new Error("ArtPlayer lifecycle has not been initialized"); - return state2; -} -function getScope(owner) { - return stateOf(owner).scope; -} -function isClosing(owner) { - const state2 = stateOf(owner); - return state2.destroying || state2.scope.closed; -} -function ownContainer(owner, container, rollback) { - const current2 = containers.get(container); - if (current2 && current2 !== owner) - throw new Error("Cannot mount multiple instances on the same dom element"); - const state2 = stateOf(owner); - state2.rollback = rollback; - containers.set(container, owner); - state2.releaseContainer = () => { - if (containers.get(container) === owner) - containers.delete(container); - }; -} -function finishLifecycle(owner) { - const state2 = stateOf(owner); - state2.rollback = void 0; - return !state2.scope.closed; -} -function destroyInstance(owner, instances2, removeHtml, removeSource, failed = false) { - const state2 = stateOf(owner); - if (state2.destroying || state2.scope.closed) - return; - state2.destroying = true; - const errors = []; - const attempt = (cleanup) => { - try { - cleanup(); - } catch (error2) { - errors.push(...error2 instanceof ResourceCleanupError ? error2.errors : [error2]); - } - }; - if (removeSource && owner.template?.$video) - attempt(() => owner.reset()); - attempt(() => state2.scope.dispose()); - attempt(() => owner.template?.destroy(removeHtml)); - const index = instances2.indexOf(owner); - if (index !== -1) - instances2.splice(index, 1); - owner.isDestroy = true; - if (!failed) { - state2.releaseContainer?.(); - state2.releaseContainer = void 0; - } - attempt(() => owner.emit("destroy")); - if (failed && state2.rollback) - attempt(state2.rollback); - state2.rollback = void 0; - state2.releaseContainer?.(); - state2.releaseContainer = void 0; - for (const error2 of errors.slice(1)) - console.warn("Additional ArtPlayer cleanup failure:", error2); - if (errors.length) - throw errors[0]; -} function timeout(scope, callback, delay) { if (scope.closed) return () => { @@ -1346,8 +1457,9 @@ function airplay$1(option) { ...option, tooltip: art.i18n.get("AirPlay"), mounted: ($control) => { - const { proxy, icons } = art; - append($control, icons.airplay); + const { proxy } = controlEvents(art, $control); + const { icons } = art; + appendElement($control, icons.airplay); proxy($control, "click", () => art.airplay()); } }); @@ -1357,14 +1469,15 @@ function fullscreen(option) { ...option, tooltip: art.i18n.get("Fullscreen"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $fullscreenOn = append($control, icons.fullscreenOn); - const $fullscreenOff = append($control, icons.fullscreenOff); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $fullscreenOn = appendElement($control, icons.fullscreenOn); + const $fullscreenOff = appendElement($control, icons.fullscreenOff); setStyle($fullscreenOff, "display", "none"); proxy($control, "click", () => { art.fullscreen = !art.fullscreen; }); - art.on("fullscreen", (state2) => { + on("fullscreen", (state2) => { if (state2) { tooltip($control, i18n.get("Exit Fullscreen")); setStyle($fullscreenOn, "display", "none"); @@ -1383,14 +1496,15 @@ function fullscreenWeb(option) { ...option, tooltip: art.i18n.get("Web Fullscreen"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $fullscreenWebOn = append($control, icons.fullscreenWebOn); - const $fullscreenWebOff = append($control, icons.fullscreenWebOff); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $fullscreenWebOn = appendElement($control, icons.fullscreenWebOn); + const $fullscreenWebOff = appendElement($control, icons.fullscreenWebOff); setStyle($fullscreenWebOff, "display", "none"); proxy($control, "click", () => { art.fullscreenWeb = !art.fullscreenWeb; }); - art.on("fullscreenWeb", (value) => { + on("fullscreenWeb", (value) => { if (value) { tooltip($control, i18n.get("Exit Web Fullscreen")); setStyle($fullscreenWebOn, "display", "none"); @@ -1409,12 +1523,13 @@ function pip$1(option) { ...option, tooltip: art.i18n.get("PIP Mode"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - append($control, icons.pip); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + appendElement($control, icons.pip); proxy($control, "click", () => { art.pip = !art.pip; }); - art.on("pip", (value) => { + on("pip", (value) => { tooltip($control, i18n.get(value ? "Exit PIP Mode" : "PIP Mode")); }); } @@ -1424,9 +1539,10 @@ function playAndPause(option) { return (art) => ({ ...option, mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $play = append($control, icons.play); - const $pause = append($control, icons.pause); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $play = appendElement($control, icons.play); + const $pause = appendElement($control, icons.pause); tooltip($play, i18n.get("Play")); tooltip($pause, i18n.get("Pause")); proxy($play, "click", () => { @@ -1448,10 +1564,10 @@ function playAndPause(option) { } else { showPlay(); } - art.on("video:playing", () => { + on("video:playing", () => { showPause(); }); - art.on("video:pause", () => { + on("video:pause", () => { showPlay(); }); } @@ -1479,13 +1595,153 @@ function setCurrentTime(art, event) { art.seek = second; } } +function installProgressInteractions(art, $control) { + const { $progress } = art.template; + const $indicator = $control.querySelector(".art-progress-indicator"); + const { on, proxy } = controlEvents(art, $control); + if (!isMobile) { + let isDragging = false; + proxy($progress, "click", (event) => { + if (event.target !== $indicator) { + setCurrentTime(art, event); + } + }); + proxy($progress, "mousemove", (event) => { + const { percentage } = getPosFromEvent(art, event); + art.emit("setBar", "hover", percentage, event); + }); + proxy($progress, "mouseleave", (event) => { + art.emit("setBar", "hover", 0, event); + }); + proxy($progress, "mousedown", (event) => { + isDragging = event.button === 0; + }); + on("document:mousemove", (event) => { + if (isDragging) { + const { second, percentage } = getPosFromEvent(art, event); + art.emit("setBar", "played", percentage, event); + art.seek = second; + } + }); + on("document:mouseup", () => { + if (isDragging) { + isDragging = false; + } + }); + } +} +function mountProgressView(art, $control) { + const { icons, option } = art; + const { $player } = art.template; + const scope = entryScope($control); + const { on } = controlEvents(art, $control); + let cancelTip = () => { + }; + const $hover = queryElement(".art-progress-hover", $control); + const $loaded = queryElement(".art-progress-loaded", $control); + const $played = queryElement(".art-progress-played", $control); + const $highlight = queryElement(".art-progress-highlight", $control); + const $indicator = queryElement(".art-progress-indicator", $control); + const $tip = queryElement(".art-progress-tip", $control); + if (icons.indicator) { + append($indicator, icons.indicator); + } else { + setStyle($indicator, "backgroundColor", "var(--art-theme)"); + } + function showHighlight(event) { + const { width } = getPosFromEvent(art, event); + const text = event.target instanceof HTMLElement ? event.target.dataset.text : void 0; + $tip.textContent = text ?? ""; + const tipWidth = $tip.clientWidth; + if (width <= tipWidth / 2) { + setStyle($tip, "left", 0); + } else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); + } else { + setStyle($tip, "left", `${width - tipWidth / 2}px`); + } + } + function showTime(event, touch) { + const { width, time: time2 } = touch || getPosFromEvent(art, event); + $tip.textContent = time2 || "00:00"; + const tipWidth = $tip.clientWidth; + if (width <= tipWidth / 2) { + setStyle($tip, "left", 0); + } else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); + } else { + setStyle($tip, "left", `${width - tipWidth / 2}px`); + } + } + function updateHighlight() { + $highlight.textContent = ""; + for (let index = 0; index < option.highlight.length; index++) { + const item = option.highlight[index]; + const left = clamp(item.time, 0, art.duration) / art.duration * 100; + const marker = document.createElement("span"); + marker.dataset.text = item.text; + marker.dataset.time = String(item.time); + marker.style.left = `${left}%`; + append($highlight, marker); + } + } + function setBar(type, percentage, event) { + const isMobileDragging = type === "played" && event && isMobile; + if (type === "loaded") { + setStyle($loaded, "width", `${percentage * 100}%`); + } + if (type === "hover") { + setStyle($hover, "width", `${percentage * 100}%`); + if (includeFromEvent(event, $highlight)) { + showHighlight(event); + } else { + showTime(event); + } + if (percentage === 0) { + removeClass($player, "art-progress-hover"); + } else { + addClass($player, "art-progress-hover"); + } + } + if (type === "played") { + setStyle($played, "width", `${percentage * 100}%`); + setStyle($indicator, "left", `${percentage * 100}%`); + } + if (isMobileDragging) { + addClass($player, "art-progress-hover"); + const width = $control.clientWidth * percentage; + const time2 = secondToTime(percentage * art.duration); + showTime(event, { width, time: time2 }); + cancelTip(); + cancelTip = timeout(scope, () => { + removeClass($player, "art-progress-hover"); + }, 500); + } + } + on("setBar", setBar); + on("video:loadedmetadata", updateHighlight); + if (art.constructor.USE_RAF) { + on("raf", () => { + art.emit("setBar", "played", art.played); + art.emit("setBar", "loaded", art.loaded); + }); + } else { + on("video:timeupdate", () => { + art.emit("setBar", "played", art.played); + }); + on("video:progress", () => { + art.emit("setBar", "loaded", art.loaded); + }); + on("video:ended", () => { + art.emit("setBar", "played", 1); + }); + } + art.emit("setBar", "loaded", art.loaded || 0); +} function progress(options) { - return (art) => { - const { icons, option, proxy } = art; - const { $player, $progress } = art.template; - return { - ...options, - html: ` + return (art) => ({ + ...options, + html: `
@@ -1495,146 +1751,20 @@ function progress(options) {
00:00
`, - mounted: ($control) => { - let tipTimer = null; - let isDragging = false; - const $hover = query(".art-progress-hover", $control); - const $loaded = query(".art-progress-loaded", $control); - const $played = query(".art-progress-played", $control); - const $highlight = query(".art-progress-highlight", $control); - const $indicator = query(".art-progress-indicator", $control); - const $tip = query(".art-progress-tip", $control); - if (icons.indicator) { - append($indicator, icons.indicator); - } else { - setStyle($indicator, "backgroundColor", "var(--art-theme)"); - } - function showHighlight(event) { - const { width } = getPosFromEvent(art, event); - const { text } = event.target.dataset; - $tip.textContent = text; - const tipWidth = $tip.clientWidth; - if (width <= tipWidth / 2) { - setStyle($tip, "left", 0); - } else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); - } else { - setStyle($tip, "left", `${width - tipWidth / 2}px`); - } - } - function showTime(event, touch) { - const { width, time: time2 } = touch || getPosFromEvent(art, event); - $tip.textContent = time2 || "00:00"; - const tipWidth = $tip.clientWidth; - if (width <= tipWidth / 2) { - setStyle($tip, "left", 0); - } else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); - } else { - setStyle($tip, "left", `${width - tipWidth / 2}px`); - } - } - function updateHighlight() { - $highlight.textContent = ""; - for (let index = 0; index < option.highlight.length; index++) { - const item = option.highlight[index]; - const left = clamp(item.time, 0, art.duration) / art.duration * 100; - const html2 = ``; - append($highlight, html2); - } - } - function setBar(type, percentage, event) { - const isMobileDragging = type === "played" && event && isMobile; - if (type === "loaded") { - setStyle($loaded, "width", `${percentage * 100}%`); - } - if (type === "hover") { - setStyle($hover, "width", `${percentage * 100}%`); - if (includeFromEvent(event, $highlight)) { - showHighlight(event); - } else { - showTime(event); - } - if (percentage === 0) { - removeClass($player, "art-progress-hover"); - } else { - addClass($player, "art-progress-hover"); - } - } - if (type === "played") { - setStyle($played, "width", `${percentage * 100}%`); - setStyle($indicator, "left", `${percentage * 100}%`); - } - if (isMobileDragging) { - addClass($player, "art-progress-hover"); - const width = $control.clientWidth * percentage; - const time2 = secondToTime(percentage * art.duration); - showTime(event, { width, time: time2 }); - clearTimeout(tipTimer); - tipTimer = setTimeout(() => { - removeClass($player, "art-progress-hover"); - }, 500); - } - } - art.on("setBar", setBar); - art.on("video:loadedmetadata", updateHighlight); - if (art.constructor.USE_RAF) { - art.on("raf", () => { - art.emit("setBar", "played", art.played); - art.emit("setBar", "loaded", art.loaded); - }); - } else { - art.on("video:timeupdate", () => { - art.emit("setBar", "played", art.played); - }); - art.on("video:progress", () => { - art.emit("setBar", "loaded", art.loaded); - }); - art.on("video:ended", () => { - art.emit("setBar", "played", 1); - }); - } - art.emit("setBar", "loaded", art.loaded || 0); - if (!isMobile) { - proxy($progress, "click", (event) => { - if (event.target !== $indicator) { - setCurrentTime(art, event); - } - }); - proxy($progress, "mousemove", (event) => { - const { percentage } = getPosFromEvent(art, event); - art.emit("setBar", "hover", percentage, event); - }); - proxy($progress, "mouseleave", (event) => { - art.emit("setBar", "hover", 0, event); - }); - proxy($progress, "mousedown", (event) => { - isDragging = event.button === 0; - }); - art.on("document:mousemove", (event) => { - if (isDragging) { - const { second, percentage } = getPosFromEvent(art, event); - art.emit("setBar", "played", percentage, event); - art.seek = second; - } - }); - art.on("document:mouseup", () => { - if (isDragging) { - isDragging = false; - } - }); - } - } - }; - }; + mounted: ($control) => { + mountProgressView(art, $control); + installProgressInteractions(art, $control); + } + }); } function screenshot$1(option) { return (art) => ({ ...option, tooltip: art.i18n.get("Screenshot"), mounted: ($control) => { - const { proxy, icons } = art; - append($control, icons.screenshot); + const { proxy } = controlEvents(art, $control); + const { icons } = art; + appendElement($control, icons.screenshot); proxy($control, "click", () => { art.screenshot(); }); @@ -1646,13 +1776,14 @@ function setting$1(option) { ...option, tooltip: art.i18n.get("Show Setting"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - append($control, icons.setting); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + appendElement($control, icons.setting); proxy($control, "click", () => { art.setting.toggle(); art.setting.resize(); }); - art.on("setting", (value) => { + on("setting", (value) => { tooltip($control, i18n.get(value ? "Hide Setting" : "Show Setting")); }); } @@ -1669,6 +1800,7 @@ function time(option) { padding: "0 10px" }, mounted: ($control) => { + const { on } = controlEvents(art, $control); function getTime() { const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`; if (newTime !== $control.textContent) { @@ -1678,7 +1810,7 @@ function time(option) { getTime(); const events = ["video:loadedmetadata", "video:timeupdate", "video:progress"]; for (let index = 0; index < events.length; index++) { - art.on(events[index], getTime); + on(events[index], getTime); } } }); @@ -1687,16 +1819,17 @@ function volume$1(option) { return (art) => ({ ...option, mounted: ($control) => { - const { proxy, icons } = art; - const $volume = append($control, icons.volume); - const $close = append($control, icons.volumeClose); - const $panel = append($control, '
'); - const $inner = append($panel, '
'); - const $value = append($inner, `
`); - const $slider = append($inner, `
`); - const $handle = append($slider, `
`); - const $loaded = append($handle, `
`); - const $indicator = append($slider, `
`); + const { on, proxy } = controlEvents(art, $control); + const { icons } = art; + const $volume = appendElement($control, icons.volume); + const $close = appendElement($control, icons.volumeClose); + const $panel = appendElement($control, '
'); + const $inner = appendElement($panel, '
'); + const $value = appendElement($inner, `
`); + const $slider = appendElement($inner, `
`); + const $handle = appendElement($slider, `
`); + const $loaded = appendElement($handle, `
`); + const $indicator = appendElement($slider, `
`); function getVolumeFromEvent(event) { const { top, height } = getRect($slider); return 1 - (event.clientY - top) / height; @@ -1707,18 +1840,18 @@ function volume$1(option) { setStyle($close, "display", "flex"); setStyle($indicator, "top", "100%"); setStyle($loaded, "top", "100%"); - $value.textContent = 0; + $value.textContent = "0"; } else { const percentage = art.volume * 100; setStyle($volume, "display", "flex"); setStyle($close, "display", "none"); setStyle($indicator, "top", `${100 - percentage}%`); setStyle($loaded, "top", `${100 - percentage}%`); - $value.textContent = Math.floor(percentage); + $value.textContent = String(Math.floor(percentage)); } } update(); - art.on("video:volumechange", update); + on("video:volumechange", update); proxy($volume, "click", () => { art.muted = true; }); @@ -1733,13 +1866,13 @@ function volume$1(option) { isDragging = event.button === 0; art.volume = getVolumeFromEvent(event); }); - art.on("document:mousemove", (event) => { + on("document:mousemove", (event) => { if (isDragging) { art.muted = false; art.volume = getVolumeFromEvent(event); } }); - art.on("document:mouseup", () => { + on("document:mouseup", () => { if (isDragging) { isDragging = false; } @@ -1748,6 +1881,226 @@ function volume$1(option) { } }); } +function installControls(controls) { + const { option } = controls.art; + if (!option.isLive) { + controls.add( + progress({ + name: "progress", + position: "top", + index: 10 + }) + ); + } + controls.add({ + name: "thumbnails", + position: "top", + index: 20 + }); + controls.add( + playAndPause({ + name: "playAndPause", + position: "left", + index: 10 + }) + ); + controls.add( + volume$1({ + name: "volume", + position: "left", + index: 20 + }) + ); + if (!option.isLive) { + controls.add( + time({ + name: "time", + position: "left", + index: 30 + }) + ); + } + if (option.quality.length) { + wait(getScope(controls.art)).then((active) => { + if (!active || getScope(controls.art).closed) + return; + controls.art.quality = option.quality; + }).catch((error2) => { + console.warn("ArtPlayer quality initialization failed:", error2); + }); + } + if (option.screenshot && !isMobile) { + controls.add( + screenshot$1({ + name: "screenshot", + position: "right", + index: 20 + }) + ); + } + if (option.setting) { + controls.add( + setting$1({ + name: "setting", + position: "right", + index: 30 + }) + ); + } + if (option.pip) { + controls.add( + pip$1({ + name: "pip", + position: "right", + index: 40 + }) + ); + } + if (option.airplay && "WebKitPlaybackTargetAvailabilityEvent" in window && window.WebKitPlaybackTargetAvailabilityEvent) { + controls.add( + airplay$1({ + name: "airplay", + position: "right", + index: 50 + }) + ); + } + if (option.fullscreenWeb) { + controls.add( + fullscreenWeb({ + name: "fullscreenWeb", + position: "right", + index: 60 + }) + ); + } + if (option.fullscreen) { + controls.add( + fullscreen({ + name: "fullscreen", + position: "right", + index: 70 + }) + ); + } + for (let index = 0; index < option.controls.length; index++) { + controls.add(option.controls[index]); + } +} +function observeControlLayout(art) { + const { $bottom, $controls, $player } = art.template; + const scope = entryScope($bottom); + const { on } = controlEvents(art, $bottom); + const update = () => { + if (scope.closed) + return; + const height = $controls.offsetHeight; + if (height > 0 && $player.style.getPropertyValue("--art-controls-height") !== `${height}px`) + $player.style.setProperty("--art-controls-height", `${height}px`); + }; + on("resize", update); + if (typeof ResizeObserver !== "undefined") { + const observer = new ResizeObserver(update); + observer.observe($controls); + scope.add(() => { + observer.disconnect(); + }); + } else if (typeof MutationObserver !== "undefined") { + const observer = new MutationObserver(update); + observer.observe($controls, { childList: true, subtree: true, attributes: true, characterData: true }); + scope.add(() => { + observer.disconnect(); + }); + } + update(); +} +const selections = /* @__PURE__ */ new WeakMap(); +function trackSelection(event, active) { + selections.set(event, active); + return () => { + if (selections.get(event) === active) + selections.delete(event); + }; +} +function captureSelection(event) { + return event && selections.get(event) || (() => true); +} +const bindings = /* @__PURE__ */ new WeakMap(); +function bind(item, binding) { + const previous = bindings.get(item); + errorHandle(!previous || entryScope(previous.owner).closed, "Cannot share selector items between active controls"); + if (!previous) { + def(item, "$control_option", { get: () => bindings.get(item).option.selector }); + def(item, "$control_item", { get: () => bindings.get(item).item }); + def(item, "$control_value", { get: () => bindings.get(item).value }); + } + bindings.set(item, binding); +} +function setHTML(element, value) { + element.innerHTML = value; +} +function checkSelector(target) { + if (!target) + return; + setHTML(target.$control_value, target.html); + for (let index = 0; index < target.$control_option.length; index++) { + const item = target.$control_option[index]; + item.default = item === target; + if (item.default) + inverseClass(item.$control_item, "art-current"); + } +} +function renderSelector(art, check2, option, $ref, events) { + const { proxy } = art.events; + const scope = entryScope($ref); + const selector = option.selector; + addClass($ref, "art-control-selector"); + const $value = document.createElement("div"); + addClass($value, "art-selector-value"); + append($value, option.html); + $ref.textContent = ""; + append($ref, $value); + const $list = appendElement($ref, '
'); + for (let index = 0; index < selector.length; index++) { + const item = selector[index]; + const $item = document.createElement("div"); + addClass($item, "art-selector-item"); + if (item.default) + addClass($item, "art-current"); + $item.dataset.index = String(index); + $item.dataset.value = String(item.value); + setHTML($item, item.html); + append($list, $item); + bind(item, { option, item: $item, value: $value, owner: $ref }); + } + let generation = 0; + const event = proxy($list, "click", async (event2) => { + if (scope.closed) + return; + const path = getComposedPath(event2); + const item = option.selector.find((item2) => path.includes(item2.$control_item)); + if (!item) + return; + const current2 = ++generation; + const active = () => !scope.closed && current2 === generation; + const release = scope.add(trackSelection(event2, active)); + try { + check2(item); + if (scope.closed) + return; + if (option.onSelect) { + const value = await option.onSelect.call(art, item, item.$control_item, event2); + if (active()) + setHTML($value, value); + } + } catch (error2) { + console.warn("ArtPlayer selector failed:", error2); + } finally { + release(); + } + }); + events.push(event); +} class Control extends Component { constructor(art) { super(art); @@ -1756,27 +2109,29 @@ class Control extends Component { this.timer = Date.now(); const { constructor } = art; const { $player, $bottom } = this.art.template; - art.on("mousemove", () => { + ownEntry(art, $bottom); + const { on } = controlEvents(art, $bottom); + on("mousemove", () => { if (!isMobile) { this.show = true; } }); - art.on("click", () => { + on("click", () => { if (isMobile) { this.toggle(); } else { this.show = true; } }); - art.on("document:mousemove", (event) => { + on("document:mousemove", (event) => { this.isHover = includeFromEvent(event, $bottom); }); - art.on("video:timeupdate", () => { + on("video:timeupdate", () => { if (!art.setting.show && !this.isHover && !art.isInput && art.playing && this.show && Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME) { this.show = false; } }); - art.on("control", (state2) => { + on("control", (state2) => { if (state2) { removeClass($player, "art-hide-cursor"); addClass($player, "art-hover"); @@ -1787,112 +2142,15 @@ class Control extends Component { } }); this.init(); + if (!getScope(art).closed) + observeControlLayout(art); } init() { - const { option } = this.art; - if (!option.isLive) { - this.add( - progress({ - name: "progress", - position: "top", - index: 10 - }) - ); - } - this.add({ - name: "thumbnails", - position: "top", - index: 20 - }); - this.add( - playAndPause({ - name: "playAndPause", - position: "left", - index: 10 - }) - ); - this.add( - volume$1({ - name: "volume", - position: "left", - index: 20 - }) - ); - if (!option.isLive) { - this.add( - time({ - name: "time", - position: "left", - index: 30 - }) - ); - } - if (option.quality.length) { - wait(getScope(this.art)).then((active) => { - if (!active || getScope(this.art).closed) - return; - this.art.quality = option.quality; - }); - } - if (option.screenshot && !isMobile) { - this.add( - screenshot$1({ - name: "screenshot", - position: "right", - index: 20 - }) - ); - } - if (option.setting) { - this.add( - setting$1({ - name: "setting", - position: "right", - index: 30 - }) - ); - } - if (option.pip) { - this.add( - pip$1({ - name: "pip", - position: "right", - index: 40 - }) - ); - } - if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) { - this.add( - airplay$1({ - name: "airplay", - position: "right", - index: 50 - }) - ); - } - if (option.fullscreenWeb) { - this.add( - fullscreenWeb({ - name: "fullscreenWeb", - position: "right", - index: 60 - }) - ); - } - if (option.fullscreen) { - this.add( - fullscreen({ - name: "fullscreen", - position: "right", - index: 70 - }) - ); - } - for (let index = 0; index < option.controls.length; index++) { - this.add(option.controls[index]); - } + installControls(this); } add(getOption) { + if (isClosing(this.art)) + return; const option = typeof getOption === "function" ? getOption(this.art) : getOption; const { $progress, $controlsLeft, $controlsRight } = this.art.template; switch (option.position) { @@ -1912,60 +2170,10 @@ class Control extends Component { super.add(option); } check(target) { - if (!target) { - return; - } - target.$control_value.innerHTML = target.html; - for (let index = 0; index < target.$control_option.length; index++) { - const item = target.$control_option[index]; - item.default = item === target; - if (item.default) { - inverseClass(item.$control_item, "art-current"); - } - } + checkSelector(target); } selector(option, $ref, events) { - const { proxy } = this.art.events; - addClass($ref, "art-control-selector"); - const $value = createElement("div"); - addClass($value, "art-selector-value"); - append($value, option.html); - $ref.textContent = ""; - append($ref, $value); - const $list = createElement("div"); - addClass($list, "art-selector-list"); - append($ref, $list); - for (let index = 0; index < option.selector.length; index++) { - const item = option.selector[index]; - const $item = createElement("div"); - addClass($item, "art-selector-item"); - if (item.default) - addClass($item, "art-current"); - $item.dataset.index = index; - $item.dataset.value = item.value; - $item.innerHTML = item.html; - append($list, $item); - def(item, "$control_option", { - get: () => option.selector - }); - def(item, "$control_item", { - get: () => $item - }); - def(item, "$control_value", { - get: () => $value - }); - } - const event = proxy($list, "click", async (event2) => { - const path = getComposedPath(event2); - const item = option.selector.find( - (item2) => item2.$control_item === path.find(($item) => item2.$control_item === $item) - ); - this.check(item); - if (option.onSelect) { - $value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event2); - } - }); - events.push(event); + renderSelector(this.art, (target) => this.check(target), option, $ref, events); } } function clickInit(art, events) { @@ -2530,15 +2738,11 @@ class Info extends Component { class Layer extends Component { constructor(art) { super(art); - const { - option, - template: { $layer } - } = art; + const { option, template: { $layer } } = art; this.name = "layer"; this.$parent = $layer; - for (let index = 0; index < option.layers.length; index++) { + for (let index = 0; index < option.layers.length; index++) this.add(option.layers[index]); - } } } class Loading extends Component { @@ -3674,14 +3878,17 @@ function qualityMix(art) { name: "quality", position: "right", index: 10, - style: { - marginRight: "10px" - }, + style: { marginRight: "10px" }, html: qualityDefault?.html || "", selector: quality, - async onSelect(item) { + async onSelect(item, _element, event) { + const active = captureSelection(event); await art.switchQuality(item.url); - notice.show = `${i18n.get("Switch Video")}: ${item.html}`; + if (!isClosing(art) && active()) { + const message = `${i18n.get("Switch Video")}: ${item.html}`; + if (!isClosing(art) && active()) + notice.show = message; + } return item.html; } }); @@ -5128,7 +5335,7 @@ class Storage { } } } -const css = ".art-video-player {\n --art-theme: #f00;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: rgba(0, 0, 0, 0.5);\n --art-transition-duration: 0.2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: rgba(255, 255, 255, 0.25);\n --art-progress-top-gap: 10px;\n --art-hover-color: rgba(255, 255, 255, 0.25);\n --art-loaded-color: rgba(255, 255, 255, 0.25);\n --art-state-size: 80px;\n --art-state-opacity: 0.8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: rgba(255, 255, 255, 0.5);\n --art-control-height: 46px;\n --art-control-opacity: 0.75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: rgba(0, 0, 0, 0.85);\n --art-tip-background: rgba(0, 0, 0, 0.7);\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: rgba(255, 255, 255, 0.25);\n --art-scrollbar-background-hover: rgba(255, 255, 255, 0.5);\n --art-mini-progress-height: 2px;\n}\n.art-bg-cover {\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-backdrop-filter {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.art-video-player {\n position: relative;\n margin: 0 auto;\n width: 100%;\n height: 100%;\n outline: 0;\n zoom: 1;\n padding: 0;\n text-align: left;\n direction: ltr;\n font-size: 14px;\n line-height: 1.3;\n user-select: none;\n box-sizing: border-box;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n}\n.art-video-player *,\n.art-video-player *::before,\n.art-video-player *::after {\n box-sizing: border-box;\n}\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n.art-video-player img {\n max-width: 100%;\n vertical-align: top;\n}\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n.art-icon {\n line-height: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.art-video-player.art-backdrop .art-contextmenus,\n.art-video-player.art-backdrop .art-info,\n.art-video-player.art-backdrop .art-settings,\n.art-video-player.art-backdrop .art-layer-auto-playback,\n.art-video-player.art-backdrop .art-selector-list,\n.art-video-player.art-backdrop .art-volume-inner {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-video {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n}\n.art-poster {\n position: absolute;\n inset: 0;\n z-index: 11;\n width: 100%;\n height: 100%;\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: none;\n}\n.art-video-player .art-subtitle {\n display: none;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n z-index: 20;\n width: 100%;\n padding: 0 5%;\n text-align: center;\n pointer-events: none;\n gap: var(--art-subtitle-gap);\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n.art-danmuku {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: hidden;\n}\n.art-video-player .art-layers {\n position: absolute;\n inset: 0;\n z-index: 40;\n width: 100%;\n height: 100%;\n display: none;\n pointer-events: none;\n}\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n.art-video-player .art-mask {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 50;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player .art-mask .art-state {\n display: flex;\n justify-content: center;\n align-items: center;\n opacity: 0;\n transform: scale(2);\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n}\n.art-video-player.art-mask-show .art-state {\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n.art-video-player .art-loading {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 70;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n.art-video-player .art-bottom {\n position: absolute;\n inset: 0;\n z-index: 60;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-video-player .art-bottom .art-controls,\n.art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player.art-control-show .art-bottom,\n.art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n.art-video-player.art-control-show .art-bottom .art-controls,\n.art-video-player.art-hover .art-bottom .art-controls,\n.art-video-player.art-control-show .art-bottom .art-progress,\n.art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n.art-bottom .art-progress {\n position: relative;\n z-index: 0;\n cursor: pointer;\n pointer-events: auto;\n padding-top: var(--art-progress-top-gap);\n padding-bottom: var(--art-bottom-gap);\n}\n.art-bottom .art-progress .art-control-progress {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-progress-height);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n display: flex;\n align-items: center;\n position: relative;\n height: 50%;\n width: 100%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-hover-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-loaded-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n position: absolute;\n inset: 0;\n z-index: 20;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-theme);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n right: auto;\n pointer-events: auto;\n width: var(--art-highlight-width) !important;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n z-index: 40;\n left: 0;\n border-radius: 50%;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 50;\n top: -25px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-thumbnails {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n bottom: calc(var(--art-bottom-gap) + 10px);\n left: 0;\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 2px -1px rgba(0, 0, 0, 0.2);\n}\n.art-bottom .art-progress:hover .art-control-progress .art-control-progress-inner {\n height: 100%;\n}\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n.art-progress-hover .art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip,\n.art-progress-hover .art-bottom .art-progress .art-control-thumbnails {\n transform: scale(1);\n opacity: 1;\n}\n.art-video-player .art-controls {\n position: relative;\n z-index: 10;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-left,\n.art-video-player .art-controls .art-controls-right {\n display: flex;\n height: 100%;\n}\n.art-video-player .art-controls .art-controls-center {\n display: none;\n justify-content: center;\n align-items: center;\n flex: 1;\n height: 100%;\n padding: 0 10px;\n}\n.art-video-player .art-controls .art-controls-right {\n justify-content: flex-end;\n}\n.art-video-player .art-controls .art-control {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * 0.8));\n}\n.art-video-player .art-controls .art-control:hover {\n opacity: 1;\n}\n.art-control-volume {\n position: relative;\n}\n.art-control-volume .art-volume-panel {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n left: 0;\n right: 0;\n padding: 0 5px;\n font-size: 12px;\n text-align: center;\n cursor: default;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n height: 100%;\n width: 100%;\n padding: 10px 0 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n flex: 1;\n width: 100%;\n display: flex;\n cursor: pointer;\n position: relative;\n justify-content: center;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n position: relative;\n display: flex;\n justify-content: center;\n width: 2px;\n border-radius: var(--art-border-radius);\n overflow: hidden;\n background-color: rgba(255, 255, 255, 0.25);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n background-color: var(--art-theme);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n position: absolute;\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n flex-shrink: 0;\n transform: scale(1);\n border-radius: 100%;\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(0.9);\n}\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player .art-notice {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 80;\n width: 100%;\n height: 100%;\n height: auto;\n bottom: auto;\n padding: var(--art-padding);\n pointer-events: none;\n}\n.art-video-player .art-notice .art-notice-inner {\n display: inline-flex;\n padding: 5px;\n line-height: 1;\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n}\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n.art-video-player .art-contextmenus {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 120;\n padding: 5px 0;\n border-radius: var(--art-border-radius);\n font-size: 12px;\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n}\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n display: flex;\n padding: 10px 15px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n.art-video-player .art-contextmenus .art-contextmenu span:hover,\n.art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n.art-video-player .art-settings {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 90;\n left: auto;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n right: var(--art-padding);\n bottom: var(--art-control-height);\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-settings .art-setting-panel {\n display: none;\n flex-direction: column;\n}\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n cursor: pointer;\n overflow: hidden;\n transition: background-color var(--art-transition-duration) ease;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n gap: 5px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: rgba(255, 255, 255, 0.5);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n height: 3px;\n width: 80px;\n outline: none;\n appearance: none;\n background-color: rgba(255, 255, 255, 0.2);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n.art-video-player .art-info {\n display: none;\n position: absolute;\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n padding: 10px;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-info .art-info-panel {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n width: 100px;\n text-align: right;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n width: 250px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n}\n.art-video-player .art-info .art-info-close {\n position: absolute;\n top: 5px;\n right: 5px;\n cursor: pointer;\n}\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n.art-hide-cursor * {\n cursor: none !important;\n}\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n position: fixed;\n inset: 0;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n}\n.art-mini-popup {\n position: fixed;\n z-index: 9999;\n width: 320px;\n height: 180px;\n background: #000;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n overflow: hidden;\n transition: opacity 0.2s ease;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);\n}\n.art-mini-popup svg {\n fill: #fff;\n}\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n.art-mini-popup .art-mini-close {\n position: absolute;\n z-index: 20;\n right: 10px;\n top: 10px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n.art-mini-popup .art-mini-state {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s ease;\n background-color: rgba(0, 0, 0, 0.25);\n}\n.art-mini-popup .art-mini-state .art-icon {\n opacity: 0.75;\n cursor: pointer;\n transform: scale(3);\n pointer-events: auto;\n transition: transform 0.2s ease;\n}\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n.art-mini-popup.art-mini-dragging {\n opacity: 0.9;\n}\n.art-mini-popup:hover .art-mini-close,\n.art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n.art-video-player[data-flip='horizontal'] .art-video {\n transform: scaleX(-1);\n}\n.art-video-player[data-flip='vertical'] .art-video {\n transform: scaleY(-1);\n}\n.art-video-player .art-layer-lock {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n top: 50%;\n border-radius: 50%;\n transform: translateY(-50%);\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n}\n.art-video-player .art-layer-auto-playback {\n display: none;\n gap: 10px;\n align-items: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n padding: 10px;\n line-height: 1;\n left: var(--art-padding);\n bottom: calc(var(--art-control-height) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n.art-video-player.art-mini-progress-bar .art-bottom,\n.art-video-player.art-lock .art-bottom {\n opacity: 1;\n padding: 0;\n background-image: none;\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls,\n.art-video-player.art-lock .art-bottom .art-controls,\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress,\n.art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-control-height) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator,\n.art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n.art-control-selector {\n position: relative;\n display: flex;\n justify-content: center;\n}\n.art-control-selector .art-selector-list {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n overflow-y: auto;\n overflow-x: hidden;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-selector .art-selector-list .art-selector-item {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n flex-shrink: 0;\n line-height: 1;\n}\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-control-selector .art-selector-list .art-selector-item:hover,\n.art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player {\n /*! Hint.css - v2.7.0 - 2021-10-01\n * https://kushagra.dev/lab/hint/\n * Copyright (c) 2021 Kushagra Gour */\n /*-------------------------------------*\\\n HINT.css - A CSS tooltip library\n \\*-------------------------------------*/\n /**\n * HINT.css is a tooltip library made in pure CSS.\n *\n * Source: https://github.com/chinchang/hint.css\n * Demo: http://kushagragour.in/lab/hint/\n *\n */\n /**\n * source: hint-core.scss\n *\n * Defines the basic styling for the tooltip.\n * Each tooltip is made of 2 parts:\n * 1) body (:after)\n * 2) arrow (:before)\n *\n * Classes added:\n * 1) hint\n */\n /**\n * source: hint-position.scss\n *\n * Defines the positoning logic for the tooltips.\n *\n * Classes added:\n * 1) hint--top\n * 2) hint--bottom\n * 3) hint--left\n * 4) hint--right\n */\n /**\n * set default color for tooltip arrows\n */\n /**\n * top tooltip\n */\n /**\n * bottom tooltip\n */\n /**\n * right tooltip\n */\n /**\n * left tooltip\n */\n /**\n * top-left tooltip\n */\n /**\n * top-right tooltip\n */\n /**\n * bottom-left tooltip\n */\n /**\n * bottom-right tooltip\n */\n /**\n * source: hint-sizes.scss\n *\n * Defines width restricted tooltips that can span\n * across multiple lines.\n *\n * Classes added:\n * 1) hint--small\n * 2) hint--medium\n * 3) hint--large\n *\n */\n /**\n * source: hint-theme.scss\n *\n * Defines basic theme for tooltips.\n *\n */\n /**\n * source: hint-color-types.scss\n *\n * Contains tooltips of various types based on color differences.\n *\n * Classes added:\n * 1) hint--error\n * 2) hint--warning\n * 3) hint--info\n * 4) hint--success\n *\n */\n /**\n * Error\n */\n /**\n * Warning\n */\n /**\n * Info\n */\n /**\n * Success\n */\n /**\n * source: hint-always.scss\n *\n * Defines a persisted tooltip which shows always.\n *\n * Classes added:\n * 1) hint--always\n *\n */\n /**\n * source: hint-rounded.scss\n *\n * Defines rounded corner tooltips.\n *\n * Classes added:\n * 1) hint--rounded\n *\n */\n /**\n * source: hint-effects.scss\n *\n * Defines various transition effects for the tooltips.\n *\n * Classes added:\n * 1) hint--no-animate\n * 2) hint--bounce\n *\n */\n}\n.art-video-player [class*='hint--'] {\n position: relative;\n display: inline-block;\n font-style: normal;\n /**\n * tooltip arrow\n */\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:before,\n.art-video-player [class*='hint--']:after {\n position: absolute;\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n -webkit-transition: 0.3s ease;\n -moz-transition: 0.3s ease;\n transition: 0.3s ease;\n -webkit-transition-delay: 0ms;\n -moz-transition-delay: 0ms;\n transition-delay: 0ms;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n visibility: visible;\n opacity: 1;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n -webkit-transition-delay: 100ms;\n -moz-transition-delay: 100ms;\n transition-delay: 100ms;\n}\n.art-video-player [class*='hint--']:before {\n content: '';\n position: absolute;\n background: transparent;\n border: 6px solid transparent;\n z-index: 1000001;\n}\n.art-video-player [class*='hint--']:after {\n background: #000000;\n color: white;\n padding: 8px 10px;\n font-size: 12px;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n line-height: 12px;\n white-space: nowrap;\n}\n.art-video-player [class*='hint--'][aria-label]:after {\n content: attr(aria-label);\n}\n.art-video-player [class*='hint--'][data-hint]:after {\n content: attr(data-hint);\n}\n.art-video-player [aria-label='']:before,\n.art-video-player [aria-label='']:after,\n.art-video-player [data-hint='']:before,\n.art-video-player [data-hint='']:after {\n display: none !important;\n}\n.art-video-player .hint--top-left:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top-right:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--bottom-left:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom-right:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--left:before {\n border-left-color: #000000;\n}\n.art-video-player .hint--right:before {\n border-right-color: #000000;\n}\n.art-video-player .hint--top:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top:before,\n.art-video-player .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--top:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top:hover:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--bottom:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom:before,\n.art-video-player .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--bottom:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom:hover:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--right:before {\n margin-left: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--right:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--right:before,\n.art-video-player .hint--right:after {\n left: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--right:hover:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--right:hover:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--left:before {\n margin-right: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--left:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--left:before,\n.art-video-player .hint--left:after {\n right: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--left:hover:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--left:hover:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--top-left:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-left:before,\n.art-video-player .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--top-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--top-left:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--top-right:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-right:before,\n.art-video-player .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--top-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--top-right:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-right:hover:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--bottom-left:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-left:before,\n.art-video-player .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--bottom-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--bottom-left:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--bottom-right:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-right:before,\n.art-video-player .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--bottom-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--bottom-right:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-right:hover:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--small:after,\n.art-video-player .hint--medium:after,\n.art-video-player .hint--large:after {\n white-space: normal;\n line-height: 1.4em;\n word-wrap: break-word;\n}\n.art-video-player .hint--small:after {\n width: 80px;\n}\n.art-video-player .hint--medium:after {\n width: 150px;\n}\n.art-video-player .hint--large:after {\n width: 300px;\n}\n.art-video-player [class*='hint--'] {\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:after {\n text-shadow: 0 -1px 0px black;\n box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3);\n}\n.art-video-player .hint--error:after {\n background-color: #b34e4d;\n text-shadow: 0 -1px 0px #592726;\n}\n.art-video-player .hint--error.hint--top-left:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top-right:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-left:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-right:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n.art-video-player .hint--warning:after {\n background-color: #c09854;\n text-shadow: 0 -1px 0px #6c5328;\n}\n.art-video-player .hint--warning.hint--top-left:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top-right:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-left:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-right:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n.art-video-player .hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n.art-video-player .hint--info:after {\n background-color: #3986ac;\n text-shadow: 0 -1px 0px #1a3c4d;\n}\n.art-video-player .hint--info.hint--top-left:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top-right:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-left:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-right:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n.art-video-player .hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n.art-video-player .hint--success:after {\n background-color: #458746;\n text-shadow: 0 -1px 0px #1a321a;\n}\n.art-video-player .hint--success.hint--top-left:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top-right:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-left:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-right:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--left:before {\n border-left-color: #458746;\n}\n.art-video-player .hint--success.hint--right:before {\n border-right-color: #458746;\n}\n.art-video-player .hint--always:after,\n.art-video-player .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n.art-video-player .hint--always.hint--top:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--bottom:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--left:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--left:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--right:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--always.hint--right:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--rounded:after {\n border-radius: 4px;\n}\n.art-video-player .hint--no-animate:before,\n.art-video-player .hint--no-animate:after {\n -webkit-transition-duration: 0ms;\n -moz-transition-duration: 0ms;\n transition-duration: 0ms;\n}\n.art-video-player .hint--bounce:before,\n.art-video-player .hint--bounce:after {\n -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n}\n.art-video-player .hint--no-shadow:before,\n.art-video-player .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n.art-video-player .hint--no-arrow:before {\n display: none;\n}\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n"; +const css = ".art-video-player {\n --art-theme: #f00;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: rgba(0, 0, 0, 0.5);\n --art-transition-duration: 0.2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: rgba(255, 255, 255, 0.25);\n --art-progress-top-gap: 10px;\n --art-hover-color: rgba(255, 255, 255, 0.25);\n --art-loaded-color: rgba(255, 255, 255, 0.25);\n --art-state-size: 80px;\n --art-state-opacity: 0.8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: rgba(255, 255, 255, 0.5);\n --art-control-height: 46px;\n --art-control-opacity: 0.75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: rgba(0, 0, 0, 0.85);\n --art-tip-background: rgba(0, 0, 0, 0.7);\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: rgba(255, 255, 255, 0.25);\n --art-scrollbar-background-hover: rgba(255, 255, 255, 0.5);\n --art-mini-progress-height: 2px;\n}\n.art-bg-cover {\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-backdrop-filter {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.art-video-player {\n position: relative;\n margin: 0 auto;\n width: 100%;\n height: 100%;\n outline: 0;\n zoom: 1;\n padding: 0;\n text-align: left;\n direction: ltr;\n font-size: 14px;\n line-height: 1.3;\n user-select: none;\n box-sizing: border-box;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n}\n.art-video-player *,\n.art-video-player *::before,\n.art-video-player *::after {\n box-sizing: border-box;\n}\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n.art-video-player img {\n max-width: 100%;\n vertical-align: top;\n}\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n.art-icon {\n line-height: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.art-video-player.art-backdrop .art-contextmenus,\n.art-video-player.art-backdrop .art-info,\n.art-video-player.art-backdrop .art-settings,\n.art-video-player.art-backdrop .art-layer-auto-playback,\n.art-video-player.art-backdrop .art-selector-list,\n.art-video-player.art-backdrop .art-volume-inner {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-video {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n}\n.art-poster {\n position: absolute;\n inset: 0;\n z-index: 11;\n width: 100%;\n height: 100%;\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: none;\n}\n.art-video-player .art-subtitle {\n display: none;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n z-index: 20;\n width: 100%;\n padding: 0 5%;\n text-align: center;\n pointer-events: none;\n gap: var(--art-subtitle-gap);\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-subtitle-bottom));\n}\n.art-danmuku {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: hidden;\n}\n.art-video-player .art-layers {\n position: absolute;\n inset: 0;\n z-index: 40;\n width: 100%;\n height: 100%;\n display: none;\n pointer-events: none;\n}\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n.art-video-player .art-mask {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 50;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player .art-mask .art-state {\n display: flex;\n justify-content: center;\n align-items: center;\n opacity: 0;\n transform: scale(2);\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n}\n.art-video-player.art-mask-show .art-state {\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n.art-video-player .art-loading {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 70;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n.art-video-player .art-bottom {\n position: absolute;\n inset: 0;\n z-index: 60;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-video-player .art-bottom .art-controls,\n.art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player.art-control-show .art-bottom,\n.art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n.art-video-player.art-control-show .art-bottom .art-controls,\n.art-video-player.art-hover .art-bottom .art-controls,\n.art-video-player.art-control-show .art-bottom .art-progress,\n.art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n.art-bottom .art-progress {\n position: relative;\n z-index: 0;\n cursor: pointer;\n pointer-events: auto;\n padding-top: var(--art-progress-top-gap);\n padding-bottom: var(--art-bottom-gap);\n}\n.art-bottom .art-progress .art-control-progress {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-progress-height);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n display: flex;\n align-items: center;\n position: relative;\n height: 50%;\n width: 100%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-hover-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-loaded-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n position: absolute;\n inset: 0;\n z-index: 20;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-theme);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n right: auto;\n pointer-events: auto;\n width: var(--art-highlight-width) !important;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n z-index: 40;\n left: 0;\n border-radius: 50%;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 50;\n top: -25px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-thumbnails {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n bottom: calc(var(--art-bottom-gap) + 10px);\n left: 0;\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 2px -1px rgba(0, 0, 0, 0.2);\n}\n.art-bottom .art-progress:hover .art-control-progress .art-control-progress-inner {\n height: 100%;\n}\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n.art-progress-hover .art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip,\n.art-progress-hover .art-bottom .art-progress .art-control-thumbnails {\n transform: scale(1);\n opacity: 1;\n}\n.art-video-player .art-controls {\n position: relative;\n z-index: 10;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n flex-shrink: 0;\n height: auto;\n min-height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-left,\n.art-video-player .art-controls .art-controls-right {\n display: flex;\n flex-wrap: wrap;\n max-width: 100%;\n min-height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-center {\n display: none;\n justify-content: center;\n align-items: center;\n flex: 1;\n height: 100%;\n padding: 0 10px;\n}\n.art-video-player .art-controls .art-controls-right {\n justify-content: flex-end;\n margin-left: auto;\n}\n.art-video-player .art-controls .art-control {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n max-width: 100%;\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * 0.8));\n}\n.art-video-player .art-controls .art-control:hover {\n opacity: 1;\n}\n.art-control-volume {\n position: relative;\n}\n.art-control-volume .art-volume-panel {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n left: 0;\n right: 0;\n padding: 0 5px;\n font-size: 12px;\n text-align: center;\n cursor: default;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n height: 100%;\n width: 100%;\n padding: 10px 0 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n flex: 1;\n width: 100%;\n display: flex;\n cursor: pointer;\n position: relative;\n justify-content: center;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n position: relative;\n display: flex;\n justify-content: center;\n width: 2px;\n border-radius: var(--art-border-radius);\n overflow: hidden;\n background-color: rgba(255, 255, 255, 0.25);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n background-color: var(--art-theme);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n position: absolute;\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n flex-shrink: 0;\n transform: scale(1);\n border-radius: 100%;\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(0.9);\n}\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player .art-notice {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 80;\n width: 100%;\n height: 100%;\n height: auto;\n bottom: auto;\n padding: var(--art-padding);\n pointer-events: none;\n}\n.art-video-player .art-notice .art-notice-inner {\n display: inline-flex;\n padding: 5px;\n line-height: 1;\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n}\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n.art-video-player .art-contextmenus {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 120;\n padding: 5px 0;\n border-radius: var(--art-border-radius);\n font-size: 12px;\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n}\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n display: flex;\n padding: 10px 15px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n.art-video-player .art-contextmenus .art-contextmenu span:hover,\n.art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n.art-video-player .art-settings {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 90;\n left: auto;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n right: var(--art-padding);\n bottom: var(--art-controls-height, var(--art-control-height));\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-settings .art-setting-panel {\n display: none;\n flex-direction: column;\n}\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n cursor: pointer;\n overflow: hidden;\n transition: background-color var(--art-transition-duration) ease;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n gap: 5px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: rgba(255, 255, 255, 0.5);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n height: 3px;\n width: 80px;\n outline: none;\n appearance: none;\n background-color: rgba(255, 255, 255, 0.2);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n.art-video-player .art-info {\n display: none;\n position: absolute;\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n padding: 10px;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-info .art-info-panel {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n width: 100px;\n text-align: right;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n width: 250px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n}\n.art-video-player .art-info .art-info-close {\n position: absolute;\n top: 5px;\n right: 5px;\n cursor: pointer;\n}\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n.art-hide-cursor * {\n cursor: none !important;\n}\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n position: fixed;\n inset: 0;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n}\n.art-mini-popup {\n position: fixed;\n z-index: 9999;\n width: 320px;\n height: 180px;\n background: #000;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n overflow: hidden;\n transition: opacity 0.2s ease;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);\n}\n.art-mini-popup svg {\n fill: #fff;\n}\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n.art-mini-popup .art-mini-close {\n position: absolute;\n z-index: 20;\n right: 10px;\n top: 10px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n.art-mini-popup .art-mini-state {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s ease;\n background-color: rgba(0, 0, 0, 0.25);\n}\n.art-mini-popup .art-mini-state .art-icon {\n opacity: 0.75;\n cursor: pointer;\n transform: scale(3);\n pointer-events: auto;\n transition: transform 0.2s ease;\n}\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n.art-mini-popup.art-mini-dragging {\n opacity: 0.9;\n}\n.art-mini-popup:hover .art-mini-close,\n.art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n.art-video-player[data-flip='horizontal'] .art-video {\n transform: scaleX(-1);\n}\n.art-video-player[data-flip='vertical'] .art-video {\n transform: scaleY(-1);\n}\n.art-video-player .art-layer-lock {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n top: 50%;\n border-radius: 50%;\n transform: translateY(-50%);\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n}\n.art-video-player .art-layer-auto-playback {\n display: none;\n gap: 10px;\n align-items: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n padding: 10px;\n line-height: 1;\n left: var(--art-padding);\n bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n.art-video-player.art-mini-progress-bar .art-bottom,\n.art-video-player.art-lock .art-bottom {\n opacity: 1;\n padding: 0;\n background-image: none;\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls,\n.art-video-player.art-lock .art-bottom .art-controls,\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress,\n.art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator,\n.art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n.art-control-selector {\n position: relative;\n display: flex;\n justify-content: center;\n}\n.art-control-selector .art-selector-list {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n overflow-y: auto;\n overflow-x: hidden;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-selector .art-selector-list .art-selector-item {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n flex-shrink: 0;\n line-height: 1;\n}\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-control-selector .art-selector-list .art-selector-item:hover,\n.art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player {\n /*! Hint.css - v2.7.0 - 2021-10-01\n * https://kushagra.dev/lab/hint/\n * Copyright (c) 2021 Kushagra Gour */\n /*-------------------------------------*\\\n HINT.css - A CSS tooltip library\n \\*-------------------------------------*/\n /**\n * HINT.css is a tooltip library made in pure CSS.\n *\n * Source: https://github.com/chinchang/hint.css\n * Demo: http://kushagragour.in/lab/hint/\n *\n */\n /**\n * source: hint-core.scss\n *\n * Defines the basic styling for the tooltip.\n * Each tooltip is made of 2 parts:\n * 1) body (:after)\n * 2) arrow (:before)\n *\n * Classes added:\n * 1) hint\n */\n /**\n * source: hint-position.scss\n *\n * Defines the positoning logic for the tooltips.\n *\n * Classes added:\n * 1) hint--top\n * 2) hint--bottom\n * 3) hint--left\n * 4) hint--right\n */\n /**\n * set default color for tooltip arrows\n */\n /**\n * top tooltip\n */\n /**\n * bottom tooltip\n */\n /**\n * right tooltip\n */\n /**\n * left tooltip\n */\n /**\n * top-left tooltip\n */\n /**\n * top-right tooltip\n */\n /**\n * bottom-left tooltip\n */\n /**\n * bottom-right tooltip\n */\n /**\n * source: hint-sizes.scss\n *\n * Defines width restricted tooltips that can span\n * across multiple lines.\n *\n * Classes added:\n * 1) hint--small\n * 2) hint--medium\n * 3) hint--large\n *\n */\n /**\n * source: hint-theme.scss\n *\n * Defines basic theme for tooltips.\n *\n */\n /**\n * source: hint-color-types.scss\n *\n * Contains tooltips of various types based on color differences.\n *\n * Classes added:\n * 1) hint--error\n * 2) hint--warning\n * 3) hint--info\n * 4) hint--success\n *\n */\n /**\n * Error\n */\n /**\n * Warning\n */\n /**\n * Info\n */\n /**\n * Success\n */\n /**\n * source: hint-always.scss\n *\n * Defines a persisted tooltip which shows always.\n *\n * Classes added:\n * 1) hint--always\n *\n */\n /**\n * source: hint-rounded.scss\n *\n * Defines rounded corner tooltips.\n *\n * Classes added:\n * 1) hint--rounded\n *\n */\n /**\n * source: hint-effects.scss\n *\n * Defines various transition effects for the tooltips.\n *\n * Classes added:\n * 1) hint--no-animate\n * 2) hint--bounce\n *\n */\n}\n.art-video-player [class*='hint--'] {\n position: relative;\n display: inline-block;\n font-style: normal;\n /**\n * tooltip arrow\n */\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:before,\n.art-video-player [class*='hint--']:after {\n position: absolute;\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n -webkit-transition: 0.3s ease;\n -moz-transition: 0.3s ease;\n transition: 0.3s ease;\n -webkit-transition-delay: 0ms;\n -moz-transition-delay: 0ms;\n transition-delay: 0ms;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n visibility: visible;\n opacity: 1;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n -webkit-transition-delay: 100ms;\n -moz-transition-delay: 100ms;\n transition-delay: 100ms;\n}\n.art-video-player [class*='hint--']:before {\n content: '';\n position: absolute;\n background: transparent;\n border: 6px solid transparent;\n z-index: 1000001;\n}\n.art-video-player [class*='hint--']:after {\n background: #000000;\n color: white;\n padding: 8px 10px;\n font-size: 12px;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n line-height: 12px;\n white-space: nowrap;\n}\n.art-video-player [class*='hint--'][aria-label]:after {\n content: attr(aria-label);\n}\n.art-video-player [class*='hint--'][data-hint]:after {\n content: attr(data-hint);\n}\n.art-video-player [aria-label='']:before,\n.art-video-player [aria-label='']:after,\n.art-video-player [data-hint='']:before,\n.art-video-player [data-hint='']:after {\n display: none !important;\n}\n.art-video-player .hint--top-left:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top-right:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--bottom-left:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom-right:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--left:before {\n border-left-color: #000000;\n}\n.art-video-player .hint--right:before {\n border-right-color: #000000;\n}\n.art-video-player .hint--top:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top:before,\n.art-video-player .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--top:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top:hover:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--bottom:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom:before,\n.art-video-player .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--bottom:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom:hover:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--right:before {\n margin-left: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--right:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--right:before,\n.art-video-player .hint--right:after {\n left: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--right:hover:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--right:hover:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--left:before {\n margin-right: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--left:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--left:before,\n.art-video-player .hint--left:after {\n right: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--left:hover:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--left:hover:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--top-left:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-left:before,\n.art-video-player .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--top-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--top-left:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--top-right:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-right:before,\n.art-video-player .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--top-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--top-right:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-right:hover:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--bottom-left:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-left:before,\n.art-video-player .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--bottom-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--bottom-left:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--bottom-right:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-right:before,\n.art-video-player .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--bottom-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--bottom-right:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-right:hover:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--small:after,\n.art-video-player .hint--medium:after,\n.art-video-player .hint--large:after {\n white-space: normal;\n line-height: 1.4em;\n word-wrap: break-word;\n}\n.art-video-player .hint--small:after {\n width: 80px;\n}\n.art-video-player .hint--medium:after {\n width: 150px;\n}\n.art-video-player .hint--large:after {\n width: 300px;\n}\n.art-video-player [class*='hint--'] {\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:after {\n text-shadow: 0 -1px 0px black;\n box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3);\n}\n.art-video-player .hint--error:after {\n background-color: #b34e4d;\n text-shadow: 0 -1px 0px #592726;\n}\n.art-video-player .hint--error.hint--top-left:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top-right:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-left:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-right:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n.art-video-player .hint--warning:after {\n background-color: #c09854;\n text-shadow: 0 -1px 0px #6c5328;\n}\n.art-video-player .hint--warning.hint--top-left:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top-right:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-left:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-right:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n.art-video-player .hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n.art-video-player .hint--info:after {\n background-color: #3986ac;\n text-shadow: 0 -1px 0px #1a3c4d;\n}\n.art-video-player .hint--info.hint--top-left:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top-right:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-left:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-right:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n.art-video-player .hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n.art-video-player .hint--success:after {\n background-color: #458746;\n text-shadow: 0 -1px 0px #1a321a;\n}\n.art-video-player .hint--success.hint--top-left:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top-right:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-left:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-right:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--left:before {\n border-left-color: #458746;\n}\n.art-video-player .hint--success.hint--right:before {\n border-right-color: #458746;\n}\n.art-video-player .hint--always:after,\n.art-video-player .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n.art-video-player .hint--always.hint--top:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--bottom:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--left:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--left:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--right:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--always.hint--right:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--rounded:after {\n border-radius: 4px;\n}\n.art-video-player .hint--no-animate:before,\n.art-video-player .hint--no-animate:after {\n -webkit-transition-duration: 0ms;\n -moz-transition-duration: 0ms;\n transition-duration: 0ms;\n}\n.art-video-player .hint--bounce:before,\n.art-video-player .hint--bounce:after {\n -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n}\n.art-video-player .hint--no-shadow:before,\n.art-video-player .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n.art-video-player .hint--no-arrow:before {\n display: none;\n}\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n"; class Subtitle extends Component { constructor(art) { super(art); diff --git a/package.json b/package.json index 27f865069..85af3478c 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "ci:build": "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/playback.test.js test/dash-control.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:unit": "node --test test/playback.test.js test/dash-control.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": "yarn test:node && yarn test:baseline", "test:browser": "playwright test", "test:browser:install": "playwright install chromium firefox webkit", diff --git a/packages/artplayer/ARCHITECTURE.md b/packages/artplayer/ARCHITECTURE.md index 5ee805793..f8adfffca 100644 --- a/packages/artplayer/ARCHITECTURE.md +++ b/packages/artplayer/ARCHITECTURE.md @@ -4,6 +4,74 @@ ArtPlayer keeps its existing constructor, player mixins, plugins and DOM/CSS hoo The production entry is still `src/index.js`; this document marks actual migrated boundaries rather than describing the entire core as TypeScript. +## Components and controls (CORE-13) + +The public registries remain Component-based. utils/component.ts owns add/update/remove, +cache and dynamic name aliases; component/dom.ts owns insertion and known template +queries; component/types.ts defines the minimal generic host and callback shapes. +component/resources.ts owns each entry's child ResourceScope, DOM proxies and guarded +Emitter subscriptions. control/resources.ts specializes the shared subscriptions with +UIEvents; it does not create a second event bus. Builtins depend on these capabilities, +not the full player class. CORE-20 still has to integrate the constructor facade. + +Control index.ts preserves routing and visibility behavior. builtins.ts preserves +installation order and option/platform conditions. selector.ts owns item binding, +selection rendering and asynchronous completion; progress.ts keeps the factory and +its historical helper exports while progress/position.ts, view.ts and interactions.ts +separate pointer math, rendering and drag ownership. The remaining simple controls +stay individual factories. layer.ts retains the generic registry; contextmenu/index.ts +owns positioning and root listeners, while its item factories own their own updates. + +Preserve the observable registry rules: option factories are bare calls with art; +click/mounted/beforeUnmount use art as this; index 0 still follows the old index-or-id +rule; equal indexes insert before their predecessor. update mutates the cached option +before remove, so the newly supplied beforeUnmount runs on the old node. Component +add/update may return a div; Control add/update still return undefined. Source types +model that distinction; historical public declaration conflicts remain CORE-21 work. +A name of `__proto__` now creates a normal own DOM alias without replacing the registry +prototype. Other historical aliases and shadowing behavior are not broadly renamed. + +Entry ownership starts before rendering. Failed mounting releases owned effects and +removes its DOM/cache/alias without masking the original exception or deleting a +successful reentrant replacement. beforeUnmount failure retains the entry for retry; +recursive removal of that same entry is ignored. Already detached DOM can be removed. +Builtin DOM/Emitter listeners, progress drag handlers and tip timers end on entry +removal/update or root destruction; closed handlers are inert even in an Emitter +snapshot. Whole-player destruction retains its existing cache/alias and user-hook +policy: it does not newly call every beforeUnmount. User mounted hook return values +remain ignored. Arbitrary user listeners and third-party SDK work still need explicit +user cleanup; internal scopes cannot infer their ownership. + +Selector items keep their non-enumerable, non-configurable getter bindings. A WeakMap +allows the same items to bind to a replacement after the prior entry closes; sharing +items across simultaneously active controls remains invalid. Each click keeps original +item/node/Event/this arguments and synchronous default flags. Only the latest active +selection may write a delayed title; removal invalidates pending writes. Background +clicks are ignored and owned callback failures are warned with their original value. +component/selection.ts links a click's active state to the builtin quality callback, +so late source-switch completion cannot overwrite a newer or removed quality notice. +Direct callback invocations retain their Promise result and original rejection. +Deferred builtin quality installation reports errors without an unhandled Promise. +This does not cancel arbitrary user onSelect work or change switchQuality's public +settlement contract. Highlight text uses dataset assignment rather than interpolation +into HTML attributes; normal text and marker positions retain their behavior. + +controls.less allows groups to wrap inside narrow players. Individual control height +continues to use --art-control-height; control/layout.ts observes total layout height +through offsetHeight and records --art-controls-height for subtitle/panel offsets. +ResizeObserver is preferred; the fallback combines core resize and MutationObserver. +Both observers and subscriptions are owned by the bottom controls scope. Without +ResizeObserver, unrelated parent CSS resizing is not independently detected until a +core resize or control mutation occurs. The 640/320/240px tests include real 16:9 +heights and verify all buttons remain visible. This does not promise arbitrary custom +minimum widths will fit. Narrow setting-tree/panel behavior remains CORE-14 work. + +Use test/component-resources.test.js for ownership, reentry and quality settlement, +test/types/components.ts for source contracts, and test/browser/components.spec.js +for published/candidate registries, real pointer/contextmenu controls, asynchronous +selectors, failures, actual layout and local-media progress. Run the full installed +UMD and legacy browser matrices after building, not only the source fixture suite. + ## Template and public resources `src/template.ts` owns container checks, reservation, proxy replacement and destruction. @@ -29,7 +97,7 @@ uses the actual HTMLElement shape. This mismatch remains tracked for CORE-21. `i18n/index.ts` owns selected language, deep updates and key fallback. Standalone language modules keep default exports and artplayer-i18n-* aliases through publish.ts. Only own language/message keys participate in lookup; absent prototype names now return -the requested string. Explicit custom constructor/toString/**proto** messages remain +the requested string. Explicit custom constructor/toString/`__proto__` messages remain supported. Empty translations still fall back. build:i18n excludes built-in zh-cn and helper modules, retaining exactly eleven UMD/ESM pairs and their historical globals. @@ -182,7 +250,7 @@ throw stops that dispatch and propagates unchanged. Off accepts either a once wr or its original callback; duplicate registrations of a callback are removed together. The once wrapper unsubscribes before invoking user code and now records consumption, so a nested dispatch cannot execute a captured copy twice. This fixes a demonstrated -old defect without changing ordinary snapshot behavior. Event names such as **proto** +old defect without changing ordinary snapshot behavior. Event names such as `__proto__` and toString use own properties rather than inherited Object.prototype values. Shared contracts in test/contracts/emitter.js run against published, workspace and @@ -472,5 +540,5 @@ core files in docs/compiled when committing a shippable core change. For new utility behavior, extend the same old/new contract tests. Clearly separate intentional defect corrections from preserved behavior. For timers or Blob URLs, also identify the owner and verify cleanup in the consuming module. Remaining -constructor, playback, UI, Component and capability migrations are recorded +constructor, playback, setting, input and capability migrations are recorded in refactor/tasks.json and should extend this map as they land. diff --git a/packages/artplayer/dist/artplayer.js b/packages/artplayer/dist/artplayer.js index e86e16adf..4782ac7ff 100644 --- a/packages/artplayer/dist/artplayer.js +++ b/packages/artplayer/dist/artplayer.js @@ -67,4 +67,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var o=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var a=t(r);if("boolean"===a)return"boolean";if("string"===a)return"string";if("number"===a)return"number";if("symbol"===a)return"symbol";if("function"===a)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(a=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return a.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function a(t,e){var o=2=1,p=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(s)||d,h="undefined"!==typeof window&&"undefined"!==typeof document;function u(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function m(t,e=document){return e.querySelector(t)}function f(t,e=document){return Array.from(e.querySelectorAll(t))}function g(t,e){return t.classList.add(e)}function v(t,e){return t.classList.remove(e)}function y(t,e){return t.classList.contains(e)}function b(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function w(t){return t.parentNode.removeChild(t)}function x(t,e,r){return t.style[e]=r,t}function k(t,e){for(const r in e)x(t,r,e[r]);return t}function $(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function E(t,e){$(t).forEach(t=>v(t,e)),g(t,e)}function T(t,e,r="top"){p||(t.setAttribute("aria-label",e),g(t,"hint--rounded"),g(t,`hint--${r}`))}function C(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,a=window.innerWidth||document.documentElement.clientWidth,n=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=a+e&&r.left+r.width+e>=0;return n&&i}function z(t,e){return R(t).includes(e)}function L(t,e){return e.parentNode.replaceChild(t,e),t}function S(t){return document.createElement(t)}function M(t="",e=""){const r=S("i");return g(r,"art-icon"),g(r,`art-icon-${t}`),b(r,e),r}function A(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function P(t){return t.getBoundingClientRect()}function I(t,e){return new Promise((r,o)=>{const a=new Image;a.onload=function(){if(e&&1!==e){const n=document.createElement("canvas"),i=n.getContext("2d");n.width=a.width*e,n.height=a.height*e,i.drawImage(a,0,0,n.width,n.height),n.toBlob(e=>{const a=URL.createObjectURL(e),n=new Image;n.onload=function(){r(n)},n.onerror=function(){URL.revokeObjectURL(a),o(new Error(`Image load failed: ${t}`))},n.src=a})}else r(a)},a.onerror=function(){o(new Error(`Image load failed: ${t}`))},a.src=t})}function R(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function O(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class _ extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function V(t,e){if(!t)throw new _(e);return t}function Y(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function N(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function D(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function F(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function H(t){return t.charAt(0).toUpperCase()+t.slice(1)}function B(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const W={"&":"&","<":"<",">":">","'":"'",'"':"""},j={"&":"&","<":"<",">":">","'":"'",""":'"'},U=/(&|<|>|'|")/g;function q(t){return t.replace(/[&<>'"]/g,t=>W[t]||t)}const X=Object.defineProperty,{hasOwnProperty:G}=Object.prototype;function K(t,e){return G.call(t,e)}function Z(t,e){return Object.getOwnPropertyDescriptor(t,e)}function J(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const a=t[o],n=r[o];let i;i=Array.isArray(a)&&Array.isArray(n)?a.concat(...n):e(a)&&e(n)?J(a,n):n,X(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function Q(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function tt(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function et(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,a="",n="",,,i=""]=o;return{start:r(a.trim()),end:r(n.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function rt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ot=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:_,addClass:g,append:b,assToVtt:et,capitalize:H,clamp:F,createElement:S,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:X,download:D,errorHandle:V,escape:q,get:Z,getComposedPath:R,getExt:N,getIcon:M,getRect:P,getSafeAreaInsets:O,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:K,hasClass:y,includeFromEvent:z,inverseClass:E,isBrowser:h,isIOS:c,isIOS13:d,isInViewport:C,isMobile:p,isSafari:l,loadImg:I,mergeDeep:J,query:m,queryAll:f,remove:w,removeClass:v,replaceElement:L,secondToTime:B,setStyle:x,setStyleText:u,setStyles:k,siblings:$,silencePromise:Y,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:Q,supportsFlex:A,throttle:rt,tooltip:T,unescape:function(t){return t.replace(U,t=>j[t]||t)},userAgent:s,vttToBlob:tt},Symbol.toStringTag,{value:"Module"})),at="array",nt="boolean",it="string",st="number",lt="object",ct="function";function dt(t,e,r){return V(e===it||e===st||t instanceof Element,`${r.join(".")} require '${it}' or 'Element' type`)}const pt={html:dt,disable:`?${nt}`,name:`?${it}`,index:`?${st}`,style:`?${lt}`,click:`?${ct}`,mounted:`?${ct}`,tooltip:`?${it}|${st}`,width:`?${st}`,selector:`?${at}`,onSelect:`?${ct}`,switch:`?${nt}`,onSwitch:`?${ct}`,range:`?${at}`,onRange:`?${ct}`,onChange:`?${ct}`},ht={id:it,container:dt,url:it,poster:it,type:it,theme:it,lang:it,volume:st,isLive:nt,muted:nt,autoplay:nt,autoSize:nt,autoMini:nt,loop:nt,flip:nt,playbackRate:nt,aspectRatio:nt,screenshot:nt,setting:nt,hotkey:nt,pip:nt,mutex:nt,backdrop:nt,fullscreen:nt,fullscreenWeb:nt,subtitleOffset:nt,miniProgressBar:nt,useSSR:nt,playsInline:nt,lock:nt,gesture:nt,fastForward:nt,autoPlayback:nt,autoOrientation:nt,airplay:nt,proxy:`?${ct}`,plugins:[ct],layers:[pt],contextmenu:[pt],settings:[pt],controls:[{...pt,position:(t,e,r)=>{const o=["top","left","right"];return V("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}}],quality:[{default:`?${nt}`,html:it,url:it}],highlight:[{time:st,text:it}],thumbnails:{url:it,number:st,column:st,width:st,height:st,scale:st},subtitle:{url:it,name:it,type:it,style:lt,escape:nt,encoding:it,onVttLoad:ct},moreVideoAttr:lt,i18n:lt,icons:lt,cssVar:lt,customType:lt};class ut{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return y(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?g(e,r):v(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",a(e,pt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;V(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=S("div");g(o,`art-${this.name}`),g(o,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const i=n.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));i?i.insertAdjacentElement("beforebegin",o):b(this.$parent,o),e.html&&b(o,e.html),e.style&&k(o,e.style),e.tooltip&&T(o,e.tooltip);const s=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});s.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,s),this[r]=o,this.cache.set(r,{$ref:o,events:s,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){V(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],w(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class mt extends ut{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,p||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,a=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=m('[data-value="1"]',t);r&&E(r,"art-current"),e.on("video:ratechange",()=>{const r=f("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&E(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,a=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=m('[data-value="default"]',t);r&&E(r,"art-current"),e.on("aspectRatio",e=>{const r=f("span",t).find(t=>t.dataset.value===e);r&&E(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,a=o.map(t=>`${r.get(H(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${a}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=m('[data-value="normal"]',t);r&&E(r,"art-current"),e.on("flip",e=>{const r=f("span",t).find(t=>t.dataset.value===e);r&&E(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return{...t,html:`ArtPlayer ${n}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,a=t.clientY,{height:n,width:i,left:s,top:l}=P(r),{height:c,width:d}=P(o);let p=e-s,h=a-l;e+d>s+i&&(p=i-d),a+c>l+n&&(h=n-c),k(o,{top:`${h}px`,left:`${p}px`})}),e(r,"click",t=>{z(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}class ft extends Error{constructor(t){super("Failed to release ArtPlayer resources"),this.errors=t,this.name="ResourceCleanupError"}}class gt{constructor(){this.cleanups=new Set,this.disposed=!1}get closed(){return this.disposed}add(t){let e=!0;const r=()=>{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new gt,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof ft?t.push(...e.errors):t.push(e)}if(t.length)throw new ft(t)}}const vt=new WeakMap,yt=new WeakMap;function bt(t){const e=vt.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function wt(t){return bt(t).scope}function xt(t){const e=bt(t);return e.destroying||e.scope.closed}function kt(t,e,r,o,a=!1){const n=bt(t);if(n.destroying||n.scope.closed)return;n.destroying=!0;const i=[],s=t=>{try{t()}catch(e){i.push(...e instanceof ft?e.errors:[e])}};o&&t.template?.$video&&s(()=>t.reset()),s(()=>n.scope.dispose()),s(()=>t.template?.destroy(r));const l=e.indexOf(t);-1!==l&&e.splice(l,1),t.isDestroy=!0,a||(n.releaseContainer?.(),n.releaseContainer=void 0),s(()=>t.emit("destroy")),a&&n.rollback&&s(n.rollback),n.rollback=void 0,n.releaseContainer?.(),n.releaseContainer=void 0;for(const c of i.slice(1))console.warn("Additional ArtPlayer cleanup failure:",c);if(i.length)throw i[0]}function $t(t,e,r){if(t.closed)return()=>{};let o=!0,a=()=>{};const n=setTimeout(()=>{o&&(a(),t.closed||e())},r);return a=t.add(()=>{o=!1,clearTimeout(n)}),a}function Et(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,a=()=>{};const n=setTimeout(()=>{o=!0,a(),r(!0)},e);a=t.add(()=>{clearTimeout(n),o||r(!1)})})}function Tt(t,e){const{$progress:r}=t.template,{left:o}=P(r),a=F((p?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),n=a/r.clientWidth*t.duration;return{second:n,time:B(n),width:a,percentage:F(a/r.clientWidth,0,1)}}function Ct(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Tt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function zt(t){return e=>{const{icons:r,option:o,proxy:a}=e,{$player:n,$progress:i}=e.template;return{...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=m(".art-progress-hover",t),d=m(".art-progress-loaded",t),h=m(".art-progress-played",t),u=m(".art-progress-highlight",t),f=m(".art-progress-indicator",t),y=m(".art-progress-tip",t);function w(r,o){const{width:a,time:n}=o||Tt(e,r);y.textContent=n||"00:00";const i=y.clientWidth;a<=i/2?x(y,"left",0):a>t.clientWidth-i/2?x(y,"left",t.clientWidth-i+"px"):x(y,"left",a-i/2+"px")}r.indicator?b(f,r.indicator):x(f,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,a){const i="played"===r&&a&&p;if("loaded"===r&&x(d,"width",100*o+"%"),"hover"===r&&(x(c,"width",100*o+"%"),z(a,u)?function(r){const{width:o}=Tt(e,r),{text:a}=r.target.dataset;y.textContent=a;const n=y.clientWidth;o<=n/2?x(y,"left",0):o>t.clientWidth-n/2?x(y,"left",t.clientWidth-n+"px"):x(y,"left",o-n/2+"px")}(a):w(a),0===o?v(n,"art-progress-hover"):g(n,"art-progress-hover")),"played"===r&&(x(h,"width",100*o+"%"),x(f,"left",100*o+"%")),i){g(n,"art-progress-hover");w(a,{width:t.clientWidth*o,time:B(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{v(n,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){u.textContent="";for(let t=0;t`;b(u,n)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),p||(a(i,"click",t=>{t.target!==f&&Ct(e,t)}),a(i,"mousemove",t=>{const{percentage:r}=Tt(e,t);e.emit("setBar","hover",r,t)}),a(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),a(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=Tt(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}}}}class Lt extends ut{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{p||(this.show=!0)}),t.on("click",()=>{p?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=z(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(v(r,"art-hide-cursor"),g(r,"art-hover"),this.timer=Date.now()):(g(r,"art-hide-cursor"),v(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(zt({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.play),i=b(t,o.pause);function s(){x(n,"display","flex"),x(i,"display","none")}function l(){x(n,"display","none"),x(i,"display","flex")}T(n,a.get("Play")),T(i,a.get("Pause")),r(n,"click",()=>{Y(e.play())}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>({...t,mounted:t=>{const{proxy:r,icons:o}=e,a=b(t,o.volume),n=b(t,o.volumeClose),i=b(t,'
'),s=b(i,'
'),l=b(s,'
'),c=b(s,'
'),d=b(c,'
'),h=b(d,'
'),u=b(c,'
');function m(t){const{top:e,height:r}=P(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)x(a,"display","none"),x(n,"display","flex"),x(u,"top","100%"),x(h,"top","100%"),l.textContent=0;else{const t=100*e.volume;x(a,"display","flex"),x(n,"display","none"),x(u,"top",100-t+"%"),x(h,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(a,"click",()=>{e.muted=!0}),r(n,"click",()=>{e.muted=!1}),p)x(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=m(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=m(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>({...t,style:p?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${B(e.currentTime)} / ${B(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let a=0;a{e&&!wt(this.art).closed&&(this.art.quality=t.quality)}),t.screenshot&&!p&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;b(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;b(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{T(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e;b(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{T(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;b(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.fullscreenWebOn),i=b(t,o.fullscreenWebOff);x(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(T(t,a.get("Exit Web Fullscreen")),x(n,"display","none"),x(i,"display","inline-flex")):(T(t,a.get("Web Fullscreen")),x(n,"display","inline-flex"),x(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:a}=e,n=b(t,o.fullscreenOn),i=b(t,o.fullscreenOff);x(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(T(t,a.get("Exit Fullscreen")),x(n,"display","none"),x(i,"display","inline-flex")):(T(t,a.get("Fullscreen")),x(n,"display","inline-flex"),x(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),X(e,"$control_item",{get:()=>r}),X(e,"$control_value",{get:()=>a})}const i=o(n,"click",async e=>{const r=R(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(a.innerHTML=await t.onSelect.call(this.art,o,o.$control_item,e))});r.push(i)}}function St(t,e,r,o){const a=e-o,n=r-t;let i=0;if(Math.abs(n)<2&&Math.abs(a)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(n,a);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function Mt(t){if(t.constructor.USE_RAF){const e=wt(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const a=requestAnimationFrame(a=>{r&&(o(),t.closed||e(a))});return o=t.add(()=>{r=!1,cancelAnimationFrame(a)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const At=new WeakMap;class Pt{constructor(t){this.destroyEvents=new Set;const e=wt(t);At.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:a}}=t;function n(e){z(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",n),t.on("document:contextmenu",n);let i=[];e.proxy(a,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:a,DBCLICK_TIME:n,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=n);switch(c.length){case 1:t.emit("click",e),p?!t.isLock&&a&&Y(t.toggle()):Y(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),p?!t.isLock&&s&&Y(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{g(r,"art-hover"),t.emit("hover",!0,e)},e=>{v(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const a=wt(t);let n=()=>{};const i=()=>{n(),n=$t(a,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(p&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let a=null,n=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){a===o&&Ct(t,e),n=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&n&&t.duration){const{pageX:o,pageY:n}=e.touches[0],c=St(i,s,o,n),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=F((o-i)/t.width,-1,1),d=F((n-s)/t.height,-1,1),p=t.isRotate?d:c,h=a===r?t.constructor.TOUCH_MOVE_RATIO:1,u=F(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",F(u/t.duration,0,1),e),t.notice.show=`${B(u)} / ${B(t.duration)}`}}},p=()=>{n&&(i=0,s=0,l=0,n=!1,a=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{a=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{a=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,a=rt(()=>{t.emit("view",C(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>a()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],a=[];function n(n={}){for(let t=0;t{const o=n.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});a.push(s)}),o.forEach(r=>{const o=n.window||i.ownerDocument?.defaultView||window,s=e.proxy(o,r,e=>{t.emit(`window:${r}`,e)});a.push(s)})}n(),e.bindGlobalEvents=n}(t,this),Mt(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(At.get(this).closed)return()=>{};t.addEventListener(e,r,o);const a=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(a),a}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class It{constructor(t){this.art=t,this.keys={},p||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{Y(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Vt{constructor(t){const e={..._t,...t.option.icons};for(const r in e)X(this,r,{get:()=>M(r,e[r])})}}class Yt extends ut{constructor(t){super(t),this.name="info",p||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:a}}=this.art;t(o,"click",()=>{this.show=!1});let n=()=>{};const i=f("[data-video]",r)||[];this.art.on("destroy",()=>n());const s=wt(this.art);!function t(){for(let e=0;e{x(a,"display","none"),x(n,"display",null)}),o.proxy(e.$state,"click",()=>Y(t.play()))}}class Ht{constructor(t){this.art=t,this.timer=null,wt(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(wt(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,g(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",v(r,"art-notice-show")},e.NOTICE_TIME)):v(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function Bt(t,e,r,o=!1){const a=e=>{xt(t)||r(e)};t[o?"once":"on"](e,a),wt(t).add(()=>{t.off(e,a)})}function Wt(t,e,r){for(const[o,a]of e){if(xt(t)||r&&!r())return;t[o].show=a}}const jt=new WeakMap,Ut=new WeakMap,qt=new WeakMap;function Xt(t){return qt.get(t)||wt(t)}function Gt(t){const e=jt.get(t),r=qt.get(t);return()=>jt.get(t)===e&&(!e||e.active())&&qt.get(t)===r&&(!r||!r.closed)}function Kt(t){const e=qt.get(t),r=wt(t).child(),o=r.child();qt.set(t,r),r.add(()=>{qt.get(t)===r&&qt.delete(t)});const a={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!xt(t)&&!o.closed&&jt.get(t)===a};return jt.set(t,a),o.add(()=>{jt.get(t)===a&&jt.delete(t),a.onAssigned=void 0,a.onError=void 0}),e?.dispose(),a}function Zt(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&e?.()}function Jt(t,e,r){Ut.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{Ut.get(t)===e&&(Ut.delete(t),Zt(e))}}function Qt(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function te(t){const{option:e,constructor:r,i18n:o,notice:a,template:{$player:n}}=t;let i,s=Xt(t),l=0;return{reset(){l=0,i?.dispose(),v(n,"art-error")},loadStart(){v(n,"art-error")},schedule(c){(async c=>{if(xt(t))return;const d=Xt(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const h=()=>!xt(t)&&!p.closed&&d===Xt(t),u=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ee(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{xt(t)||t.emit(`video:${e.type}`,e)})}(t);const e=te(t);!function(t,e){Bt(t,"video:canplay",()=>{e.reset(),Wt(t,[["loading",!1]])}),Bt(t,"video:canplay",()=>{Wt(t,[["loading",!1],["controls",!0],["mask",!0]]),xt(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;Bt(t,"video:ended",()=>{if(e.loop){const e=Gt(t);if(t.seek=0,xt(t)||!e())return;Y(t.play()),e()&&Wt(t,[["controls",!1],["mask",!1]],e)}else Wt(t,[["controls",!0],["mask",!0]])})}(t),Bt(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;Bt(t,"video:loadedmetadata",()=>{t.emit("resize"),p&&Wt(t,[["loading",!1],["controls",!0],["mask",!0]])}),Bt(t,"video:loadstart",()=>{e.loadStart(),Wt(t,[["loading",!0],["mask",!1],["controls",!0]])}),Bt(t,"video:pause",()=>{Wt(t,[["controls",!0],["mask",!0]])}),Bt(t,"video:play",()=>{Wt(t,[["mask",!1]]),xt(t)||x(r,"display","none")}),Bt(t,"video:playing",()=>Wt(t,[["mask",!1]])),Bt(t,"video:progress",()=>{t.playing&&Wt(t,[["loading",!1]])}),Bt(t,"video:seeked",()=>Wt(t,[["loading",!1],["mask",!0]])),Bt(t,"video:seeking",()=>Wt(t,[["loading",!0],["mask",!1]])),Bt(t,"video:timeupdate",()=>Wt(t,[["mask",!1]])),Bt(t,"video:waiting",()=>Wt(t,[["loading",!0],["mask",!1]]))}(t,e)}const re=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],oe=(()=>{if("undefined"===typeof document)return!1;const t=re[0],e={};for(const r of re){if(r[1]in document){for(const[o,a]of r.entries())e[t[o]]=a;return e}}return!1})(),ae={change:oe.fullscreenchange,error:oe.fullscreenerror},ne={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const a=()=>{ne.off("change",a),r()};ne.on("change",a);const n=t[oe.requestFullscreen](e);n instanceof Promise&&n.then(a).catch(o)}),exit:()=>new Promise((t,e)=>{if(!ne.isFullscreen)return void t();const r=()=>{ne.off("change",r),t()};ne.on("change",r);const o=document[oe.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>ne.isFullscreen?ne.exit():ne.request(t,e),onchange(t){ne.on("change",t)},onerror(t){ne.on("error",t)},on(t,e){const r=ae[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=ae[t];r&&document.removeEventListener(r,e,!1)},raw:oe};function ie(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;t.once("video:loadedmetadata",()=>{var n;ne.isEnabled?(n=t,ne.on("change",()=>{n.emit("fullscreen",ne.isFullscreen),ne.isFullscreen?(n.state="fullscreen",g(a,"art-fullscreen")):v(a,"art-fullscreen"),n.emit("resize")}),ne.on("error",t=>{n.emit("fullscreenError",t)}),X(n,"fullscreen",{get:()=>ne.isFullscreen,async set(t){t?await ne.request(a):await ne.exit()}})):o.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),X(t,"fullscreen",{get:()=>document.fullscreenElement===o,set(e){e?(t.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})})(t):X(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),X(t,"fullscreen",Z(t,"fullscreen"))})}function se(t){const{icons:e,proxy:r,storage:o,template:{$player:a,$video:n}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(v(a,"art-mini"),x(e,"display","none"),a.prepend(n),t.emit("mini",!1))}function d(e,r){t.playing?(x(e,"display","none"),x(r,"display","flex")):(x(e,"display","flex"),x(r,"display","none"))}function p(){const{$mini:e}=t.template,r=P(e),a=window.innerHeight-r.height-50,n=window.innerWidth-r.width-50;o.set("top",a),o.set("left",n),x(e,"top",`${a}px`),x(e,"left",`${n}px`)}X(t,"mini",{get:()=>y(a,"art-mini"),set(h){if(h){t.state="mini",g(a,"art-mini");const h=function(){const{$mini:a}=t.template;if(a)return b(a,n),x(a,"display","flex");{const a=S("div");g(a,"art-mini-popup"),b(document.body,a),t.template.$mini=a,b(a,n);const p=b(a,'
');b(p,e.close),r(p,"click",c);const h=b(a,'
'),u=b(h,e.play),m=b(h,e.pause);return r(u,"click",()=>Y(t.play())),r(m,"click",()=>t.pause()),d(u,m),t.on("video:playing",()=>d(u,m)),t.on("video:pause",()=>d(u,m)),t.on("video:timeupdate",()=>d(u,m)),r(a,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){g(a,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;x(a,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,v(a,"art-mini-dragging");const t=P(a);o.set("left",t.left),o.set("top",t.top),x(a,"left",`${t.left}px`),x(a,"top",`${t.top}px`),x(a,"transform",null)}}),a}}(),u=o.get("top"),m=o.get("left");"number"===typeof u&&"number"===typeof m?(x(h,"top",`${u}px`),x(h,"left",`${m}px`),C(h)||p()):p(),t.emit("mini",!0)}else c()}})}function le(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,X(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),X(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):X(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function ce(t,e,r,o,a=!0){let n,i=!1;const s=e=>{t.closed||i||(a&&(i=!0,n()),o(e))};return e[a?"once":"on"](r,s),n=t.add(()=>{e.off(r,s)}),s}function de(t,e,r){return new Promise((o,a)=>{if(xt(t)||e===t.url)return void o();const n=Kt(t),i=n.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,n.onError=void 0,n.onAssigned=void 0,i.dispose(),t?a(e):o(),t&&n.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&n.active(),d=t=>l(!0,t);n.onError=d;try{const{playing:o,aspectRatio:a,playbackRate:s}=t;if(t.pause(),!c())return;const p=i.child(),h={"video:error":d,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){d(e)}},"video:canplay":()=>{if(!c())return;p.dispose();(async()=>{if(t.playbackRate=s,c()&&(t.aspectRatio=a,c())){if(o)try{await t.play()}catch{}c()&&(t.notice.show="",l())}})().catch(d)}},u=i.child(),m=[],f=Object.keys(h);for(const e of f)ce(u,t,e,t=>{n.acceptingEvents&&m.push([e,t])},!1);if(Jt(t,n,e),!c())return;if(t.notice.show="",!c())return;const g=()=>{if(u.dispose(),!e)return void l();const r={};for(const e of f)r[e]=ce(p,t,e,h[e]);for(const[t,e]of m){if(!c()||p.closed)break;r[t](e)}m.length=0};n.assigned?g():n.onAssigned=g}catch(p){d(p)}})}function pe(t){const{option:e,template:{$progress:r,$video:o}}=t;let a=null,n=!1,i=null;t.on("setBar",async(a,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:h}=e.thumbnails;if(!c||!d)return;if("hover"===a||"played"===a&&l&&p){if(i||n||(n=!0,i=await I(d,h),n=!1),!i)return;const a=r.clientWidth*s;a>0&&ar.clientWidth-h/2?x(n,"left",r.clientWidth-h+"px"):x(n,"left",a-h/2+"px")}(a)}}),X(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(a),a=null,n=!1,i=null)}})}function he(t){const{option:e,template:{$video:r}}=t;X(t,"url",{get:()=>r.src,async set(o){if(xt(t))return;const a=function(t){const e=Ut.get(t);return Ut.delete(t),e||Kt(t)}(t);a.acceptingEvents=!1;try{if(!o)return void(await Et(a.scope)&&a.active()&&(t.loading.show=!0));const n=t.url,i=e.type||N(o),s=e.customType[i];if(i&&s){if(!(await Et(a.scope))||!a.active())return;t.loading.show=!0}if(!a.active())return;const l=a.scope.child();let c=!1,d=!1;ce(l,t,"video:canplay",()=>{c=!d}),ce(l,t,"video:error",()=>{d=!0});try{if(a.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>Qt(a,t))}else{if(n&&URL.revokeObjectURL(n),!a.active())return;r.src=o}}finally{l.dispose()}if(!a.active())return;if(n!==t.url&&(t.option.url=o,a.active()&&t.isReady&&n)){const e=()=>{a.active()&&t.emit("restart",o)};c?e():d||ce(a.scope,t,"video:canplay",e)}}catch(n){Qt(a,n)}finally{Zt(a)}}})}Object.defineProperties(ne,{isFullscreen:{get:()=>Boolean(document[oe.fullscreenElement])},element:{enumerable:!0,get:()=>document[oe.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[oe.fullscreenEnabled])}});class ue{constructor(t){he(t),function(t){const{template:{$video:e}}=t;X(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:a},template:{$video:n}}=t;X(t,"play",{async value(){const i=Gt(t),s=await n.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;X(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${B(t.currentTime)} / ${B(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;X(t,"forward",{set(e){r.seek=t.currentTime+e}}),X(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:a}=t;X(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=F(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&a.set("volume",e.volume)}}),X(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;X(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=F(o,0,t.duration))}})}(t),function(t){X(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>de(t,e,0);X(t,"switchQuality",{value:e=>de(t,e,t.currentTime)}),X(t,"switchUrl",{value:e}),X(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,a=t;X(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else a.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:a}}=t;X(t,"aspectRatio",{get:()=>a.dataset.aspectRatio||"default",set(n){if(n||(n="default"),"default"===n)x(o,"width",null),x(o,"height",null),x(o,"margin",null),delete a.dataset.aspectRatio;else{const t=n.split(":").map(Number),{clientWidth:e,clientHeight:r}=a,i=e/r,s=t[0]/t[1];i>s?(x(o,"width",s*r+"px"),x(o,"height","100%"),x(o,"margin","0 auto")):(x(o,"width","100%"),x(o,"height",e/s+"px"),x(o,"margin","auto 0")),a.dataset.aspectRatio=n}r.show=`${e.get("Aspect Ratio")}: ${"default"===n?e.get("Default"):n}`,t.emit("aspectRatio",n)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=S("canvas");X(t,"getDataURL",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(n){e.show=n,a(n)}})}),X(t,"getBlobUrl",{value:()=>new Promise((t,a)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(n){e.show=n,a(n)}})}),X(t,"screenshot",{value:async e=>{const o=await t.getDataURL();return D(o,`${e||`artplayer_${B(r.currentTime)}`}.png`),t.emit("screenshot",o),o}})}(t),ie(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let a="";X(t,"fullscreenWeb",{get:()=>y(o,"art-fullscreen-web"),set(n){n?(a=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&b(document.body,o),t.state="fullscreenWeb",x(o,"width","100%"),x(o,"height","100%"),g(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&b(r,o),a&&(o.style.cssText=a,a=""),v(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),le(t),function(t){const{$video:e}=t.template,r=t;X(t,"loaded",{get:()=>r.loadedTime/e.duration}),X(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){X(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;X(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;X(t,"autoSize",{value(){const{videoWidth:a,videoHeight:n}=o,{width:i,height:s}=P(e),l=a/n;if(i/s>l)x(r,"width",s*l/i*100+"%"),x(r,"height","100%");else{const t=i/l/s*100;x(r,"width","100%"),x(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;X(t,"rect",{get:()=>P(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[a]})}X(t,"x",{get:()=>e.left+window.pageXOffset}),X(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;X(t,"flip",{get:()=>e.dataset.flip||"normal",set(a){a||(a="normal"),"normal"===a?delete e.dataset.flip:e.dataset.flip=a,o.show=`${r.get("Video Flip")}: ${r.get(H(a))}`,t.emit("flip",a)}})}(t),se(t),function(t){const{template:{$poster:e}}=t;X(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){x(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;X(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:a,videoWidth:n}=r,i=a*(o/n);x(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;X(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){X(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){X(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];X(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;oo.$track?.offset||0,set(a){const{cues:n}=t.subtitle;if(!o.$track||0===n.length)return;const i=F(a,-10,10);o.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":n=!0;break;case"not-available":n=!1}}):n=!1,X(t,"airplay",{value(){n?(a.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){X(t,"quality",{set(e){const{controls:r,notice:o,i18n:a}=t,n=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:n?.html||"",selector:e,onSelect:async e=>(await t.switchQuality(e.url),o.show=`${a.get("Switch Video")}: ${e.html}`,e.html)})}})}(t),pe(t),ee(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:a}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=F(e.volume,0,1));const n=r.get("volume");"number"===typeof n&&(o.volume=F(n,0,1)),e.poster&&x(a,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function me(t){const{notice:e,constructor:r,template:{$player:o,$video:a}}=t,n="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=a,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!y(o,n)&&function(){const e=O(),r=document.documentElement.clientWidth,a=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;x(o,"width",`${a}px`),x(o,"height",`${i}px`),x(o,"transform-origin","0 0"),x(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),g(o,n),t.isRotate=!0,t.emit("resize")}()},e)}}else y(o,n)&&(x(o,"width",""),x(o,"height",""),x(o,"transform-origin",""),x(o,"transform",""),v(o,n),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,g(o,i)}catch(a){s=!1,e.show=a}}else if(y(o,i)&&v(o,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return y(o,n)}}}function fe(t){const{i18n:e,icons:r,storage:o,constructor:a,proxy:n,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=m(".art-auto-playback-last",s),c=m(".art-auto-playback-jump",s),d=m(".art-auto-playback-close",s);b(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),x(s,"display","none"),r&&r>=a.AUTO_PLAYBACK_MIN&&(x(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${B(r)}`,c.textContent=e.get("Jump Play"),n(d,"click",()=>{x(s,"display","none")}),n(c,"click",()=>{t.seek=r,Y(t.play()),x(i,"display","none"),x(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{x(s,"display","none")},a.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>a.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function ge(t){const{constructor:e,proxy:r,template:{$player:o,$video:a}}=t;let n=null,i=!1,s=1;const l=()=>{clearTimeout(n),i&&(i=!1,t.playbackRate=s,v(o,"art-fast-forward"))};return r(a,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(n=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,g(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return y(o,"art-fast-forward")}}}function ve(t){const{layers:e,icons:r,template:{$player:o}}=t;function a(){return y(o,"art-lock")}function n(){g(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){v(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=b(e,r.lock),a=b(e,r.unlock);x(o,"display","none"),t.on("lock",t=>{t?(x(o,"display","inline-flex"),x(a,"display","none")):(x(o,"display","none"),x(a,"display","inline-flex"))})},click(){a()?i():n()}}),{name:"lock",get state(){return a()},set state(t){t?n():i()}}}function ye(t){return t.on("control",e=>{e?v(t.template.$player,"art-mini-progress-bar"):g(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class be{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){xt(t.art)||!e.miniProgressBar||e.isLive||t.add(ye),!xt(t.art)&&e.lock&&p&&t.add(ve),xt(t.art)||!e.autoPlayback||e.isLive||t.add(fe),!xt(t.art)&&e.autoOrientation&&p&&t.add(me),!xt(t.art)&&e.fastForward&&p&&!e.isLive&&t.add(ge)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){V(!xt(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(xt(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(xt(t.art))return t;let a=o;const n=K(t,a);if(xt(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return xt(t.art)||(V(!n,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(a=Reflect.ownKeys({[a]:void 0})[0]),xt(t.art)||X(t,a,{value:r})),t}(this,t,e)}}class we extends ut{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=z(t,r.setting),o=z(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:a}}=t;function n(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:n(t.playbackRate),icon:r.playbackRate,selector:a.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:n(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:a}}=t;function n(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:n(t.aspectRatio),selector:a.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:n(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:a}}=t;function n(t){return e.get(H(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:n(t.flip),icon:r.flip,selector:a.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:n(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&E(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let a=0;ae}),X(n,"$parents",{get:()=>r}),X(n,"$option",{get:()=>t});const o=[];X(n,"$events",{get:()=>o}),X(n,"$formatted",{get:()=>!0})}this.format(n.selector||[],n,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:o,$setting:a}}=this.art;if(t.setting&&this.show){const n=this.active[0]?.$parent?.width||e,{left:i,width:s}=P(t.setting),{left:l,width:c}=P(o),d=i-l+s/2-n/2;if(x(a,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),x(a,"width",`${n}px`),this.art.isRotate||p)return;d+n>c?(x(a,"left",null),x(a,"right",null)):(x(a,"left",`${d}px`),x(a,"right","auto"))}}inactivate(t){for(let e=0;e'),s=S("div");g(s,"art-setting-item-left-icon"),b(s,o),b(i,s),b(i,t.$parent.html);const l=r(n,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),b(e,n)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),o=t.$item;let a="selector";K(t,"switch")&&(a="switch"),K(t,"range")&&(a="range"),K(t,"onClick")&&(a="button");const{icons:n,proxy:i,constructor:s}=this.art,l=S("div");g(l,"art-setting-item"),x(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=b(l,'
'),d=b(l,'
'),p=S("div");switch(g(p,"art-setting-item-left-icon"),a){case"button":case"switch":case"range":b(p,t.icon||n.config);break;case"selector":t.selector?.length?b(p,t.icon||n.config):b(p,n.check)}b(c,p),X(t,"$icon",{configurable:!0,get:()=>p}),X(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",b(p,t)}});const h=S("div");g(h,"art-setting-item-left-text"),b(h,t.html||""),b(c,h),X(t,"$html",{configurable:!0,get:()=>h}),X(t,"html",{configurable:!0,get:()=>h.innerHTML,set(t){h.innerHTML="",b(h,t)}});const u=S("div");switch(g(u,"art-setting-item-right-tooltip"),b(u,t.tooltip||""),b(d,u),X(t,"$tooltip",{configurable:!0,get:()=>u}),X(t,"tooltip",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",b(u,t)}}),a){case"switch":{const e=S("div");g(e,"art-setting-item-right-icon");const r=b(e,n.switchOn),o=b(e,n.switchOff);x(t.switch?o:r,"display","none"),b(d,e),X(t,"$switch",{configurable:!0,get:()=>e});let a=t.switch;X(t,"switch",{configurable:!0,get:()=>a,set(t){a=t,t?(x(o,"display","none"),x(r,"display",null)):(x(o,"display",null),x(r,"display","none"))}});break}case"range":{const e=S("div");g(e,"art-setting-item-right-icon");const r=b(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],g(r,"art-setting-range"),b(d,e),X(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];X(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=S("div");g(t,"art-setting-item-right-icon"),b(t,n.arrowRight),b(d,t)}}switch(a){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&g(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}X(t,"$item",{configurable:!0,get:()=>l}),e?L(l,o):b(r,l),t.mounted&&$t(wt(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){E(this.cache.get(t),"art-current")}else{const e=S("div");this.cache.set(t,e),g(e,"art-setting-panel"),b(this.$parent,e),E(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?k(r,t):x(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?q(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:o,option:a}=this.art,n={...a.subtitle,...e,url:t},i=await this.init(n);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:o,option:a}=this.art,{$video:n,$track:i}=r,s=S("track");s.default=!0,s.kind=t,s.src=e,s.label=a.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,w(i),b(n,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(a(t,ht.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||N(t.url)){case"srt":{const e=Q(r);return tt(t.onVttLoad(e))}case"ass":{const e=et(r);return tt(t.onVttLoad(e))}case"vtt":return tt(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}const Ee=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${n}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Te{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=m(e.container),V(this.$container,`No container element found by ${e.container}`)),V(A(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();V("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),V(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=yt.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const a=bt(t);a.rollback=r,yt.set(e,t),a.releaseContainer=()=>{yt.get(e)===t&&yt.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:a}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=a}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ee}query(t){return m(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Te.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){V(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),L(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&g(this.$player,"art-backdrop"),p&&g(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":g(this.$player,"art-destroy")}}const Ce=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class ze{on(t,e,r){const o=this.e||(this.e={});let a=Ce(o,t)?o[t]:void 0;return a||(a=[],Object.defineProperty(o,t,{value:a,enumerable:!0,configurable:!0,writable:!0})),a.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,a=e;let n=!1;function i(...e){n||(n=!0,o.off(t,i),a.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Ce(r,t)&&r[t]||[]).slice();for(const a of o)a.fn.apply(a.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Ce(r,t)?r[t]:void 0,a=[];if(o&&e)for(let n=0,i=o.length;ne.call(this,this)),Me.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Me.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=bt(t);return e.rollback=void 0,!e.scope.closed})(this)&&Se.push(this)}catch(o){try{kt(this,Se,!0,Me.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return Se}static get version(){return n}static get config(){return i}static get utils(){return ot}static get scheme(){return ht}static get Emitter(){return ze}static get validator(){return a}static get kindOf(){return a.kindOf}static get html(){return Te.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:l?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){kt(this,Se,t,Me.REMOVE_SRC_WHEN_DESTROY)}}return Me.STYLE=ke,Me.DEBUG=!1,Me.CONTEXTMENU=!0,Me.NOTICE_TIME=2e3,Me.SETTING_WIDTH=250,Me.SETTING_ITEM_WIDTH=200,Me.SETTING_ITEM_HEIGHT=35,Me.RESIZE_TIME=200,Me.SCROLL_TIME=200,Me.SCROLL_GAP=50,Me.AUTO_PLAYBACK_MAX=10,Me.AUTO_PLAYBACK_MIN=5,Me.AUTO_PLAYBACK_TIMEOUT=3e3,Me.RECONNECT_TIME_MAX=5,Me.RECONNECT_SLEEP_TIME=1e3,Me.CONTROL_HIDE_TIME=3e3,Me.DBCLICK_TIME=300,Me.DBCLICK_FULLSCREEN=!0,Me.MOBILE_DBCLICK_PLAY=!0,Me.MOBILE_CLICK_PLAY=!1,Me.AUTO_ORIENTATION_TIME=200,Me.INFO_LOOP_TIME=1e3,Me.FAST_FORWARD_VALUE=3,Me.FAST_FORWARD_TIME=1e3,Me.TOUCH_MOVE_RATIO=.5,Me.VOLUME_STEP=.1,Me.SEEK_STEP=5,Me.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Me.ASPECT_RATIO=["default","4:3","16:9"],Me.FLIP=["normal","horizontal","vertical"],Me.FULLSCREEN_WEB_IN_BODY=!0,Me.LOG_VERSION=!0,Me.USE_RAF=!1,Me.REMOVE_SRC_WHEN_DESTROY=!0,h&&(window.Artplayer=Me,u("artplayer-style",ke),setTimeout(()=>{Me.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Me.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Me}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";function t(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var e,r={exports:{}};var o=(e||(e=1,r.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new l,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof s?t.push(...e.errors):t.push(e)}if(t.length)throw new s(t)}}const c=new WeakMap,d=new WeakMap;function p(t){const e=c.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function h(t){return p(t).scope}function u(t){const e=p(t);return e.destroying||e.scope.closed}function f(t,e,r,o,n=!1){const a=p(t);if(a.destroying||a.scope.closed)return;a.destroying=!0;const i=[],l=t=>{try{t()}catch(e){i.push(...e instanceof s?e.errors:[e])}};o&&t.template?.$video&&l(()=>t.reset()),l(()=>a.scope.dispose()),l(()=>t.template?.destroy(r));const c=e.indexOf(t);-1!==c&&e.splice(c,1),t.isDestroy=!0,n||(a.releaseContainer?.(),a.releaseContainer=void 0),l(()=>t.emit("destroy")),n&&a.rollback&&l(a.rollback),a.rollback=void 0,a.releaseContainer?.(),a.releaseContainer=void 0;for(const s of i.slice(1))console.warn("Additional ArtPlayer cleanup failure:",s);if(i.length)throw i[0]}const m=new WeakMap;function g(t,e){const r=h(t).child();return m.set(e,r),r}function v(t){const e=m.get(t);if(!e)throw new Error("ArtPlayer component has not been registered");return e}function y(t){m.get(t)?.dispose()}function b(t,e){return{on:(r,o)=>{!function(t,e,r,o){const n=v(e);if(n.closed)return;const a=(...t)=>{if(!n.closed)return o(...t)};t.on(r,a),n.add(()=>{t.off(r,a)})}(t,e,r,o)},proxy:(r,o,n)=>function(t,e,r,o,n){const a=v(e);if(a.closed)return()=>{};const i=t.events.proxy(r,o,t=>{if(!a.closed)return n(t)});return a.add(()=>{t.events.remove(i)})}(t,e,r,o,n)}}const w=globalThis?.CUSTOM_USER_AGENT??("undefined"!==typeof navigator?navigator.userAgent:""),x=/^(?:(?!chrome|android).)*safari/i.test(w),k=/iPad|iPhone|iPod/i.test(w)&&!window.MSStream,$=k||w.includes("Macintosh")&&navigator.maxTouchPoints>=1,E=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(w)||$,T="undefined"!==typeof window&&"undefined"!==typeof document;function C(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function z(t,e=document){return e.querySelector(t)}function S(t,e=document){return Array.from(e.querySelectorAll(t))}function L(t,e){return t.classList.add(e)}function M(t,e){return t.classList.remove(e)}function A(t,e){return t.classList.contains(e)}function P(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function I(t){return t.parentNode.removeChild(t)}function O(t,e,r){return t.style[e]=r,t}function R(t,e){for(const r in e)O(t,r,e[r]);return t}function _(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function V(t,e){_(t).forEach(t=>M(t,e)),L(t,e)}function Y(t,e,r="top"){E||(t.setAttribute("aria-label",e),L(t,"hint--rounded"),L(t,`hint--${r}`))}function D(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function N(t,e){return U(t).includes(e)}function F(t,e){return e.parentNode.replaceChild(t,e),t}function H(t){return document.createElement(t)}function B(t="",e=""){const r=H("i");return L(r,"art-icon"),L(r,`art-icon-${t}`),P(r,e),r}function W(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function j(t){return t.getBoundingClientRect()}function q(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function U(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function X(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class G extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function K(t,e){if(!t)throw new G(e);return t}function Z(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function J(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function Q(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function tt(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function et(t){return t.charAt(0).toUpperCase()+t.slice(1)}function rt(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const ot={"&":"&","<":"<",">":">","'":"'",'"':"""},nt={"&":"&","<":"<",">":">","'":"'",""":'"'},at=/(&|<|>|'|")/g;function it(t){return t.replace(/[&<>'"]/g,t=>ot[t]||t)}const st=Object.defineProperty,{hasOwnProperty:lt}=Object.prototype;function ct(t,e){return lt.call(t,e)}function dt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function pt(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?pt(n,a):a,st(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function ht(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function ut(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function ft(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function mt(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const gt=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:G,addClass:L,append:P,assToVtt:ft,capitalize:et,clamp:tt,createElement:H,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:st,download:Q,errorHandle:K,escape:it,get:dt,getComposedPath:U,getExt:J,getIcon:B,getRect:j,getSafeAreaInsets:X,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:ct,hasClass:A,includeFromEvent:N,inverseClass:V,isBrowser:T,isIOS:k,isIOS13:$,isInViewport:D,isMobile:E,isSafari:x,loadImg:q,mergeDeep:pt,query:z,queryAll:S,remove:I,removeClass:M,replaceElement:F,secondToTime:rt,setStyle:O,setStyleText:C,setStyles:R,siblings:_,silencePromise:Z,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:ht,supportsFlex:W,throttle:mt,tooltip:Y,unescape:function(t){return t.replace(at,t=>nt[t]||t)},userAgent:w,vttToBlob:ut},Symbol.toStringTag,{value:"Module"}));function vt(t,e){return P(t,e)}function yt(t,e){return e.querySelector(t)}const bt="array",wt="boolean",xt="string",kt="number",$t="object",Et="function";function Tt(t,e,r){return K(e===xt||e===kt||t instanceof Element,`${r.join(".")} require '${xt}' or 'Element' type`)}const Ct={html:Tt,disable:`?${wt}`,name:`?${xt}`,index:`?${kt}`,style:`?${$t}`,click:`?${Et}`,mounted:`?${Et}`,tooltip:`?${xt}|${kt}`,width:`?${kt}`,selector:`?${bt}`,onSelect:`?${Et}`,switch:`?${wt}`,onSwitch:`?${Et}`,range:`?${bt}`,onRange:`?${Et}`,onChange:`?${Et}`},zt={id:xt,container:Tt,url:xt,poster:xt,type:xt,theme:xt,lang:xt,volume:kt,isLive:wt,muted:wt,autoplay:wt,autoSize:wt,autoMini:wt,loop:wt,flip:wt,playbackRate:wt,aspectRatio:wt,screenshot:wt,setting:wt,hotkey:wt,pip:wt,mutex:wt,backdrop:wt,fullscreen:wt,fullscreenWeb:wt,subtitleOffset:wt,miniProgressBar:wt,useSSR:wt,playsInline:wt,lock:wt,gesture:wt,fastForward:wt,autoPlayback:wt,autoOrientation:wt,airplay:wt,proxy:`?${Et}`,plugins:[Et],layers:[Ct],contextmenu:[Ct],settings:[Ct],controls:[{...Ct,position:(t,e,r)=>{const o=["top","left","right"];return K("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}}],quality:[{default:`?${wt}`,html:xt,url:xt}],highlight:[{time:kt,text:xt}],thumbnails:{url:xt,number:kt,column:kt,width:kt,height:kt,scale:kt},subtitle:{url:xt,name:xt,type:xt,style:$t,escape:wt,encoding:xt,onVttLoad:Et},moreVideoAttr:$t,i18n:$t,icons:$t,cssVar:$t,customType:$t},St=new WeakSet;class Lt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return A(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?L(e,r):M(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){if(u(this.art))return;const e="function"===typeof t?t(this.art):t;if(u(this.art))return;if(e.html=e.html||"",n(e,Ct),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`,o=this.cache;K(!o.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const a=document.createElement("div"),i=g(this.art,a),s=[],l=Object.getOwnPropertyDescriptor(this,r);let c=!1;i.add(()=>{for(const t of s)this.art.events.remove(t)});try{if(i.closed)return;if(function(t,e,r,o,n,a){L(t,`art-${r}`),L(t,`art-${r}-${o}`);const i=Array.from(e.children);t.dataset.index=String(a.index||n);const s=i.find(e=>Number(e.dataset.index)>=Number(t.dataset.index));s?s.insertAdjacentElement("beforebegin",t):P(e,t),a.html&&P(t,a.html),a.style&&R(t,a.style),a.tooltip&&Y(t,a.tooltip)}(a,this.$parent,this.name,r,this.id,e),i.closed)return;if(e.click){const t=this.art.events.proxy(a,"click",t=>{i.closed||(t.preventDefault(),e.click.call(this.art,this,t))});s.push(t)}if(e.selector&&["left","right"].includes(e.position)&&this.selector(e,a,s),i.closed)return;return function(t,e,r){const o=t;"__proto__"===e?Object.defineProperty(o,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):o[e]=r}(this,r,a),c=!0,o.set(r,{$ref:a,events:s,option:e}),e.mounted&&e.mounted.call(this.art,a),a}catch(d){try{y(a)}catch(p){console.warn("ArtPlayer component cleanup failed:",p)}throw o.get(r)?.$ref===a&&o.delete(r),c&&this[r]===a&&(l?Object.defineProperty(this,r,l):delete this[r]),a.remove(),d}}remove(t){K(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);if(!St.has(e)){St.add(e);try{e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);try{y(e.$ref)}finally{this.cache.get(t)===e&&(this.cache.delete(t),delete this[t]),e.$ref.remove()}}finally{St.delete(e)}}}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Mt extends Lt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,g(t,this.$parent),E||this.init()}init(){const{option:t,template:{$player:e,$contextmenu:r}}=this.art,{on:o,proxy:n}=b(this.art,r);t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return{...t,html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="1"]',t);o&&V(o,"art-current"),r("video:ratechange",()=>{const r=Array.from(t.querySelectorAll("span")).find(t=>Number(t.dataset.value)===e.playbackRate);r&&V(r,"art-current")})}}}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return{...t,html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="default"]',t);o&&V(o,"art-current"),r("aspectRatio",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&V(r,"art-current")})}}}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(et(t))}`).join("");return{...t,html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const{on:r}=b(e,t),o=z('[data-value="normal"]',t);o&&V(o,"art-current"),r("flip",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&V(r,"art-current")})}}}}({name:"flip",index:30})),this.add(function(t){return e=>({...t,html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return{...t,html:`ArtPlayer ${a}`}}({name:"version",index:50})),this.add(function(t){return e=>({...t,html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const o=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=j(e),{height:c,width:d}=j(r);let p=o-s,h=n-l;o+d>s+i&&(p=i-d),n+c>l+a&&(h=a-c),R(r,{top:`${h}px`,left:`${p}px`})}),n(e,"click",t=>{N(t,r)||(this.show=!1)}),o("blur",()=>{this.show=!1})}}function At(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Pt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function It(t,e){const{$progress:r}=t.template,{left:o}=j(r),n=tt((E?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:rt(a),width:n,percentage:tt(n/r.clientWidth,0,1)}}function Ot(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=It(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Rt(t,e){const{icons:r,option:o}=t,{$player:n}=t.template,a=v(e),{on:i}=b(t,e);let s=()=>{};const l=yt(".art-progress-hover",e),c=yt(".art-progress-loaded",e),d=yt(".art-progress-played",e),p=yt(".art-progress-highlight",e),h=yt(".art-progress-indicator",e),u=yt(".art-progress-tip",e);function f(r,o){const{width:n,time:a}=o||It(t,r);u.textContent=a||"00:00";const i=u.clientWidth;n<=i/2?O(u,"left",0):n>e.clientWidth-i/2?O(u,"left",e.clientWidth-i+"px"):O(u,"left",n-i/2+"px")}r.indicator?P(h,r.indicator):O(h,"backgroundColor","var(--art-theme)"),i("setBar",function(r,o,i){const m="played"===r&&i&&E;if("loaded"===r&&O(c,"width",100*o+"%"),"hover"===r&&(O(l,"width",100*o+"%"),N(i,p)?function(r){const{width:o}=It(t,r),n=r.target instanceof HTMLElement?r.target.dataset.text:void 0;u.textContent=n??"";const a=u.clientWidth;o<=a/2?O(u,"left",0):o>e.clientWidth-a/2?O(u,"left",e.clientWidth-a+"px"):O(u,"left",o-a/2+"px")}(i):f(i),0===o?M(n,"art-progress-hover"):L(n,"art-progress-hover")),"played"===r&&(O(d,"width",100*o+"%"),O(h,"left",100*o+"%")),m){L(n,"art-progress-hover");f(i,{width:e.clientWidth*o,time:rt(o*t.duration)}),s(),s=At(a,()=>{M(n,"art-progress-hover")},500)}}),i("video:loadedmetadata",function(){p.textContent="";for(let e=0;e{t.emit("setBar","played",t.played),t.emit("setBar","loaded",t.loaded)}):(i("video:timeupdate",()=>{t.emit("setBar","played",t.played)}),i("video:progress",()=>{t.emit("setBar","loaded",t.loaded)}),i("video:ended",()=>{t.emit("setBar","played",1)})),t.emit("setBar","loaded",t.loaded||0)}function _t(t){return e=>({...t,html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{Rt(e,t),function(t,e){const{$progress:r}=t.template,o=e.querySelector(".art-progress-indicator"),{on:n,proxy:a}=b(t,e);if(!E){let e=!1;a(r,"click",e=>{e.target!==o&&Ot(t,e)}),a(r,"mousemove",e=>{const{percentage:r}=It(t,e);t.emit("setBar","hover",r,e)}),a(r,"mouseleave",e=>{t.emit("setBar","hover",0,e)}),a(r,"mousedown",t=>{e=0===t.button}),n("document:mousemove",r=>{if(e){const{second:e,percentage:o}=It(t,r);t.emit("setBar","played",o,r),t.seek=e}}),n("document:mouseup",()=>{e&&(e=!1)})}}(e,t)}})}function Vt(t){const{option:e}=t.art;e.isLive||t.add(_t({name:"progress",position:"top",index:10})),t.add({name:"thumbnails",position:"top",index:20}),t.add(function(t){return e=>({...t,mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.play),s=vt(t,n.pause);function l(){O(i,"display","flex"),O(s,"display","none")}function c(){O(i,"display","none"),O(s,"display","flex")}Y(i,a.get("Play")),Y(s,a.get("Pause")),o(i,"click",()=>{Z(e.play())}),o(s,"click",()=>{e.pause()}),e.playing?c():l(),r("video:playing",()=>{c()}),r("video:pause",()=>{l()})}})}({name:"playAndPause",position:"left",index:10})),t.add(function(t){return e=>({...t,mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n}=e,a=vt(t,n.volume),i=vt(t,n.volumeClose),s=vt(t,'
'),l=vt(s,'
'),c=vt(l,'
'),d=vt(l,'
'),p=vt(d,'
'),h=vt(p,'
'),u=vt(d,'
');function f(t){const{top:e,height:r}=j(d);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)O(a,"display","none"),O(i,"display","flex"),O(u,"top","100%"),O(h,"top","100%"),c.textContent="0";else{const t=100*e.volume;O(a,"display","flex"),O(i,"display","none"),O(u,"top",100-t+"%"),O(h,"top",100-t+"%"),c.textContent=String(Math.floor(t))}}if(m(),r("video:volumechange",m),o(a,"click",()=>{e.muted=!0}),o(i,"click",()=>{e.muted=!1}),E)O(s,"display","none");else{let t=!1;o(d,"mousedown",r=>{t=0===r.button,e.volume=f(r)}),r("document:mousemove",r=>{t&&(e.muted=!1,e.volume=f(r))}),r("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),e.isLive||t.add(function(t){return e=>({...t,style:E?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{const{on:r}=b(e,t);function o(){const r=`${rt(e.currentTime)} / ${rt(e.duration)}`;r!==t.textContent&&(t.textContent=r)}o();const n=["video:loadedmetadata","video:timeupdate","video:progress"];for(let e=0;e{r&&!h(t.art).closed&&(t.art.quality=e.quality)}).catch(t=>{console.warn("ArtPlayer quality initialization failed:",t)}),e.screenshot&&!E&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r}=b(e,t),{icons:o}=e;vt(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),e.setting&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e;vt(t,n.setting),o(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),r("setting",e=>{Y(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),e.pip&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e;vt(t,n.pip),o(t,"click",()=>{e.pip=!e.pip}),r("pip",e=>{Y(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),e.airplay&&"WebKitPlaybackTargetAvailabilityEvent"in window&&window.WebKitPlaybackTargetAvailabilityEvent&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r}=b(e,t),{icons:o}=e;vt(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),e.fullscreenWeb&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.fullscreenWebOn),s=vt(t,n.fullscreenWebOff);O(s,"display","none"),o(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),r("fullscreenWeb",e=>{e?(Y(t,a.get("Exit Web Fullscreen")),O(i,"display","none"),O(s,"display","inline-flex")):(Y(t,a.get("Web Fullscreen")),O(i,"display","inline-flex"),O(s,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),e.fullscreen&&t.add(function(t){return e=>({...t,tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{on:r,proxy:o}=b(e,t),{icons:n,i18n:a}=e,i=vt(t,n.fullscreenOn),s=vt(t,n.fullscreenOff);O(s,"display","none"),o(t,"click",()=>{e.fullscreen=!e.fullscreen}),r("fullscreen",e=>{e?(Y(t,a.get("Exit Fullscreen")),O(i,"display","none"),O(s,"display","inline-flex")):(Y(t,a.get("Fullscreen")),O(i,"display","inline-flex"),O(s,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let r=0;rDt.get(t).option.selector}),st(t,"$control_item",{get:()=>Dt.get(t).item}),st(t,"$control_value",{get:()=>Dt.get(t).value})),Dt.set(t,e)}function Ft(t,e){t.innerHTML=e}function Ht(t,e,r,o,n){const{proxy:a}=t.events,i=v(o),s=r.selector;L(o,"art-control-selector");const l=document.createElement("div");L(l,"art-selector-value"),P(l,r.html),o.textContent="",P(o,l);const c=vt(o,'
');for(let h=0;h{if(i.closed)return;const n=U(o),a=r.selector.find(t=>n.includes(t.$control_item));if(!a)return;const s=++d,c=()=>!i.closed&&s===d,p=i.add(function(t,e){return Yt.set(t,e),()=>{Yt.get(t)===e&&Yt.delete(t)}}(o,c));try{if(e(a),i.closed)return;if(r.onSelect){const e=await r.onSelect.call(t,a,a.$control_item,o);c()&&Ft(l,e)}}catch(h){console.warn("ArtPlayer selector failed:",h)}finally{p()}});n.push(p)}class Bt extends Lt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;g(t,o);const{on:n}=b(t,o);n("mousemove",()=>{E||(this.show=!0)}),n("click",()=>{E?this.toggle():this.show=!0}),n("document:mousemove",t=>{this.isHover=N(t,o)}),n("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),n("control",t=>{t?(M(r,"art-hide-cursor"),L(r,"art-hover"),this.timer=Date.now()):(L(r,"art-hide-cursor"),M(r,"art-hover"))}),this.init(),h(t).closed||function(t){const{$bottom:e,$controls:r,$player:o}=t.template,n=v(e),{on:a}=b(t,e),i=()=>{if(n.closed)return;const t=r.offsetHeight;t>0&&o.style.getPropertyValue("--art-controls-height")!==`${t}px`&&o.style.setProperty("--art-controls-height",`${t}px`)};if(a("resize",i),"undefined"!==typeof ResizeObserver){const t=new ResizeObserver(i);t.observe(r),n.add(()=>{t.disconnect()})}else if("undefined"!==typeof MutationObserver){const t=new MutationObserver(i);t.observe(r,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),n.add(()=>{t.disconnect()})}i()}(t)}init(){Vt(this)}add(t){if(u(this.art))return;const e="function"===typeof t?t(this.art):t,{$progress:r,$controlsLeft:o,$controlsRight:n}=this.art.template;switch(e.position){case"top":this.$parent=r;break;case"left":this.$parent=o;break;case"right":this.$parent=n;break;default:K(!1,"Control option.position must one of 'top', 'left', 'right'")}super.add(e)}check(t){!function(t){if(t){Ft(t.$control_value,t.html);for(let e=0;ethis.check(t),t,e,r)}}function Wt(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function jt(t){if(t.constructor.USE_RAF){const e=h(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const qt=new WeakMap;class Ut{constructor(t){this.destroyEvents=new Set;const e=h(t);qt.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){N(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),E?!t.isLock&&n&&Z(t.toggle()):Z(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),E?!t.isLock&&s&&Z(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{L(r,"art-hover"),t.emit("hover",!0,e)},e=>{M(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=h(t);let a=()=>{};const i=()=>{a(),a=At(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(E&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&Ot(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=Wt(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=tt((o-i)/t.width,-1,1),d=tt((a-s)/t.height,-1,1),p=t.isRotate?d:c,h=n===r?t.constructor.TOUCH_MOVE_RATIO:1,u=tt(l+t.duration*p*h,0,t.duration);t.seek=u,t.emit("setBar","played",tt(u/t.duration,0,1),e),t.notice.show=`${rt(u)} / ${rt(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=mt(()=>{t.emit("view",D(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{const o=a.window||i.ownerDocument?.defaultView||window,s=e.proxy(o,r,e=>{t.emit(`window:${r}`,e)});n.push(s)})}a(),e.bindGlobalEvents=a}(t,this),jt(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(qt.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Xt{constructor(t){this.art=t,this.keys={},E||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{Z(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Jt{constructor(t){const e={...Zt,...t.option.icons};for(const r in e)st(this,r,{get:()=>B(r,e[r])})}}class Qt extends Lt{constructor(t){super(t),this.name="info",E||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=S("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=h(this.art);!function t(){for(let e=0;e{O(n,"display","none"),O(a,"display",null)}),o.proxy(e.$state,"click",()=>Z(t.play()))}}class oe{constructor(t){this.art=t,this.timer=null,h(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(h(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,L(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",M(r,"art-notice-show")},e.NOTICE_TIME)):M(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function ne(t,e,r,o=!1){const n=e=>{u(t)||r(e)};t[o?"once":"on"](e,n),h(t).add(()=>{t.off(e,n)})}function ae(t,e,r){for(const[o,n]of e){if(u(t)||r&&!r())return;t[o].show=n}}const ie=new WeakMap,se=new WeakMap,le=new WeakMap;function ce(t){return le.get(t)||h(t)}function de(t){const e=ie.get(t),r=le.get(t);return()=>ie.get(t)===e&&(!e||e.active())&&le.get(t)===r&&(!r||!r.closed)}function pe(t){const e=le.get(t),r=h(t).child(),o=r.child();le.set(t,r),r.add(()=>{le.get(t)===r&&le.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!u(t)&&!o.closed&&ie.get(t)===n};return ie.set(t,n),o.add(()=>{ie.get(t)===n&&ie.delete(t),n.onAssigned=void 0,n.onError=void 0}),e?.dispose(),n}function he(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&e?.()}function ue(t,e,r){se.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{se.get(t)===e&&(se.delete(t),he(e))}}function fe(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function me(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=ce(t),l=0;return{reset(){l=0,i?.dispose(),M(a,"art-error")},loadStart(){M(a,"art-error")},schedule(c){(async c=>{if(u(t))return;const d=ce(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const h=()=>!u(t)&&!p.closed&&d===ce(t),f=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ge(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{u(t)||t.emit(`video:${e.type}`,e)})}(t);const e=me(t);!function(t,e){ne(t,"video:canplay",()=>{e.reset(),ae(t,[["loading",!1]])}),ne(t,"video:canplay",()=>{ae(t,[["loading",!1],["controls",!0],["mask",!0]]),u(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;ne(t,"video:ended",()=>{if(e.loop){const e=de(t);if(t.seek=0,u(t)||!e())return;Z(t.play()),e()&&ae(t,[["controls",!1],["mask",!1]],e)}else ae(t,[["controls",!0],["mask",!0]])})}(t),ne(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;ne(t,"video:loadedmetadata",()=>{t.emit("resize"),E&&ae(t,[["loading",!1],["controls",!0],["mask",!0]])}),ne(t,"video:loadstart",()=>{e.loadStart(),ae(t,[["loading",!0],["mask",!1],["controls",!0]])}),ne(t,"video:pause",()=>{ae(t,[["controls",!0],["mask",!0]])}),ne(t,"video:play",()=>{ae(t,[["mask",!1]]),u(t)||O(r,"display","none")}),ne(t,"video:playing",()=>ae(t,[["mask",!1]])),ne(t,"video:progress",()=>{t.playing&&ae(t,[["loading",!1]])}),ne(t,"video:seeked",()=>ae(t,[["loading",!1],["mask",!0]])),ne(t,"video:seeking",()=>ae(t,[["loading",!0],["mask",!1]])),ne(t,"video:timeupdate",()=>ae(t,[["mask",!1]])),ne(t,"video:waiting",()=>ae(t,[["loading",!0],["mask",!1]]))}(t,e)}const ve=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],ye=(()=>{if("undefined"===typeof document)return!1;const t=ve[0],e={};for(const r of ve){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),be={change:ye.fullscreenchange,error:ye.fullscreenerror},we={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{we.off("change",n),r()};we.on("change",n);const a=t[ye.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!we.isFullscreen)return void t();const r=()=>{we.off("change",r),t()};we.on("change",r);const o=document[ye.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>we.isFullscreen?we.exit():we.request(t,e),onchange(t){we.on("change",t)},onerror(t){we.on("error",t)},on(t,e){const r=be[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=be[t];r&&document.removeEventListener(r,e,!1)},raw:ye};function xe(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;t.once("video:loadedmetadata",()=>{var a;we.isEnabled?(a=t,we.on("change",()=>{a.emit("fullscreen",we.isFullscreen),we.isFullscreen?(a.state="fullscreen",L(n,"art-fullscreen")):M(n,"art-fullscreen"),a.emit("resize")}),we.on("error",t=>{a.emit("fullscreenError",t)}),st(a,"fullscreen",{get:()=>we.isFullscreen,async set(t){t?await we.request(n):await we.exit()}})):o.webkitSupportsFullscreen?(t=>{t.on("document:webkitfullscreenchange",()=>{t.emit("fullscreen",t.fullscreen),t.emit("resize")}),st(t,"fullscreen",{get:()=>document.fullscreenElement===o,set(e){e?(t.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})})(t):st(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),st(t,"fullscreen",dt(t,"fullscreen"))})}function ke(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(M(n,"art-mini"),O(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(O(e,"display","none"),O(r,"display","flex")):(O(e,"display","flex"),O(r,"display","none"))}function p(){const{$mini:e}=t.template,r=j(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),O(e,"top",`${n}px`),O(e,"left",`${a}px`)}st(t,"mini",{get:()=>A(n,"art-mini"),set(h){if(h){t.state="mini",L(n,"art-mini");const h=function(){const{$mini:n}=t.template;if(n)return P(n,a),O(n,"display","flex");{const n=H("div");L(n,"art-mini-popup"),P(document.body,n),t.template.$mini=n,P(n,a);const p=P(n,'
');P(p,e.close),r(p,"click",c);const h=P(n,'
'),u=P(h,e.play),f=P(h,e.pause);return r(u,"click",()=>Z(t.play())),r(f,"click",()=>t.pause()),d(u,f),t.on("video:playing",()=>d(u,f)),t.on("video:pause",()=>d(u,f)),t.on("video:timeupdate",()=>d(u,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){L(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;O(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,M(n,"art-mini-dragging");const t=j(n);o.set("left",t.left),o.set("top",t.top),O(n,"left",`${t.left}px`),O(n,"top",`${t.top}px`),O(n,"transform",null)}}),n}}(),u=o.get("top"),f=o.get("left");"number"===typeof u&&"number"===typeof f?(O(h,"top",`${u}px`),O(h,"left",`${f}px`),D(h)||p()):p(),t.emit("mini",!0)}else c()}})}function $e(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,st(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),st(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):st(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Ee(t){st(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:a?.html||"",selector:e,async onSelect(e,r,a){const i=function(t){return t&&Yt.get(t)||(()=>!0)}(a);if(await t.switchQuality(e.url),!u(t)&&i()){const r=`${n.get("Switch Video")}: ${e.html}`;!u(t)&&i()&&(o.show=r)}return e.html}})}})}function Te(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function Ce(t,e,r){return new Promise((o,n)=>{if(u(t)||e===t.url)return void o();const a=pe(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),d=t=>l(!0,t);a.onError=d;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const p=i.child(),h={"video:error":d,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){d(e)}},"video:canplay":()=>{if(!c())return;p.dispose();(async()=>{if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{await t.play()}catch{}c()&&(t.notice.show="",l())}})().catch(d)}},u=i.child(),f=[],m=Object.keys(h);for(const e of m)Te(u,t,e,t=>{a.acceptingEvents&&f.push([e,t])},!1);if(ue(t,a,e),!c())return;if(t.notice.show="",!c())return;const g=()=>{if(u.dispose(),!e)return void l();const r={};for(const e of m)r[e]=Te(p,t,e,h[e]);for(const[t,e]of f){if(!c()||p.closed)break;r[t](e)}f.length=0};a.assigned?g():a.onAssigned=g}catch(p){d(p)}})}function ze(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",async(n,s,l)=>{const c=t.controls?.thumbnails,{url:d,scale:p}=e.thumbnails;if(!c||!d)return;if("hover"===n||"played"===n&&l&&E){if(i||a||(a=!0,i=await q(d,p),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?O(a,"left",r.clientWidth-h+"px"):O(a,"left",n-h/2+"px")}(n)}}),st(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function Se(t){const{option:e,template:{$video:r}}=t;st(t,"url",{get:()=>r.src,async set(o){if(u(t))return;const n=function(t){const e=se.get(t);return se.delete(t),e||pe(t)}(t);n.acceptingEvents=!1;try{if(!o)return void(await Pt(n.scope)&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||J(o),s=e.customType[i];if(i&&s){if(!(await Pt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;Te(l,t,"video:canplay",()=>{c=!d}),Te(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>fe(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||Te(n.scope,t,"video:canplay",e)}}catch(a){fe(n,a)}finally{he(n)}}})}Object.defineProperties(we,{isFullscreen:{get:()=>Boolean(document[ye.fullscreenElement])},element:{enumerable:!0,get:()=>document[ye.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[ye.fullscreenEnabled])}});class Le{constructor(t){Se(t),function(t){const{template:{$video:e}}=t;st(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;st(t,"play",{async value(){const i=de(t),s=await a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;st(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${rt(t.currentTime)} / ${rt(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;st(t,"forward",{set(e){r.seek=t.currentTime+e}}),st(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;st(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=tt(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),st(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;st(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=tt(o,0,t.duration))}})}(t),function(t){st(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>Ce(t,e,0);st(t,"switchQuality",{value:e=>Ce(t,e,t.currentTime)}),st(t,"switchUrl",{value:e}),st(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;st(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;st(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)O(o,"width",null),O(o,"height",null),O(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(O(o,"width",s*r+"px"),O(o,"height","100%"),O(o,"margin","0 auto")):(O(o,"width","100%"),O(o,"height",e/s+"px"),O(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=H("canvas");st(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),st(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),st(t,"screenshot",{value:async e=>{const o=await t.getDataURL();return Q(o,`${e||`artplayer_${rt(r.currentTime)}`}.png`),t.emit("screenshot",o),o}})}(t),xe(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";st(t,"fullscreenWeb",{get:()=>A(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&P(document.body,o),t.state="fullscreenWeb",O(o,"width","100%"),O(o,"height","100%"),L(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&P(r,o),n&&(o.style.cssText=n,n=""),M(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),$e(t),function(t){const{$video:e}=t.template,r=t;st(t,"loaded",{get:()=>r.loadedTime/e.duration}),st(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){st(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;st(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;st(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=j(e),l=n/a;if(i/s>l)O(r,"width",s*l/i*100+"%"),O(r,"height","100%");else{const t=i/l/s*100;O(r,"width","100%"),O(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;st(t,"rect",{get:()=>j(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}st(t,"x",{get:()=>e.left+window.pageXOffset}),st(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;st(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(et(n))}`,t.emit("flip",n)}})}(t),ke(t),function(t){const{template:{$poster:e}}=t;st(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch{return""}},set(t){O(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;st(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);O(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;st(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){st(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){st(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];st(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;oo.$track?.offset||0,set(n){const{cues:a}=t.subtitle;if(!o.$track||0===a.length)return;const i=tt(n,-10,10);o.$track.offset=i;for(let e=0;e{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,st(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),Ee(t),ze(t),ge(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=tt(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=tt(a,0,1)),e.poster&&O(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Me(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{if(e){if(l()){const e=Number(r.AUTO_ORIENTATION_TIME??0);setTimeout(()=>{t.fullscreenWeb&&!A(o,a)&&function(){const e=X(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;O(o,"width",`${n}px`),O(o,"height",`${i}px`),O(o,"transform-origin","0 0"),O(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),L(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else A(o,a)&&(O(o,"width",""),O(o,"height",""),O(o,"transform-origin",""),O(o,"transform",""),M(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",async t=>{const r=!!screen?.orientation?.lock;if(t){if(r&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";await screen.orientation.lock(t),s=!0,L(o,i)}catch(n){s=!1,e.show=n}}else if(A(o,i)&&M(o,i),r&&s){try{screen.orientation.unlock()}catch{}s=!1}}),{name:"autoOrientation",get state(){return A(o,a)}}}function Ae(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=z(".art-auto-playback-last",s),c=z(".art-auto-playback-jump",s),d=z(".art-auto-playback-close",s);P(d,r.close);let p=null;function h(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),O(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(O(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${rt(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{O(s,"display","none")}),a(c,"click",()=>{t.seek=r,Z(t.play()),O(i,"display","none"),O(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{O(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",h),t.on("restart",h),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Pe(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,M(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,L(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return A(o,"art-fast-forward")}}}function Ie(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return A(o,"art-lock")}function a(){L(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){M(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=P(e,r.lock),n=P(e,r.unlock);O(o,"display","none"),t.on("lock",t=>{t?(O(o,"display","inline-flex"),O(n,"display","none")):(O(o,"display","none"),O(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function Oe(t){return t.on("control",e=>{e?M(t.template.$player,"art-mini-progress-bar"):L(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Re{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){u(t.art)||!e.miniProgressBar||e.isLive||t.add(Oe),!u(t.art)&&e.lock&&E&&t.add(Ie),u(t.art)||!e.autoPlayback||e.isLive||t.add(Ae),!u(t.art)&&e.autoOrientation&&E&&t.add(Me),!u(t.art)&&e.fastForward&&E&&!e.isLive&&t.add(Pe)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){K(!u(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(u(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(u(t.art))return t;let n=o;const a=ct(t,n);if(u(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return u(t.art)||(K(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),u(t.art)||st(t,n,{value:r})),t}(this,t,e)}}class _e extends Lt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=N(t,r.setting),o=N(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(et(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){for(let r=0;r{e.default=e===t,e.default&&e.$item&&V(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),st(a,"$parents",{get:()=>r}),st(a,"$option",{get:()=>t});const o=[];st(a,"$events",{get:()=>o}),st(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){const{controls:t,constructor:{SETTING_WIDTH:e,SETTING_ITEM_HEIGHT:r},template:{$player:o,$setting:n}}=this.art;if(t.setting&&this.show){const a=this.active[0]?.$parent?.width||e,{left:i,width:s}=j(t.setting),{left:l,width:c}=j(o),d=i-l+s/2-a/2;if(O(n,"height",`${this.active===this.option?this.active.length*r:(this.active.length+1)*r}px`),O(n,"width",`${a}px`),this.art.isRotate||E)return;d+a>c?(O(n,"left",null),O(n,"right",null)):(O(n,"left",`${d}px`),O(n,"right","auto"))}}inactivate(t){for(let e=0;e'),s=H("div");L(s,"art-setting-item-left-icon"),P(s,o),P(i,s),P(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),P(e,a)}createItem(t,e=!1){if(!this.cache.has(t.$option))return;const r=this.cache.get(t.$option),o=t.$item;let n="selector";ct(t,"switch")&&(n="switch"),ct(t,"range")&&(n="range"),ct(t,"onClick")&&(n="button");const{icons:a,proxy:i,constructor:s}=this.art,l=H("div");L(l,"art-setting-item"),O(l,"height",`${s.SETTING_ITEM_HEIGHT}px`),l.dataset.name=t.name||"",l.dataset.value=t.value||"";const c=P(l,'
'),d=P(l,'
'),p=H("div");switch(L(p,"art-setting-item-left-icon"),n){case"button":case"switch":case"range":P(p,t.icon||a.config);break;case"selector":t.selector?.length?P(p,t.icon||a.config):P(p,a.check)}P(c,p),st(t,"$icon",{configurable:!0,get:()=>p}),st(t,"icon",{configurable:!0,get:()=>p.innerHTML,set(t){p.innerHTML="",P(p,t)}});const u=H("div");L(u,"art-setting-item-left-text"),P(u,t.html||""),P(c,u),st(t,"$html",{configurable:!0,get:()=>u}),st(t,"html",{configurable:!0,get:()=>u.innerHTML,set(t){u.innerHTML="",P(u,t)}});const f=H("div");switch(L(f,"art-setting-item-right-tooltip"),P(f,t.tooltip||""),P(d,f),st(t,"$tooltip",{configurable:!0,get:()=>f}),st(t,"tooltip",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",P(f,t)}}),n){case"switch":{const e=H("div");L(e,"art-setting-item-right-icon");const r=P(e,a.switchOn),o=P(e,a.switchOff);O(t.switch?o:r,"display","none"),P(d,e),st(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;st(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(O(o,"display","none"),O(r,"display",null)):(O(o,"display",null),O(r,"display","none"))}});break}case"range":{const e=H("div");L(e,"art-setting-item-right-icon");const r=P(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],L(r,"art-setting-range"),P(d,e),st(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];st(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(t.selector?.length){const t=H("div");L(t,"art-setting-item-right-icon"),P(t,a.arrowRight),P(d,t)}}switch(n){case"switch":if(t.onSwitch){const e=i(l,"click",async e=>{t.switch=await t.onSwitch.call(this.art,t,l,e)});t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=i(t.$range,"change",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onRange.call(this.art,t,l,e)});t.$events.push(e)}if(t.onChange){const e=i(t.$range,"input",async e=>{t.range[0]=t.$range.valueAsNumber,t.tooltip=await t.onChange.call(this.art,t,l,e)});t.$events.push(e)}}break;case"selector":{const e=i(l,"click",async e=>{t.selector?.length?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=await t.$parent.onSelect.call(this.art,t,l,e)))});t.$events.push(e),t.default&&L(l,"art-current")}break;case"button":if(t.onClick){const e=i(l,"click",async e=>{t.tooltip=await t.onClick.call(this.art,t,l,e)});t.$events.push(e)}}st(t,"$item",{configurable:!0,get:()=>l}),e?F(l,o):P(r,l),t.mounted&&At(h(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){if(this.active=t,this.cache.has(t)){V(this.cache.get(t),"art-current")}else{const e=H("div");this.cache.set(t,e),L(e,"art-setting-panel"),P(this.$parent,e),V(e,"art-current"),t[0]?.$parent&&this.createHeader(t[0]);for(let r=0;rnull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){return this.art.template.$video?.textTracks?.[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?R(r,t):O(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?it(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}async switch(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a={...n.subtitle,...e,url:t},i=await this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=H("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,I(i),P(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}async init(t){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(n(t,zt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||J(t.url)){case"srt":{const e=ht(r);return ut(t.onVttLoad(e))}case"ass":{const e=ft(r);return ut(t.onVttLoad(e))}case"vtt":return ut(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null}}const Ne=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${a}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Fe{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=z(e.container),K(this.$container,`No container element found by ${e.container}`)),K(W(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();K("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),K(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=d.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=p(t);n.rollback=r,d.set(e,t),n.releaseContainer=()=>{d.get(e)===t&&d.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ne}query(t){return z(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Fe.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){K(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),F(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&L(this.$player,"art-backdrop"),E&&L(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":L(this.$player,"art-destroy")}}const He=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class Be{on(t,e,r){const o=this.e||(this.e={});let n=He(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(He(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=He(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),qe.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${qe.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=p(t);return e.rollback=void 0,!e.scope.closed})(this)&&je.push(this)}catch(o){try{f(this,je,!0,qe.REMOVE_SRC_WHEN_DESTROY,!0)}catch(a){console.warn("Failed to clean up ArtPlayer initialization:",a)}throw o}}static get instances(){return je}static get version(){return a}static get config(){return i}static get utils(){return gt}static get scheme(){return zt}static get Emitter(){return Be}static get validator(){return n}static get kindOf(){return n.kindOf}static get html(){return Fe.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:x?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:navigator?.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){f(this,je,t,qe.REMOVE_SRC_WHEN_DESTROY)}}return qe.STYLE=Ye,qe.DEBUG=!1,qe.CONTEXTMENU=!0,qe.NOTICE_TIME=2e3,qe.SETTING_WIDTH=250,qe.SETTING_ITEM_WIDTH=200,qe.SETTING_ITEM_HEIGHT=35,qe.RESIZE_TIME=200,qe.SCROLL_TIME=200,qe.SCROLL_GAP=50,qe.AUTO_PLAYBACK_MAX=10,qe.AUTO_PLAYBACK_MIN=5,qe.AUTO_PLAYBACK_TIMEOUT=3e3,qe.RECONNECT_TIME_MAX=5,qe.RECONNECT_SLEEP_TIME=1e3,qe.CONTROL_HIDE_TIME=3e3,qe.DBCLICK_TIME=300,qe.DBCLICK_FULLSCREEN=!0,qe.MOBILE_DBCLICK_PLAY=!0,qe.MOBILE_CLICK_PLAY=!1,qe.AUTO_ORIENTATION_TIME=200,qe.INFO_LOOP_TIME=1e3,qe.FAST_FORWARD_VALUE=3,qe.FAST_FORWARD_TIME=1e3,qe.TOUCH_MOVE_RATIO=.5,qe.VOLUME_STEP=.1,qe.SEEK_STEP=5,qe.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],qe.ASPECT_RATIO=["default","4:3","16:9"],qe.FLIP=["normal","horizontal","vertical"],qe.FULLSCREEN_WEB_IN_BODY=!0,qe.LOG_VERSION=!0,qe.USE_RAF=!1,qe.REMOVE_SRC_WHEN_DESTROY=!0,T&&(window.Artplayer=qe,C("artplayer-style",Ye),setTimeout(()=>{qe.LOG_VERSION&&console.log(`%c ArtPlayer %c ${qe.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),qe}); diff --git a/packages/artplayer/dist/artplayer.legacy.js b/packages/artplayer/dist/artplayer.legacy.js index b151e2b4f..bd1b8d802 100644 --- a/packages/artplayer/dist/artplayer.legacy.js +++ b/packages/artplayer/dist/artplayer.legacy.js @@ -67,4 +67,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))a.call(e,r)&&s(t,r,e[r]);if(n)for(var r of n(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,n)=>{var a=t=>{try{s(r.next(t))}catch(e){n(e)}},i=t=>{try{s(r.throw(t))}catch(e){n(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(a,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var u,h={exports:{}};var f=(u||(u=1,h.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2=1,k=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(y)||x,$="undefined"!==typeof window&&"undefined"!==typeof document;function E(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function T(t,e=document){return e.querySelector(t)}function C(t,e=document){return Array.from(e.querySelectorAll(t))}function z(t,e){return t.classList.add(e)}function L(t,e){return t.classList.remove(e)}function S(t,e){return t.classList.contains(e)}function M(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function A(t){return t.parentNode.removeChild(t)}function P(t,e,r){return t.style[e]=r,t}function I(t,e){for(const r in e)P(t,r,e[r]);return t}function O(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function R(t,e){O(t).forEach(t=>L(t,e)),z(t,e)}function _(t,e,r="top"){k||(t.setAttribute("aria-label",e),z(t,"hint--rounded"),z(t,`hint--${r}`))}function V(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function Y(t,e){return j(t).includes(e)}function D(t,e){return e.parentNode.replaceChild(t,e),t}function N(t){return document.createElement(t)}function F(t="",e=""){const r=N("i");return z(r,"art-icon"),z(r,`art-icon-${t}`),M(r,e),r}function H(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function B(t){return t.getBoundingClientRect()}function W(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function j(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function U(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class q extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function X(t,e){if(!t)throw new q(e);return t}function G(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function K(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function Z(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function J(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function Q(t){return t.charAt(0).toUpperCase()+t.slice(1)}function tt(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const et={"&":"&","<":"<",">":">","'":"'",'"':"""},rt={"&":"&","<":"<",">":">","'":"'",""":'"'},ot=/(&|<|>|'|")/g;function nt(t){return t.replace(/[&<>'"]/g,t=>et[t]||t)}const at=Object.defineProperty,{hasOwnProperty:it}=Object.prototype;function st(t,e){return it.call(t,e)}function lt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function ct(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?ct(n,a):a,at(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function dt(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function pt(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function ut(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function ht(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const ft=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:q,addClass:z,append:M,assToVtt:ut,capitalize:Q,clamp:J,createElement:N,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:at,download:Z,errorHandle:X,escape:nt,get:lt,getComposedPath:j,getExt:K,getIcon:F,getRect:B,getSafeAreaInsets:U,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:st,hasClass:S,includeFromEvent:Y,inverseClass:R,isBrowser:$,isIOS:w,isIOS13:x,isInViewport:V,isMobile:k,isSafari:b,loadImg:W,mergeDeep:ct,query:T,queryAll:C,remove:A,removeClass:L,replaceElement:D,secondToTime:tt,setStyle:P,setStyleText:E,setStyles:I,siblings:O,silencePromise:G,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:dt,supportsFlex:H,throttle:ht,tooltip:_,unescape:function(t){return t.replace(ot,t=>rt[t]||t)},userAgent:y,vttToBlob:pt},Symbol.toStringTag,{value:"Module"})),mt="array",gt="boolean",vt="string",yt="number",bt="object",wt="function";function xt(t,e,r){return X(e===vt||e===yt||t instanceof Element,`${r.join(".")} require '${vt}' or 'Element' type`)}const kt={html:xt,disable:`?${gt}`,name:`?${vt}`,index:`?${yt}`,style:`?${bt}`,click:`?${wt}`,mounted:`?${wt}`,tooltip:`?${vt}|${yt}`,width:`?${yt}`,selector:`?${mt}`,onSelect:`?${wt}`,switch:`?${gt}`,onSwitch:`?${wt}`,range:`?${mt}`,onRange:`?${wt}`,onChange:`?${wt}`},$t={id:vt,container:xt,url:vt,poster:vt,type:vt,theme:vt,lang:vt,volume:yt,isLive:gt,muted:gt,autoplay:gt,autoSize:gt,autoMini:gt,loop:gt,flip:gt,playbackRate:gt,aspectRatio:gt,screenshot:gt,setting:gt,hotkey:gt,pip:gt,mutex:gt,backdrop:gt,fullscreen:gt,fullscreenWeb:gt,subtitleOffset:gt,miniProgressBar:gt,useSSR:gt,playsInline:gt,lock:gt,gesture:gt,fastForward:gt,autoPlayback:gt,autoOrientation:gt,airplay:gt,proxy:`?${wt}`,plugins:[wt],layers:[kt],contextmenu:[kt],settings:[kt],controls:[c(l({},kt),{position:(t,e,r)=>{const o=["top","left","right"];return X("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${gt}`,html:vt,url:vt}],highlight:[{time:yt,text:vt}],thumbnails:{url:vt,number:yt,column:yt,width:yt,height:yt,scale:yt},subtitle:{url:vt,name:vt,type:vt,style:bt,escape:gt,encoding:vt,onVttLoad:wt},moreVideoAttr:bt,i18n:bt,icons:bt,cssVar:bt,customType:bt};class Et{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return S(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?z(e,r):L(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){const e="function"===typeof t?t(this.art):t;if(e.html=e.html||"",m(e,kt),!this.$parent||!this.name||e.disable)return;const r=e.name||`${this.name}${this.id}`;X(!this.cache.has(r),`Can't add an existing [${r}] to the [${this.name}]`),this.id+=1;const o=N("div");z(o,`art-${this.name}`),z(o,`art-${this.name}-${r}`);const n=Array.from(this.$parent.children);o.dataset.index=e.index||this.id;const a=n.find(t=>Number(t.dataset.index)>=Number(o.dataset.index));a?a.insertAdjacentElement("beforebegin",o):M(this.$parent,o),e.html&&M(o,e.html),e.style&&I(o,e.style),e.tooltip&&_(o,e.tooltip);const i=[];if(e.click){const t=this.art.events.proxy(o,"click",t=>{t.preventDefault(),e.click.call(this.art,this,t)});i.push(t)}return e.selector&&["left","right"].includes(e.position)&&this.selector(e,o,i),this[r]=o,this.cache.set(r,{$ref:o,events:i,option:e}),e.mounted&&e.mounted.call(this.art,o),o}remove(t){X(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);for(const r of e.events)this.art.events.remove(r);this.cache.delete(t),delete this[t],A(e.$ref)}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Tt extends Et{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,k||this.init()}init(){const{option:t,proxy:e,template:{$player:r,$contextmenu:o}}=this.art;t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const r=T('[data-value="1"]',t);r&&R(r,"art-current"),e.on("video:ratechange",()=>{const r=C("span",t).find(t=>Number(t.dataset.value)===e.playbackRate);r&&R(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const r=T('[data-value="default"]',t);r&&R(r,"art-current"),e.on("aspectRatio",e=>{const r=C("span",t).find(t=>t.dataset.value===e);r&&R(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(Q(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const{value:o}=r.target.dataset;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const r=T('[data-value="normal"]',t);r&&R(r,"art-current"),e.on("flip",e=>{const r=C("span",t).find(t=>t.dataset.value===e);r&&R(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let n=0;n{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const e=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=B(r),{height:c,width:d}=B(o);let p=e-s,u=n-l;e+d>s+i&&(p=i-d),n+c>l+a&&(u=a-c),I(o,{top:`${u}px`,left:`${p}px`})}),e(r,"click",t=>{Y(t,o)||(this.show=!1)}),this.art.on("blur",()=>{this.show=!1})}}class Ct extends Error{constructor(t){super("Failed to release ArtPlayer resources"),this.errors=t,this.name="ResourceCleanupError"}}class zt{constructor(){this.cleanups=new Set,this.disposed=!1}get closed(){return this.disposed}add(t){let e=!0;const r=()=>{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new zt,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof Ct?t.push(...e.errors):t.push(e)}if(t.length)throw new Ct(t)}}const Lt=new WeakMap,St=new WeakMap;function Mt(t){const e=Lt.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function At(t){return Mt(t).scope}function Pt(t){const e=Mt(t);return e.destroying||e.scope.closed}function It(t,e,r,o,n=!1){var a,i,s;const l=Mt(t);if(l.destroying||l.scope.closed)return;l.destroying=!0;const c=[],d=t=>{try{t()}catch(e){c.push(...e instanceof Ct?e.errors:[e])}};o&&(null==(a=t.template)?void 0:a.$video)&&d(()=>t.reset()),d(()=>l.scope.dispose()),d(()=>{var e;return null==(e=t.template)?void 0:e.destroy(r)});const p=e.indexOf(t);-1!==p&&e.splice(p,1),t.isDestroy=!0,n||(null==(i=l.releaseContainer)||i.call(l),l.releaseContainer=void 0),d(()=>t.emit("destroy")),n&&l.rollback&&d(l.rollback),l.rollback=void 0,null==(s=l.releaseContainer)||s.call(l),l.releaseContainer=void 0;for(const u of c.slice(1))console.warn("Additional ArtPlayer cleanup failure:",u);if(c.length)throw c[0]}function Ot(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Rt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function _t(t,e){const{$progress:r}=t.template,{left:o}=B(r),n=J((k?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:tt(a),width:n,percentage:J(n/r.clientWidth,0,1)}}function Vt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=_t(t,e);t.emit("setBar","played",o,e),t.seek=r}}function Yt(t){return e=>{const{icons:r,option:o,proxy:n}=e,{$player:a,$progress:i}=e.template;return c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{let s=null,l=!1;const c=T(".art-progress-hover",t),d=T(".art-progress-loaded",t),p=T(".art-progress-played",t),u=T(".art-progress-highlight",t),h=T(".art-progress-indicator",t),f=T(".art-progress-tip",t);function m(r,o){const{width:n,time:a}=o||_t(e,r);f.textContent=a||"00:00";const i=f.clientWidth;n<=i/2?P(f,"left",0):n>t.clientWidth-i/2?P(f,"left",t.clientWidth-i+"px"):P(f,"left",n-i/2+"px")}r.indicator?M(h,r.indicator):P(h,"backgroundColor","var(--art-theme)"),e.on("setBar",function(r,o,n){const i="played"===r&&n&&k;if("loaded"===r&&P(d,"width",100*o+"%"),"hover"===r&&(P(c,"width",100*o+"%"),Y(n,u)?function(r){const{width:o}=_t(e,r),{text:n}=r.target.dataset;f.textContent=n;const a=f.clientWidth;o<=a/2?P(f,"left",0):o>t.clientWidth-a/2?P(f,"left",t.clientWidth-a+"px"):P(f,"left",o-a/2+"px")}(n):m(n),0===o?L(a,"art-progress-hover"):z(a,"art-progress-hover")),"played"===r&&(P(p,"width",100*o+"%"),P(h,"left",100*o+"%")),i){z(a,"art-progress-hover");m(n,{width:t.clientWidth*o,time:tt(o*e.duration)}),clearTimeout(s),s=setTimeout(()=>{L(a,"art-progress-hover")},500)}}),e.on("video:loadedmetadata",function(){u.textContent="";for(let t=0;t`;M(u,a)}}),e.constructor.USE_RAF?e.on("raf",()=>{e.emit("setBar","played",e.played),e.emit("setBar","loaded",e.loaded)}):(e.on("video:timeupdate",()=>{e.emit("setBar","played",e.played)}),e.on("video:progress",()=>{e.emit("setBar","loaded",e.loaded)}),e.on("video:ended",()=>{e.emit("setBar","played",1)})),e.emit("setBar","loaded",e.loaded||0),k||(n(i,"click",t=>{t.target!==h&&Vt(e,t)}),n(i,"mousemove",t=>{const{percentage:r}=_t(e,t);e.emit("setBar","hover",r,t)}),n(i,"mouseleave",t=>{e.emit("setBar","hover",0,t)}),n(i,"mousedown",t=>{l=0===t.button}),e.on("document:mousemove",t=>{if(l){const{second:r,percentage:o}=_t(e,t);e.emit("setBar","played",o,t),e.seek=r}}),e.on("document:mouseup",()=>{l&&(l=!1)}))}})}}class Dt extends Et{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;t.on("mousemove",()=>{k||(this.show=!0)}),t.on("click",()=>{k?this.toggle():this.show=!0}),t.on("document:mousemove",t=>{this.isHover=Y(t,o)}),t.on("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),t.on("control",t=>{t?(L(r,"art-hide-cursor"),z(r,"art-hover"),this.timer=Date.now()):(z(r,"art-hide-cursor"),L(r,"art-hover"))}),this.init()}init(){const{option:t}=this.art;t.isLive||this.add(Yt({name:"progress",position:"top",index:10})),this.add({name:"thumbnails",position:"top",index:20}),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.play),i=M(t,o.pause);function s(){P(a,"display","flex"),P(i,"display","none")}function l(){P(a,"display","none"),P(i,"display","flex")}_(a,n.get("Play")),_(i,n.get("Pause")),r(a,"click",()=>{G(e.play())}),r(i,"click",()=>{e.pause()}),e.playing?l():s(),e.on("video:playing",()=>{l()}),e.on("video:pause",()=>{s()})}})}({name:"playAndPause",position:"left",index:10})),this.add(function(t){return e=>c(l({},t),{mounted:t=>{const{proxy:r,icons:o}=e,n=M(t,o.volume),a=M(t,o.volumeClose),i=M(t,'
'),s=M(i,'
'),l=M(s,'
'),c=M(s,'
'),d=M(c,'
'),p=M(d,'
'),u=M(c,'
');function h(t){const{top:e,height:r}=B(c);return 1-(t.clientY-e)/r}function f(){if(e.muted||0===e.volume)P(n,"display","none"),P(a,"display","flex"),P(u,"top","100%"),P(p,"top","100%"),l.textContent=0;else{const t=100*e.volume;P(n,"display","flex"),P(a,"display","none"),P(u,"top",100-t+"%"),P(p,"top",100-t+"%"),l.textContent=Math.floor(t)}}if(f(),e.on("video:volumechange",f),r(n,"click",()=>{e.muted=!0}),r(a,"click",()=>{e.muted=!1}),k)P(i,"display","none");else{let t=!1;r(c,"mousedown",r=>{t=0===r.button,e.volume=h(r)}),e.on("document:mousemove",r=>{t&&(e.muted=!1,e.volume=h(r))}),e.on("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),t.isLive||this.add(function(t){return e=>c(l({},t),{style:k?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{function r(){const r=`${tt(e.currentTime)} / ${tt(e.duration)}`;r!==t.textContent&&(t.textContent=r)}r();const o=["video:loadedmetadata","video:timeupdate","video:progress"];for(let n=0;n{e&&!At(this.art).closed&&(this.art.quality=t.quality)}),t.screenshot&&!k&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r,icons:o}=e;M(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),t.setting&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e;M(t,o.setting),r(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),e.on("setting",e=>{_(t,n.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),t.pip&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e;M(t,o.pip),r(t,"click",()=>{e.pip=!e.pip}),e.on("pip",e=>{_(t,n.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),t.airplay&&window.WebKitPlaybackTargetAvailabilityEvent&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r,icons:o}=e;M(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),t.fullscreenWeb&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.fullscreenWebOn),i=M(t,o.fullscreenWebOff);P(i,"display","none"),r(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),e.on("fullscreenWeb",e=>{e?(_(t,n.get("Exit Web Fullscreen")),P(a,"display","none"),P(i,"display","inline-flex")):(_(t,n.get("Web Fullscreen")),P(a,"display","inline-flex"),P(i,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),t.fullscreen&&this.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{proxy:r,icons:o,i18n:n}=e,a=M(t,o.fullscreenOn),i=M(t,o.fullscreenOff);P(i,"display","none"),r(t,"click",()=>{e.fullscreen=!e.fullscreen}),e.on("fullscreen",e=>{e?(_(t,n.get("Exit Fullscreen")),P(a,"display","none"),P(i,"display","inline-flex")):(_(t,n.get("Fullscreen")),P(a,"display","inline-flex"),P(i,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let e=0;et.selector}),at(e,"$control_item",{get:()=>r}),at(e,"$control_value",{get:()=>n})}const i=o(a,"click",e=>d(this,null,function*(){const r=j(e),o=t.selector.find(t=>t.$control_item===r.find(e=>t.$control_item===e));this.check(o),t.onSelect&&(n.innerHTML=yield t.onSelect.call(this.art,o,o.$control_item,e))}));r.push(i)}}function Nt(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function Ft(t){if(t.constructor.USE_RAF){const e=At(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const Ht=new WeakMap;class Bt{constructor(t){this.destroyEvents=new Set;const e=At(t);Ht.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){Y(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),k?!t.isLock&&n&&G(t.toggle()):G(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),k?!t.isLock&&s&&G(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{z(r,"art-hover"),t.emit("hover",!0,e)},e=>{L(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=At(t);let a=()=>{};const i=()=>{a(),a=Ot(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(k&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&Vt(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=Nt(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=J((o-i)/t.width,-1,1),d=J((a-s)/t.height,-1,1),p=t.isRotate?d:c,u=n===r?t.constructor.TOUCH_MOVE_RATIO:1,h=J(l+t.duration*p*u,0,t.duration);t.seek=h,t.emit("setBar","played",J(h/t.duration,0,1),e),t.notice.show=`${tt(h)} / ${tt(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=ht(()=>{t.emit("view",V(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{var o;const s=a.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});n.push(l)})}a(),e.bindGlobalEvents=a}(t,this),Ft(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(Ht.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class Wt{constructor(t){this.art=t,this.keys={},k||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{G(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class Xt{constructor(t){const e=l(l({},qt),t.option.icons);for(const r in e)at(this,r,{get:()=>F(r,e[r])})}}class Gt extends Et{constructor(t){super(t),this.name="info",k||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=C("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=At(this.art);!function t(){for(let e=0;e{P(n,"display","none"),P(a,"display",null)}),o.proxy(e.$state,"click",()=>G(t.play()))}}class Qt{constructor(t){this.art=t,this.timer=null,At(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if(At(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,z(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",L(r,"art-notice-show")},e.NOTICE_TIME)):L(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function te(t,e,r,o=!1){const n=e=>{Pt(t)||r(e)};t[o?"once":"on"](e,n),At(t).add(()=>{t.off(e,n)})}function ee(t,e,r){for(const[o,n]of e){if(Pt(t)||r&&!r())return;t[o].show=n}}const re=new WeakMap,oe=new WeakMap,ne=new WeakMap;function ae(t){return ne.get(t)||At(t)}function ie(t){const e=re.get(t),r=ne.get(t);return()=>re.get(t)===e&&(!e||e.active())&&ne.get(t)===r&&(!r||!r.closed)}function se(t){const e=ne.get(t),r=At(t).child(),o=r.child();ne.set(t,r),r.add(()=>{ne.get(t)===r&&ne.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!Pt(t)&&!o.closed&&re.get(t)===n};return re.set(t,n),o.add(()=>{re.get(t)===n&&re.delete(t),n.onAssigned=void 0,n.onError=void 0}),null==e||e.dispose(),n}function le(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&(null==e||e())}function ce(t,e,r){oe.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{oe.get(t)===e&&(oe.delete(t),le(e))}}function de(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function pe(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=ae(t),l=0;return{reset(){l=0,null==i||i.dispose(),L(a,"art-error")},loadStart(){L(a,"art-error")},schedule(c){(c=>d(null,null,function*(){if(Pt(t))return;const d=ae(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const u=()=>!Pt(t)&&!p.closed&&d===ae(t),h=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ue(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{Pt(t)||t.emit(`video:${e.type}`,e)})}(t);const e=pe(t);!function(t,e){te(t,"video:canplay",()=>{e.reset(),ee(t,[["loading",!1]])}),te(t,"video:canplay",()=>{ee(t,[["loading",!1],["controls",!0],["mask",!0]]),Pt(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;te(t,"video:ended",()=>{if(e.loop){const e=ie(t);if(t.seek=0,Pt(t)||!e())return;G(t.play()),e()&&ee(t,[["controls",!1],["mask",!1]],e)}else ee(t,[["controls",!0],["mask",!0]])})}(t),te(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;te(t,"video:loadedmetadata",()=>{t.emit("resize"),k&&ee(t,[["loading",!1],["controls",!0],["mask",!0]])}),te(t,"video:loadstart",()=>{e.loadStart(),ee(t,[["loading",!0],["mask",!1],["controls",!0]])}),te(t,"video:pause",()=>{ee(t,[["controls",!0],["mask",!0]])}),te(t,"video:play",()=>{ee(t,[["mask",!1]]),Pt(t)||P(r,"display","none")}),te(t,"video:playing",()=>ee(t,[["mask",!1]])),te(t,"video:progress",()=>{t.playing&&ee(t,[["loading",!1]])}),te(t,"video:seeked",()=>ee(t,[["loading",!1],["mask",!0]])),te(t,"video:seeking",()=>ee(t,[["loading",!0],["mask",!1]])),te(t,"video:timeupdate",()=>ee(t,[["mask",!1]])),te(t,"video:waiting",()=>ee(t,[["loading",!0],["mask",!1]]))}(t,e)}const he=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],fe=(()=>{if("undefined"===typeof document)return!1;const t=he[0],e={};for(const r of he){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),me={change:fe.fullscreenchange,error:fe.fullscreenerror},ge={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{ge.off("change",n),r()};ge.on("change",n);const a=t[fe.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!ge.isFullscreen)return void t();const r=()=>{ge.off("change",r),t()};ge.on("change",r);const o=document[fe.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>ge.isFullscreen?ge.exit():ge.request(t,e),onchange(t){ge.on("change",t)},onerror(t){ge.on("error",t)},on(t,e){const r=me[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=me[t];r&&document.removeEventListener(r,e,!1)},raw:fe};function ve(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t,a=t=>{ge.on("change",()=>{t.emit("fullscreen",ge.isFullscreen),ge.isFullscreen?(t.state="fullscreen",z(n,"art-fullscreen")):L(n,"art-fullscreen"),t.emit("resize")}),ge.on("error",e=>{t.emit("fullscreenError",e)}),at(t,"fullscreen",{get:()=>ge.isFullscreen,set(t){return d(this,null,function*(){t?yield ge.request(n):yield ge.exit()})}})};t.once("video:loadedmetadata",()=>{var n;ge.isEnabled?a(t):o.webkitSupportsFullscreen?((n=t).on("document:webkitfullscreenchange",()=>{n.emit("fullscreen",n.fullscreen),n.emit("resize")}),at(n,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(n.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):at(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),at(t,"fullscreen",lt(t,"fullscreen"))})}function ye(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(L(n,"art-mini"),P(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(P(e,"display","none"),P(r,"display","flex")):(P(e,"display","flex"),P(r,"display","none"))}function p(){const{$mini:e}=t.template,r=B(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),P(e,"top",`${n}px`),P(e,"left",`${a}px`)}at(t,"mini",{get:()=>S(n,"art-mini"),set(u){if(u){t.state="mini",z(n,"art-mini");const u=function(){const{$mini:n}=t.template;if(n)return M(n,a),P(n,"display","flex");{const n=N("div");z(n,"art-mini-popup"),M(document.body,n),t.template.$mini=n,M(n,a);const p=M(n,'
');M(p,e.close),r(p,"click",c);const u=M(n,'
'),h=M(u,e.play),f=M(u,e.pause);return r(h,"click",()=>G(t.play())),r(f,"click",()=>t.pause()),d(h,f),t.on("video:playing",()=>d(h,f)),t.on("video:pause",()=>d(h,f)),t.on("video:timeupdate",()=>d(h,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){z(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;P(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,L(n,"art-mini-dragging");const t=B(n);o.set("left",t.left),o.set("top",t.top),P(n,"left",`${t.left}px`),P(n,"top",`${t.top}px`),P(n,"transform",null)}}),n}}(),h=o.get("top"),f=o.get("left");"number"===typeof h&&"number"===typeof f?(P(u,"top",`${h}px`),P(u,"left",`${f}px`),V(u)||p()):p(),t.emit("mini",!0)}else c()}})}function be(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,at(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),at(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):at(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function we(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function xe(t,e,r){return new Promise((o,n)=>{if(Pt(t)||e===t.url)return void o();const a=se(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),p=t=>l(!0,t);a.onError=p;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const u=i.child(),h={"video:error":p,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){p(e)}},"video:canplay":()=>{if(!c())return;u.dispose();d(null,null,function*(){if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{yield t.play()}catch(e){}c()&&(t.notice.show="",l())}}).catch(p)}},f=i.child(),m=[],g=Object.keys(h);for(const e of g)we(f,t,e,t=>{a.acceptingEvents&&m.push([e,t])},!1);if(ce(t,a,e),!c())return;if(t.notice.show="",!c())return;const v=()=>{if(f.dispose(),!e)return void l();const r={};for(const e of g)r[e]=we(u,t,e,h[e]);for(const[t,e]of m){if(!c()||u.closed)break;r[t](e)}m.length=0};a.assigned?v():a.onAssigned=v}catch(u){p(u)}})}function ke(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",(n,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:u}=e.thumbnails;if(!d||!p)return;if("hover"===n||"played"===n&&l&&k){if(i||a||(a=!0,i=yield W(p,u),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?P(s,"left",r.clientWidth-h+"px"):P(s,"left",n-h/2+"px")}(n)}})),at(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function $e(t){const{option:e,template:{$video:r}}=t;at(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(Pt(t))return;const n=function(t){const e=oe.get(t);return oe.delete(t),e||se(t)}(t);n.acceptingEvents=!1;try{if(!o)return void((yield Rt(n.scope))&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||K(o),s=e.customType[i];if(i&&s){if(!(yield Rt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;we(l,t,"video:canplay",()=>{c=!d}),we(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>de(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||we(n.scope,t,"video:canplay",e)}}catch(a){de(n,a)}finally{le(n)}})}})}Object.defineProperties(ge,{isFullscreen:{get:()=>Boolean(document[fe.fullscreenElement])},element:{enumerable:!0,get:()=>document[fe.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[fe.fullscreenEnabled])}});class Ee{constructor(t){$e(t),function(t){const{template:{$video:e}}=t;at(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;at(t,"play",{value(){return d(this,null,function*(){const i=ie(t),s=yield a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;at(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${tt(t.currentTime)} / ${tt(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;at(t,"forward",{set(e){r.seek=t.currentTime+e}}),at(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;at(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=J(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),at(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;at(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=J(o,0,t.duration))}})}(t),function(t){at(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>xe(t,e,0);at(t,"switchQuality",{value:e=>xe(t,e,t.currentTime)}),at(t,"switchUrl",{value:e}),at(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;at(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;at(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)P(o,"width",null),P(o,"height",null),P(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(P(o,"width",s*r+"px"),P(o,"height","100%"),P(o,"margin","0 auto")):(P(o,"width","100%"),P(o,"height",e/s+"px"),P(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=N("canvas");at(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),at(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),at(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return Z(o,`${e||`artplayer_${tt(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),ve(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";at(t,"fullscreenWeb",{get:()=>S(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&M(document.body,o),t.state="fullscreenWeb",P(o,"width","100%"),P(o,"height","100%"),z(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&M(r,o),n&&(o.style.cssText=n,n=""),L(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),be(t),function(t){const{$video:e}=t.template,r=t;at(t,"loaded",{get:()=>r.loadedTime/e.duration}),at(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){at(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;at(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;at(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=B(e),l=n/a;if(i/s>l)P(r,"width",s*l/i*100+"%"),P(r,"height","100%");else{const t=i/l/s*100;P(r,"width","100%"),P(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;at(t,"rect",{get:()=>B(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}at(t,"x",{get:()=>e.left+window.pageXOffset}),at(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;at(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(Q(n))}`,t.emit("flip",n)}})}(t),ye(t),function(t){const{template:{$poster:e}}=t;at(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){P(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;at(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);P(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;at(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){at(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){at(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];at(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,at(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),function(t){at(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==a?void 0:a.html)||"",selector:e,onSelect(e){return d(this,null,function*(){return yield t.switchQuality(e.url),o.show=`${n.get("Switch Video")}: ${e.html}`,e.html})}})}})}(t),ke(t),ue(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=J(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=J(a,0,1)),e.poster&&P(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Te(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var n;if(e){if(l()){const e=Number(null!=(n=r.AUTO_ORIENTATION_TIME)?n:0);setTimeout(()=>{t.fullscreenWeb&&!S(o,a)&&function(){const e=U(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;P(o,"width",`${n}px`),P(o,"height",`${i}px`),P(o,"transform-origin","0 0"),P(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),z(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else S(o,a)&&(P(o,"width",""),P(o,"height",""),P(o,"transform-origin",""),P(o,"transform",""),L(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const n=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(n&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,z(o,i)}catch(a){s=!1,e.show=a}}else if(S(o,i)&&L(o,i),n&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return S(o,a)}}}function Ce(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=T(".art-auto-playback-last",s),c=T(".art-auto-playback-jump",s),d=T(".art-auto-playback-close",s);M(d,r.close);let p=null;function u(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),P(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(P(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${tt(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{P(s,"display","none")}),a(c,"click",()=>{t.seek=r,G(t.play()),P(i,"display","none"),P(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{P(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",u),t.on("restart",u),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function ze(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,L(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,z(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return S(o,"art-fast-forward")}}}function Le(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return S(o,"art-lock")}function a(){z(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){L(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=M(e,r.lock),n=M(e,r.unlock);P(o,"display","none"),t.on("lock",t=>{t?(P(o,"display","inline-flex"),P(n,"display","none")):(P(o,"display","none"),P(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function Se(t){return t.on("control",e=>{e?L(t.template.$player,"art-mini-progress-bar"):z(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class Me{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){Pt(t.art)||!e.miniProgressBar||e.isLive||t.add(Se),!Pt(t.art)&&e.lock&&k&&t.add(Le),Pt(t.art)||!e.autoPlayback||e.isLive||t.add(Ce),!Pt(t.art)&&e.autoOrientation&&k&&t.add(Te),!Pt(t.art)&&e.fastForward&&k&&!e.isLive&&t.add(ze)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){X(!Pt(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(Pt(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(Pt(t.art))return t;let n=o;const a=st(t,n);if(Pt(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return Pt(t.art)||(X(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),Pt(t.art)||at(t,n,{value:r})),t}(this,t,e)}}class Ae extends Et{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=Y(t,r.setting),o=Y(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(Q(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&R(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),at(a,"$parents",{get:()=>r}),at(a,"$option",{get:()=>t});const o=[];at(a,"$events",{get:()=>o}),at(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:n},template:{$player:a,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=B(r.setting),{left:d,width:p}=B(a),u=l-d+c/2-s/2;if(P(i,"height",`${this.active===this.option?this.active.length*n:(this.active.length+1)*n}px`),P(i,"width",`${s}px`),this.art.isRotate||k)return;u+s>p?(P(i,"left",null),P(i,"right",null)):(P(i,"left",`${u}px`),P(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=N("div");z(s,"art-setting-item-left-icon"),M(s,o),M(i,s),M(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),M(e,a)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const n=this.cache.get(t.$option),a=t.$item;let i="selector";st(t,"switch")&&(i="switch"),st(t,"range")&&(i="range"),st(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=N("div");z(p,"art-setting-item"),P(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const u=M(p,'
'),h=M(p,'
'),f=N("div");switch(z(f,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":M(f,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?M(f,t.icon||s.config):M(f,s.check)}M(u,f),at(t,"$icon",{configurable:!0,get:()=>f}),at(t,"icon",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",M(f,t)}});const m=N("div");z(m,"art-setting-item-left-text"),M(m,t.html||""),M(u,m),at(t,"$html",{configurable:!0,get:()=>m}),at(t,"html",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",M(m,t)}});const g=N("div");switch(z(g,"art-setting-item-right-tooltip"),M(g,t.tooltip||""),M(h,g),at(t,"$tooltip",{configurable:!0,get:()=>g}),at(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",M(g,t)}}),i){case"switch":{const e=N("div");z(e,"art-setting-item-right-icon");const r=M(e,s.switchOn),o=M(e,s.switchOff);P(t.switch?o:r,"display","none"),M(h,e),at(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;at(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(P(o,"display","none"),P(r,"display",null)):(P(o,"display",null),P(r,"display","none"))}});break}case"range":{const e=N("div");z(e,"art-setting-item-right-icon");const r=M(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],z(r,"art-setting-range"),M(h,e),at(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];at(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=N("div");z(t,"art-setting-item-right-icon"),M(t,s.arrowRight),M(h,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&z(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}at(t,"$item",{configurable:!0,get:()=>p}),e?D(p,a):M(n,p),t.mounted&&Ot(At(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){R(this.cache.get(t),"art-current")}else{const r=N("div");this.cache.set(t,r),z(r,"art-setting-panel"),M(this.$parent,r),R(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?I(r,t):P(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?nt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a=c(l(l({},n.subtitle),e),{url:t}),i=yield this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=N("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,A(i),M(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(m(t,$t.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||K(t.url)){case"srt":{const e=dt(r);return pt(t.onVttLoad(e))}case"ass":{const e=ut(r);return pt(t.onVttLoad(e))}case"vtt":return pt(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}const Re=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class _e{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=T(e.container),X(this.$container,`No container element found by ${e.container}`)),X(H(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();X("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),X(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=St.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=Mt(t);n.rollback=r,St.set(e,t),n.releaseContainer=()=>{St.get(e)===t&&St.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Re}query(t){return T(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=_e.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){X(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),D(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&z(this.$player,"art-backdrop"),k&&z(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":z(this.$player,"art-destroy")}}const Ve=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class Ye{on(t,e,r){const o=this.e||(this.e={});let n=Ve(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Ve(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Ve(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),Fe.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${Fe.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=Mt(t);return e.rollback=void 0,!e.scope.closed})(this)&&Ne.push(this)}catch(o){try{It(this,Ne,!0,Fe.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return Ne}static get version(){return g}static get config(){return v}static get utils(){return ft}static get scheme(){return $t}static get Emitter(){return Ye}static get validator(){return m}static get kindOf(){return m.kindOf}static get html(){return _e.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:b?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){It(this,Ne,t,Fe.REMOVE_SRC_WHEN_DESTROY)}}return Fe.STYLE=Ie,Fe.DEBUG=!1,Fe.CONTEXTMENU=!0,Fe.NOTICE_TIME=2e3,Fe.SETTING_WIDTH=250,Fe.SETTING_ITEM_WIDTH=200,Fe.SETTING_ITEM_HEIGHT=35,Fe.RESIZE_TIME=200,Fe.SCROLL_TIME=200,Fe.SCROLL_GAP=50,Fe.AUTO_PLAYBACK_MAX=10,Fe.AUTO_PLAYBACK_MIN=5,Fe.AUTO_PLAYBACK_TIMEOUT=3e3,Fe.RECONNECT_TIME_MAX=5,Fe.RECONNECT_SLEEP_TIME=1e3,Fe.CONTROL_HIDE_TIME=3e3,Fe.DBCLICK_TIME=300,Fe.DBCLICK_FULLSCREEN=!0,Fe.MOBILE_DBCLICK_PLAY=!0,Fe.MOBILE_CLICK_PLAY=!1,Fe.AUTO_ORIENTATION_TIME=200,Fe.INFO_LOOP_TIME=1e3,Fe.FAST_FORWARD_VALUE=3,Fe.FAST_FORWARD_TIME=1e3,Fe.TOUCH_MOVE_RATIO=.5,Fe.VOLUME_STEP=.1,Fe.SEEK_STEP=5,Fe.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],Fe.ASPECT_RATIO=["default","4:3","16:9"],Fe.FLIP=["normal","horizontal","vertical"],Fe.FULLSCREEN_WEB_IN_BODY=!0,Fe.LOG_VERSION=!0,Fe.USE_RAF=!1,Fe.REMOVE_SRC_WHEN_DESTROY=!0,$&&(window.Artplayer=Fe,E("artplayer-style",Ie),setTimeout(()=>{Fe.LOG_VERSION&&console.log(`%c ArtPlayer %c ${Fe.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),Fe}); +!function(t,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"==typeof define&&define.amd?(t.Artplayer=e(),define(function(){return t.Artplayer})):(t="undefined"!==typeof globalThis?globalThis:t||self).Artplayer=e()}(this,function(){"use strict";var t,e=Object.defineProperty,r=Object.defineProperties,o=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(t,r,o)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[r]=o,l=(t,e)=>{for(var r in e||(e={}))a.call(e,r)&&s(t,r,e[r]);if(n)for(var r of n(e))i.call(e,r)&&s(t,r,e[r]);return t},c=(t,e)=>r(t,o(e)),d=(t,e,r)=>new Promise((o,n)=>{var a=t=>{try{s(r.next(t))}catch(e){n(e)}},i=t=>{try{s(r.throw(t))}catch(e){n(e)}},s=t=>t.done?o(t.value):Promise.resolve(t.value).then(a,i);s((r=r.apply(t,e)).next())});function p(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var u,h={exports:{}};var f=(u||(u=1,h.exports=function(){function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}var e=Object.prototype.toString,r=function(r){if(void 0===r)return"undefined";if(null===r)return"null";var n=t(r);if("boolean"===n)return"boolean";if("string"===n)return"string";if("number"===n)return"number";if("symbol"===n)return"symbol";if("function"===n)return"GeneratorFunction"===o(r)?"generatorfunction":"function";if(function(t){return Array.isArray?Array.isArray(t):t instanceof Array}(r))return"array";if(function(t){return!(!t.constructor||"function"!=typeof t.constructor.isBuffer)&&t.constructor.isBuffer(t)}(r))return"buffer";if(function(t){try{if("number"==typeof t.length&&"function"==typeof t.callee)return!0}catch(e){if(-1!==e.message.indexOf("callee"))return!0}return!1}(r))return"arguments";if(function(t){return t instanceof Date||"function"==typeof t.toDateString&&"function"==typeof t.getDate&&"function"==typeof t.setDate}(r))return"date";if(function(t){return t instanceof Error||"string"==typeof t.message&&t.constructor&&"number"==typeof t.constructor.stackTraceLimit}(r))return"error";if(function(t){return t instanceof RegExp||"string"==typeof t.flags&&"boolean"==typeof t.ignoreCase&&"boolean"==typeof t.multiline&&"boolean"==typeof t.global}(r))return"regexp";switch(o(r)){case"Symbol":return"symbol";case"Promise":return"promise";case"WeakMap":return"weakmap";case"WeakSet":return"weakset";case"Map":return"map";case"Set":return"set";case"Int8Array":return"int8array";case"Uint8Array":return"uint8array";case"Uint8ClampedArray":return"uint8clampedarray";case"Int16Array":return"int16array";case"Uint16Array":return"uint16array";case"Int32Array":return"int32array";case"Uint32Array":return"uint32array";case"Float32Array":return"float32array";case"Float64Array":return"float64array"}if(function(t){return"function"==typeof t.throw&&"function"==typeof t.return&&"function"==typeof t.next}(r))return"generator";switch(n=e.call(r)){case"[object Object]":return"object";case"[object Map Iterator]":return"mapiterator";case"[object Set Iterator]":return"setiterator";case"[object String Iterator]":return"stringiterator";case"[object Array Iterator]":return"arrayiterator"}return n.slice(8,-1).toLowerCase().replace(/\s/g,"")};function o(t){return t.constructor?t.constructor.name:null}function n(t,e){var o=2{e&&(e=!1,this.cleanups.delete(r),t())};return this.closed?r():this.cleanups.add(r),r}child(){const t=new b,e=this.add(()=>{t.dispose()});return t.add(()=>{e()}),t}dispose(){if(this.closed)return;this.disposed=!0;const t=[];for(const r of Array.from(this.cleanups).reverse())try{r()}catch(e){e instanceof y?t.push(...e.errors):t.push(e)}if(t.length)throw new y(t)}}const w=new WeakMap,x=new WeakMap;function k(t){const e=w.get(t);if(!e)throw new Error("ArtPlayer lifecycle has not been initialized");return e}function $(t){return k(t).scope}function E(t){const e=k(t);return e.destroying||e.scope.closed}function T(t,e,r,o,n=!1){var a,i,s;const l=k(t);if(l.destroying||l.scope.closed)return;l.destroying=!0;const c=[],d=t=>{try{t()}catch(e){c.push(...e instanceof y?e.errors:[e])}};o&&(null==(a=t.template)?void 0:a.$video)&&d(()=>t.reset()),d(()=>l.scope.dispose()),d(()=>{var e;return null==(e=t.template)?void 0:e.destroy(r)});const p=e.indexOf(t);-1!==p&&e.splice(p,1),t.isDestroy=!0,n||(null==(i=l.releaseContainer)||i.call(l),l.releaseContainer=void 0),d(()=>t.emit("destroy")),n&&l.rollback&&d(l.rollback),l.rollback=void 0,null==(s=l.releaseContainer)||s.call(l),l.releaseContainer=void 0;for(const u of c.slice(1))console.warn("Additional ArtPlayer cleanup failure:",u);if(c.length)throw c[0]}const C=new WeakMap;function z(t,e){const r=$(t).child();return C.set(e,r),r}function S(t){const e=C.get(t);if(!e)throw new Error("ArtPlayer component has not been registered");return e}function L(t){var e;null==(e=C.get(t))||e.dispose()}function M(t,e){return{on:(r,o)=>{!function(t,e,r,o){const n=S(e);if(n.closed)return;const a=(...t)=>{if(!n.closed)return o(...t)};t.on(r,a),n.add(()=>{t.off(r,a)})}(t,e,r,o)},proxy:(r,o,n)=>function(t,e,r,o,n){const a=S(e);if(a.closed)return()=>{};const i=t.events.proxy(r,o,t=>{if(!a.closed)return n(t)});return a.add(()=>{t.events.remove(i)})}(t,e,r,o,n)}}const A=null!=(t=null==globalThis?void 0:globalThis.CUSTOM_USER_AGENT)?t:"undefined"!==typeof navigator?navigator.userAgent:"",P=/^(?:(?!chrome|android).)*safari/i.test(A),O=/iPad|iPhone|iPod/i.test(A)&&!window.MSStream,I=O||A.includes("Macintosh")&&navigator.maxTouchPoints>=1,R=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(A)||I,_="undefined"!==typeof window&&"undefined"!==typeof document;function V(t,e){let r=document.getElementById(t);r||(r=document.createElement("style"),r.id=t,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{document.head.appendChild(r)}):(document.head||document.documentElement).appendChild(r)),r.textContent=e}function Y(t,e=document){return e.querySelector(t)}function D(t,e=document){return Array.from(e.querySelectorAll(t))}function N(t,e){return t.classList.add(e)}function F(t,e){return t.classList.remove(e)}function H(t,e){return t.classList.contains(e)}function B(t,e){return e instanceof Element?t.appendChild(e):t.insertAdjacentHTML("beforeend",String(e)),t.lastElementChild||t.lastChild}function W(t){return t.parentNode.removeChild(t)}function j(t,e,r){return t.style[e]=r,t}function q(t,e){for(const r in e)j(t,r,e[r]);return t}function U(t){return Array.from(t.parentElement.children).filter(e=>e!==t)}function X(t,e){U(t).forEach(t=>F(t,e)),N(t,e)}function G(t,e,r="top"){R||(t.setAttribute("aria-label",e),N(t,"hint--rounded"),N(t,`hint--${r}`))}function K(t,e=0){const r=t.getBoundingClientRect(),o=window.innerHeight||document.documentElement.clientHeight,n=window.innerWidth||document.documentElement.clientWidth,a=r.top-e<=o&&r.top+r.height+e>=0,i=r.left-e<=n+e&&r.left+r.width+e>=0;return a&&i}function Z(t,e){return nt(t).includes(e)}function J(t,e){return e.parentNode.replaceChild(t,e),t}function Q(t){return document.createElement(t)}function tt(t="",e=""){const r=Q("i");return N(r,"art-icon"),N(r,`art-icon-${t}`),B(r,e),r}function et(){const t=document.createElement("div");return t.style.display="flex","flex"===t.style.display}function rt(t){return t.getBoundingClientRect()}function ot(t,e){return new Promise((r,o)=>{const n=new Image;n.onload=function(){if(e&&1!==e){const a=document.createElement("canvas"),i=a.getContext("2d");a.width=n.width*e,a.height=n.height*e,i.drawImage(n,0,0,a.width,a.height),a.toBlob(e=>{const n=URL.createObjectURL(e),a=new Image;a.onload=function(){r(a)},a.onerror=function(){URL.revokeObjectURL(n),o(new Error(`Image load failed: ${t}`))},a.src=n})}else r(n)},n.onerror=function(){o(new Error(`Image load failed: ${t}`))},n.src=t})}function nt(t){if(t.composedPath)return t.composedPath();const e=[];let r=t.target;for(;r;)e.push(r),r=r.parentNode;return e.includes(window)||void 0===window||e.push(window),e}function at(){const t=document.createElement("div");t.style.cssText="position:fixed;top:env(safe-area-inset-top,0px);right:env(safe-area-inset-right,0px);bottom:env(safe-area-inset-bottom,0px);left:env(safe-area-inset-left,0px);pointer-events:none;visibility:hidden;",document.body.appendChild(t);const e=getComputedStyle(t),r={top:Number.parseFloat(e.top)||0,right:Number.parseFloat(e.right)||0,bottom:Number.parseFloat(e.bottom)||0,left:Number.parseFloat(e.left)||0};return t.remove(),r}class it extends Error{constructor(t,e){super(t),"captureStackTrace"in Error&&"function"===typeof Error.captureStackTrace&&Error.captureStackTrace(this,e||this.constructor),this.name="ArtPlayerError"}}function st(t,e){if(!t)throw new it(e);return t}function lt(t){const e=t;return e&&"function"===typeof e.catch?e.catch(()=>{}):t}function ct(t){const e=t.search(/[?#]/),r=(e<0?t:t.slice(0,e)).trim().toLowerCase();return r.slice(r.lastIndexOf(".")+1)}function dt(t,e){const r=document.createElement("a");r.style.display="none",r.href=t,r.download=e,document.body.appendChild(r);try{r.click()}finally{r.remove()}}function pt(t,e,r){return Math.max(Math.min(t,Math.max(e,r)),Math.min(e,r))}function ut(t){return t.charAt(0).toUpperCase()+t.slice(1)}function ht(t){if(!t)return"00:00";const e=Math.floor(t/3600),r=Math.floor((t-3600*e)/60),o=Math.floor(t-3600*e-60*r);return(e>0?[e,r,o]:[r,o]).map(t=>t<10?`0${t}`:String(t)).join(":")}const ft={"&":"&","<":"<",">":">","'":"'",'"':"""},mt={"&":"&","<":"<",">":">","'":"'",""":'"'},gt=/(&|<|>|'|")/g;function vt(t){return t.replace(/[&<>'"]/g,t=>ft[t]||t)}const yt=Object.defineProperty,{hasOwnProperty:bt}=Object.prototype;function wt(t,e){return bt.call(t,e)}function xt(t,e){return Object.getOwnPropertyDescriptor(t,e)}function kt(...t){const e=t=>!!t&&"object"===typeof t&&!Array.isArray(t);return t.reduce((t,r)=>(Object.keys(r).forEach(o=>{const n=t[o],a=r[o];let i;i=Array.isArray(n)&&Array.isArray(a)?n.concat(...a):e(n)&&e(a)?kt(n,a):a,yt(t,o,{value:i,enumerable:!0,configurable:!0,writable:!0})}),t),{})}function $t(t){return"WEBVTT \r\n\r\n".concat((e=t,e.replace(/(\d\d:\d\d:\d\d)[,.](\d+)/g,(t,e,r)=>{let o=r.slice(0,3);return 1===r.length&&(o=`${r}00`),2===r.length&&(o=`${r}0`),`${e},${o}`})).replace(/\{\\([ibu])\}/g,"").replace(/\{\\([ibu])1\}/g,"<$1>").replace(/\{([ibu])\}/g,"<$1>").replace(/\{\/([ibu])\}/g,"").replace(/(\d\d:\d\d:\d\d),(\d\d\d)/g,"$1.$2").replace(/\{[\s\S]*?\}/g,"").concat("\r\n\r\n"));var e}function Et(t){return URL.createObjectURL(new Blob([t],{type:"text/vtt"}))}function Tt(t){const e=new RegExp("Dialogue:\\s\\d,(\\d+:\\d\\d:\\d\\d.\\d\\d),(\\d+:\\d\\d:\\d\\d.\\d\\d),([^,]*),([^,]*),(?:[^,]*,){4}([\\s\\S]*)$","i");function r(t=""){return t.split(/[:.]/).map((t,e,r)=>{if(e===r.length-1){if(1===t.length)return`.${t}00`;if(2===t.length)return`.${t}0`}else if(1===t.length)return(0===e?"0":":0")+t;return 0===e?t:e===r.length-1?`.${t}`:`:${t}`}).join("")}return`WEBVTT\n\n${t.split(/\r?\n/).map(t=>{const o=t.match(e);if(!o)return null;const[,n="",a="",,,i=""]=o;return{start:r(n.trim()),end:r(a.trim()),text:i.replace(/\{[\s\S]*?\}/g,"").replace(/(\\N)/g,"\n").trim().split(/\r?\n/).map(t=>t.trim()).join("\n")}}).filter(t=>t).map((t,e)=>t?`${e+1}\n${t.start} --\x3e ${t.end}\n${t.text}`:"").filter(t=>t.trim()).join("\n\n")}`}function Ct(t,e){let r=!1;return function(...o){r||(t.apply(this,o),r=!0,setTimeout(()=>{r=!1},e))}}const zt=Object.freeze(Object.defineProperty({__proto__:null,ArtPlayerError:it,addClass:N,append:B,assToVtt:Tt,capitalize:ut,clamp:pt,createElement:Q,debounce:function(t,e){let r;return function(...o){clearTimeout(r),r=setTimeout(()=>(r=void 0,t.apply(this,o)),e)}},def:yt,download:dt,errorHandle:st,escape:vt,get:xt,getComposedPath:nt,getExt:ct,getIcon:tt,getRect:rt,getSafeAreaInsets:at,getStyle:function(t,e,r=!0){const o=window.getComputedStyle(t,null).getPropertyValue(e);return r?Number.parseFloat(o):o},has:wt,hasClass:H,includeFromEvent:Z,inverseClass:X,isBrowser:_,isIOS:O,isIOS13:I,isInViewport:K,isMobile:R,isSafari:P,loadImg:ot,mergeDeep:kt,query:Y,queryAll:D,remove:W,removeClass:F,replaceElement:J,secondToTime:ht,setStyle:j,setStyleText:V,setStyles:q,siblings:U,silencePromise:lt,sleep:function(t=0){return new Promise(e=>setTimeout(e,t))},srtToVtt:$t,supportsFlex:et,throttle:Ct,tooltip:G,unescape:function(t){return t.replace(gt,t=>mt[t]||t)},userAgent:A,vttToBlob:Et},Symbol.toStringTag,{value:"Module"}));function St(t,e){return B(t,e)}function Lt(t,e){return e.querySelector(t)}const Mt="array",At="boolean",Pt="string",Ot="number",It="object",Rt="function";function _t(t,e,r){return st(e===Pt||e===Ot||t instanceof Element,`${r.join(".")} require '${Pt}' or 'Element' type`)}const Vt={html:_t,disable:`?${At}`,name:`?${Pt}`,index:`?${Ot}`,style:`?${It}`,click:`?${Rt}`,mounted:`?${Rt}`,tooltip:`?${Pt}|${Ot}`,width:`?${Ot}`,selector:`?${Mt}`,onSelect:`?${Rt}`,switch:`?${At}`,onSwitch:`?${Rt}`,range:`?${Mt}`,onRange:`?${Rt}`,onChange:`?${Rt}`},Yt={id:Pt,container:_t,url:Pt,poster:Pt,type:Pt,theme:Pt,lang:Pt,volume:Ot,isLive:At,muted:At,autoplay:At,autoSize:At,autoMini:At,loop:At,flip:At,playbackRate:At,aspectRatio:At,screenshot:At,setting:At,hotkey:At,pip:At,mutex:At,backdrop:At,fullscreen:At,fullscreenWeb:At,subtitleOffset:At,miniProgressBar:At,useSSR:At,playsInline:At,lock:At,gesture:At,fastForward:At,autoPlayback:At,autoOrientation:At,airplay:At,proxy:`?${Rt}`,plugins:[Rt],layers:[Vt],contextmenu:[Vt],settings:[Vt],controls:[c(l({},Vt),{position:(t,e,r)=>{const o=["top","left","right"];return st("string"===typeof t&&o.includes(t),`${r.join(".")} only accept ${o.toString()} as parameters`)}})],quality:[{default:`?${At}`,html:Pt,url:Pt}],highlight:[{time:Ot,text:Pt}],thumbnails:{url:Pt,number:Ot,column:Ot,width:Ot,height:Ot,scale:Ot},subtitle:{url:Pt,name:Pt,type:Pt,style:It,escape:At,encoding:Pt,onVttLoad:Rt},moreVideoAttr:It,i18n:It,icons:It,cssVar:It,customType:It},Dt=new WeakSet;class Nt{constructor(t){this.id=0,this.art=t,this.cache=new Map,this.add=this.add.bind(this),this.remove=this.remove.bind(this),this.update=this.update.bind(this)}get show(){return H(this.art.template.$player,`art-${this.name}-show`)}set show(t){const{$player:e}=this.art.template,r=`art-${this.name}-show`;t?N(e,r):F(e,r),this.art.emit(this.name,t)}toggle(){this.show=!this.show}add(t){var e;if(E(this.art))return;const r="function"===typeof t?t(this.art):t;if(E(this.art))return;if(r.html=r.html||"",m(r,Vt),!this.$parent||!this.name||r.disable)return;const o=r.name||`${this.name}${this.id}`,n=this.cache;st(!n.has(o),`Can't add an existing [${o}] to the [${this.name}]`),this.id+=1;const a=document.createElement("div"),i=z(this.art,a),s=[],l=Object.getOwnPropertyDescriptor(this,o);let c=!1;i.add(()=>{for(const t of s)this.art.events.remove(t)});try{if(i.closed)return;if(function(t,e,r,o,n,a){N(t,`art-${r}`),N(t,`art-${r}-${o}`);const i=Array.from(e.children);t.dataset.index=String(a.index||n);const s=i.find(e=>Number(e.dataset.index)>=Number(t.dataset.index));s?s.insertAdjacentElement("beforebegin",t):B(e,t),a.html&&B(t,a.html),a.style&&q(t,a.style),a.tooltip&&G(t,a.tooltip)}(a,this.$parent,this.name,o,this.id,r),i.closed)return;if(r.click){const t=this.art.events.proxy(a,"click",t=>{i.closed||(t.preventDefault(),r.click.call(this.art,this,t))});s.push(t)}if(r.selector&&["left","right"].includes(r.position)&&this.selector(r,a,s),i.closed)return;return function(t,e,r){const o=t;"__proto__"===e?Object.defineProperty(o,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):o[e]=r}(this,o,a),c=!0,n.set(o,{$ref:a,events:s,option:r}),r.mounted&&r.mounted.call(this.art,a),a}catch(d){try{L(a)}catch(p){console.warn("ArtPlayer component cleanup failed:",p)}throw(null==(e=n.get(o))?void 0:e.$ref)===a&&n.delete(o),c&&this[o]===a&&(l?Object.defineProperty(this,o,l):delete this[o]),a.remove(),d}}remove(t){st(this.cache.has(t),`Can't find [${t}] from the [${this.name}]`);const e=this.cache.get(t);if(!Dt.has(e)){Dt.add(e);try{e.option.beforeUnmount&&e.option.beforeUnmount.call(this.art,e.$ref);try{L(e.$ref)}finally{this.cache.get(t)===e&&(this.cache.delete(t),delete this[t]),e.$ref.remove()}}finally{Dt.delete(e)}}}update(t){if(this.cache.has(t.name)){const e=this.cache.get(t.name);t=Object.assign(e.option,t),this.remove(t.name)}return this.add(t)}}class Ft extends Nt{constructor(t){super(t),this.name="contextmenu",this.$parent=t.template.$contextmenu,z(t,this.$parent),R||this.init()}init(){const{option:t,template:{$player:e,$contextmenu:r}}=this.art,{on:o,proxy:n}=M(this.art,r);t.playbackRate&&this.add(function(t){return e=>{const{i18n:r,constructor:{PLAYBACK_RATE:o}}=e,n=o.map(t=>`${1===t?r.get("Normal"):t.toFixed(1)}`).join("");return c(l({},t),{html:`${r.get("Play Speed")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.playbackRate=Number(o),t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="1"]',t);o&&X(o,"art-current"),r("video:ratechange",()=>{const r=Array.from(t.querySelectorAll("span")).find(t=>Number(t.dataset.value)===e.playbackRate);r&&X(r,"art-current")})}})}}({name:"playbackRate",index:10})),t.aspectRatio&&this.add(function(t){return e=>{const{i18n:r,constructor:{ASPECT_RATIO:o}}=e,n=o.map(t=>`${"default"===t?r.get("Default"):t}`).join("");return c(l({},t),{html:`${r.get("Aspect Ratio")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.aspectRatio=o,t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="default"]',t);o&&X(o,"art-current"),r("aspectRatio",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&X(r,"art-current")})}})}}({name:"aspectRatio",index:20})),t.flip&&this.add(function(t){return e=>{const{i18n:r,constructor:{FLIP:o}}=e,n=o.map(t=>`${r.get(ut(t))}`).join("");return c(l({},t),{html:`${r.get("Video Flip")}: ${n}`,click:(t,r)=>{const o=r.target instanceof HTMLElement?r.target.dataset.value:void 0;o&&(e.flip=o.toLowerCase(),t.show=!1)},mounted:t=>{const{on:r}=M(e,t),o=Y('[data-value="normal"]',t);o&&X(o,"art-current"),r("flip",e=>{const r=Array.from(t.querySelectorAll("span")).find(t=>t.dataset.value===e);r&&X(r,"art-current")})}})}}({name:"flip",index:30})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Video Info"),click:t=>{e.info.show=!0,t.show=!1}})}({name:"info",index:40})),this.add(function(t){return c(l({},t),{html:`ArtPlayer ${g}`})}({name:"version",index:50})),this.add(function(t){return e=>c(l({},t),{html:e.i18n.get("Close"),click:t=>{t.show=!1}})}({name:"close",index:60}));for(let a=0;a{if(!this.art.constructor.CONTEXTMENU)return;t.preventDefault(),this.show=!0;const o=t.clientX,n=t.clientY,{height:a,width:i,left:s,top:l}=rt(e),{height:c,width:d}=rt(r);let p=o-s,u=n-l;o+d>s+i&&(p=i-d),n+c>l+a&&(u=a-c),q(r,{top:`${u}px`,left:`${p}px`})}),n(e,"click",t=>{Z(t,r)||(this.show=!1)}),o("blur",()=>{this.show=!1})}}function Ht(t,e,r){if(t.closed)return()=>{};let o=!0,n=()=>{};const a=setTimeout(()=>{o&&(n(),t.closed||e())},r);return n=t.add(()=>{o=!1,clearTimeout(a)}),n}function Bt(t,e=0){return t.closed?Promise.resolve(!1):new Promise(r=>{let o=!1,n=()=>{};const a=setTimeout(()=>{o=!0,n(),r(!0)},e);n=t.add(()=>{clearTimeout(a),o||r(!1)})})}function Wt(t,e){const{$progress:r}=t.template,{left:o}=rt(r),n=pt((R?e.touches[0].clientX:e.clientX)-o,0,r.clientWidth),a=n/r.clientWidth*t.duration;return{second:a,time:ht(a),width:n,percentage:pt(n/r.clientWidth,0,1)}}function jt(t,e){if(t.isRotate){const r=(e.touches[0].clientY-t.top)/t.height,o=r*t.duration;t.emit("setBar","played",r,e),t.seek=o}else{const{second:r,percentage:o}=Wt(t,e);t.emit("setBar","played",o,e),t.seek=r}}function qt(t,e){const{icons:r,option:o}=t,{$player:n}=t.template,a=S(e),{on:i}=M(t,e);let s=()=>{};const l=Lt(".art-progress-hover",e),c=Lt(".art-progress-loaded",e),d=Lt(".art-progress-played",e),p=Lt(".art-progress-highlight",e),u=Lt(".art-progress-indicator",e),h=Lt(".art-progress-tip",e);function f(r,o){const{width:n,time:a}=o||Wt(t,r);h.textContent=a||"00:00";const i=h.clientWidth;n<=i/2?j(h,"left",0):n>e.clientWidth-i/2?j(h,"left",e.clientWidth-i+"px"):j(h,"left",n-i/2+"px")}r.indicator?B(u,r.indicator):j(u,"backgroundColor","var(--art-theme)"),i("setBar",function(r,o,i){const m="played"===r&&i&&R;if("loaded"===r&&j(c,"width",100*o+"%"),"hover"===r&&(j(l,"width",100*o+"%"),Z(i,p)?function(r){const{width:o}=Wt(t,r),n=r.target instanceof HTMLElement?r.target.dataset.text:void 0;h.textContent=null!=n?n:"";const a=h.clientWidth;o<=a/2?j(h,"left",0):o>e.clientWidth-a/2?j(h,"left",e.clientWidth-a+"px"):j(h,"left",o-a/2+"px")}(i):f(i),0===o?F(n,"art-progress-hover"):N(n,"art-progress-hover")),"played"===r&&(j(d,"width",100*o+"%"),j(u,"left",100*o+"%")),m){N(n,"art-progress-hover");f(i,{width:e.clientWidth*o,time:ht(o*t.duration)}),s(),s=Ht(a,()=>{F(n,"art-progress-hover")},500)}}),i("video:loadedmetadata",function(){p.textContent="";for(let e=0;e{t.emit("setBar","played",t.played),t.emit("setBar","loaded",t.loaded)}):(i("video:timeupdate",()=>{t.emit("setBar","played",t.played)}),i("video:progress",()=>{t.emit("setBar","loaded",t.loaded)}),i("video:ended",()=>{t.emit("setBar","played",1)})),t.emit("setBar","loaded",t.loaded||0)}function Ut(t){return e=>c(l({},t),{html:'\n
\n
\n
\n
\n
\n
\n
00:00
\n
\n ',mounted:t=>{qt(e,t),function(t,e){const{$progress:r}=t.template,o=e.querySelector(".art-progress-indicator"),{on:n,proxy:a}=M(t,e);if(!R){let e=!1;a(r,"click",e=>{e.target!==o&&jt(t,e)}),a(r,"mousemove",e=>{const{percentage:r}=Wt(t,e);t.emit("setBar","hover",r,e)}),a(r,"mouseleave",e=>{t.emit("setBar","hover",0,e)}),a(r,"mousedown",t=>{e=0===t.button}),n("document:mousemove",r=>{if(e){const{second:e,percentage:o}=Wt(t,r);t.emit("setBar","played",o,r),t.seek=e}}),n("document:mouseup",()=>{e&&(e=!1)})}}(e,t)}})}function Xt(t){const{option:e}=t.art;e.isLive||t.add(Ut({name:"progress",position:"top",index:10})),t.add({name:"thumbnails",position:"top",index:20}),t.add(function(t){return e=>c(l({},t),{mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.play),s=St(t,n.pause);function l(){j(i,"display","flex"),j(s,"display","none")}function c(){j(i,"display","none"),j(s,"display","flex")}G(i,a.get("Play")),G(s,a.get("Pause")),o(i,"click",()=>{lt(e.play())}),o(s,"click",()=>{e.pause()}),e.playing?c():l(),r("video:playing",()=>{c()}),r("video:pause",()=>{l()})}})}({name:"playAndPause",position:"left",index:10})),t.add(function(t){return e=>c(l({},t),{mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n}=e,a=St(t,n.volume),i=St(t,n.volumeClose),s=St(t,'
'),l=St(s,'
'),c=St(l,'
'),d=St(l,'
'),p=St(d,'
'),u=St(p,'
'),h=St(d,'
');function f(t){const{top:e,height:r}=rt(d);return 1-(t.clientY-e)/r}function m(){if(e.muted||0===e.volume)j(a,"display","none"),j(i,"display","flex"),j(h,"top","100%"),j(u,"top","100%"),c.textContent="0";else{const t=100*e.volume;j(a,"display","flex"),j(i,"display","none"),j(h,"top",100-t+"%"),j(u,"top",100-t+"%"),c.textContent=String(Math.floor(t))}}if(m(),r("video:volumechange",m),o(a,"click",()=>{e.muted=!0}),o(i,"click",()=>{e.muted=!1}),R)j(s,"display","none");else{let t=!1;o(d,"mousedown",r=>{t=0===r.button,e.volume=f(r)}),r("document:mousemove",r=>{t&&(e.muted=!1,e.volume=f(r))}),r("document:mouseup",()=>{t&&(t=!1)})}}})}({name:"volume",position:"left",index:20})),e.isLive||t.add(function(t){return e=>c(l({},t),{style:R?{fontSize:"12px",padding:"0 5px"}:{cursor:"auto",padding:"0 10px"},mounted:t=>{const{on:r}=M(e,t);function o(){const r=`${ht(e.currentTime)} / ${ht(e.duration)}`;r!==t.textContent&&(t.textContent=r)}o();const n=["video:loadedmetadata","video:timeupdate","video:progress"];for(let e=0;e{r&&!$(t.art).closed&&(t.art.quality=e.quality)}).catch(t=>{console.warn("ArtPlayer quality initialization failed:",t)}),e.screenshot&&!R&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Screenshot"),mounted:t=>{const{proxy:r}=M(e,t),{icons:o}=e;St(t,o.screenshot),r(t,"click",()=>{e.screenshot()})}})}({name:"screenshot",position:"right",index:20})),e.setting&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Show Setting"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e;St(t,n.setting),o(t,"click",()=>{e.setting.toggle(),e.setting.resize()}),r("setting",e=>{G(t,a.get(e?"Hide Setting":"Show Setting"))})}})}({name:"setting",position:"right",index:30})),e.pip&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("PIP Mode"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e;St(t,n.pip),o(t,"click",()=>{e.pip=!e.pip}),r("pip",e=>{G(t,a.get(e?"Exit PIP Mode":"PIP Mode"))})}})}({name:"pip",position:"right",index:40})),e.airplay&&"WebKitPlaybackTargetAvailabilityEvent"in window&&window.WebKitPlaybackTargetAvailabilityEvent&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("AirPlay"),mounted:t=>{const{proxy:r}=M(e,t),{icons:o}=e;St(t,o.airplay),r(t,"click",()=>e.airplay())}})}({name:"airplay",position:"right",index:50})),e.fullscreenWeb&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Web Fullscreen"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.fullscreenWebOn),s=St(t,n.fullscreenWebOff);j(s,"display","none"),o(t,"click",()=>{e.fullscreenWeb=!e.fullscreenWeb}),r("fullscreenWeb",e=>{e?(G(t,a.get("Exit Web Fullscreen")),j(i,"display","none"),j(s,"display","inline-flex")):(G(t,a.get("Web Fullscreen")),j(i,"display","inline-flex"),j(s,"display","none"))})}})}({name:"fullscreenWeb",position:"right",index:60})),e.fullscreen&&t.add(function(t){return e=>c(l({},t),{tooltip:e.i18n.get("Fullscreen"),mounted:t=>{const{on:r,proxy:o}=M(e,t),{icons:n,i18n:a}=e,i=St(t,n.fullscreenOn),s=St(t,n.fullscreenOff);j(s,"display","none"),o(t,"click",()=>{e.fullscreen=!e.fullscreen}),r("fullscreen",e=>{e?(G(t,a.get("Exit Fullscreen")),j(i,"display","none"),j(s,"display","inline-flex")):(G(t,a.get("Fullscreen")),j(i,"display","inline-flex"),j(s,"display","none"))})}})}({name:"fullscreen",position:"right",index:70}));for(let r=0;rKt.get(t).option.selector}),yt(t,"$control_item",{get:()=>Kt.get(t).item}),yt(t,"$control_value",{get:()=>Kt.get(t).value})),Kt.set(t,e)}function Jt(t,e){t.innerHTML=e}function Qt(t,e,r,o,n){const{proxy:a}=t.events,i=S(o),s=r.selector;N(o,"art-control-selector");const l=document.createElement("div");N(l,"art-selector-value"),B(l,r.html),o.textContent="",B(o,l);const c=St(o,'
');for(let d=0;dd(null,null,function*(){if(i.closed)return;const n=nt(o),a=r.selector.find(t=>n.includes(t.$control_item));if(!a)return;const s=++p,c=()=>!i.closed&&s===p,d=i.add(function(t,e){return Gt.set(t,e),()=>{Gt.get(t)===e&&Gt.delete(t)}}(o,c));try{if(e(a),i.closed)return;if(r.onSelect){const e=yield r.onSelect.call(t,a,a.$control_item,o);c()&&Jt(l,e)}}catch(u){console.warn("ArtPlayer selector failed:",u)}finally{d()}}));n.push(u)}class te extends Nt{constructor(t){super(t),this.isHover=!1,this.name="control",this.timer=Date.now();const{constructor:e}=t,{$player:r,$bottom:o}=this.art.template;z(t,o);const{on:n}=M(t,o);n("mousemove",()=>{R||(this.show=!0)}),n("click",()=>{R?this.toggle():this.show=!0}),n("document:mousemove",t=>{this.isHover=Z(t,o)}),n("video:timeupdate",()=>{!t.setting.show&&!this.isHover&&!t.isInput&&t.playing&&this.show&&Date.now()-this.timer>=e.CONTROL_HIDE_TIME&&(this.show=!1)}),n("control",t=>{t?(F(r,"art-hide-cursor"),N(r,"art-hover"),this.timer=Date.now()):(N(r,"art-hide-cursor"),F(r,"art-hover"))}),this.init(),$(t).closed||function(t){const{$bottom:e,$controls:r,$player:o}=t.template,n=S(e),{on:a}=M(t,e),i=()=>{if(n.closed)return;const t=r.offsetHeight;t>0&&o.style.getPropertyValue("--art-controls-height")!==`${t}px`&&o.style.setProperty("--art-controls-height",`${t}px`)};if(a("resize",i),"undefined"!==typeof ResizeObserver){const t=new ResizeObserver(i);t.observe(r),n.add(()=>{t.disconnect()})}else if("undefined"!==typeof MutationObserver){const t=new MutationObserver(i);t.observe(r,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),n.add(()=>{t.disconnect()})}i()}(t)}init(){Xt(this)}add(t){if(E(this.art))return;const e="function"===typeof t?t(this.art):t,{$progress:r,$controlsLeft:o,$controlsRight:n}=this.art.template;switch(e.position){case"top":this.$parent=r;break;case"left":this.$parent=o;break;case"right":this.$parent=n;break;default:st(!1,"Control option.position must one of 'top', 'left', 'right'")}super.add(e)}check(t){!function(t){if(t){Jt(t.$control_value,t.html);for(let e=0;ethis.check(t),t,e,r)}}function ee(t,e,r,o){const n=e-o,a=r-t;let i=0;if(Math.abs(a)<2&&Math.abs(n)<2)return i;const s=function(t,e){return 180*Math.atan2(e,t)/Math.PI}(a,n);return s>=-45&&s<45?i=4:s>=45&&s<135?i=1:s>=-135&&s<-45?i=2:(s>=135&&s<=180||s>=-180&&s<-135)&&(i=3),i}function re(t){if(t.constructor.USE_RAF){const e=$(t);let r=()=>{};!function o(){t.playing&&t.emit("raf"),t.isDestroy||(r=function(t,e){if(t.closed)return()=>{};let r=!0,o=()=>{};const n=requestAnimationFrame(n=>{r&&(o(),t.closed||e(n))});return o=t.add(()=>{r=!1,cancelAnimationFrame(n)}),o}(e,o))}(),t.on("destroy",()=>{r()})}}const oe=new WeakMap;class ne{constructor(t){this.destroyEvents=new Set;const e=$(t);oe.set(this,e),e.add(()=>this.destroy()),this.proxy=this.proxy.bind(this),this.hover=this.hover.bind(this),function(t,e){const{constructor:r,template:{$player:o,$video:n}}=t;function a(e){Z(e,o)?(t.isInput="INPUT"===e.target.tagName,t.isFocus=!0,t.emit("focus",e)):(t.isInput=!1,t.isFocus=!1,t.emit("blur",e))}t.on("document:click",a),t.on("document:contextmenu",a);let i=[];e.proxy(n,"click",e=>{const o=Date.now();i.push(o);const{MOBILE_CLICK_PLAY:n,DBCLICK_TIME:a,MOBILE_DBCLICK_PLAY:s,DBCLICK_FULLSCREEN:l}=r,c=i.filter(t=>o-t<=a);switch(c.length){case 1:t.emit("click",e),R?!t.isLock&&n&<(t.toggle()):lt(t.toggle()),i=c;break;case 2:t.emit("dblclick",e),R?!t.isLock&&s&<(t.toggle()):l&&(t.fullscreen=!t.fullscreen),i=[];break;default:i=[]}})}(t,this),function(t,e){const{$player:r}=t.template;e.hover(r,e=>{N(r,"art-hover"),t.emit("hover",!0,e)},e=>{F(r,"art-hover"),t.emit("hover",!1,e)})}(t,this),function(t,e){const{$player:r}=t.template;e.proxy(r,"mousemove",e=>{t.emit("mousemove",e)})}(t,this),function(t,e){const{option:r,constructor:o}=t;t.on("resize",()=>{const{aspectRatio:e,notice:o}=t;"standard"===t.state&&r.autoSize&&t.autoSize(),t.aspectRatio=e,o.show=""});const n=$(t);let a=()=>{};const i=()=>{a(),a=Ht(n,()=>t.emit("resize"),o.RESIZE_TIME)};t.on("window:orientationchange",()=>i()),t.on("window:resize",()=>i()),screen&&screen.orientation&&screen.orientation.onchange&&e.proxy(screen.orientation,"change",()=>i())}(t,this),function(t,e){if(R&&!t.option.isLive){const{$video:r,$progress:o}=t.template;let n=null,a=!1,i=0,s=0,l=0;const c=e=>{if(1===e.touches.length&&!t.isLock){n===o&&jt(t,e),a=!0;const{pageX:r,pageY:c}=e.touches[0];i=r,s=c,l=t.currentTime}},d=e=>{if(1===e.touches.length&&a&&t.duration){const{pageX:o,pageY:a}=e.touches[0],c=ee(i,s,o,a),d=[3,4].includes(c),p=[1,2].includes(c);if(d&&!t.isRotate||p&&t.isRotate){const c=pt((o-i)/t.width,-1,1),d=pt((a-s)/t.height,-1,1),p=t.isRotate?d:c,u=n===r?t.constructor.TOUCH_MOVE_RATIO:1,h=pt(l+t.duration*p*u,0,t.duration);t.seek=h,t.emit("setBar","played",pt(h/t.duration,0,1),e),t.notice.show=`${ht(h)} / ${ht(t.duration)}`}}},p=()=>{a&&(i=0,s=0,l=0,a=!1,n=null)};t.option.gesture&&(e.proxy(r,"touchstart",t=>{n=r,c(t)}),e.proxy(r,"touchmove",d)),e.proxy(o,"touchstart",t=>{n=o,c(t)}),e.proxy(o,"touchmove",d),t.on("document:touchend",p)}}(t,this),function(t){const{option:e,constructor:r,template:{$container:o}}=t,n=Ct(()=>{t.emit("view",K(o,r.SCROLL_GAP))},r.SCROLL_TIME);t.on("window:scroll",()=>n()),t.on("view",r=>{e.autoMini&&(t.mini=!r)})}(t),function(t,e){const r=["click","mouseup","keydown","touchend","touchmove","mousemove","pointerup","contextmenu","pointermove","visibilitychange","webkitfullscreenchange"],o=["resize","scroll","orientationchange"],n=[];function a(a={}){for(let t=0;t{const o=a.document||i.ownerDocument||document,s=e.proxy(o,r,e=>{t.emit(`document:${r}`,e)});n.push(s)}),o.forEach(r=>{var o;const s=a.window||(null==(o=i.ownerDocument)?void 0:o.defaultView)||window,l=e.proxy(s,r,e=>{t.emit(`window:${r}`,e)});n.push(l)})}a(),e.bindGlobalEvents=a}(t,this),re(t)}proxy(t,e,r,o={}){if(Array.isArray(e))return e.map(e=>this.proxy(t,e,r,o));if(oe.get(this).closed)return()=>{};t.addEventListener(e,r,o);const n=()=>t.removeEventListener(e,r,o);return this.destroyEvents.add(n),n}hover(t,e,r){e&&this.proxy(t,"mouseenter",e),r&&this.proxy(t,"mouseleave",r)}remove(t){if(this.destroyEvents.has(t))try{t()}catch(e){console.warn("Failed to remove event listener:",e)}finally{this.destroyEvents.delete(t)}}destroy(){for(const e of this.destroyEvents)try{e()}catch(t){console.warn("Failed to destroy event listener:",t)}this.destroyEvents.clear()}}class ae{constructor(t){this.art=t,this.keys={},R||this.init()}init(){const{constructor:t}=this.art;this.art.option.hotkey&&(this.add("Escape",()=>{this.art.fullscreenWeb&&(this.art.fullscreenWeb=!1)}),this.add("Space",()=>{lt(this.art.toggle())}),this.add("ArrowLeft",()=>{this.art.backward=t.SEEK_STEP}),this.add("ArrowUp",()=>{this.art.volume+=t.VOLUME_STEP}),this.add("ArrowRight",()=>{this.art.forward=t.SEEK_STEP}),this.add("ArrowDown",()=>{this.art.volume-=t.VOLUME_STEP})),this.art.on("document:keydown",t=>{if(this.art.isFocus){const e=document.activeElement.tagName.toUpperCase(),r=document.activeElement.getAttribute("contenteditable");if("INPUT"!==e&&"TEXTAREA"!==e&&""!==r&&"true"!==r&&!t.altKey&&!t.ctrlKey&&!t.metaKey&&!t.shiftKey){const e=this.keys[t.code];if(e){t.preventDefault();for(let r=0;r\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n',state:'\r\n\r\n\r\n',play:'\r\n \r\n',pause:'\r\n \r\n',check:'\r\n\r\n',volume:'\r\n \r\n \r\n',volumeClose:'\r\n \r\n \r\n',screenshot:'\r\n\t\r\n\r\n',setting:'\r\n \r\n \r\n',pip:'\r\n\r\n',arrowLeft:'\r\n \r\n',arrowRight:'\r\n \r\n',playbackRate:'',aspectRatio:'',config:'',lock:'\r\n\r\n\r\n\r\n\r\n',flip:'\r\n\r\n\r\n\r\n\r\n\r\n',unlock:'\r\n\r\n\r\n',fullscreenOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenOn:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOff:'\r\n\r\n\r\n\r\n\r\n',fullscreenWebOn:'\r\n\r\n\r\n\r\n\r\n',switchOn:'\r\n\r\n\r\n \r\n',switchOff:'\r\n\r\n\r\n \r\n\r\n',error:'\r\n\r\n\r\n\r\n\r\n',close:'\r\n\r\n\r\n\r\n\r\n',airplay:'\r\n \r\n \r\n \r\n \r\n\r\n'};class ce{constructor(t){const e=l(l({},le),t.option.icons);for(const r in e)yt(this,r,{get:()=>tt(r,e[r])})}}class de extends Nt{constructor(t){super(t),this.name="info",R||this.init()}init(){const{proxy:t,constructor:e,template:{$infoPanel:r,$infoClose:o,$video:n}}=this.art;t(o,"click",()=>{this.show=!1});let a=()=>{};const i=D("[data-video]",r)||[];this.art.on("destroy",()=>a());const s=$(this.art);!function t(){for(let e=0;e{j(n,"display","none"),j(a,"display",null)}),o.proxy(e.$state,"click",()=>lt(t.play()))}}class fe{constructor(t){this.art=t,this.timer=null,$(t).add(()=>this.destroy()),t.on("destroy",()=>this.destroy())}destroy(){this.timer&&(clearTimeout(this.timer),this.timer=null)}set show(t){if($(this.art).closed)return;const{constructor:e,template:{$player:r,$noticeInner:o}}=this.art;t?(o.textContent=t instanceof Error?t.message.trim():t,N(r,"art-notice-show"),clearTimeout(this.timer),this.timer=setTimeout(()=>{o.textContent="",F(r,"art-notice-show")},e.NOTICE_TIME)):F(r,"art-notice-show")}get show(){const{template:{$player:t}}=this.art;return t.classList.contains("art-notice-show")}}function me(t,e,r,o=!1){const n=e=>{E(t)||r(e)};t[o?"once":"on"](e,n),$(t).add(()=>{t.off(e,n)})}function ge(t,e,r){for(const[o,n]of e){if(E(t)||r&&!r())return;t[o].show=n}}const ve=new WeakMap,ye=new WeakMap,be=new WeakMap;function we(t){return be.get(t)||$(t)}function xe(t){const e=ve.get(t),r=be.get(t);return()=>ve.get(t)===e&&(!e||e.active())&&be.get(t)===r&&(!r||!r.closed)}function ke(t){const e=be.get(t),r=$(t).child(),o=r.child();be.set(t,r),r.add(()=>{be.get(t)===r&&be.delete(t)});const n={scope:o,assigned:!1,acceptingEvents:!1,active:()=>!E(t)&&!o.closed&&ve.get(t)===n};return ve.set(t,n),o.add(()=>{ve.get(t)===n&&ve.delete(t),n.onAssigned=void 0,n.onError=void 0}),null==e||e.dispose(),n}function $e(t){t.assigned=!0;const e=t.onAssigned;t.onAssigned=void 0,t.active()&&(null==e||e())}function Ee(t,e,r){ye.set(t,e),e.acceptingEvents=!0;try{t.url=r}finally{ye.get(t)===e&&(ye.delete(t),$e(e))}}function Te(t,e){t.active()&&(t.onError?t.onError(e):console.warn("Failed to initialize ArtPlayer source:",e),t.scope.dispose())}function Ce(t){const{option:e,constructor:r,i18n:o,notice:n,template:{$player:a}}=t;let i,s=we(t),l=0;return{reset(){l=0,null==i||i.dispose(),F(a,"art-error")},loadStart(){F(a,"art-error")},schedule(c){(c=>d(null,null,function*(){if(E(t))return;const d=we(t);if(d!==s&&(s=d,l=0),i&&!i.closed)return;const p=d.child();i=p,p.add(()=>{i===p&&(i=void 0)});const u=()=>!E(t)&&!p.closed&&d===we(t),h=l{console.warn("ArtPlayer reconnect failed:",t)})}}}function ze(t){!function(t){const{proxy:e,template:{$video:r}}=t;for(let o=0;o{E(t)||t.emit(`video:${e.type}`,e)})}(t);const e=Ce(t);!function(t,e){me(t,"video:canplay",()=>{e.reset(),ge(t,[["loading",!1]])}),me(t,"video:canplay",()=>{ge(t,[["loading",!1],["controls",!0],["mask",!0]]),E(t)||(t.isReady=!0,t.emit("ready"))},!0)}(t,e),function(t){const{option:e}=t;me(t,"video:ended",()=>{if(e.loop){const e=xe(t);if(t.seek=0,E(t)||!e())return;lt(t.play()),e()&&ge(t,[["controls",!1],["mask",!1]],e)}else ge(t,[["controls",!0],["mask",!0]])})}(t),me(t,"video:error",e.schedule),function(t,e){const{template:{$poster:r}}=t;me(t,"video:loadedmetadata",()=>{t.emit("resize"),R&&ge(t,[["loading",!1],["controls",!0],["mask",!0]])}),me(t,"video:loadstart",()=>{e.loadStart(),ge(t,[["loading",!0],["mask",!1],["controls",!0]])}),me(t,"video:pause",()=>{ge(t,[["controls",!0],["mask",!0]])}),me(t,"video:play",()=>{ge(t,[["mask",!1]]),E(t)||j(r,"display","none")}),me(t,"video:playing",()=>ge(t,[["mask",!1]])),me(t,"video:progress",()=>{t.playing&&ge(t,[["loading",!1]])}),me(t,"video:seeked",()=>ge(t,[["loading",!1],["mask",!0]])),me(t,"video:seeking",()=>ge(t,[["loading",!0],["mask",!1]])),me(t,"video:timeupdate",()=>ge(t,[["mask",!1]])),me(t,"video:waiting",()=>ge(t,[["loading",!0],["mask",!1]]))}(t,e)}const Se=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],Le=(()=>{if("undefined"===typeof document)return!1;const t=Se[0],e={};for(const r of Se){if(r[1]in document){for(const[o,n]of r.entries())e[t[o]]=n;return e}}return!1})(),Me={change:Le.fullscreenchange,error:Le.fullscreenerror},Ae={request:(t=document.documentElement,e)=>new Promise((r,o)=>{const n=()=>{Ae.off("change",n),r()};Ae.on("change",n);const a=t[Le.requestFullscreen](e);a instanceof Promise&&a.then(n).catch(o)}),exit:()=>new Promise((t,e)=>{if(!Ae.isFullscreen)return void t();const r=()=>{Ae.off("change",r),t()};Ae.on("change",r);const o=document[Le.exitFullscreen]();o instanceof Promise&&o.then(r).catch(e)}),toggle:(t,e)=>Ae.isFullscreen?Ae.exit():Ae.request(t,e),onchange(t){Ae.on("change",t)},onerror(t){Ae.on("error",t)},on(t,e){const r=Me[t];r&&document.addEventListener(r,e,!1)},off(t,e){const r=Me[t];r&&document.removeEventListener(r,e,!1)},raw:Le};function Pe(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t,a=t=>{Ae.on("change",()=>{t.emit("fullscreen",Ae.isFullscreen),Ae.isFullscreen?(t.state="fullscreen",N(n,"art-fullscreen")):F(n,"art-fullscreen"),t.emit("resize")}),Ae.on("error",e=>{t.emit("fullscreenError",e)}),yt(t,"fullscreen",{get:()=>Ae.isFullscreen,set(t){return d(this,null,function*(){t?yield Ae.request(n):yield Ae.exit()})}})};t.once("video:loadedmetadata",()=>{var n;Ae.isEnabled?a(t):o.webkitSupportsFullscreen?((n=t).on("document:webkitfullscreenchange",()=>{n.emit("fullscreen",n.fullscreen),n.emit("resize")}),yt(n,"fullscreen",{get:()=>document.fullscreenElement===o,set(t){t?(n.state="fullscreen",o.webkitEnterFullscreen()):o.webkitExitFullscreen()}})):yt(t,"fullscreen",{get:()=>!1,set(){r.show=e.get("Fullscreen Not Supported")}}),yt(t,"fullscreen",xt(t,"fullscreen"))})}function Oe(t){const{icons:e,proxy:r,storage:o,template:{$player:n,$video:a}}=t;let i=!1,s=0,l=0;function c(){const{$mini:e}=t.template;e&&(F(n,"art-mini"),j(e,"display","none"),n.prepend(a),t.emit("mini",!1))}function d(e,r){t.playing?(j(e,"display","none"),j(r,"display","flex")):(j(e,"display","flex"),j(r,"display","none"))}function p(){const{$mini:e}=t.template,r=rt(e),n=window.innerHeight-r.height-50,a=window.innerWidth-r.width-50;o.set("top",n),o.set("left",a),j(e,"top",`${n}px`),j(e,"left",`${a}px`)}yt(t,"mini",{get:()=>H(n,"art-mini"),set(u){if(u){t.state="mini",N(n,"art-mini");const u=function(){const{$mini:n}=t.template;if(n)return B(n,a),j(n,"display","flex");{const n=Q("div");N(n,"art-mini-popup"),B(document.body,n),t.template.$mini=n,B(n,a);const p=B(n,'
');B(p,e.close),r(p,"click",c);const u=B(n,'
'),h=B(u,e.play),f=B(u,e.pause);return r(h,"click",()=>lt(t.play())),r(f,"click",()=>t.pause()),d(h,f),t.on("video:playing",()=>d(h,f)),t.on("video:pause",()=>d(h,f)),t.on("video:timeupdate",()=>d(h,f)),r(n,"mousedown",t=>{i=0===t.button,s=t.pageX,l=t.pageY}),t.on("document:mousemove",t=>{if(i){N(n,"art-mini-dragging");const e=t.pageX-s,r=t.pageY-l;j(n,"transform",`translate(${e}px, ${r}px)`)}}),t.on("document:mouseup",()=>{if(i){i=!1,F(n,"art-mini-dragging");const t=rt(n);o.set("left",t.left),o.set("top",t.top),j(n,"left",`${t.left}px`),j(n,"top",`${t.top}px`),j(n,"transform",null)}}),n}}(),h=o.get("top"),f=o.get("left");"number"===typeof h&&"number"===typeof f?(j(u,"top",`${h}px`),j(u,"left",`${f}px`),K(u)||p()):p(),t.emit("mini",!0)}else c()}})}function Ie(t){const{i18n:e,notice:r,template:{$video:o}}=t;document.pictureInPictureEnabled?function(t){const{template:{$video:e},proxy:r,notice:o}=t;e.disablePictureInPicture=!1,yt(t,"pip",{get:()=>document.pictureInPictureElement,set(r){r?(t.state="pip",e.requestPictureInPicture().catch(t=>{throw o.show=t,t})):document.exitPictureInPicture().catch(t=>{throw o.show=t,t})}}),r(e,"enterpictureinpicture",()=>{t.emit("pip",!0)}),r(e,"leavepictureinpicture",()=>{t.emit("pip",!1)})}(t):o.webkitSupportsPresentationMode?function(t){const{$video:e}=t.template;e.webkitSetPresentationMode("inline"),yt(t,"pip",{get:()=>"picture-in-picture"===e.webkitPresentationMode,set(r){r?(t.state="pip",e.webkitSetPresentationMode("picture-in-picture"),t.emit("pip",!0)):(e.webkitSetPresentationMode("inline"),t.emit("pip",!1))}})}(t):yt(t,"pip",{get:()=>!1,set(){r.show=e.get("PIP Not Supported")}})}function Re(t){yt(t,"quality",{set(e){const{controls:r,notice:o,i18n:n}=t,a=e.find(t=>t.default)||e[0];r.update({name:"quality",position:"right",index:10,style:{marginRight:"10px"},html:(null==a?void 0:a.html)||"",selector:e,onSelect(e,r,a){return d(this,null,function*(){const r=function(t){return t&&Gt.get(t)||(()=>!0)}(a);if(yield t.switchQuality(e.url),!E(t)&&r()){const a=`${n.get("Switch Video")}: ${e.html}`;!E(t)&&r()&&(o.show=a)}return e.html})}})}})}function _e(t,e,r,o,n=!0){let a,i=!1;const s=e=>{t.closed||i||(n&&(i=!0,a()),o(e))};return e[n?"once":"on"](r,s),a=t.add(()=>{e.off(r,s)}),s}function Ve(t,e,r){return new Promise((o,n)=>{if(E(t)||e===t.url)return void o();const a=ke(t),i=a.scope.child();let s=!1;const l=(t=!1,e)=>{s||(s=!0,a.onError=void 0,a.onAssigned=void 0,i.dispose(),t?n(e):o(),t&&a.scope.dispose())};i.add(()=>{l()});const c=()=>!s&&a.active(),p=t=>l(!0,t);a.onError=p;try{const{playing:o,aspectRatio:n,playbackRate:s}=t;if(t.pause(),!c())return;const u=i.child(),h={"video:error":p,"video:loadedmetadata":()=>{if(c())try{t.currentTime=r}catch(e){p(e)}},"video:canplay":()=>{if(!c())return;u.dispose();d(null,null,function*(){if(t.playbackRate=s,c()&&(t.aspectRatio=n,c())){if(o)try{yield t.play()}catch(e){}c()&&(t.notice.show="",l())}}).catch(p)}},f=i.child(),m=[],g=Object.keys(h);for(const e of g)_e(f,t,e,t=>{a.acceptingEvents&&m.push([e,t])},!1);if(Ee(t,a,e),!c())return;if(t.notice.show="",!c())return;const v=()=>{if(f.dispose(),!e)return void l();const r={};for(const e of g)r[e]=_e(u,t,e,h[e]);for(const[t,e]of m){if(!c()||u.closed)break;r[t](e)}m.length=0};a.assigned?v():a.onAssigned=v}catch(u){p(u)}})}function Ye(t){const{option:e,template:{$progress:r,$video:o}}=t;let n=null,a=!1,i=null;t.on("setBar",(n,s,l)=>d(null,null,function*(){var c;const d=null==(c=t.controls)?void 0:c.thumbnails,{url:p,scale:u}=e.thumbnails;if(!d||!p)return;if("hover"===n||"played"===n&&l&&R){if(i||a||(a=!0,i=yield ot(p,u),a=!1),!i)return;const n=r.clientWidth*s;n>0&&nr.clientWidth-h/2?j(s,"left",r.clientWidth-h+"px"):j(s,"left",n-h/2+"px")}(n)}})),yt(t,"thumbnails",{get:()=>t.option.thumbnails,set(e){e.url&&!t.option.isLive&&(t.option.thumbnails=e,clearTimeout(n),n=null,a=!1,i=null)}})}function De(t){const{option:e,template:{$video:r}}=t;yt(t,"url",{get:()=>r.src,set(o){return d(this,null,function*(){if(E(t))return;const n=function(t){const e=ye.get(t);return ye.delete(t),e||ke(t)}(t);n.acceptingEvents=!1;try{if(!o)return void((yield Bt(n.scope))&&n.active()&&(t.loading.show=!0));const a=t.url,i=e.type||ct(o),s=e.customType[i];if(i&&s){if(!(yield Bt(n.scope))||!n.active())return;t.loading.show=!0}if(!n.active())return;const l=n.scope.child();let c=!1,d=!1;_e(l,t,"video:canplay",()=>{c=!d}),_e(l,t,"video:error",()=>{d=!0});try{if(n.acceptingEvents=!0,i&&s){const e=s.call(t,r,o,t);Promise.resolve(e).catch(t=>Te(n,t))}else{if(a&&URL.revokeObjectURL(a),!n.active())return;r.src=o}}finally{l.dispose()}if(!n.active())return;if(a!==t.url&&(t.option.url=o,n.active()&&t.isReady&&a)){const e=()=>{n.active()&&t.emit("restart",o)};c?e():d||_e(n.scope,t,"video:canplay",e)}}catch(a){Te(n,a)}finally{$e(n)}})}})}Object.defineProperties(Ae,{isFullscreen:{get:()=>Boolean(document[Le.fullscreenElement])},element:{enumerable:!0,get:()=>document[Le.fullscreenElement]},isEnabled:{enumerable:!0,get:()=>Boolean(document[Le.fullscreenEnabled])}});class Ne{constructor(t){De(t),function(t){const{template:{$video:e}}=t;yt(t,"attr",{value(t,r){if(void 0===r)return e[t];e[t]=r}})}(t),function(t){const{i18n:e,notice:r,option:o,constructor:{instances:n},template:{$video:a}}=t;yt(t,"play",{value(){return d(this,null,function*(){const i=xe(t),s=yield a.play();if(!i())return s;const l=e.get("Play");if(!i())return s;if(r.show=l,!i())return s;if(t.emit("play"),o.mutex)for(let e=0;et.playing?t.pause():t.play()})}(t),function(t){const{notice:e}=t;yt(t,"seek",{set(r){t.currentTime=r,t.duration&&(e.show=`${ht(t.currentTime)} / ${ht(t.duration)}`),t.emit("seek",t.currentTime,r)}});const r=t;yt(t,"forward",{set(e){r.seek=t.currentTime+e}}),yt(t,"backward",{set(e){r.seek=t.currentTime-e}})}(t),function(t){const{template:{$video:e},i18n:r,notice:o,storage:n}=t;yt(t,"volume",{get:()=>e.volume||0,set:t=>{e.volume=pt(t,0,1),o.show=`${r.get("Volume")}: ${Number.parseInt(String(100*e.volume),10)}`,0!==e.volume&&n.set("volume",e.volume)}}),yt(t,"muted",{get:()=>e.muted,set:r=>{e.muted=r,t.emit("muted",r)}})}(t),function(t){const{$video:e}=t.template;yt(t,"currentTime",{get:()=>e.currentTime||0,set:r=>{const o=Number.parseFloat(r);Number.isNaN(o)||(e.currentTime=pt(o,0,t.duration))}})}(t),function(t){yt(t,"duration",{get:()=>{const{duration:e}=t.template.$video;return e===1/0?0:e||0}})}(t),function(t){const e=e=>Ve(t,e,0);yt(t,"switchQuality",{value:e=>Ve(t,e,t.currentTime)}),yt(t,"switchUrl",{value:e}),yt(t,"switch",{set:e})}(t),function(t){const{template:{$video:e},i18n:r,notice:o}=t,n=t;yt(t,"playbackRate",{get:()=>e.playbackRate,set(t){if(t){if(t===e.playbackRate)return;e.playbackRate=t,o.show=`${r.get("Rate")}: ${1===t?r.get("Normal"):`${t}x`}`}else n.playbackRate=1}})}(t),function(t){const{i18n:e,notice:r,template:{$video:o,$player:n}}=t;yt(t,"aspectRatio",{get:()=>n.dataset.aspectRatio||"default",set(a){if(a||(a="default"),"default"===a)j(o,"width",null),j(o,"height",null),j(o,"margin",null),delete n.dataset.aspectRatio;else{const t=a.split(":").map(Number),{clientWidth:e,clientHeight:r}=n,i=e/r,s=t[0]/t[1];i>s?(j(o,"width",s*r+"px"),j(o,"height","100%"),j(o,"margin","0 auto")):(j(o,"width","100%"),j(o,"height",e/s+"px"),j(o,"margin","auto 0")),n.dataset.aspectRatio=a}r.show=`${e.get("Aspect Ratio")}: ${"default"===a?e.get("Default"):a}`,t.emit("aspectRatio",a)}})}(t),function(t){const{notice:e,template:{$video:r}}=t,o=Q("canvas");yt(t,"getDataURL",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),t(o.toDataURL("image/png"))}catch(a){e.show=a,n(a)}})}),yt(t,"getBlobUrl",{value:()=>new Promise((t,n)=>{try{o.width=r.videoWidth,o.height=r.videoHeight,o.getContext("2d").drawImage(r,0,0),o.toBlob(e=>{t(URL.createObjectURL(e))})}catch(a){e.show=a,n(a)}})}),yt(t,"screenshot",{value:e=>d(null,null,function*(){const o=yield t.getDataURL();return dt(o,`${e||`artplayer_${ht(r.currentTime)}`}.png`),t.emit("screenshot",o),o})})}(t),Pe(t),function(t){const{constructor:e,template:{$container:r,$player:o}}=t;let n="";yt(t,"fullscreenWeb",{get:()=>H(o,"art-fullscreen-web"),set(a){a?(n=o.style.cssText,e.FULLSCREEN_WEB_IN_BODY&&B(document.body,o),t.state="fullscreenWeb",j(o,"width","100%"),j(o,"height","100%"),N(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!0)):(e.FULLSCREEN_WEB_IN_BODY&&B(r,o),n&&(o.style.cssText=n,n=""),F(o,"art-fullscreen-web"),t.emit("fullscreenWeb",!1)),t.emit("resize")}})}(t),Ie(t),function(t){const{$video:e}=t.template,r=t;yt(t,"loaded",{get:()=>r.loadedTime/e.duration}),yt(t,"loadedTime",{get:()=>e.buffered.length?e.buffered.end(e.buffered.length-1):0})}(t),function(t){yt(t,"played",{get:()=>t.currentTime/t.duration})}(t),function(t){const{$video:e}=t.template;yt(t,"playing",{get:()=>"boolean"===typeof e.playing?e.playing:!!(e.currentTime>0&&!e.paused&&!e.ended&&e.readyState>2)})}(t),function(t){const{$container:e,$player:r,$video:o}=t.template;yt(t,"autoSize",{value(){const{videoWidth:n,videoHeight:a}=o,{width:i,height:s}=rt(e),l=n/a;if(i/s>l)j(r,"width",s*l/i*100+"%"),j(r,"height","100%");else{const t=i/l/s*100;j(r,"width","100%"),j(r,"height",`${t}%`)}t.emit("autoSize",{width:t.width,height:t.height})}})}(t),function(t){const e=t;yt(t,"rect",{get:()=>rt(t.template.$player)});const r=["bottom","height","left","right","top","width"];for(let o=0;oe.rect[n]})}yt(t,"x",{get:()=>e.left+window.pageXOffset}),yt(t,"y",{get:()=>e.top+window.pageYOffset})}(t),function(t){const{template:{$player:e},i18n:r,notice:o}=t;yt(t,"flip",{get:()=>e.dataset.flip||"normal",set(n){n||(n="normal"),"normal"===n?delete e.dataset.flip:e.dataset.flip=n,o.show=`${r.get("Video Flip")}: ${r.get(ut(n))}`,t.emit("flip",n)}})}(t),Oe(t),function(t){const{template:{$poster:e}}=t;yt(t,"poster",{get:()=>{try{return e.style.backgroundImage.match(/"(.*)"/)[1]}catch(t){return""}},set(t){j(e,"backgroundImage",`url(${t})`)}})}(t),function(t){const{template:{$container:e,$video:r}}=t;yt(t,"autoHeight",{value(){const{clientWidth:o}=e,{videoHeight:n,videoWidth:a}=r,i=n*(o/a);j(e,"height",`${i}px`),t.emit("autoHeight",i)}})}(t),function(t){const{$player:e}=t.template;yt(t,"cssVar",{value:(t,r)=>r?e.style.setProperty(t,r):getComputedStyle(e).getPropertyValue(t)})}(t),function(t){yt(t,"theme",{get:()=>t.cssVar("--art-theme"),set(e){t.cssVar("--art-theme",e)}})}(t),function(t){yt(t,"type",{get:()=>t.option.type,set(e){t.option.type=e}})}(t),function(t){const e=["mini","pip","fullscreen","fullscreenWeb"];yt(t,"state",{get:()=>e.find(e=>t[e])||"standard",set(r){for(let o=0;o{switch(t.availability){case"available":a=!0;break;case"not-available":a=!1}}):a=!1,yt(t,"airplay",{value(){a?(n.webkitShowPlaybackTargetPicker(),t.emit("airplay")):r.show=e.get("AirPlay Not Available")}})}(t),Re(t),Ye(t),ze(t),function(t){const{option:e,storage:r,template:{$video:o,$poster:n}}=t;for(const i in e.moreVideoAttr)t.attr(i,e.moreVideoAttr[i]);e.muted&&(t.muted=e.muted),e.volume&&(o.volume=pt(e.volume,0,1));const a=r.get("volume");"number"===typeof a&&(o.volume=pt(a,0,1)),e.poster&&j(n,"backgroundImage",`url(${e.poster})`),e.autoplay&&(o.autoplay=e.autoplay),e.playsInline&&(o.playsInline=!0,o["webkit-playsinline"]=!0),e.theme&&(e.cssVar["--art-theme"]=e.theme);for(const i in e.cssVar)t.cssVar(i,e.cssVar[i]);t.url=e.url}(t)}}function Fe(t){const{notice:e,constructor:r,template:{$player:o,$video:n}}=t,a="art-auto-orientation",i="art-auto-orientation-fullscreen";let s=!1;function l(){const{videoWidth:t,videoHeight:e}=n,r=document.documentElement.clientWidth,o=document.documentElement.clientHeight;return t>e&&ro}return t.on("fullscreenWeb",e=>{var n;if(e){if(l()){const e=Number(null!=(n=r.AUTO_ORIENTATION_TIME)?n:0);setTimeout(()=>{t.fullscreenWeb&&!H(o,a)&&function(){const e=at(),r=document.documentElement.clientWidth,n=document.documentElement.clientHeight-e.top-e.bottom,i=r-e.left-e.right;j(o,"width",`${n}px`),j(o,"height",`${i}px`),j(o,"transform-origin","0 0"),j(o,"transform",`rotate(90deg) translate(${e.top}px, -${r-e.right}px)`),N(o,a),t.isRotate=!0,t.emit("resize")}()},e)}}else H(o,a)&&(j(o,"width",""),j(o,"height",""),j(o,"transform-origin",""),j(o,"transform",""),F(o,a),t.isRotate=!1,t.emit("resize"))}),t.on("fullscreen",t=>d(null,null,function*(){var r;const n=!!(null==(r=null==screen?void 0:screen.orientation)?void 0:r.lock);if(t){if(n&&l())try{const t=screen.orientation.type.startsWith("portrait")?"landscape":"portrait";yield screen.orientation.lock(t),s=!0,N(o,i)}catch(a){s=!1,e.show=a}}else if(H(o,i)&&F(o,i),n&&s){try{screen.orientation.unlock()}catch(c){}s=!1}})),{name:"autoOrientation",get state(){return H(o,a)}}}function He(t){const{i18n:e,icons:r,storage:o,constructor:n,proxy:a,template:{$poster:i}}=t,s=t.layers.add({name:"auto-playback",html:'\n
\n
\n
\n '}),l=Y(".art-auto-playback-last",s),c=Y(".art-auto-playback-jump",s),d=Y(".art-auto-playback-close",s);B(d,r.close);let p=null;function u(){const r=(o.get("times")||{})[t.option.id||t.option.url];clearTimeout(p),j(s,"display","none"),r&&r>=n.AUTO_PLAYBACK_MIN&&(j(s,"display","flex"),l.textContent=`${e.get("Last Seen")} ${ht(r)}`,c.textContent=e.get("Jump Play"),a(d,"click",()=>{j(s,"display","none")}),a(c,"click",()=>{t.seek=r,lt(t.play()),j(i,"display","none"),j(s,"display","none")}),t.once("video:timeupdate",()=>{p=setTimeout(()=>{j(s,"display","none")},n.AUTO_PLAYBACK_TIMEOUT)}))}return t.on("video:timeupdate",()=>{if(t.playing){const e=o.get("times")||{},r=Object.keys(e);r.length>n.AUTO_PLAYBACK_MAX&&delete e[r[0]],e[t.option.id||t.option.url]=t.currentTime,o.set("times",e)}}),t.on("ready",u),t.on("restart",u),{name:"auto-playback",get times(){return o.get("times")||{}},clear:()=>o.del("times"),delete(t){const e=o.get("times")||{};return delete e[t],o.set("times",e),e}}}function Be(t){const{constructor:e,proxy:r,template:{$player:o,$video:n}}=t;let a=null,i=!1,s=1;const l=()=>{clearTimeout(a),i&&(i=!1,t.playbackRate=s,F(o,"art-fast-forward"))};return r(n,"touchstart",r=>{1===r.touches.length&&t.playing&&!t.isLock&&(a=setTimeout(()=>{i=!0,s=t.playbackRate,t.playbackRate=e.FAST_FORWARD_VALUE,N(o,"art-fast-forward")},e.FAST_FORWARD_TIME))}),t.on("document:touchmove",l),t.on("document:touchend",l),{name:"fastForward",get state(){return H(o,"art-fast-forward")}}}function We(t){const{layers:e,icons:r,template:{$player:o}}=t;function n(){return H(o,"art-lock")}function a(){N(o,"art-lock"),t.isLock=!0,t.emit("lock",!0)}function i(){F(o,"art-lock"),t.isLock=!1,t.emit("lock",!1)}return e.add({name:"lock",mounted(e){const o=B(e,r.lock),n=B(e,r.unlock);j(o,"display","none"),t.on("lock",t=>{t?(j(o,"display","inline-flex"),j(n,"display","none")):(j(o,"display","none"),j(n,"display","inline-flex"))})},click(){n()?i():a()}}),{name:"lock",get state(){return n()},set state(t){t?a():i()}}}function je(t){return t.on("control",e=>{e?F(t.template.$player,"art-mini-progress-bar"):N(t.template.$player,"art-mini-progress-bar")}),{name:"mini-progress-bar"}}class qe{constructor(t){this.art=t,this.id=0;const{option:e}=t;!function(t,e){E(t.art)||!e.miniProgressBar||e.isLive||t.add(je),!E(t.art)&&e.lock&&R&&t.add(We),E(t.art)||!e.autoPlayback||e.isLive||t.add(He),!E(t.art)&&e.autoOrientation&&R&&t.add(Fe),!E(t.art)&&e.fastForward&&R&&!e.isLive&&t.add(Be)}(this,e);for(let r=0;rconsole.warn("Failed to initialize ArtPlayer plugin:",t))}}add(t){st(!E(this.art),"Cannot add a plugin after ArtPlayer is destroyed"),this.id+=1;const e=t.call(this.art,this.art);return e instanceof Promise?e.then(e=>this.next(t,e)):this.next(t,e)}next(t,e){return function(t,e,r){if(E(t.art))return t;const o=r&&r.name||e.name||`plugin${t.id}`;if(E(t.art))return t;let n=o;const a=wt(t,n);if(E(t.art))return t;const i=`Cannot add a plugin that already has the same name: ${o}`;return E(t.art)||(st(!a,i),("object"===typeof o&&null!==o||"function"===typeof o)&&(n=Reflect.ownKeys({[n]:void 0})[0]),E(t.art)||yt(t,n,{value:r})),t}(this,t,e)}}class Ue extends Nt{constructor(t){super(t);const{option:e,controls:r,template:{$setting:o}}=t;this.name="setting",this.$parent=o,this.id=0,this.active=null,this.cache=new Map,this.option=[...this.builtin,...e.settings],e.setting&&(this.format(),this.render(),t.on("blur",()=>{this.show&&(this.show=!1,this.render())}),t.on("focus",t=>{const e=Z(t,r.setting),o=Z(t,this.$parent);!this.show||e||o||(this.show=!1,this.render())}),t.on("resize",()=>this.resize()))}get builtin(){const t=[],{option:e}=this.art;return e.playbackRate&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,PLAYBACK_RATE:n}}=t;function a(t){return 1===t?e.get("Normal"):t.toFixed(1)}function i(){const e=t.setting.find(`playback-rate-${t.playbackRate}`);t.setting.check(e)}return{width:o,name:"playback-rate",html:e.get("Play Speed"),tooltip:a(t.playbackRate),icon:r.playbackRate,selector:n.map(e=>({value:e,name:`playback-rate-${e}`,default:e===t.playbackRate,html:a(e)})),onSelect:e=>(t.playbackRate=e.value,e.html),mounted:()=>{i(),t.on("video:ratechange",()=>i())}}}(this.art)),e.aspectRatio&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,ASPECT_RATIO:n}}=t;function a(t){return"default"===t?e.get("Default"):t}function i(){const e=t.setting.find(`aspect-ratio-${t.aspectRatio}`);t.setting.check(e)}return{width:o,name:"aspect-ratio",html:e.get("Aspect Ratio"),icon:r.aspectRatio,tooltip:a(t.aspectRatio),selector:n.map(e=>({value:e,name:`aspect-ratio-${e}`,default:e===t.aspectRatio,html:a(e)})),onSelect:e=>(t.aspectRatio=e.value,e.html),mounted:()=>{i(),t.on("aspectRatio",()=>i())}}}(this.art)),e.flip&&t.push(function(t){const{i18n:e,icons:r,constructor:{SETTING_ITEM_WIDTH:o,FLIP:n}}=t;function a(t){return e.get(ut(t))}function i(){const e=t.setting.find(`flip-${t.flip}`);t.setting.check(e)}return{width:o,name:"flip",html:e.get("Video Flip"),tooltip:a(t.flip),icon:r.flip,selector:n.map(e=>({value:e,name:`flip-${e}`,default:e===t.flip,html:a(e)})),onSelect:e=>(t.flip=e.value,e.html),mounted:()=>{i(),t.on("flip",()=>i())}}}(this.art)),e.subtitleOffset&&t.push(function(t){const{i18n:e,icons:r,constructor:o}=t;return{width:o.SETTING_ITEM_WIDTH,name:"subtitle-offset",html:e.get("Subtitle Offset"),icon:r.subtitle,tooltip:"0s",range:[0,-10,10,.1],onChange:e=>(t.subtitleOffset=e.range[0],`${e.range[0]}s`),mounted:(e,r)=>{t.on("subtitleOffset",t=>{r.$range.value=t,r.tooltip=`${t}s`})}}}(this.art)),t}traverse(t,e=this.option){var r;for(let o=0;o{e.default=e===t,e.default&&e.$item&&X(e.$item,"art-current")},t.$option),this.render(t.$parents))}format(t=this.option,e,r,o=[]){for(let n=0;ne}),yt(a,"$parents",{get:()=>r}),yt(a,"$option",{get:()=>t});const o=[];yt(a,"$events",{get:()=>o}),yt(a,"$formatted",{get:()=>!0})}this.format(a.selector||[],a,t,o)}this.option=t}find(t=""){let e=null;return this.traverse(r=>{r.name===t&&(e=r)}),e}resize(){var t,e;const{controls:r,constructor:{SETTING_WIDTH:o,SETTING_ITEM_HEIGHT:n},template:{$player:a,$setting:i}}=this.art;if(r.setting&&this.show){const s=(null==(e=null==(t=this.active[0])?void 0:t.$parent)?void 0:e.width)||o,{left:l,width:c}=rt(r.setting),{left:d,width:p}=rt(a),u=l-d+c/2-s/2;if(j(i,"height",`${this.active===this.option?this.active.length*n:(this.active.length+1)*n}px`),j(i,"width",`${s}px`),this.art.isRotate||R)return;u+s>p?(j(i,"left",null),j(i,"right",null)):(j(i,"left",`${u}px`),j(i,"right","auto"))}}inactivate(t){for(let e=0;e'),s=Q("div");N(s,"art-setting-item-left-icon"),B(s,o),B(i,s),B(i,t.$parent.html);const l=r(a,"click",()=>this.render(t.$parents));t.$parent.$events.push(l),B(e,a)}createItem(t,e=!1){var r,o;if(!this.cache.has(t.$option))return;const n=this.cache.get(t.$option),a=t.$item;let i="selector";wt(t,"switch")&&(i="switch"),wt(t,"range")&&(i="range"),wt(t,"onClick")&&(i="button");const{icons:s,proxy:l,constructor:c}=this.art,p=Q("div");N(p,"art-setting-item"),j(p,"height",`${c.SETTING_ITEM_HEIGHT}px`),p.dataset.name=t.name||"",p.dataset.value=t.value||"";const u=B(p,'
'),h=B(p,'
'),f=Q("div");switch(N(f,"art-setting-item-left-icon"),i){case"button":case"switch":case"range":B(f,t.icon||s.config);break;case"selector":(null==(r=t.selector)?void 0:r.length)?B(f,t.icon||s.config):B(f,s.check)}B(u,f),yt(t,"$icon",{configurable:!0,get:()=>f}),yt(t,"icon",{configurable:!0,get:()=>f.innerHTML,set(t){f.innerHTML="",B(f,t)}});const m=Q("div");N(m,"art-setting-item-left-text"),B(m,t.html||""),B(u,m),yt(t,"$html",{configurable:!0,get:()=>m}),yt(t,"html",{configurable:!0,get:()=>m.innerHTML,set(t){m.innerHTML="",B(m,t)}});const g=Q("div");switch(N(g,"art-setting-item-right-tooltip"),B(g,t.tooltip||""),B(h,g),yt(t,"$tooltip",{configurable:!0,get:()=>g}),yt(t,"tooltip",{configurable:!0,get:()=>g.innerHTML,set(t){g.innerHTML="",B(g,t)}}),i){case"switch":{const e=Q("div");N(e,"art-setting-item-right-icon");const r=B(e,s.switchOn),o=B(e,s.switchOff);j(t.switch?o:r,"display","none"),B(h,e),yt(t,"$switch",{configurable:!0,get:()=>e});let n=t.switch;yt(t,"switch",{configurable:!0,get:()=>n,set(t){n=t,t?(j(o,"display","none"),j(r,"display",null)):(j(o,"display",null),j(r,"display","none"))}});break}case"range":{const e=Q("div");N(e,"art-setting-item-right-icon");const r=B(e,'');r.value=t.range[0],r.min=t.range[1],r.max=t.range[2],r.step=t.range[3],N(r,"art-setting-range"),B(h,e),yt(t,"$range",{configurable:!0,get:()=>r});let o=[...t.range];yt(t,"range",{configurable:!0,get:()=>o,set(t){o=[...t],r.value=t[0],r.min=t[1],r.max=t[2],r.step=t[3]}})}break;case"selector":if(null==(o=t.selector)?void 0:o.length){const t=Q("div");N(t,"art-setting-item-right-icon"),B(t,s.arrowRight),B(h,t)}}switch(i){case"switch":if(t.onSwitch){const e=l(p,"click",e=>d(this,null,function*(){t.switch=yield t.onSwitch.call(this.art,t,p,e)}));t.$events.push(e)}break;case"range":if(t.$range){if(t.onRange){const e=l(t.$range,"change",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onRange.call(this.art,t,p,e)}));t.$events.push(e)}if(t.onChange){const e=l(t.$range,"input",e=>d(this,null,function*(){t.range[0]=t.$range.valueAsNumber,t.tooltip=yield t.onChange.call(this.art,t,p,e)}));t.$events.push(e)}}break;case"selector":{const e=l(p,"click",e=>d(this,null,function*(){var r;(null==(r=t.selector)?void 0:r.length)?this.render(t.selector):(this.check(t),t.$parent.onSelect&&(t.$parent.tooltip=yield t.$parent.onSelect.call(this.art,t,p,e)))}));t.$events.push(e),t.default&&N(p,"art-current")}break;case"button":if(t.onClick){const e=l(p,"click",e=>d(this,null,function*(){t.tooltip=yield t.onClick.call(this.art,t,p,e)}));t.$events.push(e)}}yt(t,"$item",{configurable:!0,get:()=>p}),e?J(p,a):B(n,p),t.mounted&&Ht($(this.art),()=>t.mounted.call(this.art,t.$item,t),0)}render(t=this.option){var e;if(this.active=t,this.cache.has(t)){X(this.cache.get(t),"art-current")}else{const r=Q("div");this.cache.set(t,r),N(r,"art-setting-panel"),B(this.$parent,r),X(r,"art-current"),(null==(e=t[0])?void 0:e.$parent)&&this.createHeader(t[0]);for(let e=0;enull,this.init(t.option.subtitle);let e=!1;t.on("video:timeupdate",()=>{if(!this.url)return;const t=this.art.template.$video.webkitDisplayingFullscreen;"boolean"===typeof t&&t!==e&&(e=t,this.createTrack(t?"subtitles":"metadata",this.url))})}get url(){return this.art.template.$track.src}set url(t){this.switch(t)}get textTrack(){var t,e;return null==(e=null==(t=this.art.template.$video)?void 0:t.textTracks)?void 0:e[0]}get activeCues(){return this.textTrack?Array.from(this.textTrack.activeCues):[]}get cues(){return this.textTrack?Array.from(this.textTrack.cues):[]}style(t,e){const{$subtitle:r}=this.art.template;return"object"===typeof t?q(r,t):j(r,t,e)}update(){const{option:{subtitle:t},template:{$subtitle:e}}=this.art;e.innerHTML="",this.activeCues.length&&(this.art.emit("subtitleBeforeUpdate",this.activeCues),e.innerHTML=this.activeCues.map((e,r)=>e.text.split(/\r?\n/).filter(t=>t.trim()).map(e=>`
\n ${t.escape?vt(e):e}\n
`).join("")).join(""),this.art.emit("subtitleAfterUpdate",this.activeCues))}switch(t){return d(this,arguments,function*(t,e={}){const{i18n:r,notice:o,option:n}=this.art,a=c(l(l({},n.subtitle),e),{url:t}),i=yield this.init(a);return e.name&&(o.show=`${r.get("Switch Subtitle")}: ${e.name}`),i})}createTrack(t,e){const{template:r,proxy:o,option:n}=this.art,{$video:a,$track:i}=r,s=Q("track");s.default=!0,s.kind=t,s.src=e,s.label=n.subtitle.name||"Artplayer",s.track.mode="hidden",s.onload=()=>{this.art.emit("subtitleLoad",this.cues,this.option)},this.art.events.remove(this.destroyEvent),i.onload=null,W(i),B(a,s),r.$track=s,this.destroyEvent=o(this.textTrack,"cuechange",()=>this.update())}init(t){return d(this,null,function*(){const{notice:e,template:{$subtitle:r}}=this.art;return this.textTrack?(m(t,Yt.subtitle),t.url?(this.option=t,this.style(t.style),fetch(t.url).then(t=>t.arrayBuffer()).then(e=>{const r=new TextDecoder(t.encoding).decode(e);switch(t.type||ct(t.url)){case"srt":{const e=$t(r);return Et(t.onVttLoad(e))}case"ass":{const e=Tt(r);return Et(t.onVttLoad(e))}case"vtt":return Et(t.onVttLoad(r));default:return t.url}}).then(t=>(r.innerHTML="",this.url===t||(URL.revokeObjectURL(this.url),this.createTrack("metadata",t)),t)).catch(t=>{throw r.innerHTML="",e.show=t,t})):void 0):null})}}const Ze=`\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
Player version:
\n
${g}
\n
\n
\n
Video url:
\n
\n
\n
\n
Video volume:
\n
\n
\n
\n
Video time:
\n
\n
\n
\n
Video duration:
\n
\n
\n
\n
Video resolution:
\n
\n x \n
\n
\n
\n
[x]
\n
\n
\n
\n `;class Je{constructor(t){this.art=t;const{option:e,constructor:r}=t;e.container instanceof Element?this.$container=e.container:(this.$container=Y(e.container),st(this.$container,`No container element found by ${e.container}`)),st(et(),"The current browser does not support flex layout");const o=this.$container.tagName.toLowerCase();st("div"===o,`Unsupported container element type, only support 'div' but got '${o}'`),st(r.instances.every(t=>t.template.$container!==this.$container),"Cannot mount multiple instances on the same dom element"),this.query=this.query.bind(this),function(t,e,r){const o=x.get(e);if(o&&o!==t)throw new Error("Cannot mount multiple instances on the same dom element");const n=k(t);n.rollback=r,x.set(e,t),n.releaseContainer=()=>{x.get(e)===t&&x.delete(e)}}(t,this.$container,function(t){const e=[];return function t(r){const o=Array.from(r.childNodes);e.push({node:r,children:o,attributes:1===r.nodeType?Array.from(r.attributes,t=>[t.name,t.value]):void 0,value:r.nodeValue}),o.forEach(t)}(t),()=>{for(const{node:t,children:r,attributes:o,value:n}of e){for(;t.firstChild;)t.removeChild(t.firstChild);for(const e of r)t.appendChild(e);if(o){const e=t;for(const t of Array.from(e.attributes))e.removeAttribute(t.name);for(const[t,r]of o)e.setAttribute(t,r)}else t.nodeValue=n}}}(this.$container)),this.$container.dataset.artId=String(t.id),this.init()}static get html(){return Ze}query(t){return Y(t,this.$container)}init(){const{option:t}=this.art;var e;if(t.useSSR||(this.$container.innerHTML=Je.html),(e=this).$player=e.query(".art-video-player"),e.$video=e.query(".art-video"),e.$track=e.query("track"),e.$poster=e.query(".art-poster"),e.$subtitle=e.query(".art-subtitle"),e.$danmuku=e.query(".art-danmuku"),e.$bottom=e.query(".art-bottom"),e.$progress=e.query(".art-progress"),e.$controls=e.query(".art-controls"),e.$controlsLeft=e.query(".art-controls-left"),e.$controlsCenter=e.query(".art-controls-center"),e.$controlsRight=e.query(".art-controls-right"),e.$layer=e.query(".art-layers"),e.$loading=e.query(".art-loading"),e.$notice=e.query(".art-notice"),e.$noticeInner=e.query(".art-notice-inner"),e.$mask=e.query(".art-mask"),e.$state=e.query(".art-state"),e.$setting=e.query(".art-settings"),e.$info=e.query(".art-info"),e.$infoPanel=e.query(".art-info-panel"),e.$infoClose=e.query(".art-info-close"),e.$contextmenu=e.query(".art-contextmenus"),t.proxy){const e=t.proxy.call(this.art,this.art);!function(t){st(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement,"Function 'option.proxy' needs to return 'HTMLVideoElement' or 'HTMLCanvasElement'")}(e),J(e,this.$video),e.className="art-video",this.$video=e}t.backdrop&&N(this.$player,"art-backdrop"),R&&N(this.$player,"art-mobile")}destroy(t){t?this.$container.innerHTML="":N(this.$player,"art-destroy")}}const Qe=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);class tr{on(t,e,r){const o=this.e||(this.e={});let n=Qe(o,t)?o[t]:void 0;return n||(n=[],Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0})),n.push({fn:e,ctx:r}),this}once(t,e,r){const o=this,n=e;let a=!1;function i(...e){a||(a=!0,o.off(t,i),n.apply(r,e))}return i._=e,this.on(t,i,r)}emit(t,...e){const r=this.e||(this.e={}),o=(Qe(r,t)&&r[t]||[]).slice();for(const n of o)n.fn.apply(n.ctx,e);return this}off(t,e){const r=this.e||(this.e={}),o=Qe(r,t)?r[t]:void 0,n=[];if(o&&e)for(let a=0,i=o.length;ae.call(this,this)),or.DEBUG){const t=t=>console.log(`[ART.${this.id}] -> ${t}`);t(`Version@${or.version}`);for(let e=0;et(`Event@${e.type}`))}(function(t){const e=k(t);return e.rollback=void 0,!e.scope.closed})(this)&&rr.push(this)}catch(o){try{T(this,rr,!0,or.REMOVE_SRC_WHEN_DESTROY,!0)}catch(n){console.warn("Failed to clean up ArtPlayer initialization:",n)}throw o}}static get instances(){return rr}static get version(){return g}static get config(){return v}static get utils(){return zt}static get scheme(){return Yt}static get Emitter(){return tr}static get validator(){return m}static get kindOf(){return m.kindOf}static get html(){return Je.html}static get option(){return{id:"",container:"#artplayer",url:"",poster:"",type:"",theme:"#f00",volume:.7,isLive:!1,muted:!1,autoplay:!1,autoSize:!1,autoMini:!1,loop:!1,flip:!1,playbackRate:!1,aspectRatio:!1,screenshot:!1,setting:!1,hotkey:!0,pip:!1,mutex:!0,backdrop:!0,fullscreen:!1,fullscreenWeb:!1,subtitleOffset:!1,miniProgressBar:!1,useSSR:!1,playsInline:!0,lock:!1,gesture:!0,fastForward:!1,autoPlayback:!1,autoOrientation:!1,airplay:!1,proxy:void 0,layers:[],contextmenu:[],controls:[],settings:[],quality:[],highlight:[],plugins:[],thumbnails:{url:"",number:60,column:10,width:0,height:0,scale:1},subtitle:{url:"",type:"",style:{},name:"",escape:!0,encoding:"utf-8",onVttLoad:t=>t},moreVideoAttr:{controls:!1,preload:P?"auto":"metadata"},i18n:{},icons:{},cssVar:{},customType:{},lang:null==navigator?void 0:navigator.language.toLowerCase()}}get proxy(){return this.events.proxy}get query(){return this.template.query}get video(){return this.template.$video}reset(){this.video.removeAttribute("src"),this.video.load()}destroy(t=!0){T(this,rr,t,or.REMOVE_SRC_WHEN_DESTROY)}}return or.STYLE=Ge,or.DEBUG=!1,or.CONTEXTMENU=!0,or.NOTICE_TIME=2e3,or.SETTING_WIDTH=250,or.SETTING_ITEM_WIDTH=200,or.SETTING_ITEM_HEIGHT=35,or.RESIZE_TIME=200,or.SCROLL_TIME=200,or.SCROLL_GAP=50,or.AUTO_PLAYBACK_MAX=10,or.AUTO_PLAYBACK_MIN=5,or.AUTO_PLAYBACK_TIMEOUT=3e3,or.RECONNECT_TIME_MAX=5,or.RECONNECT_SLEEP_TIME=1e3,or.CONTROL_HIDE_TIME=3e3,or.DBCLICK_TIME=300,or.DBCLICK_FULLSCREEN=!0,or.MOBILE_DBCLICK_PLAY=!0,or.MOBILE_CLICK_PLAY=!1,or.AUTO_ORIENTATION_TIME=200,or.INFO_LOOP_TIME=1e3,or.FAST_FORWARD_VALUE=3,or.FAST_FORWARD_TIME=1e3,or.TOUCH_MOVE_RATIO=.5,or.VOLUME_STEP=.1,or.SEEK_STEP=5,or.PLAYBACK_RATE=[.5,.75,1,1.25,1.5,2],or.ASPECT_RATIO=["default","4:3","16:9"],or.FLIP=["normal","horizontal","vertical"],or.FULLSCREEN_WEB_IN_BODY=!0,or.LOG_VERSION=!0,or.USE_RAF=!1,or.REMOVE_SRC_WHEN_DESTROY=!0,_&&(window.Artplayer=or,V("artplayer-style",Ge),setTimeout(()=>{or.LOG_VERSION&&console.log(`%c ArtPlayer %c ${or.version} %c https://artplayer.org`,"color: #fff; background: #5f5f5f","color: #fff; background: #4bc729","")},100)),or}); diff --git a/packages/artplayer/dist/artplayer.mjs b/packages/artplayer/dist/artplayer.mjs index aa5a19999..86665e924 100644 --- a/packages/artplayer/dist/artplayer.mjs +++ b/packages/artplayer/dist/artplayer.mjs @@ -302,6 +302,185 @@ const config$1 = { "webkitExitFullscreen" ] }; +class ResourceCleanupError extends Error { + constructor(errors) { + super("Failed to release ArtPlayer resources"); + this.errors = errors; + this.name = "ResourceCleanupError"; + } +} +class ResourceScope { + constructor() { + this.cleanups = /* @__PURE__ */ new Set(); + this.disposed = false; + } + get closed() { + return this.disposed; + } + add(cleanup) { + let active = true; + const release = () => { + if (!active) + return; + active = false; + this.cleanups.delete(release); + cleanup(); + }; + if (this.closed) + release(); + else + this.cleanups.add(release); + return release; + } + child() { + const child = new ResourceScope(); + const release = this.add(() => { + child.dispose(); + }); + child.add(() => { + release(); + }); + return child; + } + dispose() { + if (this.closed) + return; + this.disposed = true; + const errors = []; + for (const release of Array.from(this.cleanups).reverse()) { + try { + release(); + } catch (error2) { + if (error2 instanceof ResourceCleanupError) + errors.push(...error2.errors); + else + errors.push(error2); + } + } + if (errors.length) + throw new ResourceCleanupError(errors); + } +} +const states = /* @__PURE__ */ new WeakMap(); +const containers = /* @__PURE__ */ new WeakMap(); +function beginLifecycle(owner) { + states.set(owner, { scope: new ResourceScope(), destroying: false }); +} +function stateOf(owner) { + const state2 = states.get(owner); + if (!state2) + throw new Error("ArtPlayer lifecycle has not been initialized"); + return state2; +} +function getScope(owner) { + return stateOf(owner).scope; +} +function isClosing(owner) { + const state2 = stateOf(owner); + return state2.destroying || state2.scope.closed; +} +function ownContainer(owner, container, rollback) { + const current2 = containers.get(container); + if (current2 && current2 !== owner) + throw new Error("Cannot mount multiple instances on the same dom element"); + const state2 = stateOf(owner); + state2.rollback = rollback; + containers.set(container, owner); + state2.releaseContainer = () => { + if (containers.get(container) === owner) + containers.delete(container); + }; +} +function finishLifecycle(owner) { + const state2 = stateOf(owner); + state2.rollback = void 0; + return !state2.scope.closed; +} +function destroyInstance(owner, instances2, removeHtml, removeSource, failed = false) { + const state2 = stateOf(owner); + if (state2.destroying || state2.scope.closed) + return; + state2.destroying = true; + const errors = []; + const attempt = (cleanup) => { + try { + cleanup(); + } catch (error2) { + errors.push(...error2 instanceof ResourceCleanupError ? error2.errors : [error2]); + } + }; + if (removeSource && owner.template?.$video) + attempt(() => owner.reset()); + attempt(() => state2.scope.dispose()); + attempt(() => owner.template?.destroy(removeHtml)); + const index = instances2.indexOf(owner); + if (index !== -1) + instances2.splice(index, 1); + owner.isDestroy = true; + if (!failed) { + state2.releaseContainer?.(); + state2.releaseContainer = void 0; + } + attempt(() => owner.emit("destroy")); + if (failed && state2.rollback) + attempt(state2.rollback); + state2.rollback = void 0; + state2.releaseContainer?.(); + state2.releaseContainer = void 0; + for (const error2 of errors.slice(1)) + console.warn("Additional ArtPlayer cleanup failure:", error2); + if (errors.length) + throw errors[0]; +} +const scopes$1 = /* @__PURE__ */ new WeakMap(); +function ownEntry(art, element) { + const scope = getScope(art).child(); + scopes$1.set(element, scope); + return scope; +} +function entryScope(element) { + const scope = scopes$1.get(element); + if (!scope) + throw new Error("ArtPlayer component has not been registered"); + return scope; +} +function releaseEntry(element) { + scopes$1.get(element)?.dispose(); +} +function proxyEntry(art, element, target, name, callback) { + const scope = entryScope(element); + if (scope.closed) + return () => { + }; + const cleanup = art.events.proxy(target, name, (event) => { + if (!scope.closed) + return callback(event); + }); + return scope.add(() => { + art.events.remove(cleanup); + }); +} +function subscribeEntry(art, element, name, callback) { + const scope = entryScope(element); + if (scope.closed) + return; + const guarded = (...args) => { + if (!scope.closed) + return callback(...args); + }; + art.on(name, guarded); + scope.add(() => { + art.off(name, guarded); + }); +} +function controlEvents(art, element) { + return { + on: (name, callback) => { + subscribeEntry(art, element, name, callback); + }, + proxy: (target, name, callback) => proxyEntry(art, element, target, name, callback) + }; +} const userAgent = globalThis?.CUSTOM_USER_AGENT ?? (typeof navigator !== "undefined" ? navigator.userAgent : ""); const isSafari = /^(?:(?!chrome|android).)*safari/i.test(userAgent); const isIOS = /iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream; @@ -721,6 +900,29 @@ const utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert userAgent, vttToBlob }, Symbol.toStringTag, { value: "Module" })); +function renderEntry(element, parent, kind, name, id2, option) { + addClass(element, `art-${kind}`); + addClass(element, `art-${kind}-${name}`); + const children = Array.from(parent.children); + element.dataset.index = String(option.index || id2); + const next = children.find((child) => Number(child.dataset.index) >= Number(element.dataset.index)); + if (next) + next.insertAdjacentElement("beforebegin", element); + else + append(parent, element); + if (option.html) + append(element, option.html); + if (option.style) + setStyles(element, option.style); + if (option.tooltip) + tooltip(element, option.tooltip); +} +function appendElement(parent, child) { + return append(parent, child); +} +function queryElement(selector, parent) { + return parent.querySelector(selector); +} const a = "array"; const b = "boolean"; const s = "string"; @@ -840,6 +1042,7 @@ const scheme = { cssVar: o, customType: o }; +const removing = /* @__PURE__ */ new WeakSet(); class Component { constructor(art) { this.id = 0; @@ -855,75 +1058,102 @@ class Component { set show(value) { const { $player } = this.art.template; const className = `art-${this.name}-show`; - if (value) { + if (value) addClass($player, className); - } else { + else removeClass($player, className); - } this.art.emit(this.name, value); } toggle() { this.show = !this.show; } add(getOption) { + if (isClosing(this.art)) + return; const option = typeof getOption === "function" ? getOption(this.art) : getOption; + if (isClosing(this.art)) + return; option.html = option.html || ""; validator(option, ComponentOption); if (!this.$parent || !this.name || option.disable) return; const name = option.name || `${this.name}${this.id}`; - errorHandle(!this.cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`); + const cache = this.cache; + errorHandle(!cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`); this.id += 1; - const $ref = createElement("div"); - addClass($ref, `art-${this.name}`); - addClass($ref, `art-${this.name}-${name}`); - const childs = Array.from(this.$parent.children); - $ref.dataset.index = option.index || this.id; - const nextChild = childs.find((item) => Number(item.dataset.index) >= Number($ref.dataset.index)); - if (nextChild) { - nextChild.insertAdjacentElement("beforebegin", $ref); - } else { - append(this.$parent, $ref); - } - if (option.html) { - append($ref, option.html); - } - if (option.style) { - setStyles($ref, option.style); - } - if (option.tooltip) { - tooltip($ref, option.tooltip); - } + const $ref = document.createElement("div"); + const scope = ownEntry(this.art, $ref); const events = []; - if (option.click) { - const destroyEvent = this.art.events.proxy($ref, "click", (event) => { - event.preventDefault(); - option.click.call(this.art, this, event); - }); - events.push(destroyEvent); + const previous = Object.getOwnPropertyDescriptor(this, name); + let aliased = false; + scope.add(() => { + for (const event of events) + this.art.events.remove(event); + }); + try { + if (scope.closed) + return; + renderEntry($ref, this.$parent, this.name, name, this.id, option); + if (scope.closed) + return; + if (option.click) { + const cleanup = this.art.events.proxy($ref, "click", (event) => { + if (scope.closed) + return; + event.preventDefault(); + option.click.call(this.art, this, event); + }); + events.push(cleanup); + } + if (option.selector && ["left", "right"].includes(option.position)) + this.selector(option, $ref, events); + if (scope.closed) + return; + assignAlias(this, name, $ref); + aliased = true; + cache.set(name, { $ref, events, option }); + if (option.mounted) + option.mounted.call(this.art, $ref); + return $ref; + } catch (error2) { + try { + releaseEntry($ref); + } catch (cleanupError) { + console.warn("ArtPlayer component cleanup failed:", cleanupError); + } + if (cache.get(name)?.$ref === $ref) + cache.delete(name); + if (aliased && this[name] === $ref) { + if (previous) + Object.defineProperty(this, name, previous); + else + delete this[name]; + } + $ref.remove(); + throw error2; } - if (option.selector && ["left", "right"].includes(option.position)) { - this.selector(option, $ref, events); - } - this[name] = $ref; - this.cache.set(name, { $ref, events, option }); - if (option.mounted) { - option.mounted.call(this.art, $ref); - } - return $ref; } remove(name) { errorHandle(this.cache.has(name), `Can't find [${name}] from the [${this.name}]`); const item = this.cache.get(name); - if (item.option.beforeUnmount) { - item.option.beforeUnmount.call(this.art, item.$ref); + if (removing.has(item)) + return; + removing.add(item); + try { + if (item.option.beforeUnmount) + item.option.beforeUnmount.call(this.art, item.$ref); + try { + releaseEntry(item.$ref); + } finally { + if (this.cache.get(name) === item) { + this.cache.delete(name); + delete this[name]; + } + item.$ref.remove(); + } + } finally { + removing.delete(item); } - for (const event of item.events) { - this.art.events.remove(event); - } - this.cache.delete(name); - delete this[name]; - remove(item.$ref); } update(option) { if (this.cache.has(option.name)) { @@ -934,6 +1164,13 @@ class Component { return this.add(option); } } +function assignAlias(owner, name, value) { + const aliases = owner; + if (name === "__proto__") + Object.defineProperty(aliases, name, { value, enumerable: true, configurable: true, writable: true }); + else + aliases[name] = value; +} function aspectRatio$2(option) { return (art) => { const { @@ -947,19 +1184,20 @@ function aspectRatio$2(option) { ...option, html: `${i18n.get("Aspect Ratio")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.aspectRatio = value; contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="default"]', $panel); if ($default) { inverseClass($default, "art-current"); } - art.on("aspectRatio", (value) => { - const $current = queryAll("span", $panel).find((item) => item.dataset.value === value); + on("aspectRatio", (value) => { + const $current = Array.from($panel.querySelectorAll("span")).find((item) => item.dataset.value === value); if ($current) { inverseClass($current, "art-current"); } @@ -988,19 +1226,20 @@ function flip$2(option) { ...option, html: `${i18n.get("Video Flip")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.flip = value.toLowerCase(); contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="normal"]', $panel); if ($default) { inverseClass($default, "art-current"); } - art.on("flip", (value) => { - const $current = queryAll("span", $panel).find((item) => item.dataset.value === value); + on("flip", (value) => { + const $current = Array.from($panel.querySelectorAll("span")).find((item) => item.dataset.value === value); if ($current) { inverseClass($current, "art-current"); } @@ -1032,18 +1271,19 @@ function playbackRate$2(option) { ...option, html: `${i18n.get("Play Speed")}: ${html2}`, click: (contextmenu, event) => { - const { value } = event.target.dataset; + const value = event.target instanceof HTMLElement ? event.target.dataset.value : void 0; if (value) { art.playbackRate = Number(value); contextmenu.show = false; } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel); const $default = query('[data-value="1"]', $panel); if ($default) inverseClass($default, "art-current"); - art.on("video:ratechange", () => { - const $current = queryAll("span", $panel).find( + on("video:ratechange", () => { + const $current = Array.from($panel.querySelectorAll("span")).find( (item) => Number(item.dataset.value) === art.playbackRate ); if ($current) { @@ -1065,6 +1305,7 @@ class Contextmenu extends Component { super(art); this.name = "contextmenu"; this.$parent = art.template.$contextmenu; + ownEntry(art, this.$parent); if (!isMobile) { this.init(); } @@ -1072,9 +1313,9 @@ class Contextmenu extends Component { init() { const { option, - proxy, template: { $player, $contextmenu } } = this.art; + const { on, proxy } = controlEvents(this.art, $contextmenu); if (option.playbackRate) { this.add( playbackRate$2({ @@ -1147,141 +1388,11 @@ class Contextmenu extends Component { this.show = false; } }); - this.art.on("blur", () => { + on("blur", () => { this.show = false; }); } } -class ResourceCleanupError extends Error { - constructor(errors) { - super("Failed to release ArtPlayer resources"); - this.errors = errors; - this.name = "ResourceCleanupError"; - } -} -class ResourceScope { - constructor() { - this.cleanups = /* @__PURE__ */ new Set(); - this.disposed = false; - } - get closed() { - return this.disposed; - } - add(cleanup) { - let active = true; - const release = () => { - if (!active) - return; - active = false; - this.cleanups.delete(release); - cleanup(); - }; - if (this.closed) - release(); - else - this.cleanups.add(release); - return release; - } - child() { - const child = new ResourceScope(); - const release = this.add(() => { - child.dispose(); - }); - child.add(() => { - release(); - }); - return child; - } - dispose() { - if (this.closed) - return; - this.disposed = true; - const errors = []; - for (const release of Array.from(this.cleanups).reverse()) { - try { - release(); - } catch (error2) { - if (error2 instanceof ResourceCleanupError) - errors.push(...error2.errors); - else - errors.push(error2); - } - } - if (errors.length) - throw new ResourceCleanupError(errors); - } -} -const states = /* @__PURE__ */ new WeakMap(); -const containers = /* @__PURE__ */ new WeakMap(); -function beginLifecycle(owner) { - states.set(owner, { scope: new ResourceScope(), destroying: false }); -} -function stateOf(owner) { - const state2 = states.get(owner); - if (!state2) - throw new Error("ArtPlayer lifecycle has not been initialized"); - return state2; -} -function getScope(owner) { - return stateOf(owner).scope; -} -function isClosing(owner) { - const state2 = stateOf(owner); - return state2.destroying || state2.scope.closed; -} -function ownContainer(owner, container, rollback) { - const current2 = containers.get(container); - if (current2 && current2 !== owner) - throw new Error("Cannot mount multiple instances on the same dom element"); - const state2 = stateOf(owner); - state2.rollback = rollback; - containers.set(container, owner); - state2.releaseContainer = () => { - if (containers.get(container) === owner) - containers.delete(container); - }; -} -function finishLifecycle(owner) { - const state2 = stateOf(owner); - state2.rollback = void 0; - return !state2.scope.closed; -} -function destroyInstance(owner, instances2, removeHtml, removeSource, failed = false) { - const state2 = stateOf(owner); - if (state2.destroying || state2.scope.closed) - return; - state2.destroying = true; - const errors = []; - const attempt = (cleanup) => { - try { - cleanup(); - } catch (error2) { - errors.push(...error2 instanceof ResourceCleanupError ? error2.errors : [error2]); - } - }; - if (removeSource && owner.template?.$video) - attempt(() => owner.reset()); - attempt(() => state2.scope.dispose()); - attempt(() => owner.template?.destroy(removeHtml)); - const index = instances2.indexOf(owner); - if (index !== -1) - instances2.splice(index, 1); - owner.isDestroy = true; - if (!failed) { - state2.releaseContainer?.(); - state2.releaseContainer = void 0; - } - attempt(() => owner.emit("destroy")); - if (failed && state2.rollback) - attempt(state2.rollback); - state2.rollback = void 0; - state2.releaseContainer?.(); - state2.releaseContainer = void 0; - for (const error2 of errors.slice(1)) - console.warn("Additional ArtPlayer cleanup failure:", error2); - if (errors.length) - throw errors[0]; -} function timeout(scope, callback, delay) { if (scope.closed) return () => { @@ -1346,8 +1457,9 @@ function airplay$1(option) { ...option, tooltip: art.i18n.get("AirPlay"), mounted: ($control) => { - const { proxy, icons } = art; - append($control, icons.airplay); + const { proxy } = controlEvents(art, $control); + const { icons } = art; + appendElement($control, icons.airplay); proxy($control, "click", () => art.airplay()); } }); @@ -1357,14 +1469,15 @@ function fullscreen(option) { ...option, tooltip: art.i18n.get("Fullscreen"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $fullscreenOn = append($control, icons.fullscreenOn); - const $fullscreenOff = append($control, icons.fullscreenOff); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $fullscreenOn = appendElement($control, icons.fullscreenOn); + const $fullscreenOff = appendElement($control, icons.fullscreenOff); setStyle($fullscreenOff, "display", "none"); proxy($control, "click", () => { art.fullscreen = !art.fullscreen; }); - art.on("fullscreen", (state2) => { + on("fullscreen", (state2) => { if (state2) { tooltip($control, i18n.get("Exit Fullscreen")); setStyle($fullscreenOn, "display", "none"); @@ -1383,14 +1496,15 @@ function fullscreenWeb(option) { ...option, tooltip: art.i18n.get("Web Fullscreen"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $fullscreenWebOn = append($control, icons.fullscreenWebOn); - const $fullscreenWebOff = append($control, icons.fullscreenWebOff); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $fullscreenWebOn = appendElement($control, icons.fullscreenWebOn); + const $fullscreenWebOff = appendElement($control, icons.fullscreenWebOff); setStyle($fullscreenWebOff, "display", "none"); proxy($control, "click", () => { art.fullscreenWeb = !art.fullscreenWeb; }); - art.on("fullscreenWeb", (value) => { + on("fullscreenWeb", (value) => { if (value) { tooltip($control, i18n.get("Exit Web Fullscreen")); setStyle($fullscreenWebOn, "display", "none"); @@ -1409,12 +1523,13 @@ function pip$1(option) { ...option, tooltip: art.i18n.get("PIP Mode"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - append($control, icons.pip); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + appendElement($control, icons.pip); proxy($control, "click", () => { art.pip = !art.pip; }); - art.on("pip", (value) => { + on("pip", (value) => { tooltip($control, i18n.get(value ? "Exit PIP Mode" : "PIP Mode")); }); } @@ -1424,9 +1539,10 @@ function playAndPause(option) { return (art) => ({ ...option, mounted: ($control) => { - const { proxy, icons, i18n } = art; - const $play = append($control, icons.play); - const $pause = append($control, icons.pause); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + const $play = appendElement($control, icons.play); + const $pause = appendElement($control, icons.pause); tooltip($play, i18n.get("Play")); tooltip($pause, i18n.get("Pause")); proxy($play, "click", () => { @@ -1448,10 +1564,10 @@ function playAndPause(option) { } else { showPlay(); } - art.on("video:playing", () => { + on("video:playing", () => { showPause(); }); - art.on("video:pause", () => { + on("video:pause", () => { showPlay(); }); } @@ -1479,13 +1595,153 @@ function setCurrentTime(art, event) { art.seek = second; } } +function installProgressInteractions(art, $control) { + const { $progress } = art.template; + const $indicator = $control.querySelector(".art-progress-indicator"); + const { on, proxy } = controlEvents(art, $control); + if (!isMobile) { + let isDragging = false; + proxy($progress, "click", (event) => { + if (event.target !== $indicator) { + setCurrentTime(art, event); + } + }); + proxy($progress, "mousemove", (event) => { + const { percentage } = getPosFromEvent(art, event); + art.emit("setBar", "hover", percentage, event); + }); + proxy($progress, "mouseleave", (event) => { + art.emit("setBar", "hover", 0, event); + }); + proxy($progress, "mousedown", (event) => { + isDragging = event.button === 0; + }); + on("document:mousemove", (event) => { + if (isDragging) { + const { second, percentage } = getPosFromEvent(art, event); + art.emit("setBar", "played", percentage, event); + art.seek = second; + } + }); + on("document:mouseup", () => { + if (isDragging) { + isDragging = false; + } + }); + } +} +function mountProgressView(art, $control) { + const { icons, option } = art; + const { $player } = art.template; + const scope = entryScope($control); + const { on } = controlEvents(art, $control); + let cancelTip = () => { + }; + const $hover = queryElement(".art-progress-hover", $control); + const $loaded = queryElement(".art-progress-loaded", $control); + const $played = queryElement(".art-progress-played", $control); + const $highlight = queryElement(".art-progress-highlight", $control); + const $indicator = queryElement(".art-progress-indicator", $control); + const $tip = queryElement(".art-progress-tip", $control); + if (icons.indicator) { + append($indicator, icons.indicator); + } else { + setStyle($indicator, "backgroundColor", "var(--art-theme)"); + } + function showHighlight(event) { + const { width } = getPosFromEvent(art, event); + const text = event.target instanceof HTMLElement ? event.target.dataset.text : void 0; + $tip.textContent = text ?? ""; + const tipWidth = $tip.clientWidth; + if (width <= tipWidth / 2) { + setStyle($tip, "left", 0); + } else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); + } else { + setStyle($tip, "left", `${width - tipWidth / 2}px`); + } + } + function showTime(event, touch) { + const { width, time: time2 } = touch || getPosFromEvent(art, event); + $tip.textContent = time2 || "00:00"; + const tipWidth = $tip.clientWidth; + if (width <= tipWidth / 2) { + setStyle($tip, "left", 0); + } else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); + } else { + setStyle($tip, "left", `${width - tipWidth / 2}px`); + } + } + function updateHighlight() { + $highlight.textContent = ""; + for (let index = 0; index < option.highlight.length; index++) { + const item = option.highlight[index]; + const left = clamp(item.time, 0, art.duration) / art.duration * 100; + const marker = document.createElement("span"); + marker.dataset.text = item.text; + marker.dataset.time = String(item.time); + marker.style.left = `${left}%`; + append($highlight, marker); + } + } + function setBar(type, percentage, event) { + const isMobileDragging = type === "played" && event && isMobile; + if (type === "loaded") { + setStyle($loaded, "width", `${percentage * 100}%`); + } + if (type === "hover") { + setStyle($hover, "width", `${percentage * 100}%`); + if (includeFromEvent(event, $highlight)) { + showHighlight(event); + } else { + showTime(event); + } + if (percentage === 0) { + removeClass($player, "art-progress-hover"); + } else { + addClass($player, "art-progress-hover"); + } + } + if (type === "played") { + setStyle($played, "width", `${percentage * 100}%`); + setStyle($indicator, "left", `${percentage * 100}%`); + } + if (isMobileDragging) { + addClass($player, "art-progress-hover"); + const width = $control.clientWidth * percentage; + const time2 = secondToTime(percentage * art.duration); + showTime(event, { width, time: time2 }); + cancelTip(); + cancelTip = timeout(scope, () => { + removeClass($player, "art-progress-hover"); + }, 500); + } + } + on("setBar", setBar); + on("video:loadedmetadata", updateHighlight); + if (art.constructor.USE_RAF) { + on("raf", () => { + art.emit("setBar", "played", art.played); + art.emit("setBar", "loaded", art.loaded); + }); + } else { + on("video:timeupdate", () => { + art.emit("setBar", "played", art.played); + }); + on("video:progress", () => { + art.emit("setBar", "loaded", art.loaded); + }); + on("video:ended", () => { + art.emit("setBar", "played", 1); + }); + } + art.emit("setBar", "loaded", art.loaded || 0); +} function progress(options) { - return (art) => { - const { icons, option, proxy } = art; - const { $player, $progress } = art.template; - return { - ...options, - html: ` + return (art) => ({ + ...options, + html: `
@@ -1495,146 +1751,20 @@ function progress(options) {
00:00
`, - mounted: ($control) => { - let tipTimer = null; - let isDragging = false; - const $hover = query(".art-progress-hover", $control); - const $loaded = query(".art-progress-loaded", $control); - const $played = query(".art-progress-played", $control); - const $highlight = query(".art-progress-highlight", $control); - const $indicator = query(".art-progress-indicator", $control); - const $tip = query(".art-progress-tip", $control); - if (icons.indicator) { - append($indicator, icons.indicator); - } else { - setStyle($indicator, "backgroundColor", "var(--art-theme)"); - } - function showHighlight(event) { - const { width } = getPosFromEvent(art, event); - const { text } = event.target.dataset; - $tip.textContent = text; - const tipWidth = $tip.clientWidth; - if (width <= tipWidth / 2) { - setStyle($tip, "left", 0); - } else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); - } else { - setStyle($tip, "left", `${width - tipWidth / 2}px`); - } - } - function showTime(event, touch) { - const { width, time: time2 } = touch || getPosFromEvent(art, event); - $tip.textContent = time2 || "00:00"; - const tipWidth = $tip.clientWidth; - if (width <= tipWidth / 2) { - setStyle($tip, "left", 0); - } else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, "left", `${$control.clientWidth - tipWidth}px`); - } else { - setStyle($tip, "left", `${width - tipWidth / 2}px`); - } - } - function updateHighlight() { - $highlight.textContent = ""; - for (let index = 0; index < option.highlight.length; index++) { - const item = option.highlight[index]; - const left = clamp(item.time, 0, art.duration) / art.duration * 100; - const html2 = ``; - append($highlight, html2); - } - } - function setBar(type, percentage, event) { - const isMobileDragging = type === "played" && event && isMobile; - if (type === "loaded") { - setStyle($loaded, "width", `${percentage * 100}%`); - } - if (type === "hover") { - setStyle($hover, "width", `${percentage * 100}%`); - if (includeFromEvent(event, $highlight)) { - showHighlight(event); - } else { - showTime(event); - } - if (percentage === 0) { - removeClass($player, "art-progress-hover"); - } else { - addClass($player, "art-progress-hover"); - } - } - if (type === "played") { - setStyle($played, "width", `${percentage * 100}%`); - setStyle($indicator, "left", `${percentage * 100}%`); - } - if (isMobileDragging) { - addClass($player, "art-progress-hover"); - const width = $control.clientWidth * percentage; - const time2 = secondToTime(percentage * art.duration); - showTime(event, { width, time: time2 }); - clearTimeout(tipTimer); - tipTimer = setTimeout(() => { - removeClass($player, "art-progress-hover"); - }, 500); - } - } - art.on("setBar", setBar); - art.on("video:loadedmetadata", updateHighlight); - if (art.constructor.USE_RAF) { - art.on("raf", () => { - art.emit("setBar", "played", art.played); - art.emit("setBar", "loaded", art.loaded); - }); - } else { - art.on("video:timeupdate", () => { - art.emit("setBar", "played", art.played); - }); - art.on("video:progress", () => { - art.emit("setBar", "loaded", art.loaded); - }); - art.on("video:ended", () => { - art.emit("setBar", "played", 1); - }); - } - art.emit("setBar", "loaded", art.loaded || 0); - if (!isMobile) { - proxy($progress, "click", (event) => { - if (event.target !== $indicator) { - setCurrentTime(art, event); - } - }); - proxy($progress, "mousemove", (event) => { - const { percentage } = getPosFromEvent(art, event); - art.emit("setBar", "hover", percentage, event); - }); - proxy($progress, "mouseleave", (event) => { - art.emit("setBar", "hover", 0, event); - }); - proxy($progress, "mousedown", (event) => { - isDragging = event.button === 0; - }); - art.on("document:mousemove", (event) => { - if (isDragging) { - const { second, percentage } = getPosFromEvent(art, event); - art.emit("setBar", "played", percentage, event); - art.seek = second; - } - }); - art.on("document:mouseup", () => { - if (isDragging) { - isDragging = false; - } - }); - } - } - }; - }; + mounted: ($control) => { + mountProgressView(art, $control); + installProgressInteractions(art, $control); + } + }); } function screenshot$1(option) { return (art) => ({ ...option, tooltip: art.i18n.get("Screenshot"), mounted: ($control) => { - const { proxy, icons } = art; - append($control, icons.screenshot); + const { proxy } = controlEvents(art, $control); + const { icons } = art; + appendElement($control, icons.screenshot); proxy($control, "click", () => { art.screenshot(); }); @@ -1646,13 +1776,14 @@ function setting$1(option) { ...option, tooltip: art.i18n.get("Show Setting"), mounted: ($control) => { - const { proxy, icons, i18n } = art; - append($control, icons.setting); + const { on, proxy } = controlEvents(art, $control); + const { icons, i18n } = art; + appendElement($control, icons.setting); proxy($control, "click", () => { art.setting.toggle(); art.setting.resize(); }); - art.on("setting", (value) => { + on("setting", (value) => { tooltip($control, i18n.get(value ? "Hide Setting" : "Show Setting")); }); } @@ -1669,6 +1800,7 @@ function time(option) { padding: "0 10px" }, mounted: ($control) => { + const { on } = controlEvents(art, $control); function getTime() { const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}`; if (newTime !== $control.textContent) { @@ -1678,7 +1810,7 @@ function time(option) { getTime(); const events = ["video:loadedmetadata", "video:timeupdate", "video:progress"]; for (let index = 0; index < events.length; index++) { - art.on(events[index], getTime); + on(events[index], getTime); } } }); @@ -1687,16 +1819,17 @@ function volume$1(option) { return (art) => ({ ...option, mounted: ($control) => { - const { proxy, icons } = art; - const $volume = append($control, icons.volume); - const $close = append($control, icons.volumeClose); - const $panel = append($control, '
'); - const $inner = append($panel, '
'); - const $value = append($inner, `
`); - const $slider = append($inner, `
`); - const $handle = append($slider, `
`); - const $loaded = append($handle, `
`); - const $indicator = append($slider, `
`); + const { on, proxy } = controlEvents(art, $control); + const { icons } = art; + const $volume = appendElement($control, icons.volume); + const $close = appendElement($control, icons.volumeClose); + const $panel = appendElement($control, '
'); + const $inner = appendElement($panel, '
'); + const $value = appendElement($inner, `
`); + const $slider = appendElement($inner, `
`); + const $handle = appendElement($slider, `
`); + const $loaded = appendElement($handle, `
`); + const $indicator = appendElement($slider, `
`); function getVolumeFromEvent(event) { const { top, height } = getRect($slider); return 1 - (event.clientY - top) / height; @@ -1707,18 +1840,18 @@ function volume$1(option) { setStyle($close, "display", "flex"); setStyle($indicator, "top", "100%"); setStyle($loaded, "top", "100%"); - $value.textContent = 0; + $value.textContent = "0"; } else { const percentage = art.volume * 100; setStyle($volume, "display", "flex"); setStyle($close, "display", "none"); setStyle($indicator, "top", `${100 - percentage}%`); setStyle($loaded, "top", `${100 - percentage}%`); - $value.textContent = Math.floor(percentage); + $value.textContent = String(Math.floor(percentage)); } } update(); - art.on("video:volumechange", update); + on("video:volumechange", update); proxy($volume, "click", () => { art.muted = true; }); @@ -1733,13 +1866,13 @@ function volume$1(option) { isDragging = event.button === 0; art.volume = getVolumeFromEvent(event); }); - art.on("document:mousemove", (event) => { + on("document:mousemove", (event) => { if (isDragging) { art.muted = false; art.volume = getVolumeFromEvent(event); } }); - art.on("document:mouseup", () => { + on("document:mouseup", () => { if (isDragging) { isDragging = false; } @@ -1748,6 +1881,226 @@ function volume$1(option) { } }); } +function installControls(controls) { + const { option } = controls.art; + if (!option.isLive) { + controls.add( + progress({ + name: "progress", + position: "top", + index: 10 + }) + ); + } + controls.add({ + name: "thumbnails", + position: "top", + index: 20 + }); + controls.add( + playAndPause({ + name: "playAndPause", + position: "left", + index: 10 + }) + ); + controls.add( + volume$1({ + name: "volume", + position: "left", + index: 20 + }) + ); + if (!option.isLive) { + controls.add( + time({ + name: "time", + position: "left", + index: 30 + }) + ); + } + if (option.quality.length) { + wait(getScope(controls.art)).then((active) => { + if (!active || getScope(controls.art).closed) + return; + controls.art.quality = option.quality; + }).catch((error2) => { + console.warn("ArtPlayer quality initialization failed:", error2); + }); + } + if (option.screenshot && !isMobile) { + controls.add( + screenshot$1({ + name: "screenshot", + position: "right", + index: 20 + }) + ); + } + if (option.setting) { + controls.add( + setting$1({ + name: "setting", + position: "right", + index: 30 + }) + ); + } + if (option.pip) { + controls.add( + pip$1({ + name: "pip", + position: "right", + index: 40 + }) + ); + } + if (option.airplay && "WebKitPlaybackTargetAvailabilityEvent" in window && window.WebKitPlaybackTargetAvailabilityEvent) { + controls.add( + airplay$1({ + name: "airplay", + position: "right", + index: 50 + }) + ); + } + if (option.fullscreenWeb) { + controls.add( + fullscreenWeb({ + name: "fullscreenWeb", + position: "right", + index: 60 + }) + ); + } + if (option.fullscreen) { + controls.add( + fullscreen({ + name: "fullscreen", + position: "right", + index: 70 + }) + ); + } + for (let index = 0; index < option.controls.length; index++) { + controls.add(option.controls[index]); + } +} +function observeControlLayout(art) { + const { $bottom, $controls, $player } = art.template; + const scope = entryScope($bottom); + const { on } = controlEvents(art, $bottom); + const update = () => { + if (scope.closed) + return; + const height = $controls.offsetHeight; + if (height > 0 && $player.style.getPropertyValue("--art-controls-height") !== `${height}px`) + $player.style.setProperty("--art-controls-height", `${height}px`); + }; + on("resize", update); + if (typeof ResizeObserver !== "undefined") { + const observer = new ResizeObserver(update); + observer.observe($controls); + scope.add(() => { + observer.disconnect(); + }); + } else if (typeof MutationObserver !== "undefined") { + const observer = new MutationObserver(update); + observer.observe($controls, { childList: true, subtree: true, attributes: true, characterData: true }); + scope.add(() => { + observer.disconnect(); + }); + } + update(); +} +const selections = /* @__PURE__ */ new WeakMap(); +function trackSelection(event, active) { + selections.set(event, active); + return () => { + if (selections.get(event) === active) + selections.delete(event); + }; +} +function captureSelection(event) { + return event && selections.get(event) || (() => true); +} +const bindings = /* @__PURE__ */ new WeakMap(); +function bind(item, binding) { + const previous = bindings.get(item); + errorHandle(!previous || entryScope(previous.owner).closed, "Cannot share selector items between active controls"); + if (!previous) { + def(item, "$control_option", { get: () => bindings.get(item).option.selector }); + def(item, "$control_item", { get: () => bindings.get(item).item }); + def(item, "$control_value", { get: () => bindings.get(item).value }); + } + bindings.set(item, binding); +} +function setHTML(element, value) { + element.innerHTML = value; +} +function checkSelector(target) { + if (!target) + return; + setHTML(target.$control_value, target.html); + for (let index = 0; index < target.$control_option.length; index++) { + const item = target.$control_option[index]; + item.default = item === target; + if (item.default) + inverseClass(item.$control_item, "art-current"); + } +} +function renderSelector(art, check2, option, $ref, events) { + const { proxy } = art.events; + const scope = entryScope($ref); + const selector = option.selector; + addClass($ref, "art-control-selector"); + const $value = document.createElement("div"); + addClass($value, "art-selector-value"); + append($value, option.html); + $ref.textContent = ""; + append($ref, $value); + const $list = appendElement($ref, '
'); + for (let index = 0; index < selector.length; index++) { + const item = selector[index]; + const $item = document.createElement("div"); + addClass($item, "art-selector-item"); + if (item.default) + addClass($item, "art-current"); + $item.dataset.index = String(index); + $item.dataset.value = String(item.value); + setHTML($item, item.html); + append($list, $item); + bind(item, { option, item: $item, value: $value, owner: $ref }); + } + let generation = 0; + const event = proxy($list, "click", async (event2) => { + if (scope.closed) + return; + const path = getComposedPath(event2); + const item = option.selector.find((item2) => path.includes(item2.$control_item)); + if (!item) + return; + const current2 = ++generation; + const active = () => !scope.closed && current2 === generation; + const release = scope.add(trackSelection(event2, active)); + try { + check2(item); + if (scope.closed) + return; + if (option.onSelect) { + const value = await option.onSelect.call(art, item, item.$control_item, event2); + if (active()) + setHTML($value, value); + } + } catch (error2) { + console.warn("ArtPlayer selector failed:", error2); + } finally { + release(); + } + }); + events.push(event); +} class Control extends Component { constructor(art) { super(art); @@ -1756,27 +2109,29 @@ class Control extends Component { this.timer = Date.now(); const { constructor } = art; const { $player, $bottom } = this.art.template; - art.on("mousemove", () => { + ownEntry(art, $bottom); + const { on } = controlEvents(art, $bottom); + on("mousemove", () => { if (!isMobile) { this.show = true; } }); - art.on("click", () => { + on("click", () => { if (isMobile) { this.toggle(); } else { this.show = true; } }); - art.on("document:mousemove", (event) => { + on("document:mousemove", (event) => { this.isHover = includeFromEvent(event, $bottom); }); - art.on("video:timeupdate", () => { + on("video:timeupdate", () => { if (!art.setting.show && !this.isHover && !art.isInput && art.playing && this.show && Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME) { this.show = false; } }); - art.on("control", (state2) => { + on("control", (state2) => { if (state2) { removeClass($player, "art-hide-cursor"); addClass($player, "art-hover"); @@ -1787,112 +2142,15 @@ class Control extends Component { } }); this.init(); + if (!getScope(art).closed) + observeControlLayout(art); } init() { - const { option } = this.art; - if (!option.isLive) { - this.add( - progress({ - name: "progress", - position: "top", - index: 10 - }) - ); - } - this.add({ - name: "thumbnails", - position: "top", - index: 20 - }); - this.add( - playAndPause({ - name: "playAndPause", - position: "left", - index: 10 - }) - ); - this.add( - volume$1({ - name: "volume", - position: "left", - index: 20 - }) - ); - if (!option.isLive) { - this.add( - time({ - name: "time", - position: "left", - index: 30 - }) - ); - } - if (option.quality.length) { - wait(getScope(this.art)).then((active) => { - if (!active || getScope(this.art).closed) - return; - this.art.quality = option.quality; - }); - } - if (option.screenshot && !isMobile) { - this.add( - screenshot$1({ - name: "screenshot", - position: "right", - index: 20 - }) - ); - } - if (option.setting) { - this.add( - setting$1({ - name: "setting", - position: "right", - index: 30 - }) - ); - } - if (option.pip) { - this.add( - pip$1({ - name: "pip", - position: "right", - index: 40 - }) - ); - } - if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) { - this.add( - airplay$1({ - name: "airplay", - position: "right", - index: 50 - }) - ); - } - if (option.fullscreenWeb) { - this.add( - fullscreenWeb({ - name: "fullscreenWeb", - position: "right", - index: 60 - }) - ); - } - if (option.fullscreen) { - this.add( - fullscreen({ - name: "fullscreen", - position: "right", - index: 70 - }) - ); - } - for (let index = 0; index < option.controls.length; index++) { - this.add(option.controls[index]); - } + installControls(this); } add(getOption) { + if (isClosing(this.art)) + return; const option = typeof getOption === "function" ? getOption(this.art) : getOption; const { $progress, $controlsLeft, $controlsRight } = this.art.template; switch (option.position) { @@ -1912,60 +2170,10 @@ class Control extends Component { super.add(option); } check(target) { - if (!target) { - return; - } - target.$control_value.innerHTML = target.html; - for (let index = 0; index < target.$control_option.length; index++) { - const item = target.$control_option[index]; - item.default = item === target; - if (item.default) { - inverseClass(item.$control_item, "art-current"); - } - } + checkSelector(target); } selector(option, $ref, events) { - const { proxy } = this.art.events; - addClass($ref, "art-control-selector"); - const $value = createElement("div"); - addClass($value, "art-selector-value"); - append($value, option.html); - $ref.textContent = ""; - append($ref, $value); - const $list = createElement("div"); - addClass($list, "art-selector-list"); - append($ref, $list); - for (let index = 0; index < option.selector.length; index++) { - const item = option.selector[index]; - const $item = createElement("div"); - addClass($item, "art-selector-item"); - if (item.default) - addClass($item, "art-current"); - $item.dataset.index = index; - $item.dataset.value = item.value; - $item.innerHTML = item.html; - append($list, $item); - def(item, "$control_option", { - get: () => option.selector - }); - def(item, "$control_item", { - get: () => $item - }); - def(item, "$control_value", { - get: () => $value - }); - } - const event = proxy($list, "click", async (event2) => { - const path = getComposedPath(event2); - const item = option.selector.find( - (item2) => item2.$control_item === path.find(($item) => item2.$control_item === $item) - ); - this.check(item); - if (option.onSelect) { - $value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event2); - } - }); - events.push(event); + renderSelector(this.art, (target) => this.check(target), option, $ref, events); } } function clickInit(art, events) { @@ -2530,15 +2738,11 @@ class Info extends Component { class Layer extends Component { constructor(art) { super(art); - const { - option, - template: { $layer } - } = art; + const { option, template: { $layer } } = art; this.name = "layer"; this.$parent = $layer; - for (let index = 0; index < option.layers.length; index++) { + for (let index = 0; index < option.layers.length; index++) this.add(option.layers[index]); - } } } class Loading extends Component { @@ -3674,14 +3878,17 @@ function qualityMix(art) { name: "quality", position: "right", index: 10, - style: { - marginRight: "10px" - }, + style: { marginRight: "10px" }, html: qualityDefault?.html || "", selector: quality, - async onSelect(item) { + async onSelect(item, _element, event) { + const active = captureSelection(event); await art.switchQuality(item.url); - notice.show = `${i18n.get("Switch Video")}: ${item.html}`; + if (!isClosing(art) && active()) { + const message = `${i18n.get("Switch Video")}: ${item.html}`; + if (!isClosing(art) && active()) + notice.show = message; + } return item.html; } }); @@ -5128,7 +5335,7 @@ class Storage { } } } -const css = ".art-video-player {\n --art-theme: #f00;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: rgba(0, 0, 0, 0.5);\n --art-transition-duration: 0.2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: rgba(255, 255, 255, 0.25);\n --art-progress-top-gap: 10px;\n --art-hover-color: rgba(255, 255, 255, 0.25);\n --art-loaded-color: rgba(255, 255, 255, 0.25);\n --art-state-size: 80px;\n --art-state-opacity: 0.8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: rgba(255, 255, 255, 0.5);\n --art-control-height: 46px;\n --art-control-opacity: 0.75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: rgba(0, 0, 0, 0.85);\n --art-tip-background: rgba(0, 0, 0, 0.7);\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: rgba(255, 255, 255, 0.25);\n --art-scrollbar-background-hover: rgba(255, 255, 255, 0.5);\n --art-mini-progress-height: 2px;\n}\n.art-bg-cover {\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-backdrop-filter {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.art-video-player {\n position: relative;\n margin: 0 auto;\n width: 100%;\n height: 100%;\n outline: 0;\n zoom: 1;\n padding: 0;\n text-align: left;\n direction: ltr;\n font-size: 14px;\n line-height: 1.3;\n user-select: none;\n box-sizing: border-box;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n}\n.art-video-player *,\n.art-video-player *::before,\n.art-video-player *::after {\n box-sizing: border-box;\n}\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n.art-video-player img {\n max-width: 100%;\n vertical-align: top;\n}\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n.art-icon {\n line-height: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.art-video-player.art-backdrop .art-contextmenus,\n.art-video-player.art-backdrop .art-info,\n.art-video-player.art-backdrop .art-settings,\n.art-video-player.art-backdrop .art-layer-auto-playback,\n.art-video-player.art-backdrop .art-selector-list,\n.art-video-player.art-backdrop .art-volume-inner {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-video {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n}\n.art-poster {\n position: absolute;\n inset: 0;\n z-index: 11;\n width: 100%;\n height: 100%;\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: none;\n}\n.art-video-player .art-subtitle {\n display: none;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n z-index: 20;\n width: 100%;\n padding: 0 5%;\n text-align: center;\n pointer-events: none;\n gap: var(--art-subtitle-gap);\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom));\n}\n.art-danmuku {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: hidden;\n}\n.art-video-player .art-layers {\n position: absolute;\n inset: 0;\n z-index: 40;\n width: 100%;\n height: 100%;\n display: none;\n pointer-events: none;\n}\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n.art-video-player .art-mask {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 50;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player .art-mask .art-state {\n display: flex;\n justify-content: center;\n align-items: center;\n opacity: 0;\n transform: scale(2);\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n}\n.art-video-player.art-mask-show .art-state {\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n.art-video-player .art-loading {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 70;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n.art-video-player .art-bottom {\n position: absolute;\n inset: 0;\n z-index: 60;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-video-player .art-bottom .art-controls,\n.art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player.art-control-show .art-bottom,\n.art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n.art-video-player.art-control-show .art-bottom .art-controls,\n.art-video-player.art-hover .art-bottom .art-controls,\n.art-video-player.art-control-show .art-bottom .art-progress,\n.art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n.art-bottom .art-progress {\n position: relative;\n z-index: 0;\n cursor: pointer;\n pointer-events: auto;\n padding-top: var(--art-progress-top-gap);\n padding-bottom: var(--art-bottom-gap);\n}\n.art-bottom .art-progress .art-control-progress {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-progress-height);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n display: flex;\n align-items: center;\n position: relative;\n height: 50%;\n width: 100%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-hover-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-loaded-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n position: absolute;\n inset: 0;\n z-index: 20;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-theme);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n right: auto;\n pointer-events: auto;\n width: var(--art-highlight-width) !important;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n z-index: 40;\n left: 0;\n border-radius: 50%;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 50;\n top: -25px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-thumbnails {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n bottom: calc(var(--art-bottom-gap) + 10px);\n left: 0;\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 2px -1px rgba(0, 0, 0, 0.2);\n}\n.art-bottom .art-progress:hover .art-control-progress .art-control-progress-inner {\n height: 100%;\n}\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n.art-progress-hover .art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip,\n.art-progress-hover .art-bottom .art-progress .art-control-thumbnails {\n transform: scale(1);\n opacity: 1;\n}\n.art-video-player .art-controls {\n position: relative;\n z-index: 10;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-left,\n.art-video-player .art-controls .art-controls-right {\n display: flex;\n height: 100%;\n}\n.art-video-player .art-controls .art-controls-center {\n display: none;\n justify-content: center;\n align-items: center;\n flex: 1;\n height: 100%;\n padding: 0 10px;\n}\n.art-video-player .art-controls .art-controls-right {\n justify-content: flex-end;\n}\n.art-video-player .art-controls .art-control {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * 0.8));\n}\n.art-video-player .art-controls .art-control:hover {\n opacity: 1;\n}\n.art-control-volume {\n position: relative;\n}\n.art-control-volume .art-volume-panel {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n left: 0;\n right: 0;\n padding: 0 5px;\n font-size: 12px;\n text-align: center;\n cursor: default;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n height: 100%;\n width: 100%;\n padding: 10px 0 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n flex: 1;\n width: 100%;\n display: flex;\n cursor: pointer;\n position: relative;\n justify-content: center;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n position: relative;\n display: flex;\n justify-content: center;\n width: 2px;\n border-radius: var(--art-border-radius);\n overflow: hidden;\n background-color: rgba(255, 255, 255, 0.25);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n background-color: var(--art-theme);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n position: absolute;\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n flex-shrink: 0;\n transform: scale(1);\n border-radius: 100%;\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(0.9);\n}\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player .art-notice {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 80;\n width: 100%;\n height: 100%;\n height: auto;\n bottom: auto;\n padding: var(--art-padding);\n pointer-events: none;\n}\n.art-video-player .art-notice .art-notice-inner {\n display: inline-flex;\n padding: 5px;\n line-height: 1;\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n}\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n.art-video-player .art-contextmenus {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 120;\n padding: 5px 0;\n border-radius: var(--art-border-radius);\n font-size: 12px;\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n}\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n display: flex;\n padding: 10px 15px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n.art-video-player .art-contextmenus .art-contextmenu span:hover,\n.art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n.art-video-player .art-settings {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 90;\n left: auto;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n right: var(--art-padding);\n bottom: var(--art-control-height);\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-settings .art-setting-panel {\n display: none;\n flex-direction: column;\n}\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n cursor: pointer;\n overflow: hidden;\n transition: background-color var(--art-transition-duration) ease;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n gap: 5px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: rgba(255, 255, 255, 0.5);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n height: 3px;\n width: 80px;\n outline: none;\n appearance: none;\n background-color: rgba(255, 255, 255, 0.2);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n.art-video-player .art-info {\n display: none;\n position: absolute;\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n padding: 10px;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-info .art-info-panel {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n width: 100px;\n text-align: right;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n width: 250px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n}\n.art-video-player .art-info .art-info-close {\n position: absolute;\n top: 5px;\n right: 5px;\n cursor: pointer;\n}\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n.art-hide-cursor * {\n cursor: none !important;\n}\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n position: fixed;\n inset: 0;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n}\n.art-mini-popup {\n position: fixed;\n z-index: 9999;\n width: 320px;\n height: 180px;\n background: #000;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n overflow: hidden;\n transition: opacity 0.2s ease;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);\n}\n.art-mini-popup svg {\n fill: #fff;\n}\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n.art-mini-popup .art-mini-close {\n position: absolute;\n z-index: 20;\n right: 10px;\n top: 10px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n.art-mini-popup .art-mini-state {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s ease;\n background-color: rgba(0, 0, 0, 0.25);\n}\n.art-mini-popup .art-mini-state .art-icon {\n opacity: 0.75;\n cursor: pointer;\n transform: scale(3);\n pointer-events: auto;\n transition: transform 0.2s ease;\n}\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n.art-mini-popup.art-mini-dragging {\n opacity: 0.9;\n}\n.art-mini-popup:hover .art-mini-close,\n.art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n.art-video-player[data-flip='horizontal'] .art-video {\n transform: scaleX(-1);\n}\n.art-video-player[data-flip='vertical'] .art-video {\n transform: scaleY(-1);\n}\n.art-video-player .art-layer-lock {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n top: 50%;\n border-radius: 50%;\n transform: translateY(-50%);\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n}\n.art-video-player .art-layer-auto-playback {\n display: none;\n gap: 10px;\n align-items: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n padding: 10px;\n line-height: 1;\n left: var(--art-padding);\n bottom: calc(var(--art-control-height) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n.art-video-player.art-mini-progress-bar .art-bottom,\n.art-video-player.art-lock .art-bottom {\n opacity: 1;\n padding: 0;\n background-image: none;\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls,\n.art-video-player.art-lock .art-bottom .art-controls,\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress,\n.art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-control-height) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator,\n.art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n.art-control-selector {\n position: relative;\n display: flex;\n justify-content: center;\n}\n.art-control-selector .art-selector-list {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n overflow-y: auto;\n overflow-x: hidden;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-selector .art-selector-list .art-selector-item {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n flex-shrink: 0;\n line-height: 1;\n}\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-control-selector .art-selector-list .art-selector-item:hover,\n.art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player {\n /*! Hint.css - v2.7.0 - 2021-10-01\n * https://kushagra.dev/lab/hint/\n * Copyright (c) 2021 Kushagra Gour */\n /*-------------------------------------*\\\n HINT.css - A CSS tooltip library\n \\*-------------------------------------*/\n /**\n * HINT.css is a tooltip library made in pure CSS.\n *\n * Source: https://github.com/chinchang/hint.css\n * Demo: http://kushagragour.in/lab/hint/\n *\n */\n /**\n * source: hint-core.scss\n *\n * Defines the basic styling for the tooltip.\n * Each tooltip is made of 2 parts:\n * 1) body (:after)\n * 2) arrow (:before)\n *\n * Classes added:\n * 1) hint\n */\n /**\n * source: hint-position.scss\n *\n * Defines the positoning logic for the tooltips.\n *\n * Classes added:\n * 1) hint--top\n * 2) hint--bottom\n * 3) hint--left\n * 4) hint--right\n */\n /**\n * set default color for tooltip arrows\n */\n /**\n * top tooltip\n */\n /**\n * bottom tooltip\n */\n /**\n * right tooltip\n */\n /**\n * left tooltip\n */\n /**\n * top-left tooltip\n */\n /**\n * top-right tooltip\n */\n /**\n * bottom-left tooltip\n */\n /**\n * bottom-right tooltip\n */\n /**\n * source: hint-sizes.scss\n *\n * Defines width restricted tooltips that can span\n * across multiple lines.\n *\n * Classes added:\n * 1) hint--small\n * 2) hint--medium\n * 3) hint--large\n *\n */\n /**\n * source: hint-theme.scss\n *\n * Defines basic theme for tooltips.\n *\n */\n /**\n * source: hint-color-types.scss\n *\n * Contains tooltips of various types based on color differences.\n *\n * Classes added:\n * 1) hint--error\n * 2) hint--warning\n * 3) hint--info\n * 4) hint--success\n *\n */\n /**\n * Error\n */\n /**\n * Warning\n */\n /**\n * Info\n */\n /**\n * Success\n */\n /**\n * source: hint-always.scss\n *\n * Defines a persisted tooltip which shows always.\n *\n * Classes added:\n * 1) hint--always\n *\n */\n /**\n * source: hint-rounded.scss\n *\n * Defines rounded corner tooltips.\n *\n * Classes added:\n * 1) hint--rounded\n *\n */\n /**\n * source: hint-effects.scss\n *\n * Defines various transition effects for the tooltips.\n *\n * Classes added:\n * 1) hint--no-animate\n * 2) hint--bounce\n *\n */\n}\n.art-video-player [class*='hint--'] {\n position: relative;\n display: inline-block;\n font-style: normal;\n /**\n * tooltip arrow\n */\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:before,\n.art-video-player [class*='hint--']:after {\n position: absolute;\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n -webkit-transition: 0.3s ease;\n -moz-transition: 0.3s ease;\n transition: 0.3s ease;\n -webkit-transition-delay: 0ms;\n -moz-transition-delay: 0ms;\n transition-delay: 0ms;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n visibility: visible;\n opacity: 1;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n -webkit-transition-delay: 100ms;\n -moz-transition-delay: 100ms;\n transition-delay: 100ms;\n}\n.art-video-player [class*='hint--']:before {\n content: '';\n position: absolute;\n background: transparent;\n border: 6px solid transparent;\n z-index: 1000001;\n}\n.art-video-player [class*='hint--']:after {\n background: #000000;\n color: white;\n padding: 8px 10px;\n font-size: 12px;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n line-height: 12px;\n white-space: nowrap;\n}\n.art-video-player [class*='hint--'][aria-label]:after {\n content: attr(aria-label);\n}\n.art-video-player [class*='hint--'][data-hint]:after {\n content: attr(data-hint);\n}\n.art-video-player [aria-label='']:before,\n.art-video-player [aria-label='']:after,\n.art-video-player [data-hint='']:before,\n.art-video-player [data-hint='']:after {\n display: none !important;\n}\n.art-video-player .hint--top-left:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top-right:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--bottom-left:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom-right:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--left:before {\n border-left-color: #000000;\n}\n.art-video-player .hint--right:before {\n border-right-color: #000000;\n}\n.art-video-player .hint--top:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top:before,\n.art-video-player .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--top:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top:hover:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--bottom:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom:before,\n.art-video-player .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--bottom:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom:hover:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--right:before {\n margin-left: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--right:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--right:before,\n.art-video-player .hint--right:after {\n left: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--right:hover:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--right:hover:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--left:before {\n margin-right: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--left:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--left:before,\n.art-video-player .hint--left:after {\n right: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--left:hover:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--left:hover:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--top-left:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-left:before,\n.art-video-player .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--top-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--top-left:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--top-right:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-right:before,\n.art-video-player .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--top-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--top-right:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-right:hover:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--bottom-left:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-left:before,\n.art-video-player .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--bottom-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--bottom-left:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--bottom-right:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-right:before,\n.art-video-player .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--bottom-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--bottom-right:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-right:hover:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--small:after,\n.art-video-player .hint--medium:after,\n.art-video-player .hint--large:after {\n white-space: normal;\n line-height: 1.4em;\n word-wrap: break-word;\n}\n.art-video-player .hint--small:after {\n width: 80px;\n}\n.art-video-player .hint--medium:after {\n width: 150px;\n}\n.art-video-player .hint--large:after {\n width: 300px;\n}\n.art-video-player [class*='hint--'] {\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:after {\n text-shadow: 0 -1px 0px black;\n box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3);\n}\n.art-video-player .hint--error:after {\n background-color: #b34e4d;\n text-shadow: 0 -1px 0px #592726;\n}\n.art-video-player .hint--error.hint--top-left:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top-right:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-left:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-right:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n.art-video-player .hint--warning:after {\n background-color: #c09854;\n text-shadow: 0 -1px 0px #6c5328;\n}\n.art-video-player .hint--warning.hint--top-left:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top-right:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-left:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-right:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n.art-video-player .hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n.art-video-player .hint--info:after {\n background-color: #3986ac;\n text-shadow: 0 -1px 0px #1a3c4d;\n}\n.art-video-player .hint--info.hint--top-left:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top-right:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-left:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-right:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n.art-video-player .hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n.art-video-player .hint--success:after {\n background-color: #458746;\n text-shadow: 0 -1px 0px #1a321a;\n}\n.art-video-player .hint--success.hint--top-left:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top-right:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-left:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-right:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--left:before {\n border-left-color: #458746;\n}\n.art-video-player .hint--success.hint--right:before {\n border-right-color: #458746;\n}\n.art-video-player .hint--always:after,\n.art-video-player .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n.art-video-player .hint--always.hint--top:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--bottom:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--left:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--left:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--right:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--always.hint--right:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--rounded:after {\n border-radius: 4px;\n}\n.art-video-player .hint--no-animate:before,\n.art-video-player .hint--no-animate:after {\n -webkit-transition-duration: 0ms;\n -moz-transition-duration: 0ms;\n transition-duration: 0ms;\n}\n.art-video-player .hint--bounce:before,\n.art-video-player .hint--bounce:after {\n -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n}\n.art-video-player .hint--no-shadow:before,\n.art-video-player .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n.art-video-player .hint--no-arrow:before {\n display: none;\n}\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n"; +const css = ".art-video-player {\n --art-theme: #f00;\n --art-font-color: #fff;\n --art-background-color: #000;\n --art-text-shadow-color: rgba(0, 0, 0, 0.5);\n --art-transition-duration: 0.2s;\n --art-padding: 10px;\n --art-border-radius: 3px;\n --art-progress-height: 6px;\n --art-progress-color: rgba(255, 255, 255, 0.25);\n --art-progress-top-gap: 10px;\n --art-hover-color: rgba(255, 255, 255, 0.25);\n --art-loaded-color: rgba(255, 255, 255, 0.25);\n --art-state-size: 80px;\n --art-state-opacity: 0.8;\n --art-bottom-height: 100px;\n --art-bottom-offset: 20px;\n --art-bottom-gap: 5px;\n --art-highlight-width: 8px;\n --art-highlight-color: rgba(255, 255, 255, 0.5);\n --art-control-height: 46px;\n --art-control-opacity: 0.75;\n --art-control-icon-size: 36px;\n --art-control-icon-scale: 1.1;\n --art-volume-height: 120px;\n --art-volume-handle-size: 14px;\n --art-lock-size: 36px;\n --art-indicator-scale: 0;\n --art-indicator-size: 16px;\n --art-fullscreen-web-index: 9999;\n --art-settings-icon-size: 24px;\n --art-settings-max-height: 300px;\n --art-selector-max-height: 300px;\n --art-contextmenus-min-width: 250px;\n --art-subtitle-font-size: 20px;\n --art-subtitle-gap: 5px;\n --art-subtitle-bottom: 15px;\n --art-subtitle-border: #000;\n --art-widget-background: rgba(0, 0, 0, 0.85);\n --art-tip-background: rgba(0, 0, 0, 0.7);\n --art-scrollbar-size: 4px;\n --art-scrollbar-background: rgba(255, 255, 255, 0.25);\n --art-scrollbar-background-hover: rgba(255, 255, 255, 0.5);\n --art-mini-progress-height: 2px;\n}\n.art-bg-cover {\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.art-bottom-gradient {\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-backdrop-filter {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.art-video-player {\n position: relative;\n margin: 0 auto;\n width: 100%;\n height: 100%;\n outline: 0;\n zoom: 1;\n padding: 0;\n text-align: left;\n direction: ltr;\n font-size: 14px;\n line-height: 1.3;\n user-select: none;\n box-sizing: border-box;\n color: var(--art-font-color);\n background-color: var(--art-background-color);\n text-shadow: 0 0 2px var(--art-text-shadow-color);\n font-family: PingFang SC, Helvetica Neue, Microsoft YaHei, Roboto, Arial, sans-serif;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n -ms-high-contrast-adjust: none;\n}\n.art-video-player *,\n.art-video-player *::before,\n.art-video-player *::after {\n box-sizing: border-box;\n}\n.art-video-player ::-webkit-scrollbar {\n width: var(--art-scrollbar-size);\n height: var(--art-scrollbar-size);\n}\n.art-video-player ::-webkit-scrollbar-thumb {\n background-color: var(--art-scrollbar-background);\n}\n.art-video-player ::-webkit-scrollbar-thumb:hover {\n background-color: var(--art-scrollbar-background-hover);\n}\n.art-video-player img {\n max-width: 100%;\n vertical-align: top;\n}\n.art-video-player svg {\n fill: var(--art-font-color);\n}\n.art-video-player a {\n color: var(--art-font-color);\n text-decoration: none;\n}\n.art-icon {\n line-height: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.art-video-player.art-backdrop .art-contextmenus,\n.art-video-player.art-backdrop .art-info,\n.art-video-player.art-backdrop .art-settings,\n.art-video-player.art-backdrop .art-layer-auto-playback,\n.art-video-player.art-backdrop .art-selector-list,\n.art-video-player.art-backdrop .art-volume-inner {\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n background-color: rgba(0, 0, 0, 0.75) !important;\n}\n.art-video {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n}\n.art-poster {\n position: absolute;\n inset: 0;\n z-index: 11;\n width: 100%;\n height: 100%;\n background-position: center center;\n background-repeat: no-repeat;\n background-size: cover;\n pointer-events: none;\n}\n.art-video-player .art-subtitle {\n display: none;\n justify-content: center;\n align-items: center;\n flex-direction: column;\n position: absolute;\n z-index: 20;\n width: 100%;\n padding: 0 5%;\n text-align: center;\n pointer-events: none;\n gap: var(--art-subtitle-gap);\n bottom: var(--art-subtitle-bottom);\n font-size: var(--art-subtitle-font-size);\n transition: bottom var(--art-transition-duration) ease;\n text-shadow: var(--art-subtitle-border) 1px 0 1px, var(--art-subtitle-border) 0 1px 1px, var(--art-subtitle-border) -1px 0 1px, var(--art-subtitle-border) 0 -1px 1px, var(--art-subtitle-border) 1px 1px 1px, var(--art-subtitle-border) -1px -1px 1px, var(--art-subtitle-border) 1px -1px 1px, var(--art-subtitle-border) -1px 1px 1px;\n}\n.art-video-player.art-subtitle-show .art-subtitle {\n display: flex;\n}\n.art-video-player.art-control-show .art-subtitle {\n bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-subtitle-bottom));\n}\n.art-danmuku {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: hidden;\n}\n.art-video-player .art-layers {\n position: absolute;\n inset: 0;\n z-index: 40;\n width: 100%;\n height: 100%;\n display: none;\n pointer-events: none;\n}\n.art-video-player .art-layers .art-layer {\n pointer-events: auto;\n}\n.art-video-player.art-layer-show .art-layers {\n display: flex;\n}\n.art-video-player .art-mask {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 50;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player .art-mask .art-state {\n display: flex;\n justify-content: center;\n align-items: center;\n opacity: 0;\n transform: scale(2);\n width: var(--art-state-size);\n height: var(--art-state-size);\n transition: all var(--art-transition-duration) ease;\n}\n.art-video-player.art-mask-show .art-state {\n pointer-events: auto;\n opacity: var(--art-state-opacity);\n transform: scale(1);\n}\n.art-video-player.art-loading-show .art-state {\n display: none;\n}\n.art-video-player .art-loading {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n inset: 0;\n z-index: 70;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-video-player.art-loading-show .art-loading {\n display: flex;\n}\n.art-video-player.art-loading-show .art-mask {\n display: none;\n}\n.art-video-player .art-bottom {\n position: absolute;\n inset: 0;\n z-index: 60;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n padding: 0 var(--art-padding);\n transition: all var(--art-transition-duration) ease;\n background-size: 100% var(--art-bottom-height);\n background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0.4), transparent);\n background-repeat: repeat-x;\n background-position: center bottom;\n}\n.art-video-player .art-bottom .art-controls,\n.art-video-player .art-bottom .art-progress {\n transform: translateY(var(--art-bottom-offset));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player.art-control-show .art-bottom,\n.art-video-player.art-hover .art-bottom {\n opacity: 1;\n}\n.art-video-player.art-control-show .art-bottom .art-controls,\n.art-video-player.art-hover .art-bottom .art-controls,\n.art-video-player.art-control-show .art-bottom .art-progress,\n.art-video-player.art-hover .art-bottom .art-progress {\n transform: translateY(0);\n}\n.art-bottom .art-progress {\n position: relative;\n z-index: 0;\n cursor: pointer;\n pointer-events: auto;\n padding-top: var(--art-progress-top-gap);\n padding-bottom: var(--art-bottom-gap);\n}\n.art-bottom .art-progress .art-control-progress {\n position: relative;\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-progress-height);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner {\n display: flex;\n align-items: center;\n position: relative;\n height: 50%;\n width: 100%;\n transition: height var(--art-transition-duration) ease;\n background-color: var(--art-progress-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-hover {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-hover-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-loaded {\n position: absolute;\n inset: 0;\n z-index: 10;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-loaded-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-played {\n position: absolute;\n inset: 0;\n z-index: 20;\n width: 100%;\n height: 100%;\n width: 0%;\n background-color: var(--art-theme);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-highlight span {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n right: auto;\n pointer-events: auto;\n width: var(--art-highlight-width) !important;\n transform: translateX(calc(var(--art-highlight-width) / -2));\n background-color: var(--art-highlight-color);\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n z-index: 40;\n left: 0;\n border-radius: 50%;\n width: var(--art-indicator-size);\n height: var(--art-indicator-size);\n transform: scale(var(--art-indicator-scale));\n margin-left: calc(var(--art-indicator-size) / -2);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator .art-icon {\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:hover {\n transform: scale(1.2) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator:active {\n transform: scale(1) !important;\n}\n.art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n z-index: 50;\n top: -25px;\n left: 0;\n padding: 3px 5px;\n line-height: 1;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n white-space: nowrap;\n background-color: var(--art-tip-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n}\n.art-bottom .art-progress .art-control-thumbnails {\n transform-origin: bottom center;\n transform: scale(0.5);\n opacity: 0;\n position: absolute;\n bottom: calc(var(--art-bottom-gap) + 10px);\n left: 0;\n border-radius: var(--art-border-radius);\n pointer-events: none;\n background-color: var(--art-widget-background);\n transition: transform var(--art-transition-duration) ease, opacity var(--art-transition-duration) ease;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 2px -1px rgba(0, 0, 0, 0.2);\n}\n.art-bottom .art-progress:hover .art-control-progress .art-control-progress-inner {\n height: 100%;\n}\n.art-bottom:hover .art-progress .art-control-progress .art-control-progress-inner .art-progress-indicator {\n transform: scale(1);\n}\n.art-progress-hover .art-bottom .art-progress .art-control-progress .art-control-progress-inner .art-progress-tip,\n.art-progress-hover .art-bottom .art-progress .art-control-thumbnails {\n transform: scale(1);\n opacity: 1;\n}\n.art-video-player .art-controls {\n position: relative;\n z-index: 10;\n pointer-events: auto;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n flex-shrink: 0;\n height: auto;\n min-height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-left,\n.art-video-player .art-controls .art-controls-right {\n display: flex;\n flex-wrap: wrap;\n max-width: 100%;\n min-height: var(--art-control-height);\n}\n.art-video-player .art-controls .art-controls-center {\n display: none;\n justify-content: center;\n align-items: center;\n flex: 1;\n height: 100%;\n padding: 0 10px;\n}\n.art-video-player .art-controls .art-controls-right {\n justify-content: flex-end;\n margin-left: auto;\n}\n.art-video-player .art-controls .art-control {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n max-width: 100%;\n cursor: pointer;\n white-space: nowrap;\n opacity: var(--art-control-opacity);\n min-height: var(--art-control-height);\n min-width: var(--art-control-height);\n transition: opacity var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon {\n height: var(--art-control-icon-size);\n width: var(--art-control-icon-size);\n transform: scale(var(--art-control-icon-scale));\n transition: transform var(--art-transition-duration) ease;\n}\n.art-video-player .art-controls .art-control .art-icon:active {\n transform: scale(calc(var(--art-control-icon-scale) * 0.8));\n}\n.art-video-player .art-controls .art-control:hover {\n opacity: 1;\n}\n.art-control-volume {\n position: relative;\n}\n.art-control-volume .art-volume-panel {\n display: flex;\n justify-content: center;\n align-items: center;\n position: absolute;\n left: 0;\n right: 0;\n padding: 0 5px;\n font-size: 12px;\n text-align: center;\n cursor: default;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n width: var(--art-control-height);\n height: var(--art-volume-height);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n height: 100%;\n width: 100%;\n padding: 10px 0 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider {\n flex: 1;\n width: 100%;\n display: flex;\n cursor: pointer;\n position: relative;\n justify-content: center;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle {\n position: relative;\n display: flex;\n justify-content: center;\n width: 2px;\n border-radius: var(--art-border-radius);\n overflow: hidden;\n background-color: rgba(255, 255, 255, 0.25);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-handle .art-volume-loaded {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n background-color: var(--art-theme);\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider .art-volume-indicator {\n position: absolute;\n width: var(--art-volume-handle-size);\n height: var(--art-volume-handle-size);\n margin-top: calc(var(--art-volume-handle-size) / -2);\n flex-shrink: 0;\n transform: scale(1);\n border-radius: 100%;\n background-color: var(--art-theme);\n transition: transform var(--art-transition-duration) ease;\n}\n.art-control-volume .art-volume-panel .art-volume-inner .art-volume-slider:active .art-volume-indicator {\n transform: scale(0.9);\n}\n.art-control-volume:hover .art-volume-panel {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player .art-notice {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 80;\n width: 100%;\n height: 100%;\n height: auto;\n bottom: auto;\n padding: var(--art-padding);\n pointer-events: none;\n}\n.art-video-player .art-notice .art-notice-inner {\n display: inline-flex;\n padding: 5px;\n line-height: 1;\n border-radius: var(--art-border-radius);\n background-color: var(--art-tip-background);\n}\n.art-video-player.art-notice-show .art-notice {\n display: flex;\n}\n.art-video-player .art-contextmenus {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 120;\n padding: 5px 0;\n border-radius: var(--art-border-radius);\n font-size: 12px;\n background-color: var(--art-widget-background);\n min-width: var(--art-contextmenus-min-width);\n}\n.art-video-player .art-contextmenus .art-contextmenu {\n cursor: pointer;\n display: flex;\n padding: 10px 15px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu span {\n padding: 0 8px;\n}\n.art-video-player .art-contextmenus .art-contextmenu span:hover,\n.art-video-player .art-contextmenus .art-contextmenu span.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-contextmenus .art-contextmenu:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-contextmenus .art-contextmenu:last-child {\n border-bottom: none;\n}\n.art-video-player.art-contextmenu-show .art-contextmenus {\n display: flex;\n}\n.art-video-player .art-settings {\n display: none;\n flex-direction: column;\n position: absolute;\n z-index: 90;\n left: auto;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: var(--art-border-radius);\n max-height: var(--art-settings-max-height);\n right: var(--art-padding);\n bottom: var(--art-controls-height, var(--art-control-height));\n transition: all var(--art-transition-duration) ease;\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-settings .art-setting-panel {\n display: none;\n flex-direction: column;\n}\n.art-video-player .art-settings .art-setting-panel.art-current {\n display: flex;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0 5px;\n cursor: pointer;\n overflow: hidden;\n transition: background-color var(--art-transition-duration) ease;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current {\n color: var(--art-theme);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-icon-check {\n visibility: hidden;\n height: 15px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item.art-current .art-icon-check {\n visibility: visible;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left {\n display: flex;\n justify-content: center;\n align-items: center;\n flex-shrink: 0;\n gap: 5px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-left .art-setting-item-left-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n height: var(--art-settings-icon-size);\n width: var(--art-settings-icon-size);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-tooltip {\n white-space: nowrap;\n color: rgba(255, 255, 255, 0.5);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-item-right-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n min-width: 32px;\n height: 24px;\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item .art-setting-item-right .art-setting-range {\n height: 3px;\n width: 80px;\n outline: none;\n appearance: none;\n background-color: rgba(255, 255, 255, 0.2);\n}\n.art-video-player .art-settings .art-setting-panel .art-setting-item-back {\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.art-video-player.art-setting-show .art-settings {\n display: flex;\n}\n.art-video-player .art-info {\n display: none;\n position: absolute;\n left: var(--art-padding);\n top: var(--art-padding);\n z-index: 100;\n padding: 10px;\n font-size: 12px;\n border-radius: var(--art-border-radius);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-info .art-info-panel {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item {\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-title {\n width: 100px;\n text-align: right;\n}\n.art-video-player .art-info .art-info-panel .art-info-item .art-info-content {\n width: 250px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n user-select: all;\n}\n.art-video-player .art-info .art-info-close {\n position: absolute;\n top: 5px;\n right: 5px;\n cursor: pointer;\n}\n.art-video-player.art-info-show .art-info {\n display: flex;\n}\n.art-hide-cursor * {\n cursor: none !important;\n}\n.art-video-player[data-aspect-ratio] {\n overflow: hidden;\n}\n.art-video-player[data-aspect-ratio] .art-video {\n object-fit: fill;\n box-sizing: content-box;\n}\n.art-fullscreen {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n}\n.art-fullscreen-web {\n --art-progress-height: 8px;\n --art-indicator-size: 20px;\n --art-control-height: 60px;\n --art-control-icon-scale: 1.3;\n position: fixed;\n inset: 0;\n z-index: var(--art-fullscreen-web-index);\n width: 100%;\n height: 100%;\n}\n.art-mini-popup {\n position: fixed;\n z-index: 9999;\n width: 320px;\n height: 180px;\n background: #000;\n border-radius: var(--art-border-radius);\n cursor: move;\n user-select: none;\n overflow: hidden;\n transition: opacity 0.2s ease;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);\n}\n.art-mini-popup svg {\n fill: #fff;\n}\n.art-mini-popup .art-video {\n pointer-events: none;\n}\n.art-mini-popup .art-mini-close {\n position: absolute;\n z-index: 20;\n right: 10px;\n top: 10px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n.art-mini-popup .art-mini-state {\n position: absolute;\n inset: 0;\n z-index: 30;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.2s ease;\n background-color: rgba(0, 0, 0, 0.25);\n}\n.art-mini-popup .art-mini-state .art-icon {\n opacity: 0.75;\n cursor: pointer;\n transform: scale(3);\n pointer-events: auto;\n transition: transform 0.2s ease;\n}\n.art-mini-popup .art-mini-state .art-icon:active {\n transform: scale(2.5);\n}\n.art-mini-popup.art-mini-dragging {\n opacity: 0.9;\n}\n.art-mini-popup:hover .art-mini-close,\n.art-mini-popup:hover .art-mini-state {\n opacity: 1;\n}\n.art-video-player[data-flip='horizontal'] .art-video {\n transform: scaleX(-1);\n}\n.art-video-player[data-flip='vertical'] .art-video {\n transform: scaleY(-1);\n}\n.art-video-player .art-layer-lock {\n display: none;\n justify-content: center;\n align-items: center;\n position: absolute;\n top: 50%;\n border-radius: 50%;\n transform: translateY(-50%);\n height: var(--art-lock-size);\n width: var(--art-lock-size);\n left: var(--art-padding);\n background-color: var(--art-tip-background);\n}\n.art-video-player .art-layer-auto-playback {\n display: none;\n gap: 10px;\n align-items: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n padding: 10px;\n line-height: 1;\n left: var(--art-padding);\n bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + 10px);\n background-color: var(--art-widget-background);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close {\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-close svg {\n width: 15px;\n height: 15px;\n fill: var(--art-theme);\n}\n.art-video-player .art-layer-auto-playback .art-auto-playback-jump {\n color: var(--art-theme);\n cursor: pointer;\n}\n.art-video-player.art-lock .art-subtitle {\n bottom: var(--art-subtitle-bottom) !important;\n}\n.art-video-player.art-mini-progress-bar .art-bottom,\n.art-video-player.art-lock .art-bottom {\n opacity: 1;\n padding: 0;\n background-image: none;\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-controls,\n.art-video-player.art-lock .art-bottom .art-controls,\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress,\n.art-video-player.art-lock .art-bottom .art-progress {\n transform: translateY(calc(var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + var(--art-progress-height) / 4));\n}\n.art-video-player.art-mini-progress-bar .art-bottom .art-progress-indicator,\n.art-video-player.art-lock .art-bottom .art-progress-indicator {\n display: none !important;\n}\n.art-video-player.art-control-show .art-layer-lock {\n display: flex;\n}\n.art-control-selector {\n position: relative;\n display: flex;\n justify-content: center;\n}\n.art-control-selector .art-selector-list {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n position: absolute;\n border-radius: var(--art-border-radius);\n overflow-y: auto;\n overflow-x: hidden;\n opacity: 0;\n transform: translateY(10px);\n pointer-events: none;\n bottom: var(--art-control-height);\n max-height: var(--art-selector-max-height);\n background-color: var(--art-widget-background);\n transition: all var(--art-transition-duration) ease;\n}\n.art-control-selector .art-selector-list .art-selector-item {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n padding: 10px 15px;\n flex-shrink: 0;\n line-height: 1;\n}\n.art-control-selector .art-selector-list .art-selector-item:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n.art-control-selector .art-selector-list .art-selector-item:hover,\n.art-control-selector .art-selector-list .art-selector-item.art-current {\n color: var(--art-theme);\n}\n.art-control-selector:hover .art-selector-list {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n.art-video-player {\n /*! Hint.css - v2.7.0 - 2021-10-01\n * https://kushagra.dev/lab/hint/\n * Copyright (c) 2021 Kushagra Gour */\n /*-------------------------------------*\\\n HINT.css - A CSS tooltip library\n \\*-------------------------------------*/\n /**\n * HINT.css is a tooltip library made in pure CSS.\n *\n * Source: https://github.com/chinchang/hint.css\n * Demo: http://kushagragour.in/lab/hint/\n *\n */\n /**\n * source: hint-core.scss\n *\n * Defines the basic styling for the tooltip.\n * Each tooltip is made of 2 parts:\n * 1) body (:after)\n * 2) arrow (:before)\n *\n * Classes added:\n * 1) hint\n */\n /**\n * source: hint-position.scss\n *\n * Defines the positoning logic for the tooltips.\n *\n * Classes added:\n * 1) hint--top\n * 2) hint--bottom\n * 3) hint--left\n * 4) hint--right\n */\n /**\n * set default color for tooltip arrows\n */\n /**\n * top tooltip\n */\n /**\n * bottom tooltip\n */\n /**\n * right tooltip\n */\n /**\n * left tooltip\n */\n /**\n * top-left tooltip\n */\n /**\n * top-right tooltip\n */\n /**\n * bottom-left tooltip\n */\n /**\n * bottom-right tooltip\n */\n /**\n * source: hint-sizes.scss\n *\n * Defines width restricted tooltips that can span\n * across multiple lines.\n *\n * Classes added:\n * 1) hint--small\n * 2) hint--medium\n * 3) hint--large\n *\n */\n /**\n * source: hint-theme.scss\n *\n * Defines basic theme for tooltips.\n *\n */\n /**\n * source: hint-color-types.scss\n *\n * Contains tooltips of various types based on color differences.\n *\n * Classes added:\n * 1) hint--error\n * 2) hint--warning\n * 3) hint--info\n * 4) hint--success\n *\n */\n /**\n * Error\n */\n /**\n * Warning\n */\n /**\n * Info\n */\n /**\n * Success\n */\n /**\n * source: hint-always.scss\n *\n * Defines a persisted tooltip which shows always.\n *\n * Classes added:\n * 1) hint--always\n *\n */\n /**\n * source: hint-rounded.scss\n *\n * Defines rounded corner tooltips.\n *\n * Classes added:\n * 1) hint--rounded\n *\n */\n /**\n * source: hint-effects.scss\n *\n * Defines various transition effects for the tooltips.\n *\n * Classes added:\n * 1) hint--no-animate\n * 2) hint--bounce\n *\n */\n}\n.art-video-player [class*='hint--'] {\n position: relative;\n display: inline-block;\n font-style: normal;\n /**\n * tooltip arrow\n */\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:before,\n.art-video-player [class*='hint--']:after {\n position: absolute;\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n visibility: hidden;\n opacity: 0;\n z-index: 1000000;\n pointer-events: none;\n -webkit-transition: 0.3s ease;\n -moz-transition: 0.3s ease;\n transition: 0.3s ease;\n -webkit-transition-delay: 0ms;\n -moz-transition-delay: 0ms;\n transition-delay: 0ms;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n visibility: visible;\n opacity: 1;\n}\n.art-video-player [class*='hint--']:hover:before,\n.art-video-player [class*='hint--']:hover:after {\n -webkit-transition-delay: 100ms;\n -moz-transition-delay: 100ms;\n transition-delay: 100ms;\n}\n.art-video-player [class*='hint--']:before {\n content: '';\n position: absolute;\n background: transparent;\n border: 6px solid transparent;\n z-index: 1000001;\n}\n.art-video-player [class*='hint--']:after {\n background: #000000;\n color: white;\n padding: 8px 10px;\n font-size: 12px;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n line-height: 12px;\n white-space: nowrap;\n}\n.art-video-player [class*='hint--'][aria-label]:after {\n content: attr(aria-label);\n}\n.art-video-player [class*='hint--'][data-hint]:after {\n content: attr(data-hint);\n}\n.art-video-player [aria-label='']:before,\n.art-video-player [aria-label='']:after,\n.art-video-player [data-hint='']:before,\n.art-video-player [data-hint='']:after {\n display: none !important;\n}\n.art-video-player .hint--top-left:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top-right:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--top:before {\n border-top-color: #000000;\n}\n.art-video-player .hint--bottom-left:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom-right:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--bottom:before {\n border-bottom-color: #000000;\n}\n.art-video-player .hint--left:before {\n border-left-color: #000000;\n}\n.art-video-player .hint--right:before {\n border-right-color: #000000;\n}\n.art-video-player .hint--top:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top:before,\n.art-video-player .hint--top:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--top:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top:hover:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--bottom:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom:before,\n.art-video-player .hint--bottom:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom:after {\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.art-video-player .hint--bottom:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom:hover:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--right:before {\n margin-left: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--right:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--right:before,\n.art-video-player .hint--right:after {\n left: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--right:hover:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--right:hover:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--left:before {\n margin-right: -11px;\n margin-bottom: -6px;\n}\n.art-video-player .hint--left:after {\n margin-bottom: -14px;\n}\n.art-video-player .hint--left:before,\n.art-video-player .hint--left:after {\n right: 100%;\n bottom: 50%;\n}\n.art-video-player .hint--left:hover:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--left:hover:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--top-left:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-left:before,\n.art-video-player .hint--top-left:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--top-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--top-left:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--top-right:before {\n margin-bottom: -11px;\n}\n.art-video-player .hint--top-right:before,\n.art-video-player .hint--top-right:after {\n bottom: 100%;\n left: 50%;\n}\n.art-video-player .hint--top-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--top-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--top-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--top-right:hover:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--top-right:hover:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--bottom-left:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-left:before,\n.art-video-player .hint--bottom-left:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-left:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-left:after {\n -webkit-transform: translateX(-100%);\n -moz-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.art-video-player .hint--bottom-left:after {\n margin-left: 12px;\n}\n.art-video-player .hint--bottom-left:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-left:hover:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--bottom-right:before {\n margin-top: -11px;\n}\n.art-video-player .hint--bottom-right:before,\n.art-video-player .hint--bottom-right:after {\n top: 100%;\n left: 50%;\n}\n.art-video-player .hint--bottom-right:before {\n left: calc(50% - 6px);\n}\n.art-video-player .hint--bottom-right:after {\n -webkit-transform: translateX(0);\n -moz-transform: translateX(0);\n transform: translateX(0);\n}\n.art-video-player .hint--bottom-right:after {\n margin-left: -12px;\n}\n.art-video-player .hint--bottom-right:hover:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--bottom-right:hover:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--small:after,\n.art-video-player .hint--medium:after,\n.art-video-player .hint--large:after {\n white-space: normal;\n line-height: 1.4em;\n word-wrap: break-word;\n}\n.art-video-player .hint--small:after {\n width: 80px;\n}\n.art-video-player .hint--medium:after {\n width: 150px;\n}\n.art-video-player .hint--large:after {\n width: 300px;\n}\n.art-video-player [class*='hint--'] {\n /**\n * tooltip body\n */\n}\n.art-video-player [class*='hint--']:after {\n text-shadow: 0 -1px 0px black;\n box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3);\n}\n.art-video-player .hint--error:after {\n background-color: #b34e4d;\n text-shadow: 0 -1px 0px #592726;\n}\n.art-video-player .hint--error.hint--top-left:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top-right:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--top:before {\n border-top-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-left:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom-right:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--bottom:before {\n border-bottom-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--left:before {\n border-left-color: #b34e4d;\n}\n.art-video-player .hint--error.hint--right:before {\n border-right-color: #b34e4d;\n}\n.art-video-player .hint--warning:after {\n background-color: #c09854;\n text-shadow: 0 -1px 0px #6c5328;\n}\n.art-video-player .hint--warning.hint--top-left:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top-right:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--top:before {\n border-top-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-left:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom-right:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--bottom:before {\n border-bottom-color: #c09854;\n}\n.art-video-player .hint--warning.hint--left:before {\n border-left-color: #c09854;\n}\n.art-video-player .hint--warning.hint--right:before {\n border-right-color: #c09854;\n}\n.art-video-player .hint--info:after {\n background-color: #3986ac;\n text-shadow: 0 -1px 0px #1a3c4d;\n}\n.art-video-player .hint--info.hint--top-left:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top-right:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--top:before {\n border-top-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-left:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom-right:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--bottom:before {\n border-bottom-color: #3986ac;\n}\n.art-video-player .hint--info.hint--left:before {\n border-left-color: #3986ac;\n}\n.art-video-player .hint--info.hint--right:before {\n border-right-color: #3986ac;\n}\n.art-video-player .hint--success:after {\n background-color: #458746;\n text-shadow: 0 -1px 0px #1a321a;\n}\n.art-video-player .hint--success.hint--top-left:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top-right:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--top:before {\n border-top-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-left:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom-right:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--bottom:before {\n border-bottom-color: #458746;\n}\n.art-video-player .hint--success.hint--left:before {\n border-left-color: #458746;\n}\n.art-video-player .hint--success.hint--right:before {\n border-right-color: #458746;\n}\n.art-video-player .hint--always:after,\n.art-video-player .hint--always:before {\n opacity: 1;\n visibility: visible;\n}\n.art-video-player .hint--always.hint--top:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top:after {\n -webkit-transform: translateX(-50%) translateY(-8px);\n -moz-transform: translateX(-50%) translateY(-8px);\n transform: translateX(-50%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-left:after {\n -webkit-transform: translateX(-100%) translateY(-8px);\n -moz-transform: translateX(-100%) translateY(-8px);\n transform: translateX(-100%) translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:before {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--top-right:after {\n -webkit-transform: translateY(-8px);\n -moz-transform: translateY(-8px);\n transform: translateY(-8px);\n}\n.art-video-player .hint--always.hint--bottom:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom:after {\n -webkit-transform: translateX(-50%) translateY(8px);\n -moz-transform: translateX(-50%) translateY(8px);\n transform: translateX(-50%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-left:after {\n -webkit-transform: translateX(-100%) translateY(8px);\n -moz-transform: translateX(-100%) translateY(8px);\n transform: translateX(-100%) translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:before {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--bottom-right:after {\n -webkit-transform: translateY(8px);\n -moz-transform: translateY(8px);\n transform: translateY(8px);\n}\n.art-video-player .hint--always.hint--left:before {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--left:after {\n -webkit-transform: translateX(-8px);\n -moz-transform: translateX(-8px);\n transform: translateX(-8px);\n}\n.art-video-player .hint--always.hint--right:before {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--always.hint--right:after {\n -webkit-transform: translateX(8px);\n -moz-transform: translateX(8px);\n transform: translateX(8px);\n}\n.art-video-player .hint--rounded:after {\n border-radius: 4px;\n}\n.art-video-player .hint--no-animate:before,\n.art-video-player .hint--no-animate:after {\n -webkit-transition-duration: 0ms;\n -moz-transition-duration: 0ms;\n transition-duration: 0ms;\n}\n.art-video-player .hint--bounce:before,\n.art-video-player .hint--bounce:after {\n -webkit-transition: opacity 0.3s ease, visibility 0.3s ease, -webkit-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n -moz-transition: opacity 0.3s ease, visibility 0.3s ease, -moz-transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s cubic-bezier(0.71, 1.7, 0.77, 1.24);\n}\n.art-video-player .hint--no-shadow:before,\n.art-video-player .hint--no-shadow:after {\n text-shadow: initial;\n box-shadow: initial;\n}\n.art-video-player .hint--no-arrow:before {\n display: none;\n}\n.art-video-player.art-mobile {\n --art-bottom-gap: 10px;\n --art-control-height: 38px;\n --art-control-icon-scale: 1;\n --art-state-size: 60px;\n --art-settings-max-height: 180px;\n --art-selector-max-height: 180px;\n --art-indicator-scale: 1;\n --art-control-opacity: 1;\n}\n.art-video-player.art-mobile .art-controls-left {\n margin-left: calc(var(--art-padding) / -1);\n}\n.art-video-player.art-mobile .art-controls-right {\n margin-right: calc(var(--art-padding) / -1);\n}\n"; class Subtitle extends Component { constructor(art) { super(art); diff --git a/packages/artplayer/src/component/dom.ts b/packages/artplayer/src/component/dom.ts new file mode 100644 index 000000000..7ec18fd77 --- /dev/null +++ b/packages/artplayer/src/component/dom.ts @@ -0,0 +1,29 @@ +import type { ComponentHost, EntryOption } from './types' +import { addClass, append, setStyles, tooltip } from '../utils/dom' + +export function renderEntry(element: HTMLDivElement, parent: HTMLElement, kind: string, name: string, id: number, option: EntryOption): void { + addClass(element, `art-${kind}`) + addClass(element, `art-${kind}-${name}`) + const children = Array.from(parent.children) as HTMLElement[] + element.dataset.index = String(option.index || id) + const next = children.find(child => Number(child.dataset.index) >= Number(element.dataset.index)) + if (next) + next.insertAdjacentElement('beforebegin', element) + else + append(parent, element) + if (option.html) + append(element, option.html) + if (option.style) + setStyles(element, option.style) + if (option.tooltip) + tooltip(element, option.tooltip) +} + +// Builtin renderers append known element markup or existing icon wrappers. +export function appendElement(parent: Element, child: string | Element): HTMLElement { + return append(parent, child) as HTMLElement +} + +export function queryElement(selector: string, parent: ParentNode): HTMLElement { + return parent.querySelector(selector)! +} diff --git a/packages/artplayer/src/component/resources.ts b/packages/artplayer/src/component/resources.ts new file mode 100644 index 000000000..68c77a09b --- /dev/null +++ b/packages/artplayer/src/component/resources.ts @@ -0,0 +1,54 @@ +import type ResourceScope from '../lifecycle/scope' +import type { ComponentHost } from './types' +import { getScope } from '../lifecycle/instance' + +const scopes = new WeakMap() + +export function ownEntry(art: ComponentHost, element: HTMLElement): ResourceScope { + const scope = getScope(art).child() + scopes.set(element, scope) + return scope +} + +export function entryScope(element: HTMLElement): ResourceScope { + const scope = scopes.get(element) + if (!scope) + throw new Error('ArtPlayer component has not been registered') + return scope +} + +export function releaseEntry(element: HTMLElement): void { + scopes.get(element)?.dispose() +} + +export function proxyEntry(art: ComponentHost, element: HTMLElement, target: EventTarget, name: Name, callback: (event: HTMLElementEventMap[Name]) => unknown): () => void { + const scope = entryScope(element) + if (scope.closed) + return () => {} + const cleanup = art.events.proxy(target, name, (event) => { + if (!scope.closed) + return callback(event as HTMLElementEventMap[Name]) + }) + return scope.add(() => { + art.events.remove(cleanup) + }) +} + +export interface SubscriptionHost { + on: (name: Name, callback: (...args: [...Events[Name]]) => unknown) => unknown + off: (name: Name, callback: (...args: [...Events[Name]]) => unknown) => unknown +} + +export function subscribeEntry(art: SubscriptionHost, element: HTMLElement, name: Name, callback: (...args: [...Events[Name]]) => unknown): void { + const scope = entryScope(element) + if (scope.closed) + return + const guarded = (...args: [...Events[Name]]) => { + if (!scope.closed) + return callback(...args) + } + art.on(name, guarded) + scope.add(() => { + art.off(name, guarded) + }) +} diff --git a/packages/artplayer/src/component/selection.ts b/packages/artplayer/src/component/selection.ts new file mode 100644 index 000000000..270228c7d --- /dev/null +++ b/packages/artplayer/src/component/selection.ts @@ -0,0 +1,15 @@ +import type { Cleanup } from '../lifecycle/scope' + +const selections = new WeakMap boolean>() + +export function trackSelection(event: Event, active: () => boolean): Cleanup { + selections.set(event, active) + return () => { + if (selections.get(event) === active) + selections.delete(event) + } +} + +export function captureSelection(event?: Event): () => boolean { + return (event && selections.get(event)) || (() => true) +} diff --git a/packages/artplayer/src/component/types.ts b/packages/artplayer/src/component/types.ts new file mode 100644 index 000000000..de88746cc --- /dev/null +++ b/packages/artplayer/src/component/types.ts @@ -0,0 +1,44 @@ +import type Component from '../utils/component' + +export type EventCleanup = () => void + +export interface ComponentHost { + template: { $player: HTMLElement } + emit: (name: string, ...args: unknown[]) => unknown + events: { + proxy: (target: EventTarget, name: string, callback: (event: Event) => unknown) => EventCleanup + remove: (cleanup: EventCleanup) => void + } +} + +export interface SelectorItem { + html: string | HTMLElement | number + value?: string | number + default?: boolean + readonly $control_option?: SelectorItem[] + readonly $control_item?: HTMLDivElement + readonly $control_value?: HTMLDivElement +} + +export interface EntryOption { + html?: string | HTMLElement | number + disable?: boolean + name?: string + index?: number + style?: Partial + tooltip?: string | number + position?: string + selector?: SelectorItem[] + click?: (this: Host, component: Component, event: Event) => unknown + mounted?: (this: Host, element: HTMLDivElement) => unknown + beforeUnmount?: (this: Host, element: HTMLDivElement) => unknown + onSelect?: (this: Host, item: SelectorItem, element: HTMLDivElement, event: Event) => unknown +} + +export type EntryInput = EntryOption | ((art: Host) => EntryOption) + +export interface Entry { + $ref: HTMLDivElement + events: EventCleanup[] + option: EntryOption +} diff --git a/packages/artplayer/src/contextmenu/aspectRatio.js b/packages/artplayer/src/contextmenu/aspectRatio.ts similarity index 58% rename from packages/artplayer/src/contextmenu/aspectRatio.js rename to packages/artplayer/src/contextmenu/aspectRatio.ts index eb05190b6..a7ad1d2dc 100644 --- a/packages/artplayer/src/contextmenu/aspectRatio.js +++ b/packages/artplayer/src/contextmenu/aspectRatio.ts @@ -1,6 +1,8 @@ -import { inverseClass, query, queryAll } from '../utils' +import type { ContextmenuFactory, ContextmenuOption } from './types' +import { controlEvents } from '../control/resources' +import { inverseClass, query } from '../utils' -export default function aspectRatio(option) { +export default function aspectRatio(option: ContextmenuOption): ContextmenuFactory { return (art) => { const { i18n, @@ -15,19 +17,20 @@ export default function aspectRatio(option) { ...option, html: `${i18n.get('Aspect Ratio')}: ${html}`, click: (contextmenu, event) => { - const { value } = event.target.dataset + const value = event.target instanceof HTMLElement ? event.target.dataset.value : undefined if (value) { art.aspectRatio = value contextmenu.show = false } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel) const $default = query('[data-value="default"]', $panel) if ($default) { inverseClass($default, 'art-current') } - art.on('aspectRatio', (value) => { - const $current = queryAll('span', $panel).find(item => item.dataset.value === value) + on('aspectRatio', (value) => { + const $current = Array.from($panel.querySelectorAll('span')).find(item => item.dataset.value === value) if ($current) { inverseClass($current, 'art-current') } diff --git a/packages/artplayer/src/contextmenu/close.js b/packages/artplayer/src/contextmenu/close.js deleted file mode 100644 index ce8af7079..000000000 --- a/packages/artplayer/src/contextmenu/close.js +++ /dev/null @@ -1,9 +0,0 @@ -export default function close(option) { - return art => ({ - ...option, - html: art.i18n.get('Close'), - click: (contextmenu) => { - contextmenu.show = false - }, - }) -} diff --git a/packages/artplayer/src/contextmenu/close.ts b/packages/artplayer/src/contextmenu/close.ts new file mode 100644 index 000000000..599955d7b --- /dev/null +++ b/packages/artplayer/src/contextmenu/close.ts @@ -0,0 +1,11 @@ +import type { ContextmenuFactory, ContextmenuOption } from './types' + +export default function close(option: ContextmenuOption): ContextmenuFactory { + return art => ({ + ...option, + html: art.i18n.get('Close'), + click: (contextmenu) => { + contextmenu.show = false + }, + }) +} diff --git a/packages/artplayer/src/contextmenu/flip.js b/packages/artplayer/src/contextmenu/flip.ts similarity index 56% rename from packages/artplayer/src/contextmenu/flip.js rename to packages/artplayer/src/contextmenu/flip.ts index ece8ed1e1..3b1d065aa 100644 --- a/packages/artplayer/src/contextmenu/flip.js +++ b/packages/artplayer/src/contextmenu/flip.ts @@ -1,6 +1,8 @@ -import { capitalize, inverseClass, query, queryAll } from '../utils' +import type { ContextmenuFactory, ContextmenuOption } from './types' +import { controlEvents } from '../control/resources' +import { capitalize, inverseClass, query } from '../utils' -export default function flip(option) { +export default function flip(option: ContextmenuOption): ContextmenuFactory { return (art) => { const { i18n, @@ -13,19 +15,20 @@ export default function flip(option) { ...option, html: `${i18n.get('Video Flip')}: ${html}`, click: (contextmenu, event) => { - const { value } = event.target.dataset + const value = event.target instanceof HTMLElement ? event.target.dataset.value : undefined if (value) { art.flip = value.toLowerCase() contextmenu.show = false } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel) const $default = query('[data-value="normal"]', $panel) if ($default) { inverseClass($default, 'art-current') } - art.on('flip', (value) => { - const $current = queryAll('span', $panel).find(item => item.dataset.value === value) + on('flip', (value) => { + const $current = Array.from($panel.querySelectorAll('span')).find(item => item.dataset.value === value) if ($current) { inverseClass($current, 'art-current') } diff --git a/packages/artplayer/src/contextmenu/index.js b/packages/artplayer/src/contextmenu/index.ts similarity index 83% rename from packages/artplayer/src/contextmenu/index.js rename to packages/artplayer/src/contextmenu/index.ts index dfe76cf73..52ac0fa67 100644 --- a/packages/artplayer/src/contextmenu/index.js +++ b/packages/artplayer/src/contextmenu/index.ts @@ -1,3 +1,6 @@ +import type { ContextmenuHost } from './types' +import { ownEntry } from '../component/resources' +import { controlEvents } from '../control/resources' import { getRect, includeFromEvent, isMobile, setStyles } from '../utils' import Component from '../utils/component' import aspectRatio from './aspectRatio' @@ -7,24 +10,25 @@ import info from './info' import playbackRate from './playbackRate' import version from './version' -export default class Contextmenu extends Component { - constructor(art) { +export default class Contextmenu extends Component { + constructor(art: ContextmenuHost) { super(art) this.name = 'contextmenu' this.$parent = art.template.$contextmenu + ownEntry(art, this.$parent) if (!isMobile) { this.init() } } - init() { + init(): void { const { option, - proxy, template: { $player, $contextmenu }, } = this.art + const { on, proxy } = controlEvents(this.art, $contextmenu) if (option.playbackRate) { this.add( @@ -75,7 +79,7 @@ export default class Contextmenu extends Component { ) for (let index = 0; index < option.contextmenu.length; index++) { - this.add(option.contextmenu[index]) + this.add(option.contextmenu[index]!) } proxy($player, 'contextmenu', (event) => { @@ -112,7 +116,7 @@ export default class Contextmenu extends Component { } }) - this.art.on('blur', () => { + on('blur', () => { this.show = false }) } diff --git a/packages/artplayer/src/contextmenu/info.js b/packages/artplayer/src/contextmenu/info.ts similarity index 54% rename from packages/artplayer/src/contextmenu/info.js rename to packages/artplayer/src/contextmenu/info.ts index cb8ce6964..c6077ee75 100644 --- a/packages/artplayer/src/contextmenu/info.js +++ b/packages/artplayer/src/contextmenu/info.ts @@ -1,4 +1,6 @@ -export default function info(option) { +import type { ContextmenuFactory, ContextmenuOption } from './types' + +export default function info(option: ContextmenuOption): ContextmenuFactory { return art => ({ ...option, html: art.i18n.get('Video Info'), diff --git a/packages/artplayer/src/contextmenu/playbackRate.js b/packages/artplayer/src/contextmenu/playbackRate.ts similarity index 61% rename from packages/artplayer/src/contextmenu/playbackRate.js rename to packages/artplayer/src/contextmenu/playbackRate.ts index c1e94d47b..e45191314 100644 --- a/packages/artplayer/src/contextmenu/playbackRate.js +++ b/packages/artplayer/src/contextmenu/playbackRate.ts @@ -1,6 +1,8 @@ -import { inverseClass, query, queryAll } from '../utils' +import type { ContextmenuFactory, ContextmenuOption } from './types' +import { controlEvents } from '../control/resources' +import { inverseClass, query } from '../utils' -export default function playbackRate(option) { +export default function playbackRate(option: ContextmenuOption): ContextmenuFactory { return (art) => { const { i18n, @@ -15,18 +17,19 @@ export default function playbackRate(option) { ...option, html: `${i18n.get('Play Speed')}: ${html}`, click: (contextmenu, event) => { - const { value } = event.target.dataset + const value = event.target instanceof HTMLElement ? event.target.dataset.value : undefined if (value) { art.playbackRate = Number(value) contextmenu.show = false } }, mounted: ($panel) => { + const { on } = controlEvents(art, $panel) const $default = query('[data-value="1"]', $panel) if ($default) inverseClass($default, 'art-current') - art.on('video:ratechange', () => { - const $current = queryAll('span', $panel).find( + on('video:ratechange', () => { + const $current = Array.from($panel.querySelectorAll('span')).find( item => Number(item.dataset.value) === art.playbackRate, ) if ($current) { diff --git a/packages/artplayer/src/contextmenu/types.ts b/packages/artplayer/src/contextmenu/types.ts new file mode 100644 index 000000000..189878b62 --- /dev/null +++ b/packages/artplayer/src/contextmenu/types.ts @@ -0,0 +1,17 @@ +import type { SubscriptionHost } from '../component/resources' +import type { ComponentHost, EntryInput, EntryOption } from '../component/types' +import type { UIEvents } from '../control/types' + +export interface ContextmenuHost extends ComponentHost, SubscriptionHost { + template: { $player: HTMLDivElement, $contextmenu: HTMLDivElement } + option: { playbackRate: boolean, aspectRatio: boolean, flip: boolean, contextmenu: EntryInput[] } + constructor: { CONTEXTMENU: boolean, PLAYBACK_RATE: number[], ASPECT_RATIO: string[], FLIP: string[] } + i18n: { get: (key: string) => string } + info: { show: boolean } + playbackRate: number + aspectRatio: string + flip: string +} + +export type ContextmenuOption = EntryOption +export type ContextmenuFactory = (art: ContextmenuHost) => ContextmenuOption diff --git a/packages/artplayer/src/contextmenu/version.js b/packages/artplayer/src/contextmenu/version.ts similarity index 60% rename from packages/artplayer/src/contextmenu/version.js rename to packages/artplayer/src/contextmenu/version.ts index 4128f768d..b18128d5f 100644 --- a/packages/artplayer/src/contextmenu/version.js +++ b/packages/artplayer/src/contextmenu/version.ts @@ -1,6 +1,7 @@ +import type { ContextmenuOption } from './types' import { version } from '../../package.json' -export default function (option) { +export default function (option: ContextmenuOption): ContextmenuOption { return { ...option, html: `ArtPlayer ${version}`, diff --git a/packages/artplayer/src/control/airplay.js b/packages/artplayer/src/control/airplay.js deleted file mode 100644 index 48ddf54b3..000000000 --- a/packages/artplayer/src/control/airplay.js +++ /dev/null @@ -1,13 +0,0 @@ -import { append } from '../utils' - -export default function airplay(option) { - return art => ({ - ...option, - tooltip: art.i18n.get('AirPlay'), - mounted: ($control) => { - const { proxy, icons } = art - append($control, icons.airplay) - proxy($control, 'click', () => art.airplay()) - }, - }) -} diff --git a/packages/artplayer/src/control/airplay.ts b/packages/artplayer/src/control/airplay.ts new file mode 100644 index 000000000..52e5e49fe --- /dev/null +++ b/packages/artplayer/src/control/airplay.ts @@ -0,0 +1,16 @@ +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { controlEvents } from './resources' + +export default function airplay(option: ControlOption): ControlFactory { + return art => ({ + ...option, + tooltip: art.i18n.get('AirPlay'), + mounted: ($control) => { + const { proxy } = controlEvents(art, $control) + const { icons } = art + appendElement($control, icons.airplay) + proxy($control, 'click', () => art.airplay()) + }, + }) +} diff --git a/packages/artplayer/src/control/builtins.ts b/packages/artplayer/src/control/builtins.ts new file mode 100644 index 000000000..3743d8c3c --- /dev/null +++ b/packages/artplayer/src/control/builtins.ts @@ -0,0 +1,135 @@ +import type { EntryInput } from '../component/types' +import type { ControlHost } from './types' +import { getScope } from '../lifecycle/instance' +import { wait } from '../lifecycle/resources' +import { isMobile } from '../utils' +import airplay from './airplay' +import fullscreen from './fullscreen' +import fullscreenWeb from './fullscreenWeb' +import pip from './pip' +import playAndPause from './playAndPause' +import progress from './progress' +import screenshot from './screenshot' +import setting from './setting' +import time from './time' +import volume from './volume' + +export function installControls(controls: { art: ControlHost, add: (option: EntryInput) => undefined }): void { + const { option } = controls.art + + if (!option.isLive) { + controls.add( + progress({ + name: 'progress', + position: 'top', + index: 10, + }), + ) + } + + controls.add({ + name: 'thumbnails', + position: 'top', + index: 20, + }) + + controls.add( + playAndPause({ + name: 'playAndPause', + position: 'left', + index: 10, + }), + ) + + controls.add( + volume({ + name: 'volume', + position: 'left', + index: 20, + }), + ) + + if (!option.isLive) { + controls.add( + time({ + name: 'time', + position: 'left', + index: 30, + }), + ) + } + + if (option.quality.length) { + wait(getScope(controls.art)).then((active) => { + if (!active || getScope(controls.art).closed) + return + controls.art.quality = option.quality + }).catch((error) => { + console.warn('ArtPlayer quality initialization failed:', error) + }) + } + + if (option.screenshot && !isMobile) { + controls.add( + screenshot({ + name: 'screenshot', + position: 'right', + index: 20, + }), + ) + } + + if (option.setting) { + controls.add( + setting({ + name: 'setting', + position: 'right', + index: 30, + }), + ) + } + + if (option.pip) { + controls.add( + pip({ + name: 'pip', + position: 'right', + index: 40, + }), + ) + } + + if (option.airplay && 'WebKitPlaybackTargetAvailabilityEvent' in window && window.WebKitPlaybackTargetAvailabilityEvent) { + controls.add( + airplay({ + name: 'airplay', + position: 'right', + index: 50, + }), + ) + } + + if (option.fullscreenWeb) { + controls.add( + fullscreenWeb({ + name: 'fullscreenWeb', + position: 'right', + index: 60, + }), + ) + } + + if (option.fullscreen) { + controls.add( + fullscreen({ + name: 'fullscreen', + position: 'right', + index: 70, + }), + ) + } + + for (let index = 0; index < option.controls.length; index++) { + controls.add(option.controls[index]!) + } +} diff --git a/packages/artplayer/src/control/fullscreen.js b/packages/artplayer/src/control/fullscreen.ts similarity index 54% rename from packages/artplayer/src/control/fullscreen.js rename to packages/artplayer/src/control/fullscreen.ts index bc61c45f3..3134ae8eb 100644 --- a/packages/artplayer/src/control/fullscreen.js +++ b/packages/artplayer/src/control/fullscreen.ts @@ -1,21 +1,25 @@ -import { append, setStyle, tooltip } from '../utils' +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { setStyle, tooltip } from '../utils' +import { controlEvents } from './resources' -export default function fullscreen(option) { +export default function fullscreen(option: ControlOption): ControlFactory { return art => ({ ...option, tooltip: art.i18n.get('Fullscreen'), mounted: ($control) => { - const { proxy, icons, i18n } = art + const { on, proxy } = controlEvents(art, $control) + const { icons, i18n } = art - const $fullscreenOn = append($control, icons.fullscreenOn) - const $fullscreenOff = append($control, icons.fullscreenOff) + const $fullscreenOn = appendElement($control, icons.fullscreenOn) + const $fullscreenOff = appendElement($control, icons.fullscreenOff) setStyle($fullscreenOff, 'display', 'none') proxy($control, 'click', () => { art.fullscreen = !art.fullscreen }) - art.on('fullscreen', (state) => { + on('fullscreen', (state) => { if (state) { tooltip($control, i18n.get('Exit Fullscreen')) setStyle($fullscreenOn, 'display', 'none') diff --git a/packages/artplayer/src/control/fullscreenWeb.js b/packages/artplayer/src/control/fullscreenWeb.ts similarity index 55% rename from packages/artplayer/src/control/fullscreenWeb.js rename to packages/artplayer/src/control/fullscreenWeb.ts index 4cdc50e47..65b6a4e91 100644 --- a/packages/artplayer/src/control/fullscreenWeb.js +++ b/packages/artplayer/src/control/fullscreenWeb.ts @@ -1,21 +1,25 @@ -import { append, setStyle, tooltip } from '../utils' +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { setStyle, tooltip } from '../utils' +import { controlEvents } from './resources' -export default function fullscreenWeb(option) { +export default function fullscreenWeb(option: ControlOption): ControlFactory { return art => ({ ...option, tooltip: art.i18n.get('Web Fullscreen'), mounted: ($control) => { - const { proxy, icons, i18n } = art + const { on, proxy } = controlEvents(art, $control) + const { icons, i18n } = art - const $fullscreenWebOn = append($control, icons.fullscreenWebOn) - const $fullscreenWebOff = append($control, icons.fullscreenWebOff) + const $fullscreenWebOn = appendElement($control, icons.fullscreenWebOn) + const $fullscreenWebOff = appendElement($control, icons.fullscreenWebOff) setStyle($fullscreenWebOff, 'display', 'none') proxy($control, 'click', () => { art.fullscreenWeb = !art.fullscreenWeb }) - art.on('fullscreenWeb', (value) => { + on('fullscreenWeb', (value) => { if (value) { tooltip($control, i18n.get('Exit Web Fullscreen')) setStyle($fullscreenWebOn, 'display', 'none') diff --git a/packages/artplayer/src/control/index.js b/packages/artplayer/src/control/index.js deleted file mode 100644 index d9f44be6f..000000000 --- a/packages/artplayer/src/control/index.js +++ /dev/null @@ -1,290 +0,0 @@ -import { getScope } from '../lifecycle/instance' -import { wait } from '../lifecycle/resources' -import { - addClass, - append, - createElement, - def, - errorHandle, - getComposedPath, - includeFromEvent, - inverseClass, - isMobile, - removeClass, -} from '../utils' -import Component from '../utils/component' -import airplay from './airplay' -import fullscreen from './fullscreen' -import fullscreenWeb from './fullscreenWeb' -import pip from './pip' -import playAndPause from './playAndPause' -import progress from './progress' -import screenshot from './screenshot' -import setting from './setting' -import time from './time' -import volume from './volume' - -export default class Control extends Component { - constructor(art) { - super(art) - - this.isHover = false - this.name = 'control' - this.timer = Date.now() - - const { constructor } = art - const { $player, $bottom } = this.art.template - - art.on('mousemove', () => { - if (!isMobile) { - this.show = true - } - }) - - art.on('click', () => { - if (isMobile) { - this.toggle() - } - else { - this.show = true - } - }) - - art.on('document:mousemove', (event) => { - this.isHover = includeFromEvent(event, $bottom) - }) - - art.on('video:timeupdate', () => { - if ( - !art.setting.show - && !this.isHover - && !art.isInput - && art.playing - && this.show - && Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME - ) { - this.show = false - } - }) - - art.on('control', (state) => { - if (state) { - removeClass($player, 'art-hide-cursor') - addClass($player, 'art-hover') - this.timer = Date.now() - } - else { - addClass($player, 'art-hide-cursor') - removeClass($player, 'art-hover') - } - }) - - this.init() - } - - init() { - const { option } = this.art - - if (!option.isLive) { - this.add( - progress({ - name: 'progress', - position: 'top', - index: 10, - }), - ) - } - - this.add({ - name: 'thumbnails', - position: 'top', - index: 20, - }) - - this.add( - playAndPause({ - name: 'playAndPause', - position: 'left', - index: 10, - }), - ) - - this.add( - volume({ - name: 'volume', - position: 'left', - index: 20, - }), - ) - - if (!option.isLive) { - this.add( - time({ - name: 'time', - position: 'left', - index: 30, - }), - ) - } - - if (option.quality.length) { - wait(getScope(this.art)).then((active) => { - if (!active || getScope(this.art).closed) - return - this.art.quality = option.quality - }) - } - - if (option.screenshot && !isMobile) { - this.add( - screenshot({ - name: 'screenshot', - position: 'right', - index: 20, - }), - ) - } - - if (option.setting) { - this.add( - setting({ - name: 'setting', - position: 'right', - index: 30, - }), - ) - } - - if (option.pip) { - this.add( - pip({ - name: 'pip', - position: 'right', - index: 40, - }), - ) - } - - if (option.airplay && window.WebKitPlaybackTargetAvailabilityEvent) { - this.add( - airplay({ - name: 'airplay', - position: 'right', - index: 50, - }), - ) - } - - if (option.fullscreenWeb) { - this.add( - fullscreenWeb({ - name: 'fullscreenWeb', - position: 'right', - index: 60, - }), - ) - } - - if (option.fullscreen) { - this.add( - fullscreen({ - name: 'fullscreen', - position: 'right', - index: 70, - }), - ) - } - - for (let index = 0; index < option.controls.length; index++) { - this.add(option.controls[index]) - } - } - - add(getOption) { - const option = typeof getOption === 'function' ? getOption(this.art) : getOption - const { $progress, $controlsLeft, $controlsRight } = this.art.template - - switch (option.position) { - case 'top': - this.$parent = $progress - break - case 'left': - this.$parent = $controlsLeft - break - case 'right': - this.$parent = $controlsRight - break - default: - errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`) - break - } - - super.add(option) - } - - check(target) { - if (!target) { - return - } - target.$control_value.innerHTML = target.html - for (let index = 0; index < target.$control_option.length; index++) { - const item = target.$control_option[index] - item.default = item === target - if (item.default) { - inverseClass(item.$control_item, 'art-current') - } - } - } - - selector(option, $ref, events) { - const { proxy } = this.art.events - - addClass($ref, 'art-control-selector') - const $value = createElement('div') - addClass($value, 'art-selector-value') - append($value, option.html) - $ref.textContent = '' - append($ref, $value) - - const $list = createElement('div') - addClass($list, 'art-selector-list') - append($ref, $list) - - for (let index = 0; index < option.selector.length; index++) { - const item = option.selector[index] - const $item = createElement('div') - addClass($item, 'art-selector-item') - if (item.default) - addClass($item, 'art-current') - $item.dataset.index = index - $item.dataset.value = item.value - $item.innerHTML = item.html - append($list, $item) - - def(item, '$control_option', { - get: () => option.selector, - }) - - def(item, '$control_item', { - get: () => $item, - }) - - def(item, '$control_value', { - get: () => $value, - }) - } - - const event = proxy($list, 'click', async (event) => { - const path = getComposedPath(event) - const item = option.selector.find( - item => item.$control_item === path.find($item => item.$control_item === $item), - ) - this.check(item) - if (option.onSelect) { - $value.innerHTML = await option.onSelect.call(this.art, item, item.$control_item, event) - } - }) - - events.push(event) - } -} diff --git a/packages/artplayer/src/control/index.ts b/packages/artplayer/src/control/index.ts new file mode 100644 index 000000000..35c70ae99 --- /dev/null +++ b/packages/artplayer/src/control/index.ts @@ -0,0 +1,118 @@ +import type { EntryInput, EntryOption, EventCleanup, SelectorItem } from '../component/types' +import type { ControlHost } from './types' +import { ownEntry } from '../component/resources' +import { getScope, isClosing } from '../lifecycle/instance' +import { + addClass, + errorHandle, + includeFromEvent, + isMobile, + removeClass, +} from '../utils' +import Component from '../utils/component' +import { installControls } from './builtins' +import { observeControlLayout } from './layout' +import { controlEvents } from './resources' +import { checkSelector, renderSelector } from './selector' + +export default class Control extends Component { + declare isHover: boolean + declare timer: number + + constructor(art: ControlHost) { + super(art) + + this.isHover = false + this.name = 'control' + this.timer = Date.now() + + const { constructor } = art + const { $player, $bottom } = this.art.template + ownEntry(art, $bottom) + const { on } = controlEvents(art, $bottom) + + on('mousemove', () => { + if (!isMobile) { + this.show = true + } + }) + + on('click', () => { + if (isMobile) { + this.toggle() + } + else { + this.show = true + } + }) + + on('document:mousemove', (event) => { + this.isHover = includeFromEvent(event, $bottom) + }) + + on('video:timeupdate', () => { + if ( + !art.setting.show + && !this.isHover + && !art.isInput + && art.playing + && this.show + && Date.now() - this.timer >= constructor.CONTROL_HIDE_TIME + ) { + this.show = false + } + }) + + on('control', (state) => { + if (state) { + removeClass($player, 'art-hide-cursor') + addClass($player, 'art-hover') + this.timer = Date.now() + } + else { + addClass($player, 'art-hide-cursor') + removeClass($player, 'art-hover') + } + }) + + this.init() + if (!getScope(art).closed) + observeControlLayout(art) + } + + init(): void { + installControls(this) + } + + override add(getOption: EntryInput): undefined { + if (isClosing(this.art)) + return + const option = typeof getOption === 'function' ? getOption(this.art) : getOption + const { $progress, $controlsLeft, $controlsRight } = this.art.template + + switch (option.position) { + case 'top': + this.$parent = $progress + break + case 'left': + this.$parent = $controlsLeft + break + case 'right': + this.$parent = $controlsRight + break + default: + errorHandle(false, `Control option.position must one of 'top', 'left', 'right'`) + break + } + + super.add(option) + } + + check(target?: SelectorItem): void { + checkSelector(target) + } + + override selector(option: EntryOption, $ref: HTMLDivElement, events: EventCleanup[]): void { + renderSelector(this.art, target => this.check(target), option, $ref, events) + } +} diff --git a/packages/artplayer/src/control/layout.ts b/packages/artplayer/src/control/layout.ts new file mode 100644 index 000000000..5608d5138 --- /dev/null +++ b/packages/artplayer/src/control/layout.ts @@ -0,0 +1,33 @@ +import type { ControlHost } from './types' +import { entryScope } from '../component/resources' +import { controlEvents } from './resources' + +export function observeControlLayout(art: ControlHost): void { + const { $bottom, $controls, $player } = art.template + const scope = entryScope($bottom) + const { on } = controlEvents(art, $bottom) + const update = () => { + if (scope.closed) + return + // Layout height is unaffected by the player's rotation/scale transform. + const height = $controls.offsetHeight + if (height > 0 && $player.style.getPropertyValue('--art-controls-height') !== `${height}px`) + $player.style.setProperty('--art-controls-height', `${height}px`) + } + on('resize', update) + if (typeof ResizeObserver !== 'undefined') { + const observer = new ResizeObserver(update) + observer.observe($controls) + scope.add(() => { + observer.disconnect() + }) + } + else if (typeof MutationObserver !== 'undefined') { + const observer = new MutationObserver(update) + observer.observe($controls, { childList: true, subtree: true, attributes: true, characterData: true }) + scope.add(() => { + observer.disconnect() + }) + } + update() +} diff --git a/packages/artplayer/src/control/pip.js b/packages/artplayer/src/control/pip.js deleted file mode 100644 index 1ddb925a4..000000000 --- a/packages/artplayer/src/control/pip.js +++ /dev/null @@ -1,21 +0,0 @@ -import { append, tooltip } from '../utils' - -export default function pip(option) { - return art => ({ - ...option, - tooltip: art.i18n.get('PIP Mode'), - mounted: ($control) => { - const { proxy, icons, i18n } = art - - append($control, icons.pip) - - proxy($control, 'click', () => { - art.pip = !art.pip - }) - - art.on('pip', (value) => { - tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode')) - }) - }, - }) -} diff --git a/packages/artplayer/src/control/pip.ts b/packages/artplayer/src/control/pip.ts new file mode 100644 index 000000000..43f783b2e --- /dev/null +++ b/packages/artplayer/src/control/pip.ts @@ -0,0 +1,25 @@ +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { tooltip } from '../utils' +import { controlEvents } from './resources' + +export default function pip(option: ControlOption): ControlFactory { + return art => ({ + ...option, + tooltip: art.i18n.get('PIP Mode'), + mounted: ($control) => { + const { on, proxy } = controlEvents(art, $control) + const { icons, i18n } = art + + appendElement($control, icons.pip) + + proxy($control, 'click', () => { + art.pip = !art.pip + }) + + on('pip', (value) => { + tooltip($control, i18n.get(value ? 'Exit PIP Mode' : 'PIP Mode')) + }) + }, + }) +} diff --git a/packages/artplayer/src/control/playAndPause.js b/packages/artplayer/src/control/playAndPause.ts similarity index 55% rename from packages/artplayer/src/control/playAndPause.js rename to packages/artplayer/src/control/playAndPause.ts index 957e75e91..095ec251d 100644 --- a/packages/artplayer/src/control/playAndPause.js +++ b/packages/artplayer/src/control/playAndPause.ts @@ -1,13 +1,17 @@ -import { append, setStyle, silencePromise, tooltip } from '../utils' +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { setStyle, silencePromise, tooltip } from '../utils' +import { controlEvents } from './resources' -export default function playAndPause(option) { +export default function playAndPause(option: ControlOption): ControlFactory { return art => ({ ...option, mounted: ($control) => { - const { proxy, icons, i18n } = art + const { on, proxy } = controlEvents(art, $control) + const { icons, i18n } = art - const $play = append($control, icons.play) - const $pause = append($control, icons.pause) + const $play = appendElement($control, icons.play) + const $pause = appendElement($control, icons.pause) tooltip($play, i18n.get('Play')) tooltip($pause, i18n.get('Pause')) @@ -36,11 +40,11 @@ export default function playAndPause(option) { showPlay() } - art.on('video:playing', () => { + on('video:playing', () => { showPause() }) - art.on('video:pause', () => { + on('video:pause', () => { showPlay() }) }, diff --git a/packages/artplayer/src/control/progress.js b/packages/artplayer/src/control/progress.js deleted file mode 100644 index 425580cb5..000000000 --- a/packages/artplayer/src/control/progress.js +++ /dev/null @@ -1,208 +0,0 @@ -import { addClass, append, clamp, getRect, includeFromEvent, isMobile, query, removeClass, secondToTime, setStyle } from '../utils' - -export function getPosFromEvent(art, event) { - const { $progress } = art.template - const { left } = getRect($progress) - const eventLeft = isMobile ? event.touches[0].clientX : event.clientX - const width = clamp(eventLeft - left, 0, $progress.clientWidth) - const second = (width / $progress.clientWidth) * art.duration - const time = secondToTime(second) - const percentage = clamp(width / $progress.clientWidth, 0, 1) - return { second, time, width, percentage } -} - -export function setCurrentTime(art, event) { - if (art.isRotate) { - const percentage = (event.touches[0].clientY - art.top) / art.height - const second = percentage * art.duration - art.emit('setBar', 'played', percentage, event) - art.seek = second - } - else { - const { second, percentage } = getPosFromEvent(art, event) - art.emit('setBar', 'played', percentage, event) - art.seek = second - } -} - -export default function progress(options) { - return (art) => { - const { icons, option, proxy } = art - const { $player, $progress } = art.template - - return { - ...options, - html: ` -
-
-
-
-
-
-
00:00
-
- `, - mounted: ($control) => { - let tipTimer = null - let isDragging = false - - const $hover = query('.art-progress-hover', $control) - const $loaded = query('.art-progress-loaded', $control) - const $played = query('.art-progress-played', $control) - const $highlight = query('.art-progress-highlight', $control) - const $indicator = query('.art-progress-indicator', $control) - const $tip = query('.art-progress-tip', $control) - - if (icons.indicator) { - append($indicator, icons.indicator) - } - else { - setStyle($indicator, 'backgroundColor', 'var(--art-theme)') - } - - function showHighlight(event) { - const { width } = getPosFromEvent(art, event) - const { text } = event.target.dataset - $tip.textContent = text - const tipWidth = $tip.clientWidth - if (width <= tipWidth / 2) { - setStyle($tip, 'left', 0) - } - else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`) - } - else { - setStyle($tip, 'left', `${width - tipWidth / 2}px`) - } - } - - function showTime(event, touch) { - const { width, time } = touch || getPosFromEvent(art, event) - $tip.textContent = time || '00:00' - const tipWidth = $tip.clientWidth - if (width <= tipWidth / 2) { - setStyle($tip, 'left', 0) - } - else if (width > $control.clientWidth - tipWidth / 2) { - setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`) - } - else { - setStyle($tip, 'left', `${width - tipWidth / 2}px`) - } - } - - function updateHighlight() { - $highlight.textContent = '' - for (let index = 0; index < option.highlight.length; index++) { - const item = option.highlight[index] - const left = (clamp(item.time, 0, art.duration) / art.duration) * 100 - const html = `` - append($highlight, html) - } - } - - function setBar(type, percentage, event) { - const isMobileDragging = type === 'played' && event && isMobile - - if (type === 'loaded') { - setStyle($loaded, 'width', `${percentage * 100}%`) - } - - if (type === 'hover') { - setStyle($hover, 'width', `${percentage * 100}%`) - - if (includeFromEvent(event, $highlight)) { - showHighlight(event) - } - else { - showTime(event) - } - - if (percentage === 0) { - removeClass($player, 'art-progress-hover') - } - else { - addClass($player, 'art-progress-hover') - } - } - - if (type === 'played') { - setStyle($played, 'width', `${percentage * 100}%`) - setStyle($indicator, 'left', `${percentage * 100}%`) - } - - if (isMobileDragging) { - addClass($player, 'art-progress-hover') - const width = $control.clientWidth * percentage - const time = secondToTime(percentage * art.duration) - showTime(event, { width, time }) - clearTimeout(tipTimer) - tipTimer = setTimeout(() => { - removeClass($player, 'art-progress-hover') - }, 500) - } - } - - art.on('setBar', setBar) - art.on('video:loadedmetadata', updateHighlight) - - if (art.constructor.USE_RAF) { - art.on('raf', () => { - art.emit('setBar', 'played', art.played) - art.emit('setBar', 'loaded', art.loaded) - }) - } - else { - art.on('video:timeupdate', () => { - art.emit('setBar', 'played', art.played) - }) - - art.on('video:progress', () => { - art.emit('setBar', 'loaded', art.loaded) - }) - - art.on('video:ended', () => { - art.emit('setBar', 'played', 1) - }) - } - - art.emit('setBar', 'loaded', art.loaded || 0) - - if (!isMobile) { - proxy($progress, 'click', (event) => { - if (event.target !== $indicator) { - setCurrentTime(art, event) - } - }) - - proxy($progress, 'mousemove', (event) => { - const { percentage } = getPosFromEvent(art, event) - art.emit('setBar', 'hover', percentage, event) - }) - - proxy($progress, 'mouseleave', (event) => { - art.emit('setBar', 'hover', 0, event) - }) - - proxy($progress, 'mousedown', (event) => { - isDragging = event.button === 0 - }) - - art.on('document:mousemove', (event) => { - if (isDragging) { - const { second, percentage } = getPosFromEvent(art, event) - art.emit('setBar', 'played', percentage, event) - art.seek = second - } - }) - - art.on('document:mouseup', () => { - if (isDragging) { - isDragging = false - } - }) - } - }, - } - } -} diff --git a/packages/artplayer/src/control/progress.ts b/packages/artplayer/src/control/progress.ts new file mode 100644 index 000000000..d0d69b495 --- /dev/null +++ b/packages/artplayer/src/control/progress.ts @@ -0,0 +1,25 @@ +import type { ControlFactory, ControlOption } from './types' +import { installProgressInteractions } from './progress/interactions' +import { mountProgressView } from './progress/view' + +export { getPosFromEvent, setCurrentTime } from './progress/position' + +export default function progress(options: ControlOption): ControlFactory { + return art => ({ + ...options, + html: ` +
+
+
+
+
+
+
00:00
+
+ `, + mounted: ($control) => { + mountProgressView(art, $control) + installProgressInteractions(art, $control) + }, + }) +} diff --git a/packages/artplayer/src/control/progress/interactions.ts b/packages/artplayer/src/control/progress/interactions.ts new file mode 100644 index 000000000..161f032eb --- /dev/null +++ b/packages/artplayer/src/control/progress/interactions.ts @@ -0,0 +1,45 @@ +import type { ControlHost } from '../types' +import { isMobile } from '../../utils' +import { controlEvents } from '../resources' +import { getPosFromEvent, setCurrentTime } from './position' + +export function installProgressInteractions(art: ControlHost, $control: HTMLDivElement): void { + const { $progress } = art.template + const $indicator = $control.querySelector('.art-progress-indicator') + const { on, proxy } = controlEvents(art, $control) + if (!isMobile) { + let isDragging = false + proxy($progress, 'click', (event) => { + if (event.target !== $indicator) { + setCurrentTime(art, event) + } + }) + + proxy($progress, 'mousemove', (event) => { + const { percentage } = getPosFromEvent(art, event) + art.emit('setBar', 'hover', percentage, event) + }) + + proxy($progress, 'mouseleave', (event) => { + art.emit('setBar', 'hover', 0, event) + }) + + proxy($progress, 'mousedown', (event) => { + isDragging = event.button === 0 + }) + + on('document:mousemove', (event) => { + if (isDragging) { + const { second, percentage } = getPosFromEvent(art, event) + art.emit('setBar', 'played', percentage, event) + art.seek = second + } + }) + + on('document:mouseup', () => { + if (isDragging) { + isDragging = false + } + }) + } +} diff --git a/packages/artplayer/src/control/progress/position.ts b/packages/artplayer/src/control/progress/position.ts new file mode 100644 index 000000000..38a47bad1 --- /dev/null +++ b/packages/artplayer/src/control/progress/position.ts @@ -0,0 +1,30 @@ +import type { ControlHost } from '../types' +import { clamp, getRect, isMobile, secondToTime } from '../../utils' + +export type ProgressEvent = MouseEvent | TouchEvent +type ProgressPositionHost = Pick + +export function getPosFromEvent(art: ProgressPositionHost, event: ProgressEvent) { + const { $progress } = art.template + const { left } = getRect($progress) + const eventLeft = isMobile ? (event as TouchEvent).touches[0]!.clientX : (event as MouseEvent).clientX + const width = clamp(eventLeft - left, 0, $progress.clientWidth) + const second = (width / $progress.clientWidth) * art.duration + const time = secondToTime(second) + const percentage = clamp(width / $progress.clientWidth, 0, 1) + return { second, time, width, percentage } +} + +export function setCurrentTime(art: ProgressPositionHost, event: ProgressEvent) { + if (art.isRotate) { + const percentage = ((event as TouchEvent).touches[0]!.clientY - art.top) / art.height + const second = percentage * art.duration + art.emit('setBar', 'played', percentage, event) + art.seek = second + } + else { + const { second, percentage } = getPosFromEvent(art, event) + art.emit('setBar', 'played', percentage, event) + art.seek = second + } +} diff --git a/packages/artplayer/src/control/progress/view.ts b/packages/artplayer/src/control/progress/view.ts new file mode 100644 index 000000000..83b5911ca --- /dev/null +++ b/packages/artplayer/src/control/progress/view.ts @@ -0,0 +1,141 @@ +import type { ControlHost } from '../types' +import type { ProgressEvent } from './position' +import { queryElement } from '../../component/dom' +import { entryScope } from '../../component/resources' +import { timeout } from '../../lifecycle/resources' +import { addClass, append, clamp, includeFromEvent, isMobile, removeClass, secondToTime, setStyle } from '../../utils' +import { controlEvents } from '../resources' +import { getPosFromEvent } from './position' + +export function mountProgressView(art: ControlHost, $control: HTMLDivElement): void { + const { icons, option } = art + const { $player } = art.template + const scope = entryScope($control) + const { on } = controlEvents(art, $control) + let cancelTip = () => {} + + const $hover = queryElement('.art-progress-hover', $control) + const $loaded = queryElement('.art-progress-loaded', $control) + const $played = queryElement('.art-progress-played', $control) + const $highlight = queryElement('.art-progress-highlight', $control) + const $indicator = queryElement('.art-progress-indicator', $control) + const $tip = queryElement('.art-progress-tip', $control) + + if (icons.indicator) { + append($indicator, icons.indicator) + } + else { + setStyle($indicator, 'backgroundColor', 'var(--art-theme)') + } + + function showHighlight(event: ProgressEvent) { + const { width } = getPosFromEvent(art, event) + const text = event.target instanceof HTMLElement ? event.target.dataset.text : undefined + $tip.textContent = text ?? '' + const tipWidth = $tip.clientWidth + if (width <= tipWidth / 2) { + setStyle($tip, 'left', 0) + } + else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`) + } + else { + setStyle($tip, 'left', `${width - tipWidth / 2}px`) + } + } + + function showTime(event: ProgressEvent, touch?: { width: number, time: string }) { + const { width, time } = touch || getPosFromEvent(art, event) + $tip.textContent = time || '00:00' + const tipWidth = $tip.clientWidth + if (width <= tipWidth / 2) { + setStyle($tip, 'left', 0) + } + else if (width > $control.clientWidth - tipWidth / 2) { + setStyle($tip, 'left', `${$control.clientWidth - tipWidth}px`) + } + else { + setStyle($tip, 'left', `${width - tipWidth / 2}px`) + } + } + + function updateHighlight() { + $highlight.textContent = '' + for (let index = 0; index < option.highlight.length; index++) { + const item = option.highlight[index]! + const left = (clamp(item.time, 0, art.duration) / art.duration) * 100 + const marker = document.createElement('span') + marker.dataset.text = item.text + marker.dataset.time = String(item.time) + marker.style.left = `${left}%` + append($highlight, marker) + } + } + + function setBar(type: string, percentage: number, event?: ProgressEvent) { + const isMobileDragging = type === 'played' && event && isMobile + + if (type === 'loaded') { + setStyle($loaded, 'width', `${percentage * 100}%`) + } + + if (type === 'hover') { + setStyle($hover, 'width', `${percentage * 100}%`) + + if (includeFromEvent(event!, $highlight)) { + showHighlight(event!) + } + else { + showTime(event!) + } + + if (percentage === 0) { + removeClass($player, 'art-progress-hover') + } + else { + addClass($player, 'art-progress-hover') + } + } + + if (type === 'played') { + setStyle($played, 'width', `${percentage * 100}%`) + setStyle($indicator, 'left', `${percentage * 100}%`) + } + + if (isMobileDragging) { + addClass($player, 'art-progress-hover') + const width = $control.clientWidth * percentage + const time = secondToTime(percentage * art.duration) + showTime(event!, { width, time }) + cancelTip() + cancelTip = timeout(scope, () => { + removeClass($player, 'art-progress-hover') + }, 500) + } + } + + on('setBar', setBar) + on('video:loadedmetadata', updateHighlight) + + if (art.constructor.USE_RAF) { + on('raf', () => { + art.emit('setBar', 'played', art.played) + art.emit('setBar', 'loaded', art.loaded) + }) + } + else { + on('video:timeupdate', () => { + art.emit('setBar', 'played', art.played) + }) + + on('video:progress', () => { + art.emit('setBar', 'loaded', art.loaded) + }) + + on('video:ended', () => { + art.emit('setBar', 'played', 1) + }) + } + + art.emit('setBar', 'loaded', art.loaded || 0) +} diff --git a/packages/artplayer/src/control/resources.ts b/packages/artplayer/src/control/resources.ts new file mode 100644 index 000000000..b42ea0ec3 --- /dev/null +++ b/packages/artplayer/src/control/resources.ts @@ -0,0 +1,13 @@ +import type { SubscriptionHost } from '../component/resources' +import type { ComponentHost } from '../component/types' +import type { UIEvents } from './types' +import { proxyEntry, subscribeEntry } from '../component/resources' + +export function controlEvents(art: ComponentHost & SubscriptionHost, element: HTMLElement) { + return { + on: (name: Name, callback: (...args: [...UIEvents[Name]]) => unknown): void => { + subscribeEntry(art, element, name, callback) + }, + proxy: (target: EventTarget, name: Name, callback: (event: HTMLElementEventMap[Name]) => unknown): (() => void) => proxyEntry(art, element, target, name, callback), + } +} diff --git a/packages/artplayer/src/control/screenshot.js b/packages/artplayer/src/control/screenshot.js deleted file mode 100644 index d13940d57..000000000 --- a/packages/artplayer/src/control/screenshot.js +++ /dev/null @@ -1,16 +0,0 @@ -import { append } from '../utils' - -export default function screenshot(option) { - return art => ({ - ...option, - tooltip: art.i18n.get('Screenshot'), - mounted: ($control) => { - const { proxy, icons } = art - - append($control, icons.screenshot) - proxy($control, 'click', () => { - art.screenshot() - }) - }, - }) -} diff --git a/packages/artplayer/src/control/screenshot.ts b/packages/artplayer/src/control/screenshot.ts new file mode 100644 index 000000000..0c9d99f5c --- /dev/null +++ b/packages/artplayer/src/control/screenshot.ts @@ -0,0 +1,19 @@ +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { controlEvents } from './resources' + +export default function screenshot(option: ControlOption): ControlFactory { + return art => ({ + ...option, + tooltip: art.i18n.get('Screenshot'), + mounted: ($control) => { + const { proxy } = controlEvents(art, $control) + const { icons } = art + + appendElement($control, icons.screenshot) + proxy($control, 'click', () => { + art.screenshot() + }) + }, + }) +} diff --git a/packages/artplayer/src/control/selector.ts b/packages/artplayer/src/control/selector.ts new file mode 100644 index 000000000..6cda2c199 --- /dev/null +++ b/packages/artplayer/src/control/selector.ts @@ -0,0 +1,96 @@ +import type { EntryOption, EventCleanup, SelectorItem } from '../component/types' +import type { ControlHost } from './types' +import { appendElement } from '../component/dom' +import { entryScope } from '../component/resources' +import { trackSelection } from '../component/selection' +import { addClass, append, def, errorHandle, getComposedPath, inverseClass } from '../utils' + +interface Binding { + option: EntryOption + item: HTMLDivElement + value: HTMLDivElement + owner: HTMLDivElement +} +const bindings = new WeakMap() + +function bind(item: SelectorItem, binding: Binding): void { + const previous = bindings.get(item) + errorHandle(!previous || entryScope(previous.owner).closed, 'Cannot share selector items between active controls') + if (!previous) { + def(item, '$control_option', { get: () => bindings.get(item)!.option.selector }) + def(item, '$control_item', { get: () => bindings.get(item)!.item }) + def(item, '$control_value', { get: () => bindings.get(item)!.value }) + } + bindings.set(item, binding) +} + +// WebIDL keeps legacy numeric/Element coercion and null-to-empty innerHTML behavior. +function setHTML(element: HTMLElement, value: unknown): void { + element.innerHTML = value as string +} + +export function checkSelector(target?: SelectorItem): void { + if (!target) + return + setHTML(target.$control_value!, target.html) + for (let index = 0; index < target.$control_option!.length; index++) { + const item = target.$control_option![index]! + item.default = item === target + if (item.default) + inverseClass(item.$control_item, 'art-current') + } +} + +export function renderSelector(art: ControlHost, check: (target?: SelectorItem) => void, option: EntryOption, $ref: HTMLDivElement, events: EventCleanup[]): void { + const { proxy } = art.events + const scope = entryScope($ref) + const selector = option.selector! + addClass($ref, 'art-control-selector') + const $value = document.createElement('div') + addClass($value, 'art-selector-value') + append($value, option.html) + $ref.textContent = '' + append($ref, $value) + const $list = appendElement($ref, '
') + for (let index = 0; index < selector.length; index++) { + const item = selector[index]! + const $item = document.createElement('div') + addClass($item, 'art-selector-item') + if (item.default) + addClass($item, 'art-current') + $item.dataset.index = String(index) + $item.dataset.value = String(item.value) + setHTML($item, item.html) + append($list, $item) + bind(item, { option, item: $item, value: $value, owner: $ref }) + } + let generation = 0 + const event = proxy($list, 'click', async (event) => { + if (scope.closed) + return + const path = getComposedPath(event) + const item = option.selector!.find(item => path.includes(item.$control_item)) + if (!item) + return + const current = ++generation + const active = () => !scope.closed && current === generation + const release = scope.add(trackSelection(event, active)) + try { + check(item) + if (scope.closed) + return + if (option.onSelect) { + const value = await option.onSelect.call(art, item, item.$control_item!, event) + if (active()) + setHTML($value, value) + } + } + catch (error) { + console.warn('ArtPlayer selector failed:', error) + } + finally { + release() + } + }) + events.push(event) +} diff --git a/packages/artplayer/src/control/setting.js b/packages/artplayer/src/control/setting.js deleted file mode 100644 index 3478686a7..000000000 --- a/packages/artplayer/src/control/setting.js +++ /dev/null @@ -1,22 +0,0 @@ -import { append, tooltip } from '../utils' - -export default function setting(option) { - return art => ({ - ...option, - tooltip: art.i18n.get('Show Setting'), - mounted: ($control) => { - const { proxy, icons, i18n } = art - - append($control, icons.setting) - - proxy($control, 'click', () => { - art.setting.toggle() - art.setting.resize() - }) - - art.on('setting', (value) => { - tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting')) - }) - }, - }) -} diff --git a/packages/artplayer/src/control/setting.ts b/packages/artplayer/src/control/setting.ts new file mode 100644 index 000000000..180a9c857 --- /dev/null +++ b/packages/artplayer/src/control/setting.ts @@ -0,0 +1,26 @@ +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { tooltip } from '../utils' +import { controlEvents } from './resources' + +export default function setting(option: ControlOption): ControlFactory { + return art => ({ + ...option, + tooltip: art.i18n.get('Show Setting'), + mounted: ($control) => { + const { on, proxy } = controlEvents(art, $control) + const { icons, i18n } = art + + appendElement($control, icons.setting) + + proxy($control, 'click', () => { + art.setting.toggle() + art.setting.resize() + }) + + on('setting', (value) => { + tooltip($control, i18n.get(value ? 'Hide Setting' : 'Show Setting')) + }) + }, + }) +} diff --git a/packages/artplayer/src/control/time.js b/packages/artplayer/src/control/time.ts similarity index 69% rename from packages/artplayer/src/control/time.js rename to packages/artplayer/src/control/time.ts index d755321c6..1b0265129 100644 --- a/packages/artplayer/src/control/time.js +++ b/packages/artplayer/src/control/time.ts @@ -1,6 +1,8 @@ +import type { ControlFactory, ControlOption } from './types' import { isMobile, secondToTime } from '../utils' +import { controlEvents } from './resources' -export default function time(option) { +export default function time(option: ControlOption): ControlFactory { return art => ({ ...option, style: isMobile @@ -13,6 +15,7 @@ export default function time(option) { padding: '0 10px', }, mounted: ($control) => { + const { on } = controlEvents(art, $control) function getTime() { const newTime = `${secondToTime(art.currentTime)} / ${secondToTime(art.duration)}` if (newTime !== $control.textContent) { @@ -22,9 +25,9 @@ export default function time(option) { getTime() - const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress'] + const events = ['video:loadedmetadata', 'video:timeupdate', 'video:progress'] as const for (let index = 0; index < events.length; index++) { - art.on(events[index], getTime) + on(events[index]!, getTime) } }, }) diff --git a/packages/artplayer/src/control/types.ts b/packages/artplayer/src/control/types.ts new file mode 100644 index 000000000..a1bbe5508 --- /dev/null +++ b/packages/artplayer/src/control/types.ts @@ -0,0 +1,82 @@ +import type { SubscriptionHost } from '../component/resources' +import type { ComponentHost, EntryInput, EntryOption } from '../component/types' + +export interface UIEvents { + 'mousemove': [MouseEvent] + 'click': [MouseEvent] + 'document:mousemove': [MouseEvent] + 'document:mouseup': [MouseEvent] + 'video:timeupdate': [Event] + 'video:loadedmetadata': [Event] + 'video:progress': [Event] + 'video:ended': [Event] + 'video:playing': [Event] + 'video:pause': [Event] + 'video:volumechange': [Event] + 'video:ratechange': [Event] + 'setBar': [type: string, percentage: number, event?: MouseEvent | TouchEvent] + 'raf': [] + 'control': [boolean] + 'fullscreen': [boolean] + 'fullscreenWeb': [boolean] + 'pip': [boolean] + 'setting': [boolean] + 'aspectRatio': [string] + 'flip': [string] + 'blur': [] + 'resize': [] +} + +export interface QualityItem { html: string, url: string, default?: boolean } + +type IconName = 'play' | 'pause' | 'volume' | 'volumeClose' | 'fullscreenOn' | 'fullscreenOff' | 'fullscreenWebOn' | 'fullscreenWebOff' | 'pip' | 'setting' | 'screenshot' | 'airplay' + +export interface ControlHost extends ComponentHost, SubscriptionHost { + template: { + $player: HTMLDivElement + $bottom: HTMLDivElement + $controls: HTMLDivElement + $progress: HTMLDivElement + $controlsLeft: HTMLDivElement + $controlsRight: HTMLDivElement + } + option: { + isLive: boolean + quality: QualityItem[] + screenshot: boolean + setting: boolean + pip: boolean + airplay: boolean + fullscreenWeb: boolean + fullscreen: boolean + controls: EntryInput[] + highlight: { time: number, text: string }[] + } + icons: Record & { indicator?: HTMLElement } + i18n: { get: (key: string) => string } + constructor: { CONTROL_HIDE_TIME: number, USE_RAF: boolean } + setting: { show: boolean, toggle: () => void, resize: () => void } + isInput: boolean + isRotate: boolean + playing: boolean + muted: boolean + volume: number + currentTime: number + duration: number + played: number + loaded: number + top: number + height: number + fullscreen: boolean + fullscreenWeb: boolean + pip: boolean + set seek(second: number) + set quality(value: QualityItem[]) + play: () => unknown + pause: () => unknown + screenshot: () => unknown + airplay: () => unknown +} + +export type ControlOption = EntryOption +export type ControlFactory = (art: ControlHost) => ControlOption diff --git a/packages/artplayer/src/control/volume.js b/packages/artplayer/src/control/volume.ts similarity index 50% rename from packages/artplayer/src/control/volume.js rename to packages/artplayer/src/control/volume.ts index cc834c407..972328e0c 100644 --- a/packages/artplayer/src/control/volume.js +++ b/packages/artplayer/src/control/volume.ts @@ -1,22 +1,26 @@ -import { append, getRect, isMobile, setStyle } from '../utils' +import type { ControlFactory, ControlOption } from './types' +import { appendElement } from '../component/dom' +import { getRect, isMobile, setStyle } from '../utils' +import { controlEvents } from './resources' -export default function volume(option) { +export default function volume(option: ControlOption): ControlFactory { return art => ({ ...option, mounted: ($control) => { - const { proxy, icons } = art + const { on, proxy } = controlEvents(art, $control) + const { icons } = art - const $volume = append($control, icons.volume) - const $close = append($control, icons.volumeClose) - const $panel = append($control, '
') - const $inner = append($panel, '
') - const $value = append($inner, `
`) - const $slider = append($inner, `
`) - const $handle = append($slider, `
`) - const $loaded = append($handle, `
`) - const $indicator = append($slider, `
`) + const $volume = appendElement($control, icons.volume) + const $close = appendElement($control, icons.volumeClose) + const $panel = appendElement($control, '
') + const $inner = appendElement($panel, '
') + const $value = appendElement($inner, `
`) + const $slider = appendElement($inner, `
`) + const $handle = appendElement($slider, `
`) + const $loaded = appendElement($handle, `
`) + const $indicator = appendElement($slider, `
`) - function getVolumeFromEvent(event) { + function getVolumeFromEvent(event: MouseEvent) { const { top, height } = getRect($slider) return 1 - (event.clientY - top) / height } @@ -27,7 +31,7 @@ export default function volume(option) { setStyle($close, 'display', 'flex') setStyle($indicator, 'top', '100%') setStyle($loaded, 'top', '100%') - $value.textContent = 0 + $value.textContent = '0' } else { const percentage = art.volume * 100 @@ -35,12 +39,12 @@ export default function volume(option) { setStyle($close, 'display', 'none') setStyle($indicator, 'top', `${100 - percentage}%`) setStyle($loaded, 'top', `${100 - percentage}%`) - $value.textContent = Math.floor(percentage) + $value.textContent = String(Math.floor(percentage)) } } update() - art.on('video:volumechange', update) + on('video:volumechange', update) proxy($volume, 'click', () => { art.muted = true @@ -61,14 +65,14 @@ export default function volume(option) { art.volume = getVolumeFromEvent(event) }) - art.on('document:mousemove', (event) => { + on('document:mousemove', (event) => { if (isDragging) { art.muted = false art.volume = getVolumeFromEvent(event) } }) - art.on('document:mouseup', () => { + on('document:mouseup', () => { if (isDragging) { isDragging = false } diff --git a/packages/artplayer/src/layer.js b/packages/artplayer/src/layer.js deleted file mode 100644 index eb4e8edb0..000000000 --- a/packages/artplayer/src/layer.js +++ /dev/null @@ -1,19 +0,0 @@ -import Component from './utils/component' - -export default class Layer extends Component { - constructor(art) { - super(art) - - const { - option, - template: { $layer }, - } = art - - this.name = 'layer' - this.$parent = $layer - - for (let index = 0; index < option.layers.length; index++) { - this.add(option.layers[index]) - } - } -} diff --git a/packages/artplayer/src/layer.ts b/packages/artplayer/src/layer.ts new file mode 100644 index 000000000..e450b9056 --- /dev/null +++ b/packages/artplayer/src/layer.ts @@ -0,0 +1,18 @@ +import type { ComponentHost, EntryInput } from './component/types' +import Component from './utils/component' + +export interface LayerHost extends ComponentHost { + option: { layers: EntryInput[] } + template: { $player: HTMLElement, $layer: HTMLElement } +} + +export default class Layer extends Component { + constructor(art: LayerHost) { + super(art) + const { option, template: { $layer } } = art + this.name = 'layer' + this.$parent = $layer + for (let index = 0; index < option.layers.length; index++) + this.add(option.layers[index]!) + } +} diff --git a/packages/artplayer/src/player/qualityMix.js b/packages/artplayer/src/player/qualityMix.js deleted file mode 100644 index 435fa6efe..000000000 --- a/packages/artplayer/src/player/qualityMix.js +++ /dev/null @@ -1,25 +0,0 @@ -import { def } from '../utils' - -export default function qualityMix(art) { - def(art, 'quality', { - set(quality) { - const { controls, notice, i18n } = art - const qualityDefault = quality.find(item => item.default) || quality[0] - controls.update({ - name: 'quality', - position: 'right', - index: 10, - style: { - marginRight: '10px', - }, - html: qualityDefault?.html || '', - selector: quality, - async onSelect(item) { - await art.switchQuality(item.url) - notice.show = `${i18n.get('Switch Video')}: ${item.html}` - return item.html - }, - }) - }, - }) -} diff --git a/packages/artplayer/src/player/qualityMix.ts b/packages/artplayer/src/player/qualityMix.ts new file mode 100644 index 000000000..735210d2d --- /dev/null +++ b/packages/artplayer/src/player/qualityMix.ts @@ -0,0 +1,40 @@ +import type { ComponentHost, EntryOption } from '../component/types' +import type { QualityItem } from '../control/types' +import { captureSelection } from '../component/selection' +import { isClosing } from '../lifecycle/instance' +import { def } from '../utils' + +export interface QualityHost extends ComponentHost { + controls: { update: (option: EntryOption) => unknown } + notice: { set show(message: string) } + i18n: { get: (key: string) => string } + switchQuality: (url: string) => Promise +} + +export default function qualityMix(art: QualityHost): void { + def(art, 'quality', { + set(quality: QualityItem[]) { + const { controls, notice, i18n } = art + const qualityDefault = quality.find(item => item.default) || quality[0] + controls.update({ + name: 'quality', + position: 'right', + index: 10, + style: { marginRight: '10px' }, + html: qualityDefault?.html || '', + selector: quality, + async onSelect(item, _element, event) { + const active = captureSelection(event) + // This callback is installed with the quality array above. + await art.switchQuality((item as QualityItem).url) + if (!isClosing(art) && active()) { + const message = `${i18n.get('Switch Video')}: ${item.html}` + if (!isClosing(art) && active()) + notice.show = message + } + return item.html + }, + }) + }, + }) +} diff --git a/packages/artplayer/src/style/controls.less b/packages/artplayer/src/style/controls.less index cfcbbaeca..1cc291306 100644 --- a/packages/artplayer/src/style/controls.less +++ b/packages/artplayer/src/style/controls.less @@ -6,12 +6,17 @@ display: flex; align-items: center; justify-content: space-between; - height: var(--art-control-height); + flex-wrap: wrap; + flex-shrink: 0; + height: auto; + min-height: var(--art-control-height); .art-controls-left, .art-controls-right { display: flex; - height: 100%; + flex-wrap: wrap; + max-width: 100%; + min-height: var(--art-control-height); } .art-controls-center { @@ -23,11 +28,13 @@ .art-controls-right { justify-content: flex-end; + margin-left: auto; } .art-control { .art-center(); flex-shrink: 0; + max-width: 100%; cursor: pointer; white-space: nowrap; opacity: var(--art-control-opacity); diff --git a/packages/artplayer/src/style/plugins.less b/packages/artplayer/src/style/plugins.less index 4e6d50d8c..85dd4bb36 100644 --- a/packages/artplayer/src/style/plugins.less +++ b/packages/artplayer/src/style/plugins.less @@ -20,7 +20,7 @@ padding: 10px; line-height: 1; left: var(--art-padding); - bottom: calc(var(--art-control-height) + var(--art-bottom-gap) + 10px); + bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + 10px); background-color: var(--art-widget-background); .art-auto-playback-close { @@ -55,7 +55,12 @@ .art-controls, .art-progress { - transform: translateY(calc(var(--art-control-height) + var(--art-bottom-gap) + var(--art-progress-height) / 4)); + transform: translateY( + calc( + var(--art-controls-height, var(--art-control-height)) + var(--art-bottom-gap) + var(--art-progress-height) / + 4 + ) + ); } .art-progress-indicator { diff --git a/packages/artplayer/src/style/setting.less b/packages/artplayer/src/style/setting.less index 03ddb0095..616cd0a39 100644 --- a/packages/artplayer/src/style/setting.less +++ b/packages/artplayer/src/style/setting.less @@ -10,7 +10,7 @@ border-radius: var(--art-border-radius); max-height: var(--art-settings-max-height); right: var(--art-padding); - bottom: var(--art-control-height); + bottom: var(--art-controls-height, var(--art-control-height)); transition: all var(--art-transition-duration) ease; background-color: var(--art-widget-background); diff --git a/packages/artplayer/src/style/subtitle.less b/packages/artplayer/src/style/subtitle.less index 1a0d596da..da90b3aea 100644 --- a/packages/artplayer/src/style/subtitle.less +++ b/packages/artplayer/src/style/subtitle.less @@ -31,7 +31,7 @@ &.art-control-show { .art-subtitle { - bottom: calc(var(--art-control-height) + var(--art-subtitle-bottom)); + bottom: calc(var(--art-controls-height, var(--art-control-height)) + var(--art-subtitle-bottom)); } } } diff --git a/packages/artplayer/src/utils/component.js b/packages/artplayer/src/utils/component.js deleted file mode 100644 index dbfea8711..000000000 --- a/packages/artplayer/src/utils/component.js +++ /dev/null @@ -1,120 +0,0 @@ -import validator from 'option-validator' -import { ComponentOption } from '../scheme' -import { addClass, append, createElement, hasClass, remove, removeClass, setStyles, tooltip } from './dom' -import { errorHandle } from './error' - -export default class Component { - constructor(art) { - this.id = 0 - this.art = art - this.cache = new Map() - this.add = this.add.bind(this) - this.remove = this.remove.bind(this) - this.update = this.update.bind(this) - } - - get show() { - return hasClass(this.art.template.$player, `art-${this.name}-show`) - } - - set show(value) { - const { $player } = this.art.template - const className = `art-${this.name}-show` - if (value) { - addClass($player, className) - } - else { - removeClass($player, className) - } - this.art.emit(this.name, value) - } - - toggle() { - this.show = !this.show - } - - add(getOption) { - const option = typeof getOption === 'function' ? getOption(this.art) : getOption - option.html = option.html || '' - validator(option, ComponentOption) - if (!this.$parent || !this.name || option.disable) - return - const name = option.name || `${this.name}${this.id}` - errorHandle(!this.cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`) - - this.id += 1 - const $ref = createElement('div') - addClass($ref, `art-${this.name}`) - addClass($ref, `art-${this.name}-${name}`) - - const childs = Array.from(this.$parent.children) - $ref.dataset.index = option.index || this.id - const nextChild = childs.find(item => Number(item.dataset.index) >= Number($ref.dataset.index)) - if (nextChild) { - nextChild.insertAdjacentElement('beforebegin', $ref) - } - else { - append(this.$parent, $ref) - } - - if (option.html) { - append($ref, option.html) - } - - if (option.style) { - setStyles($ref, option.style) - } - - if (option.tooltip) { - tooltip($ref, option.tooltip) - } - - const events = [] - if (option.click) { - const destroyEvent = this.art.events.proxy($ref, 'click', (event) => { - event.preventDefault() - option.click.call(this.art, this, event) - }) - events.push(destroyEvent) - } - - if (option.selector && ['left', 'right'].includes(option.position)) { - this.selector(option, $ref, events) - } - - this[name] = $ref - this.cache.set(name, { $ref, events, option }) - - if (option.mounted) { - option.mounted.call(this.art, $ref) - } - - return $ref - } - - remove(name) { - errorHandle(this.cache.has(name), `Can't find [${name}] from the [${this.name}]`) - const item = this.cache.get(name) - - if (item.option.beforeUnmount) { - item.option.beforeUnmount.call(this.art, item.$ref) - } - - for (const event of item.events) { - this.art.events.remove(event) - } - - this.cache.delete(name) - delete this[name] - remove(item.$ref) - } - - update(option) { - if (this.cache.has(option.name)) { - const item = this.cache.get(option.name) - option = Object.assign(item.option, option) - this.remove(option.name) - } - return this.add(option) - } -} diff --git a/packages/artplayer/src/utils/component.ts b/packages/artplayer/src/utils/component.ts new file mode 100644 index 000000000..596d2161c --- /dev/null +++ b/packages/artplayer/src/utils/component.ts @@ -0,0 +1,158 @@ +import type { ComponentHost, Entry, EntryInput, EntryOption, EventCleanup } from '../component/types' +import validator from 'option-validator' +import { renderEntry } from '../component/dom' +import { ownEntry, releaseEntry } from '../component/resources' +import { isClosing } from '../lifecycle/instance' +import { ComponentOption } from '../scheme' +import { addClass, hasClass, removeClass } from './dom' +import { errorHandle } from './error' + +const removing = new WeakSet() + +export default class Component { + declare id: number + declare art: Host + declare cache: Map> + declare name?: string + declare $parent?: HTMLElement + selector?(option: EntryOption, element: HTMLDivElement, events: EventCleanup[]): void + + constructor(art: Host) { + this.id = 0 + this.art = art + this.cache = new Map() + this.add = this.add.bind(this) + this.remove = this.remove.bind(this) + this.update = this.update.bind(this) + } + + get show(): boolean { + return hasClass(this.art.template.$player, `art-${this.name}-show`) + } + + set show(value: boolean) { + const { $player } = this.art.template + const className = `art-${this.name}-show` + if (value) + addClass($player, className) + else + removeClass($player, className) + this.art.emit(this.name!, value) + } + + toggle(): void { + this.show = !this.show + } + + add(getOption: EntryInput): HTMLDivElement | undefined { + if (isClosing(this.art)) + return + const option = typeof getOption === 'function' ? getOption(this.art) : getOption + if (isClosing(this.art)) + return + option.html = option.html || '' + validator(option, ComponentOption) + if (!this.$parent || !this.name || option.disable) + return + const name = option.name || `${this.name}${this.id}` + const cache = this.cache + errorHandle(!cache.has(name), `Can't add an existing [${name}] to the [${this.name}]`) + this.id += 1 + const $ref = document.createElement('div') + const scope = ownEntry(this.art, $ref) + const events: EventCleanup[] = [] + const previous = Object.getOwnPropertyDescriptor(this, name) + let aliased = false + scope.add(() => { + for (const event of events) + this.art.events.remove(event) + }) + try { + if (scope.closed) + return + renderEntry($ref, this.$parent, this.name, name, this.id, option) + if (scope.closed) + return + if (option.click) { + const cleanup = this.art.events.proxy($ref, 'click', (event) => { + if (scope.closed) + return + event.preventDefault() + option.click!.call(this.art, this, event) + }) + events.push(cleanup) + } + if (option.selector && ['left', 'right'].includes(option.position!)) + this.selector!(option, $ref, events) + if (scope.closed) + return + assignAlias(this, name, $ref) + aliased = true + cache.set(name, { $ref, events, option }) + if (option.mounted) + option.mounted.call(this.art, $ref) + return $ref + } + catch (error) { + try { + releaseEntry($ref) + } + catch (cleanupError) { + console.warn('ArtPlayer component cleanup failed:', cleanupError) + } + if (cache.get(name)?.$ref === $ref) + cache.delete(name) + if (aliased && (this as unknown as Record)[name] === $ref) { + if (previous) + Object.defineProperty(this, name, previous) + else + delete (this as unknown as Record)[name] + } + $ref.remove() + throw error + } + } + + remove(name: string): void { + errorHandle(this.cache.has(name), `Can't find [${name}] from the [${this.name}]`) + const item = this.cache.get(name)! + if (removing.has(item)) + return + removing.add(item) + try { + if (item.option.beforeUnmount) + item.option.beforeUnmount.call(this.art, item.$ref) + try { + releaseEntry(item.$ref) + } + finally { + if (this.cache.get(name) === item) { + this.cache.delete(name) + delete (this as unknown as Record)[name] + } + item.$ref.remove() + } + } + finally { + removing.delete(item) + } + } + + update(option: EntryOption): ReturnType { + if (this.cache.has(option.name!)) { + const item = this.cache.get(option.name!)! + option = Object.assign(item.option, option) + this.remove(option.name!) + } + // add is polymorphic: Control intentionally returns undefined. + return this.add(option) as ReturnType + } +} + +function assignAlias(owner: object, name: string, value: HTMLElement): void { + const aliases = owner as Record + if (name === '__proto__') + Object.defineProperty(aliases, name, { value, enumerable: true, configurable: true, writable: true }) + else + aliases[name] = value +} diff --git a/refactor/baselines/components-validation.json b/refactor/baselines/components-validation.json new file mode 100644 index 000000000..f43584498 --- /dev/null +++ b/refactor/baselines/components-validation.json @@ -0,0 +1,6354 @@ +{ + "task": "CORE-13", + "date": "2026-09-11", + "status": "validated", + "node": "v24.21.0", + "parentCommit": "9eb7c945cad7e68187362ed4ac8f836925c4b0bb", + "source": { + "packages/artplayer/src/component/dom.ts": "740f63e6e5942c444b9f05605880f8d56a77b066dbe5c4791da74f78cb96c668", + "packages/artplayer/src/component/resources.ts": "ff158ef0db8ba13343ff6ba329713820cfe2f5c2c446a7873a6cfff782855edf", + "packages/artplayer/src/component/selection.ts": "1f0bd089415da28db862647ffd1a0b4af752576465fb616d4b97ae4f8dcae3a7", + "packages/artplayer/src/component/types.ts": "d7b0e7008b0f6c82e3e97ac43e0188598dca4f740a860e7a60b3b38a46f4565d", + "packages/artplayer/src/config/index.js": "d6d2bd612daaf6c5c6e982158acbdf724b16d3c35bb5f1a5c923284665a8de79", + "packages/artplayer/src/contextmenu/aspectRatio.ts": "a25464e14216b2be392fcb3fdda2439e6d6f98d1962f0acbba30e3bd53bcb2d4", + "packages/artplayer/src/contextmenu/close.ts": "84b7a96df910e6f38140df8b1e73519d209a7331e9be9f42d076ae791757024f", + "packages/artplayer/src/contextmenu/flip.ts": "42c192d23e347d74e0bb814697a4d59eac20afbec102a282d5aa15780cab5f72", + "packages/artplayer/src/contextmenu/index.ts": "4fd292a931b5bda9f16a1c2bedd50cd0d8c0b8fb6010ffc5faaad2c197d2d9e5", + "packages/artplayer/src/contextmenu/info.ts": "f37cf0104510c13a130d2f55114c8f7ff15cc1b51863f97e60825442bdb2bf01", + "packages/artplayer/src/contextmenu/playbackRate.ts": "e177f4017ea9291794fb4023715c81bfc01f927324ab9bd0e32c741e4a3b0ca7", + "packages/artplayer/src/contextmenu/types.ts": "a93fc90f4e17b731e8f6b486a507117810b61c1f1b0d9e775eba27dabeaeee1d", + "packages/artplayer/src/contextmenu/version.ts": "0553a716be0ba49f614059c41eef6dc694a9641fca79e6448b1b30382c6b582b", + "packages/artplayer/src/control/airplay.ts": "a02ab41654a963e06fb2eb206cfe606cebc27252ba00b3fc2116ea232c8d7d51", + "packages/artplayer/src/control/builtins.ts": "2a0e12a9741713c92938e1d2009149bbbde498284aa85c63f270d02b27dc22b1", + "packages/artplayer/src/control/fullscreen.ts": "6856d98530877b9458275d8e064a94a81b9e2a4de079cce1a83e7cbe71e5ab8b", + "packages/artplayer/src/control/fullscreenWeb.ts": "e20f8fe9788738adfccb21e7bf248e5e8068312e856bb2626d05fbb20cfdb65d", + "packages/artplayer/src/control/index.ts": "ce23b79a0a40f22bdd8ad5f461d6b0df9366c7e4ab78571e0c67649f6e6d38e7", + "packages/artplayer/src/control/layout.ts": "b5134a9d0cb5ad128b1fb229dce79a306b944f750d8620e224a99f5791e6cab5", + "packages/artplayer/src/control/pip.ts": "9299d785ce21b16dc9edbcb6a803f8748157ed16e1924f461bdbc4853adaa5ac", + "packages/artplayer/src/control/playAndPause.ts": "e65461f5bf29680f12b7e0efa7d44186f07bbe9936247a9a220f724c9d9774bb", + "packages/artplayer/src/control/progress/interactions.ts": "19d6f73c21f75daaef109247bee392d82b46fecffd04be0944386c307496b250", + "packages/artplayer/src/control/progress/position.ts": "1008c5129097cd2c51fefb56e88e9df6fa07f09ed5f4492505da9153d8284cd1", + "packages/artplayer/src/control/progress/view.ts": "60ee16d5170be81b8132bb56dd0bc0eaf23e50f5c268d0697c9187b38a14aba9", + "packages/artplayer/src/control/progress.ts": "f0876ddbdc01f812a5a776bdeefdff8dc52e557aff684f99b5ea7f6bfc8c0fb3", + "packages/artplayer/src/control/resources.ts": "16fd7c53ac8f47b333041c4f298313390dc102523d47767b8a16f39a2564ba74", + "packages/artplayer/src/control/screenshot.ts": "430dc1b0283bc8a5c5396539b291dce1197470611696b32fde4b2c56d2db6b1f", + "packages/artplayer/src/control/selector.ts": "5d946c36d0308f32e08dd0e189f0c959f738ed7ab521230833c76a5bf9ca6478", + "packages/artplayer/src/control/setting.ts": "63e9824ffee2221ba82be9f2bc430b9b3133a2186905fcce2a61b8aa946a3d8a", + "packages/artplayer/src/control/time.ts": "fa572092e0848878689367fb536e9658d13888d0a0d476babc5acd165af0f8d3", + "packages/artplayer/src/control/types.ts": "7fab47c7106efa51aae89026af335f74d9f3ea52ef9864ec2801d0ea2deffc4c", + "packages/artplayer/src/control/volume.ts": "b50d1a5d2697d6440ac0f3d82634b13f7c2fff00c185a1adf4451ed8ba810709", + "packages/artplayer/src/events/clickInit.js": "bc680c921a958c25705962577513677d5d97de94e4eff6a04ba20d2f60e6a1be", + "packages/artplayer/src/events/gestureInit.js": "a5dcdb4216c8e3544fc85a1b4d3ebd929ec6f7d51ab17f2cee713030ae7ad464", + "packages/artplayer/src/events/globalInit.js": "5d8c3147f17755b0d35504cfc69cf8cbff510b66b2a52686d8f2a235a6c5b9df", + "packages/artplayer/src/events/hoverInit.js": "7ed5666e01972dc0955d1c1b4006001c99dd55ed133ca026f685b71d6b4d01c6", + "packages/artplayer/src/events/index.js": "94ddb9ad5ceb21901fbbc974d983fec60c488314474c89138e4ab2b40e205d5a", + "packages/artplayer/src/events/moveInit.js": "782d627260c9fdf46c0766876138f05836860bc9c2fa2c519d22b43f3d24de15", + "packages/artplayer/src/events/resizeInit.js": "26fc9628490e6c45ef741e7bc7c1353097b21da1dc83aae65dc80783226e36bc", + "packages/artplayer/src/events/updateInit.js": "1b4ef85c819ae68eb0de1791241b2c3d4e22bb108746518fa67f7c322591e55a", + "packages/artplayer/src/events/viewInit.js": "2b4ce508812b8f03cf5801a5e3a7eaa4a5a8b05d6be500d217aeb6231fb93a51", + "packages/artplayer/src/hotkey.js": "689fb87b2ed8a424cbc2880c8f70610b3695dc5b0346c9a5833699996682c0d6", + "packages/artplayer/src/i18n/ar.ts": "c1e41787c700096ecbc91de6558353f43d8930929ee312b7aa2c7da14a07ec75", + "packages/artplayer/src/i18n/cs.ts": "62c5ffcf3ac24e0dc2d7222b7ebb2b4d3454e9c04b80930a50defb3867d645be", + "packages/artplayer/src/i18n/es.ts": "5d31184b41ef29c1544c91ff08e3bbf9fc5c5776f0af0aa0238f90a9d161b9b1", + "packages/artplayer/src/i18n/fa.ts": "1294b91178ebdc7bc26d14a6f407ba8598207ae0dc812f3b821b62b7bf0089e5", + "packages/artplayer/src/i18n/fr.ts": "7125c0011b90f507d5b5fe20afd875992b62af9cdd44f02bbabed051c4ebc107", + "packages/artplayer/src/i18n/id.ts": "0d2e79cc0118cff6be83786a3fc048461785a64bdffc6bc45ffb68cb595f6da4", + "packages/artplayer/src/i18n/index.ts": "09c6f5bce58e4118dde10e8b2a2d3808785b7fde913a54dd189e0b473e21266a", + "packages/artplayer/src/i18n/pl.ts": "f6fb58a0d3fa118e22cfa6df5edd74c7bf39dc9ff1d416fb2b01e1bb8708b06f", + "packages/artplayer/src/i18n/publish.ts": "5b216bbe313b3cda56a5da41fba4fb9d095eeec0dc903fcf284ddd8f94926e99", + "packages/artplayer/src/i18n/ru.ts": "473c43197acec10991b0f67814f79421dfe9ec4f534fb15413a32cf2a4d8ad38", + "packages/artplayer/src/i18n/tr.ts": "7b6afbbe452c4907c8bef36663bd218fd140bd1a4b3c776f31c53415e78e8f16", + "packages/artplayer/src/i18n/vi.ts": "29ea7f23d7400c847596632c86a4ca10c39cbafe1e6d723ed099b819aca7e764", + "packages/artplayer/src/i18n/zh-cn.ts": "22584521b0aa92da5278b01581e6e8e5bb3a23a2c3029e9df8642b7f0bded392", + "packages/artplayer/src/i18n/zh-tw.ts": "8da94a4fd508176bbb6b7ce2f4ba6ef6a56e7b1229bc67cc42d1a7bde70a7e9d", + "packages/artplayer/src/icons/airplay.svg": "8c75a40f1bfacee2be2a425e132ff51f3712eba60679010f7b1349d4a04374bc", + "packages/artplayer/src/icons/arrow-left.svg": "8b9d544b7bd728d01747005fc7a2d63f822eed3b605393e2435b6733861b585f", + "packages/artplayer/src/icons/arrow-right.svg": "68c63d6d5810173ec9192c9e96ee7b6aefdc3b79d3c1329fb4d6c750f859fe10", + "packages/artplayer/src/icons/aspect-ratio.svg": "987752a87701523057d8dfa7c45a6a139c4542b96fdcfaf8665722bbeb41f3b2", + "packages/artplayer/src/icons/check.svg": "963ce0aee2337fdee951aa6c917cc75ee0b4e75158887ccc16baebfd3925942b", + "packages/artplayer/src/icons/close.svg": "ebabfe8044f48d5df4d13f4f906a163fd55a4d6f1dedb3b5ba95601209bc8888", + "packages/artplayer/src/icons/config.svg": "e1884d5411296b5cd1bfec7803b558b0afa5ab64478393977b07a662e2e0f15c", + "packages/artplayer/src/icons/defaults.ts": "31df862d754922fe5d68b20911c477d7c22893a6a67b5dcb1a48d3b437a0b23a", + "packages/artplayer/src/icons/error.svg": "b40c01e511a599c9dd369aeb9a3b2a0d1a76ef3c5ede8124cbbc23f8e4e7248c", + "packages/artplayer/src/icons/fast-forward.svg": "abef6fe4d75ffa74d3a84683373b4702a4eda2a5b4045952f969ee62cc68b0be", + "packages/artplayer/src/icons/flip.svg": "474a9d53a97add71e3fb7bc6530a68580ce63a1d83f9b75d1c2908a7cf494152", + "packages/artplayer/src/icons/fullscreen-off.svg": "71125ac56586897e2c0e52035a4d65cff34cf52043a95b45d186e0d268671399", + "packages/artplayer/src/icons/fullscreen-on.svg": "d46cdf265cac729c9b7382722ebe7a4c76d71ad4e5a27c2d5ed8323fd595ebf5", + "packages/artplayer/src/icons/fullscreen-web-off.svg": "52a6862ecd7cba12ab7042de5064c498bc2e9f86b430358c912401fafe4f4a98", + "packages/artplayer/src/icons/fullscreen-web-on.svg": "5cfaae62b61456251e771bff01356fad8376ebedb10a4b8819740f60e6e5a073", + "packages/artplayer/src/icons/index.ts": "3ef720aee403e6b7baf1ab472dbdd16c671f2d691ecea48ff1c25ca1ffc66296", + "packages/artplayer/src/icons/loading.svg": "485472153890eff3ed49963f7bf7d841f66ca2f40894c01d6e8bcf1bf4ad1c58", + "packages/artplayer/src/icons/lock.svg": "431e9a25fae051016be0efa286387ec3e5f7651c3ecf569bf0ece9842f57156c", + "packages/artplayer/src/icons/pause.svg": "57405dba81dd3d9f329d957fdc704101cbb6f6654325eb0083c03324c4453a68", + "packages/artplayer/src/icons/pip.svg": "1e922140e0941e5b9ef53dc0b4776813e1c470ea229fe3ec786fd148148c3352", + "packages/artplayer/src/icons/play.svg": "41a961c629a55cb25a813e115a25204e492d4e935a0879177e65d6e1ddfd6796", + "packages/artplayer/src/icons/playback-rate.svg": "872deecac0365ab04aeb5ccb1cdd9a0c88589a1442709fdac7c0ed12a241ff2b", + "packages/artplayer/src/icons/screenshot.svg": "538b5cd0c6b20afb98bd850e15019072d652d191075c2869f2fc0f28b597b131", + "packages/artplayer/src/icons/setting.svg": "2976b00d1f03e78f28d0e55ebcb01d5a0746ec1a6ff8de97a5e8294bacdd1fad", + "packages/artplayer/src/icons/state.svg": "620a127f74bb5e249993bd7008c027373263eacb4a44af8adeaa0d7523346887", + "packages/artplayer/src/icons/switch-off.svg": "95a8d81a4a3bfcf7c016d5f71d46a72be73c5e94790c55fd1d31023416ef5deb", + "packages/artplayer/src/icons/switch-on.svg": "cccd0f9c1e54d9ac50c323360da944d8ff44633a82ff17889914b6bc8b1652ae", + "packages/artplayer/src/icons/unlock.svg": "fc058db3d99a475fb9ffbbbb6248978a95990a9c532b83d0955ac28eaa626c60", + "packages/artplayer/src/icons/volume-close.svg": "f7e100fd9e9f3f6e06afe5bc994d5d9305ee4d1ee23fae37e4108cf286dab379", + "packages/artplayer/src/icons/volume.svg": "3a78f40d8b48595e8f15d9189e4d767e0c7abbf0338d3f2db1ac810049dd3942", + "packages/artplayer/src/index.js": "cb874ac34fa650bd364b3fef7eed4830bf3bd47093097ae7ba0432e7e64b1a10", + "packages/artplayer/src/info.js": "6dcdb4457d63ddb74fb6268df64522722420d6c0eb7b1654d6fb7703466d3b8c", + "packages/artplayer/src/layer.ts": "4014268eed043d5dd7b925cdeef6245e357cda67192a1301c5612ef98cdbec12", + "packages/artplayer/src/libs/screenfull.js": "2332b50c0c6364d5c99080be0f5739255e4b9e465d2cca40f761adce9a1908f8", + "packages/artplayer/src/lifecycle/instance.ts": "19a89de4ae22cb57eea7302265ce07422d12d1aea5acb99deb44fd0dba351a13", + "packages/artplayer/src/lifecycle/resources.ts": "399ea5e84545c973f8967e8ffd7326dad7b3168ca6f96f77286995a5b62ee389", + "packages/artplayer/src/lifecycle/scope.ts": "e2188e8544b27cf8c7ac149e7146af628a2d6166c82b719a247adef5d85be5db", + "packages/artplayer/src/lifecycle/template-rollback.ts": "7a83da6739bcec1587b02f8157934988910d7f9103fe489a0d6f4f65290c3d77", + "packages/artplayer/src/loading.js": "4b08a8f9fa69f71d054cdf1508bbb9e92c075c8df1eda0fa8a79efbf08eb8c40", + "packages/artplayer/src/mask.js": "094162e28ec76c81f73bb7bfe276bf5832080ffb7aa9d9dc9dc013479659c2e5", + "packages/artplayer/src/media/events/forward.ts": "6b1b7e80036bfb523b51843dc6ec6d83c2b949cefb9cef085b2d679a444e46d8", + "packages/artplayer/src/media/events/listen.ts": "4eb7e943c1ebca77da8025d83b7d408276187cd02860b7793284344378bd0fe0", + "packages/artplayer/src/media/events/playback.ts": "2c68e4f6274a0dc65e56d42c928e500fc1d63bf3e03bbdd8a83c3f3ed7ae8ee4", + "packages/artplayer/src/media/events/readiness.ts": "3ba74f26dd9ff0729967097c2cb6f329a9cea57745bfe8173f9173e0d134476a", + "packages/artplayer/src/media/events/reconnect.ts": "876027b5116d0d3628755705682b30630f4b713199ed8015541932d81d2944be", + "packages/artplayer/src/media/events/types.ts": "5532f57129032a9685305d0d319543146c3e8af134ac12c8aa521cca9e83a6c2", + "packages/artplayer/src/media/hosts.ts": "7129cb93290a250e932464b71a4e4abce8a98e83935d4fd6c36a59fc6357b6af", + "packages/artplayer/src/media/playback.ts": "b0e8ae22f2660249361bf05bb2333685e14f5a7ac3e9ba0c62ee7efd38338b93", + "packages/artplayer/src/media/types.ts": "96d4a7f066cbb6fb9138165dd736b4ca500cb19c827bd7702134d61c44cc0e87", + "packages/artplayer/src/notice.js": "72e97833e0499993d8d133111e32f32f031b911426117397be2003e824023664", + "packages/artplayer/src/option/defaults.ts": "f357ef80cf32085fcbc3409d92dfa27b31c13fbcf823f576052c0347911c0cca", + "packages/artplayer/src/option/resolve.ts": "53a73627cd540e3f21349c0a43beda35ea5195647a31e3f5b30ac292390b4b1b", + "packages/artplayer/src/option/types.ts": "f2ce01c01acf45fac6cbb34685b8e6c321bcad6b0da2526f3f189eb5962ea0e5", + "packages/artplayer/src/player/airplayMix.js": "b9ce49489e75045b6a1df4d8ed28f123c1b105ac4c04fefaabcffe4353ad004d", + "packages/artplayer/src/player/aspectRatioMix.js": "c0a4cbd84bd0d70f078d87fc2ed082ee81fd33eed12b6265fa2d6f043b8f0f97", + "packages/artplayer/src/player/attrMix.js": "c873d587ff71e024cfda5b5464d0c70a09a6a319da3f18fbaa7451a16c9ae055", + "packages/artplayer/src/player/autoHeightMix.js": "e7400a46eeb01416d5ac7c6b787295cd9b9f90b38ce640a737ef5a34a8affd6d", + "packages/artplayer/src/player/autoSizeMix.js": "341e8c6a6a1b451c43f758a7774d1cd6cdf9e1f9e818692e03eb58c2fbda4525", + "packages/artplayer/src/player/cssVarMix.js": "93e641dd760e8f844a643a0b7d8af92b73a7f205e55087d9501934d218701bd2", + "packages/artplayer/src/player/currentTimeMix.ts": "78c749ec4dc94f4a3a0ce02a87156f07894401b64d12c6c7c3cb1192ff266902", + "packages/artplayer/src/player/durationMix.ts": "60a9d665cf302dcb6b3e37e2f057e31720935e5e588fd7709231f691f6014191", + "packages/artplayer/src/player/eventInit.ts": "a915c5a618e70b1ab10536b1273ba0fea4ec11d3a2ca629b538e90b5ad2b55f9", + "packages/artplayer/src/player/flipMix.js": "f5abb8d079d0a9c4f9eaa31c4940723bf407ba422ac713dc73443dfa6cb6ac4f", + "packages/artplayer/src/player/fullscreenMix.js": "fe28104d9b3ab5f197204b69950b14c274d17b7a918dc9c45f749884f2e41cb8", + "packages/artplayer/src/player/fullscreenWebMix.js": "85f8800b4ed9027cdfdf79387b2dc95ed130fb03de267b85ac37badc15967661", + "packages/artplayer/src/player/index.js": "c3eaeab0aa5015a51dfeeb4de6f25b02b8cd66e1f8471940367d628b5fd0bdec", + "packages/artplayer/src/player/loadedMix.ts": "6a4c4a08ed74346dad3e138b1dda22c8c9c12f175fe6d00da41b89c78cbe2c18", + "packages/artplayer/src/player/miniMix.js": "7355a66a23de47be91ab08dd28e8d54116aa2a603bd47b687014e4ab4736094e", + "packages/artplayer/src/player/optionInit.js": "9d1d9d276da2403a580498c62f947373e000d9cd6e4bef5831d272c3055b5592", + "packages/artplayer/src/player/pauseMix.ts": "5bbb68eab7dcf2170c944cabb8d4b82be4e6d7623e37ad6ea464b81c1028bc0b", + "packages/artplayer/src/player/pipMix.js": "15322751e235a70e6f9dc4d5e2b6b0ee6a8b93080370c6a90cd96268e101a8ab", + "packages/artplayer/src/player/playbackRateMix.ts": "e185c6ff52cd567f7fd7c30553bbd6c65517324d1d16c4948c3623ef457ef536", + "packages/artplayer/src/player/playedMix.ts": "5b6b89bf8dec1efb19cd51e46af1505bae006bdb3fb798e9dec7e3fb5cf0acaa", + "packages/artplayer/src/player/playingMix.ts": "968c9f6e6d23c233c77d62a593db64adcc6d1a2411f5f1c61a35c6996d6a54d9", + "packages/artplayer/src/player/playMix.ts": "60249fcacdc5b1bc6f33bcd806e8a4f5472cea21d40550b042794a75027fe34a", + "packages/artplayer/src/player/posterMix.js": "a96b0a9f5817919e373a5a55b43fe7ea94af357051c01ddd6ce9c68bc932ecba", + "packages/artplayer/src/player/qualityMix.ts": "8dfcb94f695cf983f313f00abe1aec183ceb2af4b398fbf62bf1d114257a8f43", + "packages/artplayer/src/player/rectMix.ts": "a741ee09fa3271df84363c5d73eac1b2e5adb39491f95f8112af81f1219ffed4", + "packages/artplayer/src/player/screenshotMix.js": "c64871270b224233ea67ff31c3fbc0c2e2eb35635da5e4d5a263b930fb96e6e7", + "packages/artplayer/src/player/seekMix.ts": "e6e1bf00e8441f1ce58d2a67a66f7e5e98c86d78620ff10a5e6268d54f13fadb", + "packages/artplayer/src/player/stateMix.ts": "e45b3209a93ab14665d19c5740d5c632187e9fe234b019a2a0263e26884ab3b2", + "packages/artplayer/src/player/subtitleOffsetMix.js": "c0ebf552e025dc5ede6ff3e5c2a82ff3382610268130941e5f56746568ac5baf", + "packages/artplayer/src/player/switchMix.ts": "b47e174ef0edb2b96ff29f2ddd3c9f2dd2a38713db2a81002b18c89ce71994e9", + "packages/artplayer/src/player/themeMix.js": "382acfaf113fbd1ee77c63dba72953d984ea715f2d99748a12b9eae70c081d49", + "packages/artplayer/src/player/thumbnailsMix.js": "43bdbd9b62a803f4966103c6718305a9ef665d25df26f735d3e34558ddf339bf", + "packages/artplayer/src/player/toggleMix.ts": "a3050136248e7d0b942387484c61286ac2b33a90724b1dc3460f5061be76f247", + "packages/artplayer/src/player/typeMix.js": "70920c8f785dca6d4bd66d82b996c37f1b69265190d7747ae8de298afae3604e", + "packages/artplayer/src/player/urlMix.ts": "23ee05577af66e3608f9c6d63f060bd3de68a99b1992e4e35e45f16a08a8c14f", + "packages/artplayer/src/player/volumeMix.ts": "d830bb27b984e0ab2f687943fb49abcbd0331d71fe96049fd81edbddaa64f07f", + "packages/artplayer/src/plugins/autoOrientation.js": "6ceb81bb3a778323f88ecaa78ef5646b642dad3f7d3176031c4ce53815a8d153", + "packages/artplayer/src/plugins/autoPlayback.js": "26f4a21691a2b2f767304b7d2fe40a35c599575651b9ace0c55a709a2be279b8", + "packages/artplayer/src/plugins/builtins.ts": "4b9f83959ebaea9991636ee670c3344a5ede5990d1631177ca470ecc156ddc67", + "packages/artplayer/src/plugins/fastForward.js": "d1f396efb22a279f9450fd02f85dc2245d274dbf0d36c99e87a5e5f895cc0029", + "packages/artplayer/src/plugins/index.ts": "28d13abc95cbedafadae0fdb682bf86fda9b705191c51843943a5dadddbd0a53", + "packages/artplayer/src/plugins/lock.js": "843caf8c7981463e8dadf1510cd028e7e70049f5a10038bd66dfccbc63bb7886", + "packages/artplayer/src/plugins/miniProgressBar.js": "3bf48d30c209105a0144c17062d6ea4e2bdd351b1bc928df73ea1680b78462e2", + "packages/artplayer/src/plugins/registration.ts": "9891686c32aeaa33c48ca500cf30ab24ffbb0835c6248769b4c645a5ff20129b", + "packages/artplayer/src/plugins/types.ts": "6823098d5ec1bf053f60ddfdd36bfcd3f06f3b528cc5dd30fd676a1318dac590", + "packages/artplayer/src/scheme/index.ts": "dc4a3b5e08478cf72b46b0b59c023359ad5f79b891ea8a6a119ce24a5251821a", + "packages/artplayer/src/setting/aspectRatio.js": "c07e382eb4a2dd29d6bbf5c697274809777bd72091239e108ddc3ca15b60fa64", + "packages/artplayer/src/setting/flip.js": "d9972868640ec6ad1e6600aa97ed8cf75702552ecaafed49f16002939fd8f832", + "packages/artplayer/src/setting/index.js": "9c16ee2161e100e0223d2878ffc40dd6b410afa35acd5b1908d18242049f9675", + "packages/artplayer/src/setting/playbackRate.js": "063e196324bd6f0e0cd841292b70f469593949073b60c9999b250addf1208e81", + "packages/artplayer/src/setting/subtitleOffset.js": "d1a18118c34e6121dd030e464bfe9047330ea7a60a83045aa762272d0b4b455f", + "packages/artplayer/src/source/listen.ts": "c0596b98258c1544c8e4b762509646428450e56588da36908cb8583b8b716c37", + "packages/artplayer/src/source/operation.ts": "a6cb65594a5b28247e3a6889fe0a2f47a34aeb08cdde5f0125800a87862cd559", + "packages/artplayer/src/source/switch.ts": "697ab56a765f957e3ce1da076c69cfc11dbf0901efecae0199cd94c729e0b236", + "packages/artplayer/src/source/types.ts": "9456d3d2f798188b730d99ef015e8a0a145598b0fe3ad1036b84f4a7cc1c5e6d", + "packages/artplayer/src/storage.js": "92067265b7f1104c4680e27e35726cf033811c6551e7c38d66028f2dd5300491", + "packages/artplayer/src/style/artplayer.less": "4e8513138d5d10c05b66986977d24ed17f1de3c0df3816dec6d90db7a97b5da3", + "packages/artplayer/src/style/aspectRatio.less": "091931a0cdc83e65a669332811ef3276b85bca9e55f7fff42aa46893d728c1ef", + "packages/artplayer/src/style/backdrop.less": "6c2cd0fa200d1f3525df98c3c56dbdc553445724aece3feb0386949245813343", + "packages/artplayer/src/style/bottom.less": "6fb307d8449fd04b804d5e72ea0f175f8aa9c9dd2bf1efbf756f800b39ac97ab", + "packages/artplayer/src/style/contextmenu.less": "70f6c7e26dc96652b659c7bf6fdad92737ed477dea69d253c57dc7266c76586d", + "packages/artplayer/src/style/controls.less": "eb6d4bf4e4ff903d724d45f3ff60f0cf10c02e622fba195555a8179100cdce87", + "packages/artplayer/src/style/danmuku.less": "e4215ee9fa2f1d0599e7311a2415cc975138265b7c6af0448d27d21b6c9e3511", + "packages/artplayer/src/style/flip.less": "5d3c7a81df9be455c2f683ebf48f39597d218dc2144addacb72ee1736bac3b7f", + "packages/artplayer/src/style/fullscreen.less": "dd350d3a0fc556d59b622a53c786b8c2a583e8fb28176e4b9e91baff90479496", + "packages/artplayer/src/style/fullscreenWeb.less": "d74e785c2fbbb2976e131620e751326f622f2916eceff9f2333059ca3296cdc9", + "packages/artplayer/src/style/hideCursor.less": "09a4607c8b0005dc199828172aa8dda395f861e407769b9696d793476c4a7823", + "packages/artplayer/src/style/hint.less": "ae9f3115dfdb1e2d7b8249497c080e6a25f9667f915f6e89820338d67bbc2d85", + "packages/artplayer/src/style/icon.less": "52d8f75c1d193e6160f57ca6997c3f9135adad8eb2338ed60c1eb8e5fe443be5", + "packages/artplayer/src/style/index.less": "ec67999b458d5545a4f17eeda922872823d655da012fa69113902629ad847548", + "packages/artplayer/src/style/index.ts": "856afc037ffcd4d18c4b54901ddbb30e310014553fe9d19560e34fb54b8378c1", + "packages/artplayer/src/style/info.less": "fa56d1b8c8936218e581b2426026e4ba85cd5fea20d045c4f69aca96be4059be", + "packages/artplayer/src/style/inject.ts": "9cddbe51b5de0da74f27c045ab982b509c3854cc6b81eeb02a6b974914760a4d", + "packages/artplayer/src/style/layers.less": "9653c581190bb22d60a706109819cd010908898740701c9526957b5682991c5f", + "packages/artplayer/src/style/loading.less": "185b0f05274196ba71fdb1d088b55af568f3342a495490c99c3f0e058a40659e", + "packages/artplayer/src/style/mask.less": "d1239a171b71ea6184cb4aee6660d74d6ffc0c48f7c47c3cf5fbe52d2e93ac92", + "packages/artplayer/src/style/mini.less": "a352e7a63f9529f18e6e389202fc277c500bc70acb38c7aa6eea9d7dba831c0f", + "packages/artplayer/src/style/mixins.less": "c6be95aa682f266749fe37cb89796fbec6488abc537174f817da79bdac6e00b5", + "packages/artplayer/src/style/mobile.less": "ff3f64fca5d2dd7ddd50385d88d9b2fa1a645909488ab7a0978ba4f1670b7c0e", + "packages/artplayer/src/style/notice.less": "72a935c0effc557a9d7ab3baccb2c3b77fc3a1783450b4e3178a40a5325fe369", + "packages/artplayer/src/style/plugins.less": "589d05e12a62e04fe848b36ba748433d23f0b909a04e861b1d6737f2799be183", + "packages/artplayer/src/style/poster.less": "36b38fe138f8c9537ff4e93f7ec4f2dbdba1ec41d243d741ddf1da7c6581e546", + "packages/artplayer/src/style/progress.less": "59b9d95d49dbcb1be40752d7086239b6de5925b0574da231199d999e22ff4990", + "packages/artplayer/src/style/selector.less": "295012ba379a7e957a24476616a0c3623d6a06e82ebbdaa45b916dd6412d7f4f", + "packages/artplayer/src/style/setting.less": "95f9d690c9be46a5cd29dacf98a802c1079282a4101a407385ea7be3bfc362c1", + "packages/artplayer/src/style/subtitle.less": "273cacb63ec0214ba434dcf19a4a455dbbdd408fb2d1749de4878804c1371e41", + "packages/artplayer/src/style/variables.less": "703739b2bdfc77bfde063d8788ef6b6a55b8730764baae8e7d755b7c54d8ecc7", + "packages/artplayer/src/style/video.less": "b89c6f6e27592d49825c68c9ab98d46e81cb1e5add855863f89d19637f98e35f", + "packages/artplayer/src/style/volume.less": "a3954794a9478d3872202b90d349c873cbb51639dcd7d1e3d73a55ce635fcd99", + "packages/artplayer/src/subtitle.js": "7f926d99cc581f38804a9400bfe7159d0c4ef4c15c887811f9443bbb5ae7dd20", + "packages/artplayer/src/template/html.ts": "351c472bfd01fa5ba1a4e347ed31bd5faaf823d9b4c5cab1ce8c651e3b175021", + "packages/artplayer/src/template/nodes.ts": "1572746a636647e4d313cc8752d3a110ff81fddb390ad7b0feb6a0db0d42b9d4", + "packages/artplayer/src/template/types.ts": "23f67e78ee43f9ad9099c94f28e51c6113b167603ffbbcf2d6ca2b68cc40b803", + "packages/artplayer/src/template.ts": "05c1499adc5dce27addf5761bec58d803f526d9b5b62c367c631e4cf2991391d", + "packages/artplayer/src/utils/compatibility.js": "51290838ef62be8e4251f4db8ecdd45a626cecd8c732e4e53a1c55df8d454a13", + "packages/artplayer/src/utils/component.ts": "d04a66213406ae3223326c2d470363e197dd1540519caa632f9d06378af989cc", + "packages/artplayer/src/utils/dom.js": "a625a0d832f717fbdf186099d1ace1f0dd51f1ea871417ffa856a7186206fb91", + "packages/artplayer/src/utils/emitter.ts": "26a93d3ff35b53e71a5f3bb22c252a854559d8151ede50a66a28d9eefae6c008", + "packages/artplayer/src/utils/error.ts": "ba303c7d4e4228919088f9d608fa364596f5853ee646eda2008deee354866f38", + "packages/artplayer/src/utils/file.ts": "ea71d7fc0e818d473bf5a596211ba9d571e4febdf1878014eadefa8d0a98d4cc", + "packages/artplayer/src/utils/format.ts": "891df5b7542b713aef46bf2b93924f42e68eee574afd802db3e6c62ff2655ede", + "packages/artplayer/src/utils/index.ts": "5211af833dddb2937d25dcc772740d62f9d5c5039ce5505bffff0796d4afd756", + "packages/artplayer/src/utils/property.ts": "c737d4582a4382f4038d12dafdf8b43418e508c9b8b859b2f0cc17c20f370343", + "packages/artplayer/src/utils/subtitle.ts": "f058851d11a418e321a8a498472b67fa535fec2c7b5d3df739b6b4f263d00337", + "packages/artplayer/src/utils/time.ts": "b8ce3d50865f6c343e8e3ce9f5c87de565a87b4e9fbcbccbe7030e30e80b93fe" + }, + "initialSeekObservations": [ + { + "engine": "webkit", + "status": "failed", + "value": { + "beforeSwitch": { + "time": 0.0027273, + "seeking": false, + "paused": true + }, + "mediaEvents": [ + { + "name": "seeking", + "time": 3, + "seeking": true, + "source": "http://127.0.0.1:8084/test/pattern.mp4?custom=initial" + }, + { + "name": "seeked", + "time": 0.0027273, + "seeking": false, + "source": "http://127.0.0.1:8084/test/pattern.mp4?custom=initial" + }, + { + "name": "canplay", + "time": 0.0027273, + "seeking": false, + "source": "http://127.0.0.1:8084/test/pattern.mp4?custom=initial" + }, + { + "name": "loadedmetadata", + "time": 0.0027273, + "seeking": true, + "source": "http://127.0.0.1:8084/test/pattern.mp4?custom=next" + } + ], + "calls": [ + { + "thisIdentity": true, + "ownerIdentity": true, + "videoIdentity": true, + "count": 3, + "url": "/test/pattern.mp4?custom=next" + } + ], + "restart": [ + "/test/pattern.mp4?custom=next" + ], + "time": 0.0027273, + "rate": 1.5, + "ratio": "16:9", + "paused": true, + "error": 0 + } + } + ], + "nativeRanges": [ + { + "engine": "webkit", + "status": "failed", + "value": { + "buffered": [], + "seekable": [ + [ + 0, + 8 + ] + ], + "readyState": 4, + "duration": 8, + "currentTime": 0.2850583 + } + } + ], + "confirmedSwitchPositions": [ + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "chromium", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "firefox", + "status": "passed", + "before": { + "time": 3, + "seeking": false, + "paused": true + }, + "after": { + "time": 3, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0021623, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0021623, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0014676, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0014676, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0028816, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0028816, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0005005, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0005005, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.003517, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.003517, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0017471, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0017471, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0034428, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0034428, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0022116, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0022116, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0022345, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0022345, + "rate": 1.5, + "paused": true, + "error": 0 + } + }, + { + "engine": "webkit", + "status": "passed", + "before": { + "time": 3.0020878, + "seeking": false, + "paused": true + }, + "after": { + "time": 3.0020878, + "rate": 1.5, + "paused": true, + "error": 0 + } + } + ], + "tests": { + "test/component-resources.test.js": "89df91b719158c43e3b0560046dfc2952df047a84ac1157da36423134effb494", + "test/types/components.ts": "e705f0c3efdf531e0eb4a5f733332c141e7bddf2450024cd71ea67bb3efc5b24", + "test/browser/components.spec.js": "2be381b052b69baa3b4ae9cf2582593b9d611158e709e056aaa5df3cf969bef4", + "test/browser/source.spec.js": "0e6a9396e329bbd055afe14da2e029c08881d09454aa58c8711476a690a44c14", + "package.json": "5b238c58a0fb8ca6605096ef513dbface431b82fb844f226f01d2828c744cad4" + }, + "ci": { + "command": "yarn ci:check", + "passed": 177, + "unit": 148, + "engineering": 4, + "baseline": 25, + "strictSourceFiles": 110, + "logSha256": "9a66950380ac5a09e84a2799f2f68da759b097720a6c6b1aa88886a01df35a06" + }, + "packages": [ + { + "name": "artplayer", + "version": "5.4.1", + "archive": "artplayer.tgz", + "sha256": "fc1658a64cdebfb510e3bd036fd507294a6bfb4713200336486757bb6b916311", + "files": { + "package/ARCHITECTURE.md": "1b06682013ea23c380b9e0605ea274280e6aa97adfa1b9c2a6b9e773276af36d", + "package/README.md": "1e185e65f67fc2081b4182bbc6c4558ea05b6e3fa3acc5dd0c3ac7df1d542b09", + "package/THIRD_PARTY_NOTICES": "b77b5b46b79fa0cda850b0781f78c3b1112c4ed9672fa291956fe8eff53098e7", + "package/dist/artplayer.js": "94ad520180207e7939cbb70af9fe50b0882110953f17877431c97d687428d22c", + "package/dist/artplayer.legacy.js": "e2eefd6ae2f753b864ef8b89b39f4069cce8ebafb67741884e2e3a4f00b62de9", + "package/dist/artplayer.mjs": "231f3ff5216b466dc2e40e10ba54fb06faec72f5646889a6f84be67ddc3d2df6", + "package/dist/i18n/ar.js": "5885c469efc9f07aafd6a4aa6698edae2c2683f42497ebbe15374130f9b6e2c7", + "package/dist/i18n/ar.mjs": "a275cf39ae2317ea1cea73b65ba5451a909b34a881d35920391cef2ff0d6a86f", + "package/dist/i18n/cs.js": "5adef10fadb219948eb5e58e204207ca0afdd2dd941a08d9455fd302ef2447cc", + "package/dist/i18n/cs.mjs": "2d274b61c2be9a472a3cc19dfa775e6209867f8d1d5a9116923f075446f47969", + "package/dist/i18n/es.js": "4c6662edce1398d0fe285978df83b271cce23e4f24e0e6a9d24a5b8a6845839b", + "package/dist/i18n/es.mjs": "09c0806a979feb4ae0e3ff32dbee9fd435847d3a66f80b6768ff69ab63289696", + "package/dist/i18n/fa.js": "db37cade9454df0b829c514e088d4d9175199faaff2b4a7838e6a401741131fe", + "package/dist/i18n/fa.mjs": "83290582155ee2a7a08a8c9cf8c2903545e78260e81a2a091092f3fbe61b4dd0", + "package/dist/i18n/fr.js": "54eee11fdf245e9882cb1f440f8909ccb8112f2e10722447cb313cab4752abea", + "package/dist/i18n/fr.mjs": "621844a04365da3d9e5d225d64e233d322cb9fd9c1ffcc2db77e5d7e0e78ea8e", + "package/dist/i18n/id.js": "5d4ee91a123c417b5b2e84890d85f416444389bdcd12c40d49073e1061796463", + "package/dist/i18n/id.mjs": "ffca08de9515704ef160dd902534df4b4113ff3f62b37f70330264d27daf5c34", + "package/dist/i18n/pl.js": "47e0d39623896436722439c758488ec660752c56a0294375bf0fce4f3b2aa27b", + "package/dist/i18n/pl.mjs": "05fbb3b2d09b44b5d3a237ea35a1f6865d45c2985e32b517dec4a00670cddebc", + "package/dist/i18n/ru.js": "3af3b15b1554579352b9b1ecfc8ac27abb584a5af9bcc7a8369a813c55df8834", + "package/dist/i18n/ru.mjs": "12281df03fc45c40ab8ad2a7dd8bbbab35f086dadd7e51f35e27826fff16e1ce", + "package/dist/i18n/tr.js": "0f8da88d4f770d9ec2e83311bbd6cc6ecfc0b2bbb3997f8db8eea8b795746967", + "package/dist/i18n/tr.mjs": "ea533927a7f32b3124177e87d9d5adbd279dc80efca7b11ad94696b3b47f7e94", + "package/dist/i18n/vi.js": "e3302f5c90f3e7df4bf8667c17598d0e46b66b31aab0d94fa70f3e617b5277c0", + "package/dist/i18n/vi.mjs": "f7a0ce8d821bff93354be31922a73be854a685e14170e8875cd5375f155e8737", + "package/dist/i18n/zh-tw.js": "13446c81dccf57e6b5d2be0a55b8ef6a668c6b8005ef4a497439557d6ccb16ec", + "package/dist/i18n/zh-tw.mjs": "730ae246aef8cffb34d7ba3b48aefab38fa812cf84ea7ebbd827f8639ee7eba7", + "package/package.json": "38fa5a41fe142c34ba52ce4ecd7cc81f25a7aba5adbe9e8fab843caedbddc15c", + "package/types/COMPATIBILITY.md": "72f619eb708e18040d12e0fbc5ce79f80bb22967687fa0d5afae6f2c6eae6d00", + "package/types/README.md": "93438f6009fc8017147ff4293e78849c102acce9aecc3d196ff135151081ff27", + "package/types/artplayer.d.cts": "a40ac7abd689b270e95eb0c3b70d67e1897b422d3d85d68f59173936bf80c332", + "package/types/artplayer.d.mts": "f6292596a9ccb1d43a6d6a12c35f859b1889ad15924c5ae0f9f280941aade313", + "package/types/artplayer.d.ts": "b57d9ac0a6f7a0215288ea286fedaf73043ac15557a3d82fc4b905f6d006f092", + "package/types/component.d.ts": "aa1c43be67322781b4b355b143bc69d9f29d22e578e4974d6a13e957a7c0334f", + "package/types/config.d.ts": "c4fd8681bf32b10c743e3e561c532520c8f32e43fd765524850b15e55cb91c72", + "package/types/cssVar.d.ts": "e027d82fb4f01c9ce7559cf679b2d5ee1962d3f7e5b4dd64ca21f472b933efb6", + "package/types/emitter.d.ts": "9c62551cdcc6dd3966bed8a7a85dd477435db977c91a294d2ac8f162f9592537", + "package/types/events.d.ts": "53ace64a29cbef8e0c30e124d09c71e1dfa3ba6cdeecde8c7f928161b54084ef", + "package/types/i18n.d.ts": "3e14759caf71f97f01650839248c8737c42d2c2979dabc43ad92b724da648708", + "package/types/icons.d.ts": "0d8e8e52e52130dd4a29bab551dd7a2a954797e42e92a6e068c85d583e23e6a4", + "package/types/language.d.cts": "1c9e0c47fae3c2d68c3e144d95a55071318a03bb31554dd049109efd3d0f95a4", + "package/types/language.d.mts": "c391e863012c77769e661afbf8fa949e9373aa88d17f58cbba7f5696edb8077f", + "package/types/legacy/language.d.ts": "c452ffd764ff9b29b819b3475c42395d2ea7a33560d8c186ef5df3844b9524c3", + "package/types/option.d.ts": "850e5264219b8b438c80694402225b690b131786677a5da0d22739ec2352d263", + "package/types/playback.d.ts": "1ceaed3aa1cef511fe8b20f4874647f6065c723ad805b742a0a9247e16bb1bb5", + "package/types/player.d.ts": "f1e50257df2ea592d0a0e1f36078dda77eaf2cf3b3d795307501396562d99f28", + "package/types/plugin.d.ts": "2a57e148fda00ee687da5036b890b0f611cb94bb403a1ed52602179060259d35", + "package/types/quality.d.ts": "7ed6ed78cea52991b2f6ddd2bd3b7bd8c5146fdfff7486fe8b814c3e632f1567", + "package/types/setting.d.ts": "d12a75b656fff70cbb30be4bffec46d9c4273636e8722bce971a4d2b188712a1", + "package/types/subtitle.d.ts": "d25b470e47d6a9bd696d9c1ad8adb58e56a208f05695186d513bc8c43c2e8acf", + "package/types/template.d.ts": "68aed9e97d006d6be4fabb8504ca84dafab770b0925f4d6e7319e67c82f21b0d", + "package/types/utils.d.ts": "494ec447ab467a07ddd7a2c2abf778b3fce69fd28a09aaa8ced9759f8de2e3f6" + } + }, + { + "name": "artplayer-plugin-chapter", + "version": "1.1.0", + "archive": "artplayer-plugin-chapter.tgz", + "sha256": "268fd1adda03a7d8985c5e0e53b5042ba9e8e7e5b77cc6946abe9bb34dd209ac", + "files": { + "package/ARCHITECTURE.md": "20743bad87a174b0450e0d876b6aa6b2a9f47df296d479511ce7cc9298fdb57c", + "package/README.md": "b95400ff3d525621a15268bb56a2d353aacaaadefde7e735d7abd91a34edd96f", + "package/dist/artplayer-plugin-chapter.js": "6ac3dfe28f46084ac7caedd571b1a97dcee3cf9d708112f1b8bbd6566e1dc5c5", + "package/dist/artplayer-plugin-chapter.legacy.js": "6d9bff885412169e701670961aa00c2e46c4b42c9b9647ff4e6d198777d2a359", + "package/dist/artplayer-plugin-chapter.mjs": "26415cecab2c0198c566cef0232e20123413782d5bad7534a32939b3298617af", + "package/package.json": "24eec6907b3218439189adab6af3f932c1497c47c2d41209311c01042b07fd4f", + "package/types/artplayer-plugin-chapter.d.cts": "4f07514b37453cd6cea8e5aa28fa018ff31738e0d423c11a3b5eccd50ed30bcc", + "package/types/artplayer-plugin-chapter.d.mts": "610179754db36276e161a07bccf4eaba8b4480f053e716a2bcc5a1574871a171", + "package/types/artplayer-plugin-chapter.d.ts": "581aa2862e709601c87a23585f54a969ebd350be56a7469a31ff53f1311b578d" + } + } + ], + "runtime": [ + "DIST.cjs", + "DIST.cjs-legacy", + "DIST.esm", + "DIST.esm-default-only", + "DIST.esm-legacy", + "DIST.global-core", + "DIST.amd-core", + "DIST.global-core-legacy", + "DIST.amd-core-legacy", + "DIST.global-chapter", + "DIST.amd-chapter", + "DIST.global-chapter-legacy", + "DIST.amd-chapter-legacy", + "SSR.import-template", + "SSR.constructor-browser-only", + "DIST.i18n-cjs-esm-global", + "DIST.exports-boundary", + "DIST.direct-esm-file", + "EVENT.lazy-registry", + "EVENT.symbol-number-channels", + "EVENT.context-removal", + "EVENT.once-throw-consumed", + "EVENT.chain-context-arguments", + "EVENT.once-reentry", + "EVENT.dispatch-snapshot", + "EVENT.off-original-once", + "EVENT.throw-propagation" + ], + "languages": [ + { + "name": "ar", + "globalName": "artplayerI18nAr", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "تشغيل" + }, + { + "name": "cs", + "globalName": "artplayerI18nCs", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Přehrát" + }, + { + "name": "es", + "globalName": "artplayerI18nEs", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Reproduciendo" + }, + { + "name": "fa", + "globalName": "artplayerI18nFa", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "پخش" + }, + { + "name": "fr", + "globalName": "artplayerI18nFr", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Lire" + }, + { + "name": "id", + "globalName": "artplayerI18nId", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Putar" + }, + { + "name": "pl", + "globalName": "artplayerI18nPl", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Odtwórz" + }, + { + "name": "ru", + "globalName": "artplayerI18nRu", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Играть" + }, + { + "name": "tr", + "globalName": "artplayerI18nTr", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Oynat" + }, + { + "name": "vi", + "globalName": "artplayerI18nVi", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "Phát" + }, + { + "name": "zh-tw", + "globalName": "artplayerI18nZhTw", + "keys": [ + "AirPlay", + "AirPlay Not Available", + "Aspect Ratio", + "Close", + "Default", + "Exit Fullscreen", + "Exit PIP Mode", + "Exit Web Fullscreen", + "Fullscreen", + "Fullscreen Not Supported", + "Hide Setting", + "Horizontal", + "Jump Play", + "Last Seen", + "Mini Player", + "Mute", + "Normal", + "Open", + "PIP Mode", + "PIP Not Supported", + "Pause", + "Play", + "Play Speed", + "Rate", + "Reconnect", + "Screenshot", + "Show Setting", + "Subtitle Offset", + "Switch Subtitle", + "Switch Video", + "Vertical", + "Video Flip", + "Video Info", + "Video Load Failed", + "Volume", + "Web Fullscreen" + ], + "play": "播放" + } + ], + "i18n": { + "package/dist/i18n/ar.js": "5885c469efc9f07aafd6a4aa6698edae2c2683f42497ebbe15374130f9b6e2c7", + "package/dist/i18n/ar.mjs": "a275cf39ae2317ea1cea73b65ba5451a909b34a881d35920391cef2ff0d6a86f", + "package/dist/i18n/cs.js": "5adef10fadb219948eb5e58e204207ca0afdd2dd941a08d9455fd302ef2447cc", + "package/dist/i18n/cs.mjs": "2d274b61c2be9a472a3cc19dfa775e6209867f8d1d5a9116923f075446f47969", + "package/dist/i18n/es.js": "4c6662edce1398d0fe285978df83b271cce23e4f24e0e6a9d24a5b8a6845839b", + "package/dist/i18n/es.mjs": "09c0806a979feb4ae0e3ff32dbee9fd435847d3a66f80b6768ff69ab63289696", + "package/dist/i18n/fa.js": "db37cade9454df0b829c514e088d4d9175199faaff2b4a7838e6a401741131fe", + "package/dist/i18n/fa.mjs": "83290582155ee2a7a08a8c9cf8c2903545e78260e81a2a091092f3fbe61b4dd0", + "package/dist/i18n/fr.js": "54eee11fdf245e9882cb1f440f8909ccb8112f2e10722447cb313cab4752abea", + "package/dist/i18n/fr.mjs": "621844a04365da3d9e5d225d64e233d322cb9fd9c1ffcc2db77e5d7e0e78ea8e", + "package/dist/i18n/id.js": "5d4ee91a123c417b5b2e84890d85f416444389bdcd12c40d49073e1061796463", + "package/dist/i18n/id.mjs": "ffca08de9515704ef160dd902534df4b4113ff3f62b37f70330264d27daf5c34", + "package/dist/i18n/pl.js": "47e0d39623896436722439c758488ec660752c56a0294375bf0fce4f3b2aa27b", + "package/dist/i18n/pl.mjs": "05fbb3b2d09b44b5d3a237ea35a1f6865d45c2985e32b517dec4a00670cddebc", + "package/dist/i18n/ru.js": "3af3b15b1554579352b9b1ecfc8ac27abb584a5af9bcc7a8369a813c55df8834", + "package/dist/i18n/ru.mjs": "12281df03fc45c40ab8ad2a7dd8bbbab35f086dadd7e51f35e27826fff16e1ce", + "package/dist/i18n/tr.js": "0f8da88d4f770d9ec2e83311bbd6cc6ecfc0b2bbb3997f8db8eea8b795746967", + "package/dist/i18n/tr.mjs": "ea533927a7f32b3124177e87d9d5adbd279dc80efca7b11ad94696b3b47f7e94", + "package/dist/i18n/vi.js": "e3302f5c90f3e7df4bf8667c17598d0e46b66b31aab0d94fa70f3e617b5277c0", + "package/dist/i18n/vi.mjs": "f7a0ce8d821bff93354be31922a73be854a685e14170e8875cd5375f155e8737", + "package/dist/i18n/zh-tw.js": "13446c81dccf57e6b5d2be0a55b8ef6a668c6b8005ef4a497439557d6ccb16ec", + "package/dist/i18n/zh-tw.mjs": "730ae246aef8cffb34d7ba3b48aefab38fa812cf84ea7ebbd827f8639ee7eba7" + }, + "vendors": { + "sources": [ + { + "file": "refactor/baselines/core-vendor/screenfull-6.0.2.txt", + "url": "https://raw.githubusercontent.com/sindresorhus/screenfull/v6.0.2/index.js", + "sha256": "4246711b342018b0f257f8fa6047f240a21af6218c7e79cab5c662e810bb3e01" + }, + { + "file": "refactor/baselines/core-vendor/screenfull-license.txt", + "url": "https://raw.githubusercontent.com/sindresorhus/screenfull/v6.0.2/license", + "sha256": "5c932d88256b4ab958f64a856fa48e8bd1f55bc1d96b8149c65689e0c61789d3" + }, + { + "file": "refactor/baselines/core-vendor/hint-2.7.0.txt", + "url": "https://raw.githubusercontent.com/chinchang/hint.css/v2.7.0/hint.css", + "sha256": "a804fa4b607167e579b39d192f1a29d2b27226097094e0351f2d46ac8ebaa864" + }, + { + "file": "refactor/baselines/core-vendor/hint-license.txt", + "url": "https://raw.githubusercontent.com/chinchang/hint.css/v2.7.0/LICENSE", + "sha256": "55cee0a0645d18366eaa0cd21208c224568e14c38b7894e0f9ff537702ff8ea0" + } + ], + "local": { + "packages/artplayer/src/libs/screenfull.js": "2332b50c0c6364d5c99080be0f5739255e4b9e465d2cca40f761adce9a1908f8", + "packages/artplayer/src/style/hint.less": "e2dc4940e6b212d8da75a404fd5ff1ad894008457677bc37554c6b64b735bc31", + "packages/artplayer/THIRD_PARTY_NOTICES": "b77b5b46b79fa0cda850b0781f78c3b1112c4ed9672fa291956fe8eff53098e7" + } + }, + "types": [ + { + "compiler": "5.9.3", + "mode": "node10-commonjs", + "diagnostics": [] + }, + { + "compiler": "5.9.3", + "mode": "nodenext-cjs", + "diagnostics": [] + }, + { + "compiler": "5.9.3", + "mode": "bundler-esm", + "diagnostics": [] + }, + { + "compiler": "4.3.5", + "mode": "node10-commonjs", + "diagnostics": [] + }, + { + "compiler": "5.9.3", + "mode": "nodenext-esm", + "diagnostics": [] + } + ], + "browser": { + "stats": { + "startTime": "2026-09-10T20:49:17.036Z", + "duration": 78467.95700000001, + "expected": 342, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "candidateMember": "artplayer.js", + "candidateSha256": "94ad520180207e7939cbb70af9fe50b0882110953f17877431c97d687428d22c", + "versions": { + "chromium": "153.0.8010.12", + "firefox": "155.0", + "webkit": "26.6" + }, + "cases": [ + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "chromium", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "chromium", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "firefox", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "firefox", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "webkit", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": true + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "webkit", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": true + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "webkit", + "status": "passed", + "retry": 0 + } + ] + }, + "legacyBrowser": { + "stats": { + "startTime": "2026-09-10T20:51:33.994Z", + "duration": 78007.98800000001, + "expected": 342, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "candidateMember": "artplayer.legacy.js", + "candidateSha256": "e2eefd6ae2f753b864ef8b89b39f4069cce8ebafb67741884e2e3a4f00b62de9", + "versions": { + "chromium": "153.0.8010.12", + "firefox": "155.0", + "webkit": "26.6" + }, + "cases": [ + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "published-only observations: blank title, NaN and once-only metadata are historical defects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate clears titles on blank chapters, zero hover and replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate rejects NaN and can recover after an invalid update", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate releases only its listeners and DOM across multiple instances and early destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate ignores pending metadata initialization after immediate destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "candidate deduplicates stylesheet injection while the document is loading", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "factory, registration, input normalization and safe title text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "progress bars, real hover, title edges and boundary seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "sync update, Infinity, object identity, empty lists and invalid data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "chapter.spec.js", + "title": "explicit source update and core-owned destruction", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=false", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: control layout follows resize and removal with observer fallback=true", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector background clicks and rejection ownership are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: failed mounted reentry preserves its successful replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: context menu builtin selection and owned updates preserve state", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a prototype-named component keeps the registry prototype intact", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: removed builtin time and volume controls stop owned effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: selector items can be reused by an update without changing getter flags", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: async selector results cannot overwrite a newer choice or removed entry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: reentrant beforeUnmount removes only once", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: narrow controls stay inside the player without hiding buttons", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "published: progress markers treat text as data and removed drags cannot seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector background clicks and rejection ownership are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: beforeUnmount errors remain retryable and detached nodes can be removed", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: failed mounted reentry preserves its successful replacement", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: context menu builtin selection and owned updates preserve state", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a prototype-named component keeps the registry prototype intact", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: component factories, ordering, bound methods and update hooks retain contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: removed builtin time and volume controls stop owned effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: selector items can be reused by an update without changing getter flags", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: async selector results cannot overwrite a newer choice or removed entry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: a failed mounted hook rolls back its DOM alias and listeners", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: reentrant beforeUnmount removes only once", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: narrow controls stay inside the player without hiding buttons", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "components.spec.js", + "title": "candidate: progress markers treat text as data and removed drags cannot seek", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: plugin, toggle, setting and static runtime return contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "published: native subtitle update events carry cue arrays", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: plugin, toggle, setting and static runtime return contracts", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "declarations.spec.js", + "title": "candidate: native subtitle update events carry cue arrays", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "published: emitter event names and once across nested dispatch", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "emitter.spec.js", + "title": "candidate: emitter event names and once across nested dispatch", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "published: repeated destroy preserves other live instances", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: repeated destroy preserves other live instances", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor plugin failure restores original DOM and clears resources", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: early proxy failure restores SSR nodes, attributes and text", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: reentrant destroy keeps sequence and does not repeat callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: destroying cancels queued resize, notice, RAF, reconnect and mounted work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: constructor can synchronously destroy without entering the registry", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: partial Events initialization releases listeners before its property is assigned", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: live resize still coalesces and destroy cancels the next burst", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "lifecycle.spec.js", + "title": "candidate: a container is reserved during reentrant initialization", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: replacing a failed source cancels candidate retries", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: HTTP failure retries the updated option URL with the original event and one ready", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: replacing a failed source cancels candidate retries", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: rejected real-media switch still allows current-source reconnect", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: destroying from first-ready controls prevents a candidate ghost ready event", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "published: metadata emits resize before mobile visibility changes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-events.spec.js", + "title": "candidate: metadata emits resize before mobile visibility changes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "published: existing canvas proxy keeps media identity, playback and layout", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "media-hosts.spec.js", + "title": "candidate: existing canvas proxy keeps media identity, playback and layout", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: expanded option input preserves historical JS forms", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: configuration errors occur before mounting and preserve allocation timing", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "published: container identity, partial defaults, custom fields and normal callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: expanded option input preserves historical JS forms", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: configuration errors occur before mounting and preserve allocation timing", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "options.spec.js", + "title": "candidate: container identity, partial defaults, custom fields and normal callbacks", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: real media preserves timeline, volume, rate and property descriptors", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "published: invalid time inputs and rate no-op retain native behavior", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: real media preserves timeline, volume, rate and property descriptors", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback-properties.spec.js", + "title": "candidate: invalid time inputs and rate no-op retain native behavior", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "published: real playback, pause, seek, switch and destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "candidate: real playback, pause, seek, switch and destroy", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "controlled HTTP media failure emits a real video error", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "playback.spec.js", + "title": "Range, media identity and docs candidate routes", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: late plugin registration preserves fulfillment without reviving a closed candidate", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: a plugin that closes construction prevents subsequent factories", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: constructor-owned rejection is reported once without an unhandled rejection", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "published: builtin order and live exclusions precede user plugins", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "plugins.spec.js", + "title": "candidate: builtin order and live exclusions precede user plugins", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "resource-scope.spec.js", + "title": "internal resource scope: native DOM, RAF, timer, fetch abort and URL release", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: rapid real-media switches identify the last restart and settle superseded work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "published: destroy settles the candidate switch without waiting for detached media", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: rapid real-media switches identify the last restart and settle superseded work", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: destroy settles the candidate switch without waiting for detached media", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: quality switch restores position/rate and preserves real customType identities", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: real switch settles when the controlled native resume rejects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "source.spec.js", + "title": "candidate: late native play completion cannot publish stale player effects", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "chromium", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "chromium", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "firefox", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "firefox", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": false + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: native fullscreen uses a real gesture when the engine supports it", + "engine": "webkit", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": true + } + }, + { + "file": "template-resources.spec.js", + "title": "published: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: proxy replacement preserves callback and node identity", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: i18n prototype fallback difference and custom keys are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "published: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: native fullscreen uses a real gesture when the engine supports it", + "engine": "webkit", + "status": "passed", + "retry": 0, + "nativeFullscreen": { + "native": true, + "video": true + } + }, + { + "file": "template-resources.spec.js", + "title": "candidate: SSR mounting preserves nodes, listeners, selectors and style ownership", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: proxy replacement preserves callback and node identity", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: icon access preserves descriptors and moves custom DOM into fresh wrappers", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: i18n prototype fallback difference and custom keys are explicit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "template-resources.spec.js", + "title": "candidate: fullscreen web retains DOM and CSS hooks through entry and exit", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "chromium", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "firefox", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: subtitle object URL contains real VTT data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "published: download starts and removes its temporary anchor", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: subtitle object URL contains real VTT data", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate: download starts and removes its temporary anchor", + "engine": "webkit", + "status": "passed", + "retry": 0 + }, + { + "file": "utils.spec.js", + "title": "candidate download releases the anchor even when click fails", + "engine": "webkit", + "status": "passed", + "retry": 0 + } + ] + }, + "documentationRepack": { + "originalPackage": "refactor/.cache/packages/run-D9JL0R", + "finalPackage": "refactor/.cache/packages/run-a96teA", + "reason": "Correct literal __proto__ names in packaged architecture Markdown; every core/chapter distribution member is byte-identical to the UMD-tested package. Final package runtime and all type modes rerun; legacy uses the final package." + }, + "build": { + "coreLogSha256": "0ec543a9b1c9d42f0185636cb83b5b9a0b811e81e26f5bc7c121f75cdbcd9b58", + "i18nLogSha256": "76a5ea3998694901ed7d1c958388f855f4be0fef77de5536eb84ec4843dbfebf", + "packageLogSha256": "cd80811d807f41444e52ee97e0f460936be26ae8e508ea5d823aaf61437c542f" + }, + "earlyFailures": [ + { + "reportSha256": "a8eb482ec1a285acdead3cbe5bac42fcc29a515c2532f6d89e60c3a3167dce36", + "gestureReportSha256": "07788d1607674c6c935749f17300a9ff6f372e7aef9810ef01f44f1245ace6e9", + "rangesReportSha256": "d217b641cbe87b07d15c914a525a2275070fd952e9b8e86fd3a58297f7b4c0d3", + "reason": "An attempted buffered-range prerequisite failed: local WebKit reports buffered=[] even after real playback, with seekable=[[0,8]] and readyState=4. Removed that invalid assumption; retain real gesture activation, seekable and actual-position assertions. This does not claim to fix native unstarted-pipeline seek behavior." + }, + { + "logSha256": "67db7a5444d17c198e22556fdab7b8ed5f752b9503ef7474b699e3294b2d8472", + "reportSha256": "4de06bccb6f2e358af4419935a1b8579778cd8bacecd39a9f3df3be10e917833", + "diagnosticReportSha256": "7ee2570e94fa7444c712775071b4801542f3269b512cac96d7f36d188e7f3c5b", + "confirmationReportSha256": "6cc762de704271564b45be7a9ccb59c67e736bc1381b4936757245a824306ddb", + "reason": "First full run: 341 passed and one WebKit initial-seek precondition failure. Native event instrumentation reproduced a seek finishing near zero before switch; switch kept that actual value. Diagnostic exact equality also rejected harmless millisecond offsets. Activate media with real play/pause, require a seekable initial target, assert before/after time with the original 0.05s tolerance, retain events; repeated three-engine confirmation then complete UMD/legacy matrices use unchanged player artifacts." + }, + { + "logSha256": "1fc93eb987ae215ac0ed2a47f4aa97d5225aaff16c16774bf637800a5194270d", + "reportSha256": "72ef86c813b74f008af6462da452c13cf6683e0fea2ee2581b613af06c2faaf0", + "reason": "Real 16:9 heights exposed candidate vertical clipping: child control groups still retained height:100%. Fixed their wrap, max-width and min-height; no test bypass." + }, + { + "logSha256": "0278de44390c17e0712d39b424bf497a65110262d10a3395483d5ed8872de96e", + "reportSha256": "14d50fe650de5e2a2014f3c6f87ba1927aa7ddb1dbcec6ecc67f28ab82e76de2", + "reason": "Computed subtitle bottom was read during the existing CSS transition. Poll final geometry under the existing timeout, preserving animation and assertions." + } + ], + "limits": [ + "No remote CI, physical-device or all-ecosystem release acceptance", + "BASE-DOM-02 remains open: narrow setting-tree/panel interactions belong to CORE-14", + "Public Component/Control return declarations and write-only quality property discrepancies remain CORE-21 work", + "Custom mounted return values are ignored as before; arbitrary user listeners and SDK work need explicit user cleanup", + "Without ResizeObserver, parent-only CSS resizing waits for a core resize or control mutation", + "No dependency, lockfile, package version or public declaration changes" + ], + "resolvedFindings": [ + "BASE-LIFE-09", + "BASE-LIFE-10", + "BASE-LIFE-11", + "BASE-DOM-03", + "BASE-DOM-04", + "BASE-DOM-05" + ] +} diff --git a/refactor/changes/2026-09-11-CORE-13-components.md b/refactor/changes/2026-09-11-CORE-13-components.md new file mode 100644 index 000000000..b32b13f2c --- /dev/null +++ b/refactor/changes/2026-09-11-CORE-13-components.md @@ -0,0 +1,41 @@ +# CORE-13 组件注册与控件 + +状态:完成;源码、严格类型、构建、安装包与本地三浏览器验收通过。 + +## 职责与兼容 + +Component、control、layer、contextmenu 和 qualityMix 迁移 TS。注册器、DOM、条目资源、选择生命周期、内置装配、布局观察、进度计算/视图/交互按实际职责拆分;简单控件保留独立工厂。共享 typed UIEvents 和最小宿主不引入第二套事件总线;主构造门面的整合仍交 CORE-20。包内 ARCHITECTURE.md 给出实际地图、修改入口与边界。 + +保持裸工厂调用、回调 this、原始 Event 和参数、索引排序、HTML 数字转换、更新时原配置对象合并、同步 mounted/beforeUnmount、属性别名及缓存条目形状。Component add/update 可返回 div;controls.add/update 继续返回 undefined。公开 d.ts 不在此轮收紧,BASE-TYPE-04 与只写 quality 属性的 BASE-TYPE-08 仍交 CORE-21。 + +条目资源在渲染前登记,remove/update 释放内置 DOM 与 Emitter 订阅、拖动和提示定时器;整实例销毁释放作用域,但不新增逐条 beforeUnmount 调用或清空历史 cache/alias。自定义 mounted 返回值仍忽略,用户自行创建的监听器/SDK 工作需自行 beforeUnmount 清理,没有凭空引入 disposer 协议。 + +## 缺陷与修正 + +- BASE-LIFE-09:旧控件移除后时间/音量/菜单仍响应事件,拖动仍可 seek。候选按条目释放并在 Emitter 快照内检查关闭状态,用户自己的订阅保留。 +- BASE-LIFE-10:旧 mounted 抛错残留 DOM/cache/监听器,beforeUnmount 重入重复执行并抛错,已脱离 DOM 的条目移除也抛错。候选回滚失败条目且保留成功的重入替换,递归移除同条目幂等;beforeUnmount 自身抛错仍保留条目可重试并传播原异常。 +- BASE-LIFE-11:旧 selector 背景点击及异步拒绝产生未处理异常,乱序和移除后结果仍覆盖标题。候选忽略无项点击,报告原始失败,只接受当前选择的完成;内置清晰度通知也绑定选择生命周期,包括通知文本准备期间重入。第三方 onSelect 自有异步副作用不会被自动取消。 +- BASE-DOM-03:旧 selector 数组用于更新后因不可配置属性重复定义而抛错。候选保持 getter 标志,通过 WeakMap 重绑已关闭条目;同时共享到两个活动控件仍非法。 +- BASE-DOM-04:旧 `__proto__` 名称别名会改变 registry 原型。候选为它定义普通 own 属性,仍可按名称读 DOM,不再改原型。 +- BASE-DOM-05:旧 highlight.text 可通过引号注入 DOM 属性;候选使用 dataset 按文本写入。没有声称移除用户明确支持的 HTML 控件内容。 +- BASE-DOM-02 部分:窄容器控件换行,所有按钮保持可见;新增 --art-controls-height 记录总高度,字幕/面板跟随,旧 --art-control-height 保持单行单位高度。CORE-14 仍需处理窄设置树/面板,因此此风险保持 open。 + +## 验证与过程 + +源码组件资源 8 项 Node 测试、根与核心 TS 检查通过;源码专项三浏览器 84 项通过,最终安装包 UMD 与 legacy 同套完整矩阵各 342 项通过。新增用例覆盖真实右键/点击、视频进度、旧新错误对照、回调/别名/返回值、乱序、清理和尺寸变化。ResizeObserver 不可用分支单独测试;没有将 UA 覆盖当实体设备证据。 + +首次窄容器用例增加实际 16:9 高度后暴露候选控件组仍 height:100% 的裁切:57 通过、3 失败。修正遗漏的子组 CSS,再验证 640/320/240px,保留原失败报告。之后观察器用例 81 通过、3 失败,原因是字幕仍在既有 CSS transition 中;改为有界轮询最终计算样式,未扩大超时或移除动画,随后 84 项通过。 + +本任务未新增依赖或修改锁文件;package.json 将组件资源测试加入既有 test:unit,确保 CI 执行。没有版本变更、推送或发布。原型名/生命周期/选择器修复为有旧新复现的缺陷修正,不静默改正常 API。回退需一起回退 TS 模块、样式、生成产物、测试和对应记录;不能仅回退组件基类而保留依赖其条目作用域的控件。 + +完整安装 UMD 首轮 341 通过、1 项 WebKit 切源位置失败。补充原生 seeking/seeked/loadedmetadata/canplay 轨迹后复现:初始 seek 已结束但实际落在接近 0 秒,切源保留的正是这个实际位置;旧测试仅等 seeking=false,没有证明初始 3 秒前提。诊断中精确等于 3 的临时断言也错误拒绝毫秒偏差,已改用原有 0.05 秒精度。曾尝试等待 buffered/seekable 均覆盖 3 秒,但本地 WebKit 实际播放后仍报告 buffered=[]、seekable=[[0,8]]、readyState=4,这个附加假设不成立,保留失败报告并撤回。最终用例通过真实播放/暂停手势启动媒体,再确认 seekable 目标并设置初始位置,在切换前后断言位置,保留范围与媒体轨迹;没有修改播放器逻辑、重复 seek、扩大超时或放宽原切换断言。专项每引擎重复 10 次用于确认该前提修正,再重跑完整矩阵。 + +## 最终交付证据 + +- yarn ci:check:177 项通过(148 单元、4 工程、25 基线),110 个生产 TS 文件严格检查;其中核心 105、chapter 5。 +- yarn build artplayer 与 yarn build:i18n 成功;实际核心/chapter tarball 仓库外安装消费:27 项运行时通过、五组类型零诊断。 +- 最终安装 UMD 和 legacy 各 342 项三浏览器通过,包含本任务 84 项;无跳过、重试、flaky 或未处理页面异常。旧缺陷测试显式收集并断言预期拒绝,没有把它们冒充候选成功行为。 +- [验证记录](../baselines/components-validation.json) 校验全部核心源码与打包构建快照一致,三个格式产物与 tarball 及 docs/compiled 指纹一致,公开声明、包内架构文档、22 个语言文件和完整许可一致;记录实际引擎版本、逐项结果与早期失败原因。 +- 关闭 BASE-LIFE-09/10/11 和 BASE-DOM-03/04/05;BASE-DOM-02 保持 open,窄设置面板交 CORE-14。没有远端 CI、实体设备或全生态发布验收声明。 + +本任务独立本地提交;当前总任务 214 项,49 完成、165 待办。下一项 CORE-14 设置树、渲染、选择与布局。 diff --git a/refactor/core-design.md b/refactor/core-design.md index b5985b20c..a4da84cf5 100644 --- a/refactor/core-design.md +++ b/refactor/core-design.md @@ -5,28 +5,28 @@ ## 现状证据 - [入口](../packages/artplayer/src/index.js)顺序构造所有子系统;[player](../packages/artplayer/src/player/index.js)通过 mixin 将属性安装到 art。 -- [Component](../packages/artplayer/src/utils/component.js)负责控件缓存、DOM 和监听器;[Setting](../packages/artplayer/src/setting/index.js)还有独立的树、渲染和更新语义。 +- [Component](../packages/artplayer/src/utils/component.ts)负责控件缓存、DOM 和监听器;[Setting](../packages/artplayer/src/setting/index.js)还有独立的树、渲染和更新语义。 - [Events](../packages/artplayer/src/events/index.js)集中管理一部分 DOM 监听器,但定时器、异步请求和内部 Emitter 订阅仍由各模块管理。 - [声明](../packages/artplayer/types/artplayer.d.ts)与源码独立维护;[build-ts](../scripts/build-ts.js)进行文本拼接。 ## 目标职责 -| 领域 | 现有文件范围 | 目标与迁移方式 | -| --- | --- | --- | -| 公共门面 | src/index.js、player/*Mix.js | 保留原签名和属性描述符;委托内部服务,不一次性换继承结构 | -| 配置 | option、scheme、config、默认值 | 区分用户输入与归一化配置;保持默认值、合并语义和错误时机 | -| 生命周期 | constructor、destroy、Events、各模块清理 | 实例资源作用域与操作资源作用域,清理恰好一次、可重入、失败后继续释放 | -| 内部事件 | utils/emitter.js | typed event map、未知事件兼容扩展、原调用顺序和 ctx | -| 媒体能力 | template、proxy、player | 内部精确的能力接口与原生视频类型分离;公共 video 兼容层保留 | -| 播放流程 | play/pause/toggle/seek/url/switch/eventInit | 媒体状态、操作身份、加载恢复与 UI 响应分离 | -| UI 注册 | utils/component、control、layer、contextmenu | 保留 name/cache/update/remove;明确 DOM 和绑定的归属 | -| 设置面板 | setting/index.js | 分开树整理、选择状态、渲染、布局、绑定;共享能共享的逻辑,不强行统一返回类型 | -| 字幕 | subtitle.js、utils/subtitle.js | 获取、解析、track/DOM 渲染、取消和对象 URL 回收分开 | -| 显示模式 | fullscreen/fullscreenWeb/pip/mini/auto* | 显式恢复位置和样式,保持互斥顺序、用户手势与移动端语义 | -| 输入 | events、hotkey | 鼠标/触控/键盘/焦点归属清晰,跨 document 重新绑定和清理 | -| 无障碍 | template、control、setting、显示模式 | 明确键盘导航、可访问名称、焦点进入退出和字幕能力,保留旧 DOM/CSS 与热键契约 | -| 内置功能 | plugins/*、info/notice/loading/mask | 逐项登记定时器和订阅,不能因内部插件迁移改变默认启用条件 | -| 资源 | i18n、icons、style、libs | 保持子路径、图标键、CSS 类和样式注入;记录 vendored 依赖来源 | +| 领域 | 现有文件范围 | 目标与迁移方式 | +| -------- | -------------------------------------------- | ---------------------------------------------------------------------------- | +| 公共门面 | src/index.js、player/*Mix.js | 保留原签名和属性描述符;委托内部服务,不一次性换继承结构 | +| 配置 | option、scheme、config、默认值 | 区分用户输入与归一化配置;保持默认值、合并语义和错误时机 | +| 生命周期 | constructor、destroy、Events、各模块清理 | 实例资源作用域与操作资源作用域,清理恰好一次、可重入、失败后继续释放 | +| 内部事件 | utils/emitter.js | typed event map、未知事件兼容扩展、原调用顺序和 ctx | +| 媒体能力 | template、proxy、player | 内部精确的能力接口与原生视频类型分离;公共 video 兼容层保留 | +| 播放流程 | play/pause/toggle/seek/url/switch/eventInit | 媒体状态、操作身份、加载恢复与 UI 响应分离 | +| UI 注册 | utils/component、control、layer、contextmenu | 保留 name/cache/update/remove;明确 DOM 和绑定的归属 | +| 设置面板 | setting/index.js | 分开树整理、选择状态、渲染、布局、绑定;共享能共享的逻辑,不强行统一返回类型 | +| 字幕 | subtitle.js、utils/subtitle.js | 获取、解析、track/DOM 渲染、取消和对象 URL 回收分开 | +| 显示模式 | fullscreen/fullscreenWeb/pip/mini/auto* | 显式恢复位置和样式,保持互斥顺序、用户手势与移动端语义 | +| 输入 | events、hotkey | 鼠标/触控/键盘/焦点归属清晰,跨 document 重新绑定和清理 | +| 无障碍 | template、control、setting、显示模式 | 明确键盘导航、可访问名称、焦点进入退出和字幕能力,保留旧 DOM/CSS 与热键契约 | +| 内置功能 | plugins/*、info/notice/loading/mask | 逐项登记定时器和订阅,不能因内部插件迁移改变默认启用条件 | +| 资源 | i18n、icons、style、libs | 保持子路径、图标键、CSS 类和样式注入;记录 vendored 依赖来源 | ## 生命周期设计约束 diff --git a/refactor/plan.md b/refactor/plan.md index dd2da02e7..a4dd85bcd 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 214 项,范围 22 个包及工作区/示例。 -状态:todo 166 / doing 0 / blocked 0 / done 48 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 165 / doing 0 / blocked 0 / done 49 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -116,7 +116,7 @@ | CORE-10 | artplayer
迁移播放与时间/状态属性 | CORE-09 | play/pause/toggle/seek/volume/rate/duration 等模块 | 旧返回值、拒绝、mutex、位置恢复、属性描述符与事件通过;接续 CORE-07 / BASE-TYPE-04 的 toggle void 与实际 Promise 分支冲突,不吞拒绝 | H | done | | CORE-11 | artplayer
整理媒体事件、ready 与重连 | CORE-10 | 媒体转发、重连、UI 响应职责分离 | readiness 次数/顺序、过期重连、原错误参数有回归 | H | done | | CORE-12 | artplayer
迁移模板及公开资源入口 | CORE-06, CORE-04, BASE-04 | template/icons/i18n/style、SSR 与 proxy 挂载 | DOM/CSS/global/样式注入、i18n 子路径及 SSR import 保持;不把 SSR import/useSSR 保持扩大为服务端构造播放器;复跑 BASE-05 的 SSR import/模板、浏览器 useSSR 节点复用和非浏览器构造错误;接续 VENDOR-01/02,核对 screenfull/hint 复制版本、修改与分发通知,保留 DOM/CSS/fullscreen 行为 | H | done | -| CORE-13 | artplayer
迁移组件注册与控件 | CORE-12, CORE-08 | Component/control/layer/contextmenu 的资源与 TS 边界 | add/update/remove、name、selector、mounted/beforeUnmount 通过;处理 BASE-DOM-02 窄容器控件裁切,保留 controls.update 的旧 undefined 返回值 | H | todo | +| CORE-13 | artplayer
迁移组件注册与控件 | CORE-12, CORE-08 | Component/control/layer/contextmenu 的资源与 TS 边界 | add/update/remove、name、selector、mounted/beforeUnmount 通过;处理 BASE-DOM-02 窄容器控件裁切,保留 controls.update 的旧 undefined 返回值 | H | done | | CORE-14 | artplayer
拆分设置树、渲染和布局 | CORE-13 | setting model/selection/render/layout 的分批实现 | 不强行统一控件返回值,嵌套选择、默认高亮、更新清理通过;结合 BASE-DOM-02 验证窄容器设置定位;接续 BASE-TYPE-07 的 find null、add/update item、remove undefined 声明冲突 | H | todo | | CORE-15 | artplayer
迁移字幕获取、解析和渲染 | CORE-11, CORE-13 | subtitle 请求/track/DOM/URL 生命周期与类型 | 过期结果、偏移、cue 数组、原生全屏及错误路径通过;接续 BASE-TYPE-07 的真实 cue 数组与旧隐式 scalar 回调声明兼容 | H | todo | | CORE-16 | artplayer
迁移全屏、PiP、mini 与尺寸模式 | CORE-11, CORE-12 | 显示模式服务和原公开属性门面 | 模式互斥/恢复位置、手势权限、移动方向和退出失败通过 | H | todo | @@ -447,6 +447,7 @@ - CORE-10: [记录](changes/2026-09-11-CORE-10-playback-properties.md) [记录](baselines/playback-properties-validation.json) - CORE-11: [记录](changes/2026-09-11-CORE-11-media-events.md) [记录](baselines/media-events-validation.json) - CORE-12: [记录](changes/2026-09-11-CORE-12-template-resources.md) [记录](baselines/template-resources-validation.json) +- CORE-13: [记录](changes/2026-09-11-CORE-13-components.md) [记录](baselines/components-validation.json) - PKG-CHAPTER-01: [记录](changes/2026-09-10-PKG-CHAPTER-01-contract.md) [记录](baselines/chapter-contract.md) - PKG-CHAPTER-02: [记录](changes/2026-09-10-PKG-CHAPTER-02-tests.md) [记录](baselines/chapter-validation.json) - PKG-CHAPTER-03: [记录](changes/2026-09-10-PKG-CHAPTER-03-typescript-modules.md) [记录](baselines/chapter-migration-validation.json) diff --git a/refactor/progress.md b/refactor/progress.md index 1df613bbf..65c6ddc6f 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,13 @@ # 进度与证据 +## 当前实施:CORE-13 组件注册与控件完成 + +Component/control/layer/contextmenu 与 qualityMix 迁移 TS,拆清注册、DOM、资源、选择生命周期、进度交互和布局;修复移除后残留订阅、失败注册与重入清理、过期选择写入、selector 重用和文本属性注入。正常回调/排序/别名/描述符保持,controls.add/update 仍返回 undefined。 + +177 项 Node/工程/基线通过,核心及 chapter 共 110 个生产 TS 文件严格检查;最终安装 UMD 和 legacy 各 342 项三浏览器通过,实际 tarball 27 项运行时与五组类型零诊断。见 [交付](changes/2026-09-11-CORE-13-components.md) 和 [指纹及结果](baselines/components-validation.json)。关闭 BASE-LIFE-09/10/11、BASE-DOM-03/04/05;BASE-DOM-02 的窄设置面板留 CORE-14,公开返回值与只写属性声明仍交 CORE-21。 + +当前分支 codex/compatible-modernization,214 项中 49 完成、165 待办;核心 105 个 TS 文件、chapter 5 个。下一项 CORE-14 设置树、选择、渲染与布局;CORE-13 按单任务本地提交,未推送或发布。 + ## 当前实施:CORE-12 模板及公开资源入口完成 模板、图标、语言和样式入口迁移 TS,保留 SSR/DOM/proxy 身份及语言分发。169 项 Node/工程/基线通过,最终安装 UMD 与 legacy 各 258 项三浏览器通过;打包 27 项运行时及五组类型零诊断。复制资源固定上游内容、全部适配和实际分发许可已核对,关闭 VENDOR-01/02 与 BASE-I18N-01;公开模板/图标类型差异 BASE-TYPE-09 交 CORE-21。见 [交付](changes/2026-09-11-CORE-12-template-resources.md)。当前 214 项,48 完成、166 待办;核心 71 个 TS 文件、chapter 5 个。下一项 CORE-13 组件注册与控件。 @@ -241,15 +249,15 @@ BASE-01 已提交 `1d705b30`。BASE-HARNESS-01 完成发布包采集页面/本 以下来自建立计划前的同一会话评估,属于初步诊断,不代替 BASE 阶段的已发布产物基线与完整浏览器测试: -| 检查 | 结果与限制 | -| --- | --- | -| `node --test test/playback.test.js test/dash-control.test.js` | Node 25.2.1,19 项通过;这是 mock/单元测试 | -| 核心 src/types、test、scripts/*.js 的 ESLint(不加 --fix) | 通过;没有把插件模板占位符作为普通源码 lint | -| 三个 TS 样例,TS 5.9.3、strict、types: [] | 通过;未隔离环境类型时存在第三方 DOM/WebCodecs/markdown 声明冲突 | -| 使用项目构建配置 write:false 进行 ESM/现代 UMD/legacy UMD 内存构建 | 成功;不是完整 npm pack 或全部发布构建;未写产物 | -| 销毁源码隔离探针 | 重复 destroy 可误删其他实例注册项;需要正式回归用例 | -| 连续切源源码隔离探针 | 一次 canplay 可结算两次切源;尚未真实浏览器复现影响 | -| `bun test ./test/playback.test.js ./test/dash-control.test.js` | Bun 1.3.14:1 通过、18 失败,mock.fn 不兼容;未来版本需重测 | +| 检查 | 结果与限制 | +| ------------------------------------------------------------------ | ---------------------------------------------------------------- | +| `node --test test/playback.test.js test/dash-control.test.js` | Node 25.2.1,19 项通过;这是 mock/单元测试 | +| 核心 src/types、test、scripts/*.js 的 ESLint(不加 --fix) | 通过;没有把插件模板占位符作为普通源码 lint | +| 三个 TS 样例,TS 5.9.3、strict、types: [] | 通过;未隔离环境类型时存在第三方 DOM/WebCodecs/markdown 声明冲突 | +| 使用项目构建配置 write:false 进行 ESM/现代 UMD/legacy UMD 内存构建 | 成功;不是完整 npm pack 或全部发布构建;未写产物 | +| 销毁源码隔离探针 | 重复 destroy 可误删其他实例注册项;需要正式回归用例 | +| 连续切源源码隔离探针 | 一次 canplay 可结算两次切源;尚未真实浏览器复现影响 | +| `bun test ./test/playback.test.js ./test/dash-control.test.js` | Bun 1.3.14:1 通过、18 失败,mock.fn 不兼容;未来版本需重测 | ## 清点中新增的待核对项 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 14d9cbf74..2db5bdceb 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -56,3 +56,9 @@ | BASE-LIFE-08 | resolved / 已复现 | Ready continues after a control callback destroys the instance | CORE-11 | | BASE-I18N-01 | resolved / 已复现 | Missing prototype-named translations return inherited functions | CORE-12 | | BASE-TYPE-09 | open / 源码/产物事实 | Template and icon declarations claim incompatible DOM and static shapes | CORE-21 | +| BASE-LIFE-09 | resolved / 已复现 | Removed builtin controls retain subscriptions and progress drag effects | CORE-13 | +| BASE-LIFE-10 | resolved / 已复现 | Component mounting and removal failures leave partial entries or recurse | CORE-13 | +| BASE-LIFE-11 | resolved / 已复现 | Selector failures are unhandled and obsolete completion overwrites current UI | CORE-13 | +| BASE-DOM-03 | resolved / 已复现 | Reusing selector items after update redefines nonconfigurable properties | CORE-13 | +| BASE-DOM-04 | resolved / 已复现 | A component named __proto__ changes its registry prototype | CORE-13 | +| BASE-DOM-05 | resolved / 已复现 | Highlight text interpolation permits unintended HTML attributes | CORE-13 | diff --git a/refactor/risks.json b/refactor/risks.json index 4a44e93c9..7ed7df778 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -170,7 +170,8 @@ "refactor/baselines/dom.json" ], "compatibleResolution": "在保留自定义控件扩展入口下修正布局。", - "closureCriteria": "320px 及正常容器的设置/模式操作真实可用。" + "closureCriteria": "320px 及正常容器的设置/模式操作真实可用。", + "workspaceState": "CORE-13 final installed UMD and legacy verify wrapped controls at 640/320/240px with real 16:9 heights and observed total-height offsets, including ResizeObserver fallback. Narrow setting tree/panel interactions still require CORE-14; this finding remains open." }, { "id": "BASE-DEMO-01", @@ -993,6 +994,144 @@ ], "compatibleResolution": "Keep old legal declarations accepted, expose accurate template and icon views without inventing runtime properties.", "closureCriteria": "Old consumers and accurate template/media/icon view consumers pass all supported type modes and runtime shape checks." + }, + { + "id": "BASE-LIFE-09", + "title": "Removed builtin controls retain subscriptions and progress drag effects", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Keep per-entry owned listeners, timers and drag callbacks inert after removal while preserving user subscriptions.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." + }, + { + "id": "BASE-LIFE-10", + "title": "Component mounting and removal failures leave partial entries or recurse", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Rollback failed registration, preserve successful reentrant replacement and original errors, retain failed beforeUnmount for retry.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." + }, + { + "id": "BASE-LIFE-11", + "title": "Selector failures are unhandled and obsolete completion overwrites current UI", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Keep callback arguments and default flags; report owned failures and gate titles and builtin quality notices by active selection.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." + }, + { + "id": "BASE-DOM-03", + "title": "Reusing selector items after update redefines nonconfigurable properties", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Keep getter descriptors and rebind only after the previous entry closes.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." + }, + { + "id": "BASE-DOM-04", + "title": "A component named __proto__ changes its registry prototype", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Preserve named DOM access with a normal own property without changing registry prototype.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." + }, + { + "id": "BASE-DOM-05", + "title": "Highlight text interpolation permits unintended HTML attributes", + "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "CORE-13" + ], + "evidence": [ + "test/browser/components.spec.js", + "test/component-resources.test.js", + "refactor/changes/2026-09-11-CORE-13-components.md" + ], + "compatibleResolution": "Assign highlight text through dataset while retaining marker positions and intentional control HTML APIs.", + "closureCriteria": "Published/candidate comparison, final installed UMD and legacy browser matrices, strict types and package verification must pass; original failure evidence remains recorded.", + "resolutionEvidence": [ + "refactor/changes/2026-09-11-CORE-13-components.md", + "refactor/baselines/components-validation.json", + "test/browser/components.spec.js", + "test/component-resources.test.js" + ], + "resolutionRationale": "Published/candidate behavior comparisons and both final installed artifact matrices pass. Entry ownership, transactional registration/removal, current selection guards and literal text assignment correct reproduced defects while retaining normal callbacks, return values, descriptors and public declarations. Source and shipped bytes match the tested package." } ] } diff --git a/refactor/tasks.json b/refactor/tasks.json index 5dd065304..1f9524207 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -990,11 +990,14 @@ "CORE-12", "CORE-08" ], - "status": "todo", + "status": "done", "risk": "H", "deliverable": "Component/control/layer/contextmenu 的资源与 TS 边界", "acceptance": "add/update/remove、name、selector、mounted/beforeUnmount 通过;处理 BASE-DOM-02 窄容器控件裁切,保留 controls.update 的旧 undefined 返回值", - "evidence": [] + "evidence": [ + "changes/2026-09-11-CORE-13-components.md", + "baselines/components-validation.json" + ] }, { "id": "CORE-14", diff --git a/test/browser/components.spec.js b/test/browser/components.spec.js new file mode 100644 index 000000000..4d0bad092 --- /dev/null +++ b/test/browser/components.spec.js @@ -0,0 +1,378 @@ +import { expect, test } from './fixtures.js' + +for (const fallback of [false, true]) { + test(`candidate: control layout follows resize and removal with observer fallback=${fallback}`, async ({ page }) => { + if (fallback) { + await page.addInitScript(() => { + window.ResizeObserver = undefined + }) + } + await page.goto('/test/player.html?core=candidate&chapter=published') + await page.evaluate(() => { + window.art = new window.Artplayer({ container: '.player', url: '', setting: true, fullscreenWeb: true, controls: [{ name: 'probe', position: 'right', html: 'Probe control' }] }) + }) + const heights = () => page.evaluate(() => ({ actual: window.art.template.$controls.offsetHeight, recorded: Number.parseFloat(window.art.template.$player.style.getPropertyValue('--art-controls-height')) })) + await expect.poll(heights).toEqual({ actual: 46, recorded: 46 }) + await page.evaluate(() => { + window.art.template.$container.style.width = '320px' + window.dispatchEvent(new Event('resize')) + }) + await expect.poll(heights).toEqual({ actual: 92, recorded: 92 }) + await expect.poll(() => page.evaluate(() => Number.parseFloat(getComputedStyle(window.art.template.$subtitle).bottom))).toBeGreaterThanOrEqual(92) + await page.evaluate(() => window.art.controls.remove('probe')) + await expect.poll(heights).toEqual({ actual: 46, recorded: 46 }) + await page.evaluate(() => { + window.art.destroy(false) + window.art.template.$controls.style.display = 'none' + window.art.emit('resize') + }) + await expect.poll(heights).toEqual({ actual: 0, recorded: 46 }) + }) +} + +for (const core of ['published', 'candidate']) { + test(`${core}: selector background clicks and rejection ownership are explicit`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + await page.evaluate(() => { + const failure = new Error('selection failure') + window.selectionReports = { warnings: [], rejections: [] } + window.addEventListener('unhandledrejection', (event) => { + event.preventDefault() + window.selectionReports.rejections.push({ name: event.reason.name, same: event.reason === failure }) + }) + const original = console.warn + console.warn = (message, error) => { + window.selectionReports.warnings.push({ message, same: error === failure }) + original.call(console, message, error) + } + const art = new window.Artplayer({ container: '.player', url: '' }) + window.art = art + art.controls.add({ name: 'selector', position: 'right', html: 'initial', selector: [{ html: 'A' }], onSelect() { + return Promise.reject(failure) + } }) + art.controls.selector.querySelector('.art-selector-list').dispatchEvent(new MouseEvent('click', { bubbles: true })) + }) + if (core === 'published') + await expect.poll(() => page.evaluate(() => window.selectionReports.rejections.length)).toBe(1) + await page.evaluate(() => window.art.controls.selector.querySelector('.art-selector-item').dispatchEvent(new MouseEvent('click', { bubbles: true }))) + await expect.poll(() => page.evaluate(() => window.selectionReports.warnings.length + window.selectionReports.rejections.length)).toBe(core === 'published' ? 2 : 1) + const reports = await page.evaluate(() => window.selectionReports) + expect(reports).toEqual(core === 'published' + ? { warnings: [], rejections: [{ name: 'TypeError', same: false }, { name: 'Error', same: true }] } + : { warnings: [{ message: 'ArtPlayer selector failed:', same: true }], rejections: [] }) + await page.evaluate(() => window.art.destroy()) + }) + + test(`${core}: beforeUnmount errors remain retryable and detached nodes can be removed`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const failure = new Error('before unmount') + const option = { name: 'entry', html: 'entry', beforeUnmount() { + throw failure + } } + const element = art.layers.add(option) + let same = false + try { + art.layers.remove('entry') + } + catch (error) { same = error === failure } + const retained = art.layers.cache.has('entry') && element.isConnected + option.beforeUnmount = () => {} + element.remove() + let error = null + try { + art.layers.remove('entry') + } + catch (caught) { error = caught.name } + const result = { same, retained, error, removed: !art.layers.cache.has('entry') } + art.destroy() + return result + }) + expect(result).toEqual({ same: true, retained: true, error: core === 'published' ? 'TypeError' : null, removed: true }) + }) + + test(`${core}: failed mounted reentry preserves its successful replacement`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const failure = new Error('outer failure') + let same = false + try { + art.layers.add({ name: 'entry', html: 'outer', mounted() { + art.layers.remove('entry') + art.layers.add({ name: 'entry', html: 'replacement' }) + throw failure + } }) + } + catch (error) { same = error === failure } + const result = { same, value: art.layers.entry.textContent, attached: art.layers.entry.isConnected, entries: art.layers.cache.size } + art.destroy() + return result + }) + expect(result).toEqual({ same: true, value: 'replacement', attached: true, entries: 1 }) + }) + + test(`${core}: context menu builtin selection and owned updates preserve state`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + await page.evaluate(() => { + window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', playbackRate: true, aspectRatio: true, flip: true }) + }) + await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true) + for (const [name, value] of [['playbackRate', '1.5'], ['aspectRatio', '4:3'], ['flip', 'horizontal']]) { + await page.locator('.art-video-player').click({ button: 'right', position: { x: 100, y: 80 } }) + await page.locator(`.art-contextmenu-${name} [data-value="${value}"]`).click() + await expect.poll(() => page.evaluate(name => window.art.contextmenu[name].querySelector('.art-current')?.dataset.value, name)).toBe(value) + expect(await page.evaluate(() => window.art.contextmenu.show)).toBe(false) + } + const result = await page.evaluate(() => { + const { art } = window + const menu = art.contextmenu.flip + art.contextmenu.remove('flip') + art.flip = 'normal' + const result = { rate: art.playbackRate, aspect: art.aspectRatio, changedAfterRemove: menu.querySelector('[data-value="normal"]').classList.contains('art-current') } + art.destroy() + return result + }) + expect(result).toEqual({ rate: 1.5, aspect: '4:3', changedAfterRemove: core === 'published' }) + }) + + test(`${core}: a prototype-named component keeps the registry prototype intact`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const prototype = Object.getPrototypeOf(art.layers) + const element = art.layers.add({ name: '__proto__', html: 'named' }) + const alias = Reflect.get(art.layers, '__proto__') === element + art.layers.remove('__proto__') + const result = { alias, preserved: Object.getPrototypeOf(art.layers) === prototype } + art.destroy() + return result + }) + expect(result).toEqual({ alias: true, preserved: core === 'candidate' }) + }) + + test(`${core}: component factories, ordering, bound methods and update hooks retain contracts`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const { add, update, remove } = art.layers + const calls = [] + const first = { name: 'first', index: 10, html: 'first', mounted(element) { + calls.push(['mount', this === art, element.textContent]) + } } + add(first) + add({ name: 'equal', index: 10, html: 'equal' }) + let factory + add((owner) => { + factory = owner === art + return { name: 'zero', index: 0, html: 42 } + }) + const disabled = { html: 0, disable: true } + const before = art.layers.id + const disabledResult = add(disabled) + const order = Array.from(art.template.$layer.children, node => node.textContent) + const updated = update({ name: 'first', html: 'changed', beforeUnmount(element) { + calls.push(['unmount', this === art, element.textContent, first.html]) + } }) + const controlResult = art.controls.add({ name: 'probe', position: 'right', html: 'probe', click(component, event) { + calls.push(['click', this === art, component === art.controls, event.defaultPrevented]) + } }) + art.controls.probe.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })) + const controlUpdate = art.controls.update({ name: 'probe', html: 'updated' }) + const result = { factory, order, disabled: disabledResult === undefined && art.layers.id === before + 1 && disabled.html === '', updated: updated === art.layers.first, controlReturns: [controlResult === undefined, controlUpdate === undefined], calls } + remove('first') + art.destroy() + return result + }) + expect(result.factory).toBe(true) + expect(result.order).toEqual(['42', 'equal', 'first']) + expect(result.disabled).toBe(true) + expect(result.updated).toBe(true) + expect(result.controlReturns).toEqual([true, true]) + expect(result.calls.slice(0, 4)).toEqual([['mount', true, 'first'], ['unmount', true, 'first', 'changed'], ['mount', true, 'changed'], ['click', true, true, true]]) + }) + + test(`${core}: removed builtin time and volume controls stop owned effects`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const time = art.controls.time + const before = time.textContent + const icon = art.controls.volume.querySelector('.art-icon-volume') + art.controls.remove('time') + art.controls.remove('volume') + art.video.currentTime = 12 + art.emit('video:timeupdate', new Event('timeupdate')) + art.muted = false + icon.dispatchEvent(new MouseEvent('click')) + const result = { changed: time.textContent !== before, muted: art.muted } + art.destroy() + return result + }) + expect(result).toEqual({ changed: core === 'published', muted: core === 'published' }) + }) + + test(`${core}: selector items can be reused by an update without changing getter flags`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const selector = [{ html: 'A', value: 'a', default: true }, { html: 'B', value: 'b' }] + art.controls.add({ name: 'selector', position: 'right', html: 'A', selector }) + const oldNode = selector[0].$control_item + let error = null + try { + art.controls.update({ name: 'selector', html: 'updated' }) + } + catch (caught) { error = caught.name } + const descriptor = Object.getOwnPropertyDescriptor(selector[0], '$control_item') + const result = { error, changed: selector[0].$control_item !== oldNode, flags: [descriptor.enumerable, descriptor.configurable, typeof descriptor.get], options: selector[0].$control_option === selector } + art.destroy() + return result + }) + expect(result).toEqual({ error: core === 'candidate' ? null : 'TypeError', changed: core === 'candidate', flags: [false, false, 'function'], options: true }) + }) + + test(`${core}: async selector results cannot overwrite a newer choice or removed entry`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(async () => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const selector = [{ html: 'A', value: 'a' }, { html: 'B', value: 'b' }] + const pending = [] + const calls = [] + art.controls.add({ name: 'selector', position: 'right', html: 'initial', selector, onSelect(item, node, event) { + calls.push([this === art, selector.includes(item), item.$control_item === node, event.type]) + return new Promise(resolve => pending.push(resolve)) + } }) + const click = item => item.$control_item.dispatchEvent(new MouseEvent('click', { bubbles: true })) + click(selector[0]) + click(selector[1]) + pending[1]('new') + await Promise.resolve() + pending[0]('old') + await Promise.resolve() + const value = selector[0].$control_value + const raced = value.innerHTML + click(selector[0]) + const beforeRemove = value.innerHTML + art.controls.remove('selector') + pending[2]('removed') + await Promise.resolve() + const result = { raced, changedAfterRemove: value.innerHTML !== beforeRemove, flags: selector.map(item => item.default), calls } + art.destroy() + return result + }) + expect(result.raced).toBe(core === 'candidate' ? 'new' : 'old') + expect(result.changedAfterRemove).toBe(core === 'published') + expect(result.flags).toEqual([true, false]) + expect(result.calls).toEqual(Array.from({ length: 3 }, () => [true, true, true, 'click'])) + }) + + test(`${core}: a failed mounted hook rolls back its DOM alias and listeners`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + const failure = new Error('mounted failure') + let element + let sameError = false + let clicks = 0 + try { + art.layers.add({ name: 'failed', html: 'failed', click() { + clicks++ + }, mounted(node) { + element = node + throw failure + } }) + } + catch (error) { sameError = error === failure } + element.dispatchEvent(new MouseEvent('click')) + const result = { sameError, clicks, cached: art.layers.cache.has('failed'), alias: art.layers.failed === element, attached: art.template.$layer.contains(element) } + art.destroy() + return result + }) + expect(result).toEqual({ sameError: true, clicks: core === 'candidate' ? 0 : 1, cached: core === 'published', alias: core === 'published', attached: core === 'published' }) + }) + + test(`${core}: reentrant beforeUnmount removes only once`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '' }) + let calls = 0 + art.layers.add({ name: 'reentrant', html: 'reentrant', beforeUnmount() { + calls++ + if (calls === 1) + art.layers.remove('reentrant') + } }) + let error = null + try { + art.layers.remove('reentrant') + } + catch (caught) { error = caught.name } + const result = { calls, error, cached: art.layers.cache.has('reentrant') } + art.destroy() + return result + }) + expect(result).toEqual({ calls: core === 'candidate' ? 1 : 2, error: core === 'candidate' ? null : 'TypeError', cached: false }) + }) + + test(`${core}: narrow controls stay inside the player without hiding buttons`, async ({ page }, testInfo) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + const result = await page.evaluate(() => { + const art = new window.Artplayer({ container: '.player', url: '', setting: true, fullscreenWeb: true, controls: [{ name: 'probe', position: 'right', html: 'Probe control' }] }) + const container = art.template.$container + const measure = (width) => { + container.style.width = `${width}px` + container.style.height = `${width * 9 / 16}px` + const bounds = container.getBoundingClientRect() + const controls = Array.from(container.querySelectorAll('.art-controls .art-control')) + return { count: controls.length, hidden: controls.filter(node => node.getClientRects().length === 0).length, overflow: controls.filter((node) => { + const box = node.getBoundingClientRect() + return box.left < bounds.left - 0.75 || box.right > bounds.right + 0.75 || box.top < bounds.top - 0.75 || box.bottom > bounds.bottom + 0.75 + }).length } + } + const wide = measure(640) + const narrow = measure(320) + const smaller = measure(240) + measure(320) + window.layoutArt = art + return { wide, narrow, smaller } + }) + await page.locator('.player').screenshot({ path: testInfo.outputPath('narrow-controls.png') }) + await page.evaluate(() => window.layoutArt.destroy()) + expect(result.wide.overflow).toBe(0) + expect(result.narrow.count).toBe(result.wide.count) + expect(result.narrow.hidden).toBe(0) + expect(result.smaller.hidden).toBe(0) + if (core === 'candidate') { + expect(result.narrow.overflow).toBe(0) + expect(result.smaller.overflow).toBe(0) + } + else { + expect(result.narrow.overflow).toBeGreaterThan(0) + expect(result.smaller.overflow).toBeGreaterThan(0) + } + }) + + test(`${core}: progress markers treat text as data and removed drags cannot seek`, async ({ page }) => { + await page.goto(`/test/player.html?core=${core}&chapter=published`) + await page.evaluate(() => { + window.createPlayer('/test/pattern.mp4') + window.art.option.highlight = [{ time: 1, text: 'label" data-injected="yes' }] + }) + await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true) + const result = await page.evaluate(() => { + const art = window.art + const marker = art.controls.progress.querySelector('.art-progress-highlight span') + const text = marker.dataset.text + const injected = marker.hasAttribute('data-injected') + let seeks = 0 + art.on('seek', () => seeks++) + art.template.$progress.dispatchEvent(new MouseEvent('mousedown', { button: 0 })) + art.controls.remove('progress') + art.emit('document:mousemove', new MouseEvent('mousemove', { clientX: 100 })) + art.destroy() + return { text, injected, seeks } + }) + expect(result).toEqual({ text: core === 'candidate' ? 'label" data-injected="yes' : 'label', injected: core === 'published', seeks: core === 'candidate' ? 0 : 1 }) + }) +} diff --git a/test/browser/source.spec.js b/test/browser/source.spec.js index 99e193cf5..79ba44299 100644 --- a/test/browser/source.spec.js +++ b/test/browser/source.spec.js @@ -56,11 +56,32 @@ for (const core of ['published', 'candidate']) { }) } -test('candidate: quality switch restores position/rate and preserves real customType identities', async ({ page }) => { +test('candidate: quality switch restores position/rate and preserves real customType identities', async ({ page }, testInfo) => { await page.goto('/test/player.html?core=candidate&chapter=published') await page.evaluate(() => window.createPlayer('/test/pattern.mp4?custom=initial')) await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true) + // A real gesture starts WebKit's media pipeline before the paused seek setup. + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1) + await page.locator('#pause').click() + await expect.poll(() => page.evaluate(() => window.art.video.paused)).toBe(true) + await testInfo.attach('initial-media-ranges', { + body: JSON.stringify(await page.evaluate(() => { + const { video } = window.art + const ranges = value => Array.from({ length: value.length }, (_, index) => [value.start(index), value.end(index)]) + return { buffered: ranges(video.buffered), seekable: ranges(video.seekable), readyState: video.readyState, duration: video.duration, currentTime: video.currentTime } + })), + contentType: 'application/json', + }) + await expect.poll(() => page.evaluate(() => { + const ranges = window.art.video.seekable + return Array.from({ length: ranges.length }, (_, index) => index).some(index => ranges.start(index) <= 3 && ranges.end(index) >= 3) + })).toBe(true) await page.evaluate(() => { + window.switchMediaEvents = [] + for (const name of ['loadedmetadata', 'seeking', 'seeked', 'canplay', 'pause', 'playing']) { + window.art.video.addEventListener(name, () => window.switchMediaEvents.push({ name, time: window.art.currentTime, seeking: window.art.video.seeking, source: window.art.video.currentSrc })) + } window.art.currentTime = 3 }) await expect.poll(() => page.evaluate(() => window.art.video.seeking)).toBe(false) @@ -76,11 +97,16 @@ test('candidate: quality switch restores position/rate and preserves real custom art.aspectRatio = '16:9' const restart = [] art.on('restart', url => restart.push(url)) + const beforeSwitch = { time: art.currentTime, seeking: art.video.seeking, paused: art.video.paused } await art.switchQuality('/test/pattern.mp4?custom=next') - const result = { calls, restart, time: art.currentTime, rate: art.playbackRate, ratio: art.aspectRatio, paused: art.video.paused, error: art.video.error?.code || 0 } + const result = { beforeSwitch, mediaEvents: window.switchMediaEvents, calls, restart, time: art.currentTime, rate: art.playbackRate, ratio: art.aspectRatio, paused: art.video.paused, error: art.video.error?.code || 0 } art.destroy() return result }) + await testInfo.attach('quality-switch-media-state', { body: JSON.stringify(result), contentType: 'application/json' }) + expect(result.beforeSwitch.time).toBeCloseTo(3, 1) + expect(result.beforeSwitch.seeking).toBe(false) + expect(result.beforeSwitch.paused).toBe(true) expect(result.calls).toEqual([{ thisIdentity: true, ownerIdentity: true, videoIdentity: true, count: 3, url: '/test/pattern.mp4?custom=next' }]) expect(result.restart).toEqual(['/test/pattern.mp4?custom=next']) expect(result.time).toBeCloseTo(3, 1) diff --git a/test/component-resources.test.js b/test/component-resources.test.js new file mode 100644 index 000000000..e046ac56c --- /dev/null +++ b/test/component-resources.test.js @@ -0,0 +1,221 @@ +import assert from 'node:assert/strict' +// eslint-disable-next-line test/no-import-node-test -- Use the repository Node test runner. +import { test } from 'node:test' +import { loadModules } from './helpers/load.js' + +const resources = 'packages/artplayer/src/component/resources' +const lifecycle = 'packages/artplayer/src/lifecycle/instance' +const { Emitter, Control, installControls, qualityMix, trackSelection, captureSelection, beginLifecycle, destroyInstance, getScope, ownEntry, entryScope, releaseEntry, proxyEntry, subscribeEntry } = await loadModules({ + Emitter: 'packages/artplayer/src/utils/emitter', + Control: 'packages/artplayer/src/control/index', + installControls: { file: 'packages/artplayer/src/control/builtins', name: 'installControls' }, + qualityMix: 'packages/artplayer/src/player/qualityMix', + ...Object.fromEntries(['trackSelection', 'captureSelection'].map(name => [name, { file: 'packages/artplayer/src/component/selection', name }])), + ...Object.fromEntries(['beginLifecycle', 'destroyInstance', 'getScope'].map(name => [name, { file: lifecycle, name }])), + ...Object.fromEntries(['ownEntry', 'entryScope', 'releaseEntry', 'proxyEntry', 'subscribeEntry'].map(name => [name, { file: resources, name }])), +}) + +test('deferred builtin quality initialization reports its original failure', async (t) => { + t.mock.timers.enable({ apis: ['setTimeout'] }) + const { art } = fixture() + const failure = new Error('quality option getter') + const warnings = [] + t.mock.method(console, 'warn', (...args) => warnings.push(args)) + let reads = 0 + art.option = { + controls: [], + get quality() { + if (reads++ === 0) + return [{ html: 'A', url: 'a' }] + throw failure + }, + } + installControls({ art, add() {} }) + t.mock.timers.tick(0) + await Promise.resolve() + await Promise.resolve() + assert.deepEqual(warnings, [['ArtPlayer quality initialization failed:', failure]]) + getScope(art).dispose() +}) + +test('control factories do not run during the reset portion of instance destruction', () => { + const { art } = fixture() + art.isDestroy = false + art.template = { $video: {}, destroy() {} } + let factories = 0 + art.reset = () => { + assert.equal(art.isDestroy, false) + assert.equal(getScope(art).closed, false) + const result = Control.prototype.add.call({ art }, () => { + factories++ + return { html: 'late' } + }) + assert.equal(result, undefined) + } + destroyInstance(art, [art], true, true) + assert.equal(factories, 0) + assert.equal(art.isDestroy, true) +}) + +test('quality callbacks keep return values while obsolete and removed selections stop notices', async () => { + const { art, element } = fixture() + let option + art.controls = { update(value) { + option = value + } } + art.notice = { show: '' } + art.i18n = { get: key => key } + const pending = [] + art.switchQuality = url => new Promise(resolve => pending.push({ url, resolve })) + qualityMix(art) + const quality = [{ html: 'A', url: 'a' }, { html: 'B', url: 'b' }] + art.quality = quality + let generation = 0 + const run = (item) => { + const current = ++generation + const scope = entryScope(element) + const event = new Event('click') + const release = scope.add(trackSelection(event, () => !scope.closed && current === generation)) + return option.onSelect.call(art, item, element, event).finally(release) + } + const first = run(quality[0]) + const second = run(quality[1]) + pending[1].resolve() + assert.equal(await second, 'B') + assert.equal(art.notice.show, 'Switch Video: B') + pending[0].resolve() + assert.equal(await first, 'A') + assert.equal(art.notice.show, 'Switch Video: B') + const removed = run(quality[0]) + releaseEntry(element) + pending[2].resolve() + assert.equal(await removed, 'A') + assert.equal(art.notice.show, 'Switch Video: B') + ownEntry(art, element) + art.i18n.get = (key) => { + releaseEntry(element) + return key + } + const reentrant = run(quality[0]) + pending[3].resolve() + assert.equal(await reentrant, 'A') + assert.equal(art.notice.show, 'Switch Video: B') + assert.deepEqual(pending.map(item => item.url), ['a', 'b', 'a', 'a']) +}) + +test('quality rejection identity and captured selection closure survive disposal', async () => { + const { art, element } = fixture() + let option + const failure = new Error('quality failed') + art.controls = { update(value) { + option = value + } } + art.notice = { show: '' } + art.i18n = { get: key => key } + art.switchQuality = () => Promise.reject(failure) + qualityMix(art) + const quality = [{ html: 'A', url: 'a' }] + art.quality = quality + const event = new Event('click') + const scope = entryScope(element) + scope.add(trackSelection(event, () => !scope.closed)) + const active = captureSelection(event) + const result = option.onSelect.call(art, quality[0], element, event) + releaseEntry(element) + assert.equal(active(), false) + await assert.rejects(result, error => error === failure) + assert.equal(art.notice.show, '') +}) + +function fixture() { + const art = new Emitter() + const registered = new Set() + art.events = { + proxy(target, name, callback) { + target.addEventListener(name, callback) + const cleanup = () => target.removeEventListener(name, callback) + registered.add(cleanup) + return cleanup + }, + remove(cleanup) { + cleanup() + registered.delete(cleanup) + }, + } + beginLifecycle(art) + const element = new EventTarget() + ownEntry(art, element) + return { art, element, registered } +} + +test('entry disposal removes DOM listeners and preserves unrelated entries', () => { + const { art, element, registered } = fixture() + const second = new EventTarget() + ownEntry(art, second) + const events = [] + proxyEntry(art, element, element, 'click', event => events.push(event)) + proxyEntry(art, second, second, 'click', event => events.push(event)) + const original = new Event('click') + element.dispatchEvent(original) + assert.equal(events[0], original) + releaseEntry(element) + element.dispatchEvent(new Event('click')) + second.dispatchEvent(new Event('click')) + assert.equal(events.length, 2) + assert.equal(registered.size, 1) + assert.equal(entryScope(element).closed, true) + assert.equal(getScope(art).closed, false) + getScope(art).dispose() + assert.equal(registered.size, 0) +}) + +test('entry listeners stop within an existing emitter snapshot while user listeners survive', () => { + const { art, element } = fixture() + const calls = [] + art.on('update', () => { + calls.push('first') + releaseEntry(element) + }) + subscribeEntry(art, element, 'update', () => calls.push('owned')) + art.on('update', () => calls.push('last')) + art.emit('update') + art.emit('update') + assert.deepEqual(calls, ['first', 'last', 'first', 'last']) + assert.equal(art.e.update.length, 2) +}) + +test('root closure stops all entry resources and late registrations remain inert', () => { + const { art, element, registered } = fixture() + let calls = 0 + proxyEntry(art, element, element, 'click', () => calls++) + subscribeEntry(art, element, 'update', () => calls++) + getScope(art).dispose() + proxyEntry(art, element, element, 'click', () => calls++) + subscribeEntry(art, element, 'update', () => calls++) + element.dispatchEvent(new Event('click')) + art.emit('update') + releaseEntry(element) + assert.equal(calls, 0) + assert.equal(registered.size, 0) +}) + +test('cleanup failure does not prevent releasing other component resources', () => { + const { art, element } = fixture() + const failures = [new Error('first'), new Error('second')] + const attempts = [] + art.events.remove = () => { + const error = failures[attempts.length] + attempts.push(error) + throw error + } + proxyEntry(art, element, element, 'click', () => {}) + proxyEntry(art, element, element, 'change', () => {}) + assert.throws(() => releaseEntry(element), (error) => { + assert.deepEqual(error.errors, failures) + return true + }) + assert.deepEqual(attempts, failures) + assert.equal(entryScope(element).closed, true) + releaseEntry(element) + assert.equal(attempts.length, 2) +}) diff --git a/test/types/components.ts b/test/types/components.ts new file mode 100644 index 000000000..589c5a077 --- /dev/null +++ b/test/types/components.ts @@ -0,0 +1,22 @@ +import type { ComponentHost } from '../../packages/artplayer/src/component/types' +import type { ControlHost } from '../../packages/artplayer/src/control/types' +import Control from '../../packages/artplayer/src/control' +import Component from '../../packages/artplayer/src/utils/component' + +declare const host: ComponentHost & { extra: number } +const component = new Component(host) +const added: HTMLDivElement | undefined = component.add({ html: 42, mounted(element) { + const extra: number = this.extra + const div: HTMLDivElement = element + void [extra, div] +} }) +const updated: HTMLDivElement | undefined = component.update({ name: 'entry', html: 'new' }) +declare const controlHost: ControlHost +const control = new Control(controlHost) +const empty: undefined = control.add({ position: 'right', html: 'entry' }) +const alsoEmpty: undefined = control.update({ name: 'entry', html: 'new' }) +// @ts-expect-error Control.add has always returned undefined at runtime. +const invented: HTMLDivElement = control.add({ position: 'left', html: 'entry' }) +// @ts-expect-error Component indexes are numbers. +component.add({ index: 'first' }) +void [added, updated, empty, alsoEmpty, invented]