mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
8 lines
18 KiB
JavaScript
8 lines
18 KiB
JavaScript
/*!
|
|
* artplayer-plugin-jassub.js v2.0.0
|
|
* Github: https://github.com/zhw2590582/ArtPlayer
|
|
* (c) 2017-2026 Harvey Zhao
|
|
* Released under the MIT License.
|
|
*/
|
|
!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginJassub=t(),define(function(){return e.artplayerPluginJassub})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginJassub=t()}(this,function(){"use strict";var e=Object.defineProperty,t=(t,s,i)=>((t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i)(t,"symbol"!==typeof s?s+"":s,i);typeof HTMLVideoElement<"u"&&!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype.requestVideoFrameCallback=function(e){Object.prototype.hasOwnProperty.call(this,"_rvfcpolyfillmap")||(this._rvfcpolyfillmap={});const t=this._rvfcpolyfillid=(this._rvfcpolyfillid||0)+1,s=performance.now(),i=this.getVideoPlaybackQuality(),a=this.currentTime,r=this.mozPresentedFrames||this.mozPaintedFrames||i.totalVideoFrames-i.droppedVideoFrames,n=(o,h)=>{if(!(t in this._rvfcpolyfillmap))return;const d=this.getVideoPlaybackQuality(),l=this.mozPresentedFrames||this.mozPaintedFrames||d.totalVideoFrames-d.droppedVideoFrames,c=l>r,_=0===r&&0===l&&0===i.totalVideoFrames&&0===i.droppedVideoFrames&&0===d.totalVideoFrames&&0===d.droppedVideoFrames&&Number.isFinite(this.currentTime)&&this.currentTime!==a&&this.readyState>=2&&!this.seeking&&h-s>=1e3/30;if(c||_){const s=this.mozFrameDelay||d.totalFrameDelay-i.totalFrameDelay||0,a=h-o;delete this._rvfcpolyfillmap[t],e(h,{presentationTime:h+1e3*s,expectedDisplayTime:h+a,width:this.videoWidth,height:this.videoHeight,mediaTime:_&&!c?Math.max(0,this.currentTime):Math.max(0,this.currentTime||0)+a/1e3,presentedFrames:l,processingDuration:s})}else this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(h,e))};return this._rvfcpolyfillmap[t]=requestAnimationFrame(e=>n(s,e)),t},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(e){const t=this._rvfcpolyfillmap;t&&e in t&&(cancelAnimationFrame(t[e]),delete t[e])});const s={bt709:"BT709",bt470bg:"BT601",smpte170m:"BT601"},i={BT601:{BT709:"1.0863 -0.0723 -0.014 0 0 0.0965 0.8451 0.0584 0 0 -0.0141 -0.0277 1.0418"},BT709:{BT601:"0.9137 0.0784 0.0079 0 0 -0.1049 1.1722 -0.0671 0 0 0.0096 0.0322 0.9582"},FCC:{BT709:"1.0873 -0.0736 -0.0137 0 0 0.0974 0.8494 0.0531 0 0 -0.0127 -0.0251 1.0378",BT601:"1.001 -0.0008 -0.0002 0 0 0.0009 1.005 -0.006 0 0 0.0013 0.0027 0.996"},SMPTE240M:{BT709:"0.9993 0.0006 0.0001 0 0 -0.0004 0.9812 0.0192 0 0 -0.0034 -0.0114 1.0148",BT601:"0.913 0.0774 0.0096 0 0 -0.1051 1.1508 -0.0456 0 0 0.0063 0.0207 0.973"}},a=class e extends EventTarget{constructor(t){let s;super(),this._requests=new Set;try{if(!globalThis.Worker)throw this.destroy("Worker not supported");if(!t)throw this.destroy("No options provided");if(this._loaded=new Promise(e=>{this._init=e}),s=e._test(),this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&(t.onDemandRender??!0),this._offscreenRender="transferControlToOffscreen"in HTMLCanvasElement.prototype&&!t.canvas&&(t.offscreenRender??!0),this.timeOffset=t.timeOffset||0,this._video=t.video,this._videoHeight=0,this._videoWidth=0,this._videoColorSpace=null,this._canvas=t.canvas,this._video&&!this._canvas)this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=this._createCanvas(),this._video.insertAdjacentElement("afterend",this._canvasParent);else if(!this._canvas)throw this.destroy("Don't know where to render: you should give video or canvas in options.");if(this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d"),!this._bufferCtx)throw this.destroy("Canvas rendering not supported");this._canvasctrl=this._offscreenRender?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!this._offscreenRender&&this._canvasctrl.getContext("2d"),this._lastRenderTime=0,this.debug=!!t.debug,this.prescaleFactor=t.prescaleFactor||1,this.prescaleHeightLimit=t.prescaleHeightLimit||1080,this.maxRenderHeight=t.maxRenderHeight||0,this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=()=>{this._destroyed||this.setRate(this._video.playbackRate)},this._boundUpdateColorSpace=this._updateColorSpace.bind(this),this._video&&this.setVideo(t.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null),this._worker=new Worker(t.workerUrl||"jassub-worker.js"),this._worker.onmessage=e=>this._onmessage(e),this._worker.onerror=e=>this._error(e),s.then(()=>{this._destroyed||this._worker.postMessage({target:"init",wasmUrl:e._supportsSIMD&&t.modernWasmUrl?t.modernWasmUrl:t.wasmUrl??"jassub-worker.wasm",legacyWasmUrl:t.legacyWasmUrl??"jassub-worker.wasm.js",asyncRender:typeof createImageBitmap<"u"&&(t.asyncRender??!0),onDemandRender:this._onDemandRender,width:this._canvasctrl.width||0,height:this._canvasctrl.height||0,blendMode:t.blendMode||"js",subUrl:t.subUrl,subContent:t.subContent||null,fonts:t.fonts||[],availableFonts:t.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:t.fallbackFont||"liberation sans",debug:this.debug,targetFps:t.targetFps||24,dropAllAnimations:t.dropAllAnimations,dropAllBlur:t.dropAllBlur,libassMemoryLimit:t.libassMemoryLimit||0,libassGlyphLimit:t.libassGlyphLimit||0,useLocalFonts:typeof queryLocalFonts<"u"&&(t.useLocalFonts??!0),hasBitmapBug:e._hasBitmapBug})}).catch(e=>{this._destroyed||this.destroy(e)})}catch(i){s?.catch(()=>{});try{this.destroy()}catch{}throw i}}_createCanvas(){return this._canvas=document.createElement("canvas"),this._canvas.style.display="block",this._canvas.style.position="absolute",this._canvas.style.pointerEvents="none",this._canvasParent.appendChild(this._canvas),this._canvas}static _testSIMD(){if(null===e._supportsSIMD)try{e._supportsSIMD=WebAssembly.validate(Uint8Array.of(0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11))}catch{e._supportsSIMD=!1}}static async _testImageBugs(){if(null!==e._hasBitmapBug)return;const t=document.createElement("canvas"),s=t.getContext("2d",{willReadFrequently:!0});if(!s)throw new Error("Canvas rendering not supported");if("function"==typeof ImageData.prototype.constructor)try{new ImageData(new Uint8ClampedArray([0,0,0,0]),1,1)}catch{console.log("Detected that ImageData is not constructable despite browser saying so"),self.ImageData=function(e,t,i){const a=s.createImageData(t,i);return e&&a.data.set(e),a}}const i=document.createElement("canvas"),a=i.getContext("2d",{willReadFrequently:!0});if(!a)throw new Error("Canvas rendering not supported");t.width=i.width=1,t.height=i.height=1,s.clearRect(0,0,1,1),a.clearRect(0,0,1,1);const r=a.getImageData(0,0,1,1).data;s.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),a.drawImage(t,0,0);const n=a.getImageData(0,0,1,1).data;if(e._hasAlphaBug=r[1]!==n[1],e._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),typeof createImageBitmap<"u"){const t=new Uint8ClampedArray([255,0,255,0,255]).subarray(1,5);a.drawImage(await createImageBitmap(new ImageData(t,1)),0,0);const{data:s}=a.getImageData(0,0,1,1);e._hasBitmapBug=!1;for(const[i,a]of s.entries())if(Math.abs(t[i]-a)>15){e._hasBitmapBug=!0,console.log("Detected a browser having issue with partial bitmaps, applying workaround");break}}else e._hasBitmapBug=!1;t.remove(),i.remove()}static async _test(){e._testSIMD(),await e._testImageBugs()}resize(e=0,t=0,s=0,i=0,a=this._video?.paused){if(!this._destroyed){if((!e||!t)&&this._video){const a=this._getVideoPosition();let r=null;if(this._videoWidth){const e=this._video.videoWidth/this._videoWidth,t=this._video.videoHeight/this._videoHeight;r=this._computeCanvasSize((a.width||0)/e,(a.height||0)/t)}else r=this._computeCanvasSize(a.width||0,a.height||0);e=r.width,t=r.height,this._canvasParent&&(s=a.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),i=a.x),this._canvas.style.width=a.width+"px",this._canvas.style.height=a.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=i+"px",a&&!1===this.busy?this.busy=!0:a=!1,this.sendMessage("canvas",{width:e,height:t,videoWidth:this._videoWidth||this._video?.videoWidth||e,videoHeight:this._videoHeight||this._video?.videoHeight||t,force:a})}}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:i,offsetHeight:a}=this._video;e=i,t=a,i/a>s?e=Math.floor(a*s):t=Math.floor(i/s);return{width:e,height:t,x:(i-e)/2,y:(a-t)/2}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,i=self.devicePixelRatio||1;if(t<=0||e<=0)e=0,t=0;else{const a=s<1?-1:1;let r=t*i;a*r*s<=a*this.prescaleHeightLimit?r*=s:a*r<a*this.prescaleHeightLimit&&(r=this.prescaleHeightLimit),this.maxRenderHeight>0&&r>this.maxRenderHeight&&(r=this.maxRenderHeight),e*=r/t,t=r}return{width:e,height:t}}_timeupdate({type:e}){if(this._destroyed)return;const t={seeking:!0,waiting:!0,playing:!1}[e];null!=t&&(this._playstate=t),this.setCurrentTime(this._video.paused||this._playstate,this._video.currentTime+this.timeOffset)}setVideo(e){if(!this._destroyed)if(e instanceof HTMLVideoElement){if(this._removeListeners(),this._video=e,this._videoWidth=this._videoHeight=0,this._videoColorSpace=null,this._canvasParent&&this._canvasParent.parentNode!==e.parentNode&&e.insertAdjacentElement("afterend",this._canvasParent),this._onDemandRender)this._requestFrame();else{this._playstate=e.paused;for(const t of["timeupdate","progress","waiting","seeking","playing"])e.addEventListener(t,this._boundTimeUpdate,!1);e.addEventListener("ratechange",this._boundSetRate,!1),e.addEventListener("resize",this._boundResize,!1)}"VideoFrame"in window&&(e.addEventListener("loadedmetadata",this._boundUpdateColorSpace,!1),e.readyState>2&&this._updateColorSpace()),e.videoWidth>0&&this.resize(),typeof ResizeObserver<"u"&&(this._ro||(this._ro=new ResizeObserver(()=>this.resize())),this._ro.observe(e))}else this._error("Video element invalid!")}runBenchmark(){this.sendMessage("runBenchmark")}setTrackByUrl(e){this.sendMessage("setTrackByUrl",{url:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}setTrack(e){this.sendMessage("setTrack",{content:e}),this._reAttachOffscreen(),this._ctx&&(this._ctx.filter="none")}freeTrack(){this.sendMessage("freeTrack")}setIsPaused(e){this.sendMessage("video",{isPaused:e})}setRate(e){this.sendMessage("video",{rate:e})}setCurrentTime(e,t,s){this.sendMessage("video",{isPaused:e,currentTime:t,rate:s,colorSpace:this._videoColorSpace})}createEvent(e){this.sendMessage("createEvent",{event:e})}setEvent(e,t){this.sendMessage("setEvent",{event:e,index:t})}removeEvent(e){this.sendMessage("removeEvent",{index:e})}getEvents(e){this._fetchFromWorker({target:"getEvents"},(t,{events:s}={})=>{e(t,s)})}styleOverride(e){this.sendMessage("styleOverride",{style:e})}disableStyleOverride(){this.sendMessage("disableStyleOverride")}createStyle(e){this.sendMessage("createStyle",{style:e})}setStyle(e,t){this.sendMessage("setStyle",{style:e,index:t})}removeStyle(e){this.sendMessage("removeStyle",{index:e})}getStyles(e){this._fetchFromWorker({target:"getStyles"},(t,{styles:s}={})=>{e(t,s)})}addFont(e){this.sendMessage("addFont",{font:e})}setDefaultFont(e){this.sendMessage("defaultFont",{font:e})}_sendLocalFont(e){try{queryLocalFonts().then(t=>{const s=t?.find(t=>t.fullName.toLowerCase()===e);s&&s.blob().then(e=>{e.arrayBuffer().then(e=>{this.addFont(new Uint8Array(e))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){try{navigator?.permissions?.query?navigator.permissions.query({name:"local-fonts"}).then(t=>{"granted"===t.state&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(t){console.warn("Local fonts API:",t)}}_unbusy(){this._destroyed||(this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1)}_handleRVFC(e,{mediaTime:t,width:s,height:i}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:i}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:i})),this._requestFrame()}_requestFrame(){if(this._destroyed||!this._video||null!=this._frameCallback)return;const e=this._video,t=this._videoGeneration;this._frameCallback=e.requestVideoFrameCallback((s,i)=>{this._destroyed||t!==this._videoGeneration||e!==this._video||(this._frameCallback=null,this._handleRVFC(s,i))})}_demandRender({mediaTime:e,width:t,height:s}){this._lastDemandTime=null,(t!==this._videoWidth||s!==this._videoHeight)&&(this._videoWidth=t,this._videoHeight=s,this.resize()),this.sendMessage("demand",{time:e+this.timeOffset})}_detachOffscreen(){if(!this._offscreenRender||this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas,this._ctx=this._canvasctrl.getContext("2d"),this.sendMessage("detachOffscreen"),this.busy=!1,this.resize(0,0,0,0,!0)}_reAttachOffscreen(){if(this._destroyed||!this._offscreenRender||!this._ctx)return null;this._canvas.remove(),this._createCanvas(),this._canvasctrl=this._canvas.transferControlToOffscreen(),this._ctx=!1,this.busy=!1,this._lastDemandTime=null,this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this.resize(0,0,0,0,!0)}_updateColorSpace(){if(this._destroyed||null!=this._colorCallback)return;const e=this._video,t=this._videoGeneration;this._colorCallback=e.requestVideoFrameCallback(()=>{if(this._destroyed||t!==this._videoGeneration||e!==this._video)return;let i;this._colorCallback=null;try{i=new VideoFrame(e),this._videoColorSpace=s[i.colorSpace.matrix],this.sendMessage("getColorSpace")}catch(a){console.warn(a)}finally{i?.close()}})}_verifyColorSpace({subtitleColorSpace:e,videoColorSpace:t=this._videoColorSpace}){!e||!t||e!==t&&(this._detachOffscreen(),this._ctx.filter=`url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='f'><feColorMatrix type='matrix' values='${i[e][t]} 0 0 0 0 0 1 0'/></filter></svg>#f")`)}_render({images:e,asyncRender:t,times:s,width:i,height:a,colorSpace:r}){if(this._ctx){try{this._unbusy(),this.debug&&(s.IPCTime=Date.now()-s.JSRenderTime),(this._canvasctrl.width!==i||this._canvasctrl.height!==a)&&(this._canvasctrl.width=i,this._canvasctrl.height=a,this._verifyColorSpace({subtitleColorSpace:r})),this._ctx.clearRect(0,0,this._canvasctrl.width,this._canvasctrl.height);for(const s of e)s.image&&(t?this._ctx.drawImage(s.image,s.x,s.y):(this._bufferCanvas.width=s.w,this._bufferCanvas.height=s.h,this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(s.image)),s.w,s.h),0,0),this._ctx.drawImage(this._bufferCanvas,s.x,s.y)))}finally{if(t)for(const t of e)t.image?.close()}if(this.debug){s.JSRenderTime=Date.now()-s.JSRenderTime-s.IPCTime;let t=0;const i=s.bitmaps||e.length;delete s.bitmaps;for(const e in s)t+=s[e];console.log("Bitmaps: "+i+" Total: "+(0|t)+"ms",s)}}else for(const n of e)n.image?.close?.()}_fixAlpha(t){if(e._hasAlphaBug)for(let e=3;e<t.length;e+=4)t[e]=t[e]>1?t[e]:1;return t}_ready(){this._destroyed||(!0!==this._offscreenRender||this._initialOffscreenSent||(this._initialOffscreenSent=!0,this._worker.postMessage({target:"offscreenCanvas",transferable:[this._canvasctrl]},[this._canvasctrl])),this._init(),this.dispatchEvent(new CustomEvent("ready")))}async sendMessage(e,t={},s){this._destroyed||(await this._loaded,this._destroyed||(s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})))}_fetchFromWorker(e,t){if(this._destroyed)return void t(new Error("JASSUB instance destroyed"));const s=this._worker;let i,a=!1;const r=()=>{s.removeEventListener("message",o),s.removeEventListener("error",h),clearTimeout(i),this._requests.delete(d)},n=(e,s)=>{a||(a=!0,r(),t(e,s))},o=({data:t})=>{t.target===e.target&&n(null,t)},h=e=>n(e),d=()=>{if(!a)return a=!0,r(),()=>t(new Error("JASSUB instance destroyed"))};try{this._requests.add(d),s.addEventListener("message",o),s.addEventListener("error",h),i=setTimeout(()=>h(new Error("Error: Timeout while try to fetch "+e.target)),5e3),s.postMessage(e)}catch(l){if(a)throw l;n(l)}}_console({content:e,command:t}){console[t].apply(console,JSON.parse(e))}_onmessage({data:e}){if(this._destroyed)for(const t of e.images||[])t.image?.close?.();else this["_"+e.target]&&this["_"+e.target](e)}_error(e){const t=e instanceof Error?e:e instanceof ErrorEvent?e.error:new Error(e),s=e instanceof Event?new ErrorEvent(e.type,e):new ErrorEvent("error",{error:t});return this.dispatchEvent(s),console.error(t),t}_removeListeners(){this._videoGeneration=(this._videoGeneration||0)+1;for(const e of[this._frameCallback,this._colorCallback])null!=e&&this._video?.cancelVideoFrameCallback?.(e);this._frameCallback=this._colorCallback=null,this._lastDemandTime=null,this._onDemandRender&&(this.busy=!1),this._video&&(this._ro&&this._ro.unobserve(this._video),this._ctx&&(this._ctx.filter="none"),this._video.removeEventListener("timeupdate",this._boundTimeUpdate),this._video.removeEventListener("progress",this._boundTimeUpdate),this._video.removeEventListener("waiting",this._boundTimeUpdate),this._video.removeEventListener("seeking",this._boundTimeUpdate),this._video.removeEventListener("playing",this._boundTimeUpdate),this._video.removeEventListener("ratechange",this._boundSetRate),this._video.removeEventListener("resize",this._boundResize),this._video.removeEventListener("loadedmetadata",this._boundUpdateColorSpace))}destroy(e){if(this._destroyed)return e&&this._error(e);this._destroyed=!0;let t,s=!1;const i=e=>{try{e()}catch(i){s||(t=i,s=!0)}};e&&i(()=>{e=this._error(e)}),i(()=>this._removeListeners()),i(()=>this._ro?.disconnect()),i(()=>this._canvasParent?.remove()),this._init?.();const a=[];for(const r of[...this._requests||[]])i(()=>{const e=r();e&&a.push(e)});for(const r of a)i(r);if(this._worker&&(this._worker.onmessage=this._worker.onerror=null,i(()=>this._worker.terminate())),s)throw t;return e}};t(a,"_supportsSIMD",null),t(a,"_hasAlphaBug",null),t(a,"_hasBitmapBug",null);let r=a;return function(e){return t=>function(e,t){const s=new r({video:e.video,...t});let i=!1;const a=()=>{if(!i&&!s._destroyed){i=!0;try{s.destroy()}catch(e){throw i=!1,e}}};try{s._canvasParent&&(s._canvasParent.style.zIndex=20),e.on("destroy",a)}catch(n){try{e.off("destroy",a)}catch{}try{a()}catch{}throw n}return{name:"artplayerPluginJassub",instance:s}}(t,e)}});
|