jassub 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/jassub.es.js CHANGED
@@ -1,516 +1,440 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
7
- if (!("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype) {
8
- HTMLVideoElement.prototype._rvfcpolyfillmap = {};
9
- HTMLVideoElement.prototype.requestVideoFrameCallback = function(callback) {
10
- const quality = this.getVideoPlaybackQuality();
11
- const baseline = this.mozPresentedFrames || this.mozPaintedFrames || quality.totalVideoFrames - quality.droppedVideoFrames;
12
- const check = (old, now2) => {
13
- const newquality = this.getVideoPlaybackQuality();
14
- const presentedFrames = this.mozPresentedFrames || this.mozPaintedFrames || newquality.totalVideoFrames - newquality.droppedVideoFrames;
15
- if (presentedFrames > baseline) {
16
- const processingDuration = this.mozFrameDelay || newquality.totalFrameDelay - quality.totalFrameDelay || 0;
17
- const timediff = now2 - old;
18
- callback(now2, {
19
- presentationTime: now2 + processingDuration * 1e3,
20
- expectedDisplayTime: now2 + timediff,
21
- width: this.videoWidth,
22
- height: this.videoHeight,
23
- mediaTime: Math.max(0, this.currentTime || 0) + timediff / 1e3,
24
- presentedFrames,
25
- processingDuration
26
- });
27
- delete this._rvfcpolyfillmap[handle];
28
- } else {
29
- this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now2, newer));
30
- }
31
- };
32
- const handle = Date.now();
33
- const now = performance.now();
34
- this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now, newer));
35
- return handle;
36
- };
37
- HTMLVideoElement.prototype.cancelVideoFrameCallback = function(handle) {
38
- cancelAnimationFrame(this._rvfcpolyfillmap[handle]);
39
- delete this._rvfcpolyfillmap[handle];
40
- };
41
- }
42
- const _JASSUB = class extends EventTarget {
43
- constructor(options = {}) {
44
- var _a, _b, _c;
45
- super();
46
- if (!globalThis.Worker) {
47
- this.destroy("Worker not supported");
48
- }
49
- _JASSUB._test();
50
- const blendMode = options.blendMode || "js";
51
- const asyncRender = typeof createImageBitmap !== "undefined" && ((_a = options.asyncRender) != null ? _a : true);
52
- const offscreenRender = typeof OffscreenCanvas !== "undefined" && ((_b = options.offscreenRender) != null ? _b : true);
53
- this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && ((_c = options.onDemandRender) != null ? _c : true);
54
- this.timeOffset = options.timeOffset || 0;
55
- this._video = options.video;
56
- this._videoHeight = 0;
57
- this._videoWidth = 0;
58
- this._canvas = options.canvas;
59
- if (this._video && !this._canvas) {
60
- this._canvasParent = document.createElement("div");
61
- this._canvasParent.className = "JASSUB";
62
- this._canvasParent.style.position = "relative";
63
- this._canvas = document.createElement("canvas");
64
- this._canvas.style.display = "block";
65
- this._canvas.style.position = "absolute";
66
- this._canvas.style.pointerEvents = "none";
67
- this._canvasParent.appendChild(this._canvas);
68
- if (this._video.nextSibling) {
69
- this._video.parentNode.insertBefore(this._canvasParent, this._video.nextSibling);
70
- } else {
71
- this._video.parentNode.appendChild(this._canvasParent);
72
- }
73
- } else if (!this._canvas) {
74
- this.destroy("Don't know where to render: you should give video or canvas in options.");
75
- }
76
- this._bufferCanvas = document.createElement("canvas");
77
- this._bufferCtx = this._bufferCanvas.getContext("2d", { desynchronized: true, willReadFrequently: true });
78
- this._canvasctrl = offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas;
79
- this._ctx = !offscreenRender && this._canvasctrl.getContext("2d", { desynchronized: true });
80
- this._lastRenderTime = 0;
81
- this.debug = !!options.debug;
82
- this.prescaleFactor = options.prescaleFactor || 1;
83
- this.prescaleHeightLimit = options.prescaleHeightLimit || 1080;
84
- this.maxRenderHeight = options.maxRenderHeight || 0;
85
- this._worker = new Worker(_JASSUB._supportsWebAssembly ? options.workerUrl || "jassub-worker.js" : options.legacyWorkerUrl || "jassub-worker-legacy.js");
86
- this._worker.onmessage = (e) => this._onmessage(e);
87
- this._worker.onerror = (e) => this._error(e);
88
- this._loaded = new Promise((resolve) => {
1
+ var u = Object.defineProperty;
2
+ var f = (d, e, t) => e in d ? u(d, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[e] = t;
3
+ var v = (d, e, t) => (f(d, typeof e != "symbol" ? e + "" : e, t), t);
4
+ !("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype && (HTMLVideoElement.prototype._rvfcpolyfillmap = {}, HTMLVideoElement.prototype.requestVideoFrameCallback = function(d) {
5
+ const e = this.getVideoPlaybackQuality(), t = this.mozPresentedFrames || this.mozPaintedFrames || e.totalVideoFrames - e.droppedVideoFrames, s = (r, i) => {
6
+ const o = this.getVideoPlaybackQuality(), c = this.mozPresentedFrames || this.mozPaintedFrames || o.totalVideoFrames - o.droppedVideoFrames;
7
+ if (c > t) {
8
+ const l = this.mozFrameDelay || o.totalFrameDelay - e.totalFrameDelay || 0, m = i - r;
9
+ d(i, {
10
+ presentationTime: i + l * 1e3,
11
+ expectedDisplayTime: i + m,
12
+ width: this.videoWidth,
13
+ height: this.videoHeight,
14
+ mediaTime: Math.max(0, this.currentTime || 0) + m / 1e3,
15
+ presentedFrames: c,
16
+ processingDuration: l
17
+ }), delete this._rvfcpolyfillmap[a];
18
+ } else
19
+ this._rvfcpolyfillmap[a] = requestAnimationFrame((l) => s(i, l));
20
+ }, a = Date.now(), n = performance.now();
21
+ return this._rvfcpolyfillmap[a] = requestAnimationFrame((r) => s(n, r)), a;
22
+ }, HTMLVideoElement.prototype.cancelVideoFrameCallback = function(d) {
23
+ cancelAnimationFrame(this._rvfcpolyfillmap[d]), delete this._rvfcpolyfillmap[d];
24
+ });
25
+ const h = class extends EventTarget {
26
+ /**
27
+ * @param {Object} options Settings object.
28
+ * @param {HTMLVideoElement} options.video Video to use as target for rendering and event listeners. Optional if canvas is specified instead.
29
+ * @param {HTMLCanvasElement} [options.canvas=HTMLCanvasElement] Canvas to use for manual handling. Not required if video is specified.
30
+ * @param {'js'|'wasm'} [options.blendMode='js'] Which image blending mode to use. WASM will perform better on lower end devices, JS will perform better if the device and browser supports hardware acceleration.
31
+ * @param {Boolean} [options.asyncRender=true] Whether or not to use async rendering, which offloads the CPU by creating image bitmaps on the GPU.
32
+ * @param {Boolean} [options.offscreenRender=true] Whether or not to render things fully on the worker, greatly reduces CPU usage.
33
+ * @param {Boolean} [options.onDemandRender=true] Whether or not to render subtitles as the video player decodes renders, rather than predicting which frame the player is on using events.
34
+ * @param {Number} [options.targetFps=24] Target FPS to render subtitles at. Ignored when onDemandRender is enabled.
35
+ * @param {Number} [options.timeOffset=0] Subtitle time offset in seconds.
36
+ * @param {Boolean} [options.debug=false] Whether or not to print debug information.
37
+ * @param {Number} [options.prescaleFactor=1.0] Scale down (< 1.0) the subtitles canvas to improve performance at the expense of quality, or scale it up (> 1.0).
38
+ * @param {Number} [options.prescaleHeightLimit=1080] The height in pixels beyond which the subtitles canvas won't be prescaled.
39
+ * @param {Number} [options.maxRenderHeight=0] The maximum rendering height in pixels of the subtitles canvas. Beyond this subtitles will be upscaled by the browser.
40
+ * @param {Boolean} [options.dropAllAnimations=false] Attempt to discard all animated tags. Enabling this may severly mangle complex subtitles and should only be considered as an last ditch effort of uncertain success for hardware otherwise incapable of displaing anything. Will not reliably work with manually edited or allocated events.
41
+ * @param {String} [options.workerUrl='jassub-worker.js'] The URL of the worker.
42
+ * @param {String} [options.legacyWorkerUrl='jassub-worker-legacy.js'] The URL of the legacy worker. Only loaded if the browser doesn't support WASM.
43
+ * @param {String} [options.subUrl=options.subContent] The URL of the subtitle file to play.
44
+ * @param {String} [options.subContent=options.subUrl] The content of the subtitle file to play.
45
+ * @param {String[]|Uint8Array[]} [options.fonts] An array of links or Uint8Arrays to the fonts used in the subtitle. If Uint8Array is used the array is copied, not referenced. This forces all the fonts in this array to be loaded by the renderer, regardless of if they are used.
46
+ * @param {Object} [options.availableFonts={'liberation sans': './default.woff2'}] Object with all available fonts - Key is font family in lower case, value is link or Uint8Array: { arial: '/font1.ttf' }. These fonts are selectively loaded if detected as used in the current subtitle track.
47
+ * @param {String} [options.fallbackFont='liberation sans'] The font family key of the fallback font in availableFonts to use if the other font for the style is missing special glyphs or unicode.
48
+ * @param {Boolean} [options.useLocalFonts=false] If the Local Font Access API is enabled [chrome://flags/#font-access], the library will query for permissions to use local fonts and use them if any are missing. The permission can be queried beforehand using navigator.permissions.request({ name: 'local-fonts' }).
49
+ * @param {Number} [options.libassMemoryLimit] libass bitmap cache memory limit in MiB (approximate).
50
+ * @param {Number} [options.libassGlyphLimit] libass glyph cache memory limit in MiB (approximate).
51
+ */
52
+ constructor(e = {}) {
53
+ super(), globalThis.Worker || this.destroy("Worker not supported"), h._test();
54
+ const t = e.blendMode || "js", s = typeof createImageBitmap < "u" && (e.asyncRender ?? !0), a = typeof OffscreenCanvas < "u" && (e.offscreenRender ?? !0);
55
+ this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && (e.onDemandRender ?? !0), this.timeOffset = e.timeOffset || 0, this._video = e.video, this._videoHeight = 0, this._videoWidth = 0, this._canvas = e.canvas, this._video && !this._canvas ? (this._canvasParent = document.createElement("div"), this._canvasParent.className = "JASSUB", this._canvasParent.style.position = "relative", 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._video.nextSibling ? this._video.parentNode.insertBefore(this._canvasParent, this._video.nextSibling) : this._video.parentNode.appendChild(this._canvasParent)) : this._canvas || this.destroy("Don't know where to render: you should give video or canvas in options."), this._bufferCanvas = document.createElement("canvas"), this._bufferCtx = this._bufferCanvas.getContext("2d", { desynchronized: !0, willReadFrequently: !0 }), this._canvasctrl = a ? this._canvas.transferControlToOffscreen() : this._canvas, this._ctx = !a && this._canvasctrl.getContext("2d", { desynchronized: !0 }), this._lastRenderTime = 0, this.debug = !!e.debug, this.prescaleFactor = e.prescaleFactor || 1, this.prescaleHeightLimit = e.prescaleHeightLimit || 1080, this.maxRenderHeight = e.maxRenderHeight || 0, this._worker = new Worker(h._supportsWebAssembly ? e.workerUrl || "jassub-worker.js" : e.legacyWorkerUrl || "jassub-worker-legacy.js"), this._worker.onmessage = (n) => this._onmessage(n), this._worker.onerror = (n) => this._error(n), this._loaded = new Promise((n) => {
89
56
  this._init = () => {
90
- var _a2, _b2;
91
- if (this._destroyed)
92
- return;
93
- this._worker.postMessage({
57
+ var r;
58
+ this._destroyed || (this._worker.postMessage({
94
59
  target: "init",
95
- asyncRender,
60
+ asyncRender: s,
96
61
  onDemandRender: this._onDemandRender,
97
62
  width: this._canvasctrl.width,
98
63
  height: this._canvasctrl.height,
99
- preMain: true,
100
- blendMode,
101
- subUrl: options.subUrl,
102
- subContent: options.subContent || null,
103
- fonts: options.fonts || [],
104
- availableFonts: options.availableFonts || { "liberation sans": "./default.woff2" },
105
- fallbackFont: options.fallbackFont || "liberation sans",
64
+ preMain: !0,
65
+ blendMode: t,
66
+ subUrl: e.subUrl,
67
+ subContent: e.subContent || null,
68
+ fonts: e.fonts || [],
69
+ availableFonts: e.availableFonts || { "liberation sans": "./default.woff2" },
70
+ fallbackFont: e.fallbackFont || "liberation sans",
106
71
  debug: this.debug,
107
- targetFps: options.targetFps || 24,
108
- dropAllAnimations: options.dropAllAnimations,
109
- libassMemoryLimit: options.libassMemoryLimit || 0,
110
- libassGlyphLimit: options.libassGlyphLimit || 0,
111
- hasAlphaBug: _JASSUB._hasAlphaBug,
112
- useLocalFonts: "queryLocalFonts" in self && ((_a2 = options.useLocalFonts) != null ? _a2 : true)
113
- });
114
- if (offscreenRender === true)
115
- this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
116
- this._boundResize = this.resize.bind(this);
117
- this._boundTimeUpdate = this._timeupdate.bind(this);
118
- this._boundSetRate = this.setRate.bind(this);
119
- if (this._video)
120
- this.setVideo(options.video);
121
- if (this._onDemandRender) {
122
- this.busy = false;
123
- this._lastDemandTime = null;
124
- (_b2 = this._video) == null ? void 0 : _b2.requestVideoFrameCallback(this._handleRVFC.bind(this));
125
- }
126
- resolve();
72
+ targetFps: e.targetFps || 24,
73
+ dropAllAnimations: e.dropAllAnimations,
74
+ libassMemoryLimit: e.libassMemoryLimit || 0,
75
+ libassGlyphLimit: e.libassGlyphLimit || 0,
76
+ hasAlphaBug: h._hasAlphaBug,
77
+ useLocalFonts: "queryLocalFonts" in self && (e.useLocalFonts ?? !0)
78
+ }), a === !0 && this.sendMessage("offscreenCanvas", null, [this._canvasctrl]), this._boundResize = this.resize.bind(this), this._boundTimeUpdate = this._timeupdate.bind(this), this._boundSetRate = this.setRate.bind(this), this._video && this.setVideo(e.video), this._onDemandRender && (this.busy = !1, this._lastDemandTime = null, (r = this._video) == null || r.requestVideoFrameCallback(this._handleRVFC.bind(this))), n());
127
79
  };
128
80
  });
129
81
  }
130
82
  static _test() {
131
- if (_JASSUB._supportsWebAssembly !== null)
83
+ if (h._supportsWebAssembly !== null)
132
84
  return null;
133
- const canvas1 = document.createElement("canvas");
134
- const ctx1 = canvas1.getContext("2d", { willReadFrequently: true });
135
- if (typeof ImageData.prototype.constructor === "function") {
85
+ const e = document.createElement("canvas"), t = e.getContext("2d", { willReadFrequently: !0 });
86
+ if (typeof ImageData.prototype.constructor == "function")
136
87
  try {
137
88
  new ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
138
- } catch (e) {
139
- console.log("detected that ImageData is not constructable despite browser saying so");
140
- self.ImageData = function(data, width, height) {
141
- const imageData = ctx1.createImageData(width, height);
142
- if (data)
143
- imageData.data.set(data);
144
- return imageData;
89
+ } catch {
90
+ console.log("detected that ImageData is not constructable despite browser saying so"), self.ImageData = function(o, c, l) {
91
+ const m = t.createImageData(c, l);
92
+ return o && m.data.set(o), m;
145
93
  };
146
94
  }
147
- }
148
95
  try {
149
- if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
150
- const module = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0));
151
- if (module instanceof WebAssembly.Module)
152
- _JASSUB._supportsWebAssembly = new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
96
+ if (typeof WebAssembly == "object" && typeof WebAssembly.instantiate == "function") {
97
+ const i = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0));
98
+ i instanceof WebAssembly.Module && (h._supportsWebAssembly = new WebAssembly.Instance(i) instanceof WebAssembly.Instance);
153
99
  }
154
- } catch (e) {
155
- _JASSUB._supportsWebAssembly = false;
100
+ } catch {
101
+ h._supportsWebAssembly = !1;
156
102
  }
157
- const canvas2 = document.createElement("canvas");
158
- const ctx2 = canvas2.getContext("2d", { willReadFrequently: true });
159
- canvas1.width = canvas2.width = 1;
160
- canvas1.height = canvas2.height = 1;
161
- ctx1.clearRect(0, 0, 1, 1);
162
- ctx2.clearRect(0, 0, 1, 1);
163
- const prePut = ctx2.getImageData(0, 0, 1, 1).data;
164
- ctx1.putImageData(new ImageData(new Uint8ClampedArray([0, 255, 0, 0]), 1, 1), 0, 0);
165
- ctx2.drawImage(canvas1, 0, 0);
166
- const postPut = ctx2.getImageData(0, 0, 1, 1).data;
167
- _JASSUB._hasAlphaBug = prePut[1] !== postPut[1];
168
- if (_JASSUB._hasAlphaBug)
169
- console.log("Detected a browser having issue with transparent pixels, applying workaround");
170
- canvas1.remove();
171
- canvas2.remove();
172
- }
173
- resize(width = 0, height = 0, top = 0, left = 0, force = ((_a) => (_a = this._video) == null ? void 0 : _a.paused)()) {
174
- if ((!width || !height) && this._video) {
175
- const videoSize = this._getVideoPosition();
176
- let renderSize = null;
103
+ const s = document.createElement("canvas"), a = s.getContext("2d", { willReadFrequently: !0 });
104
+ e.width = s.width = 1, e.height = s.height = 1, t.clearRect(0, 0, 1, 1), a.clearRect(0, 0, 1, 1);
105
+ const n = a.getImageData(0, 0, 1, 1).data;
106
+ t.putImageData(new ImageData(new Uint8ClampedArray([0, 255, 0, 0]), 1, 1), 0, 0), a.drawImage(e, 0, 0);
107
+ const r = a.getImageData(0, 0, 1, 1).data;
108
+ h._hasAlphaBug = n[1] !== r[1], h._hasAlphaBug && console.log("Detected a browser having issue with transparent pixels, applying workaround"), e.remove(), s.remove();
109
+ }
110
+ /**
111
+ * Resize the canvas to given parameters. Auto-generated if values are ommited.
112
+ * @param {Number} [width=0]
113
+ * @param {Number} [height=0]
114
+ * @param {Number} [top=0]
115
+ * @param {Number} [left=0]
116
+ * @param {Boolean} [force=false]
117
+ */
118
+ resize(e = 0, t = 0, s = 0, a = 0, n = ((r) => (r = this._video) == null ? void 0 : r.paused)()) {
119
+ if ((!e || !t) && this._video) {
120
+ const i = this._getVideoPosition();
121
+ let o = null;
177
122
  if (this._videoWidth) {
178
- const widthRatio = this._video.videoWidth / this._videoWidth;
179
- const heightRatio = this._video.videoHeight / this._videoHeight;
180
- renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio);
181
- } else {
182
- renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0);
183
- }
184
- width = renderSize.width;
185
- height = renderSize.height;
186
- if (this._canvasParent) {
187
- top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top);
188
- left = videoSize.x;
189
- }
190
- this._canvas.style.width = videoSize.width + "px";
191
- this._canvas.style.height = videoSize.height + "px";
192
- }
193
- this._canvas.style.top = top + "px";
194
- this._canvas.style.left = left + "px";
195
- this.sendMessage("canvas", { width, height, force: force && this.busy === false });
196
- }
197
- _getVideoPosition(width = this._video.videoWidth, height = this._video.videoHeight) {
198
- const videoRatio = width / height;
199
- const { offsetWidth, offsetHeight } = this._video;
200
- const elementRatio = offsetWidth / offsetHeight;
201
- width = offsetWidth;
202
- height = offsetHeight;
203
- if (elementRatio > videoRatio) {
204
- width = Math.floor(offsetHeight * videoRatio);
205
- } else {
206
- height = Math.floor(offsetWidth / videoRatio);
123
+ const c = this._video.videoWidth / this._videoWidth, l = this._video.videoHeight / this._videoHeight;
124
+ o = this._computeCanvasSize((i.width || 0) / c, (i.height || 0) / l);
125
+ } else
126
+ o = this._computeCanvasSize(i.width || 0, i.height || 0);
127
+ e = o.width, t = o.height, this._canvasParent && (s = i.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top), a = i.x), this._canvas.style.width = i.width + "px", this._canvas.style.height = i.height + "px";
207
128
  }
208
- const x = (offsetWidth - width) / 2;
209
- const y = (offsetHeight - height) / 2;
210
- return { width, height, x, y };
211
- }
212
- _computeCanvasSize(width = 0, height = 0) {
213
- const scalefactor = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor;
214
- const ratio = self.devicePixelRatio || 1;
215
- width = width * ratio;
216
- height = height * ratio;
217
- if (height <= 0 || width <= 0) {
218
- width = 0;
219
- height = 0;
220
- } else {
221
- const sgn = scalefactor < 1 ? -1 : 1;
222
- let newH = height * ratio;
223
- if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
224
- newH *= scalefactor;
225
- } else if (sgn * newH < sgn * this.prescaleHeightLimit) {
226
- newH = this.prescaleHeightLimit;
227
- }
228
- if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight)
229
- newH = this.maxRenderHeight;
230
- width *= newH / height;
231
- height = newH;
232
- }
233
- return { width, height };
234
- }
235
- _timeupdate({ type }) {
236
- const eventmap = {
237
- seeking: true,
238
- waiting: true,
239
- playing: false
240
- };
241
- const playing = eventmap[type];
242
- if (playing != null)
243
- this._playstate = playing;
244
- this.setCurrentTime(this._video.paused || this._playstate, this._video.currentTime + this.timeOffset);
245
- }
246
- setVideo(video) {
247
- if (video instanceof HTMLVideoElement) {
248
- this._removeListeners();
249
- this._video = video;
250
- if (this._onDemandRender) {
251
- this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
252
- } else {
253
- this._playstate = video.paused;
254
- video.addEventListener("timeupdate", this._boundTimeUpdate, false);
255
- video.addEventListener("progress", this._boundTimeUpdate, false);
256
- video.addEventListener("waiting", this._boundTimeUpdate, false);
257
- video.addEventListener("seeking", this._boundTimeUpdate, false);
258
- video.addEventListener("playing", this._boundTimeUpdate, false);
259
- video.addEventListener("ratechange", this._boundSetRate, false);
260
- video.addEventListener("resize", this._boundResize);
261
- }
262
- if (video.videoWidth > 0)
263
- this.resize();
264
- if (typeof ResizeObserver !== "undefined") {
265
- if (!this._ro)
266
- this._ro = new ResizeObserver(() => this.resize());
267
- this._ro.observe(video);
268
- }
269
- } else {
270
- this._error("Video element invalid!");
129
+ this._canvas.style.top = s + "px", this._canvas.style.left = a + "px", this.sendMessage("canvas", { width: e, height: t, force: n && this.busy === !1 });
130
+ }
131
+ _getVideoPosition(e = this._video.videoWidth, t = this._video.videoHeight) {
132
+ const s = e / t, { offsetWidth: a, offsetHeight: n } = this._video, r = a / n;
133
+ e = a, t = n, r > s ? e = Math.floor(n * s) : t = Math.floor(a / s);
134
+ const i = (a - e) / 2, o = (n - t) / 2;
135
+ return { width: e, height: t, x: i, y: o };
136
+ }
137
+ _computeCanvasSize(e = 0, t = 0) {
138
+ const s = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor, a = self.devicePixelRatio || 1;
139
+ if (e = e * a, t = t * a, t <= 0 || e <= 0)
140
+ e = 0, t = 0;
141
+ else {
142
+ const n = s < 1 ? -1 : 1;
143
+ let r = t * a;
144
+ n * r * s <= n * this.prescaleHeightLimit ? r *= s : n * r < n * this.prescaleHeightLimit && (r = this.prescaleHeightLimit), this.maxRenderHeight > 0 && r > this.maxRenderHeight && (r = this.maxRenderHeight), e *= r / t, t = r;
271
145
  }
146
+ return { width: e, height: t };
147
+ }
148
+ _timeupdate({ type: e }) {
149
+ const s = {
150
+ seeking: !0,
151
+ waiting: !0,
152
+ playing: !1
153
+ }[e];
154
+ s != null && (this._playstate = s), this.setCurrentTime(this._video.paused || this._playstate, this._video.currentTime + this.timeOffset);
155
+ }
156
+ /**
157
+ * Change the video to use as target for event listeners.
158
+ * @param {HTMLVideoElement} video
159
+ */
160
+ setVideo(e) {
161
+ e instanceof HTMLVideoElement ? (this._removeListeners(), this._video = e, this._onDemandRender ? this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)) : (this._playstate = e.paused, e.addEventListener("timeupdate", this._boundTimeUpdate, !1), e.addEventListener("progress", this._boundTimeUpdate, !1), e.addEventListener("waiting", this._boundTimeUpdate, !1), e.addEventListener("seeking", this._boundTimeUpdate, !1), e.addEventListener("playing", this._boundTimeUpdate, !1), e.addEventListener("ratechange", this._boundSetRate, !1), e.addEventListener("resize", this._boundResize)), e.videoWidth > 0 && this.resize(), typeof ResizeObserver < "u" && (this._ro || (this._ro = new ResizeObserver(() => this.resize())), this._ro.observe(e))) : this._error("Video element invalid!");
272
162
  }
273
163
  runBenchmark() {
274
164
  this.sendMessage("runBenchmark");
275
165
  }
276
- setTrackByUrl(url) {
277
- this.sendMessage("setTrackByUrl", { url });
278
- }
279
- setTrack(content) {
280
- this.sendMessage("setTrack", { content });
281
- }
166
+ /**
167
+ * Overwrites the current subtitle content.
168
+ * @param {String} url URL to load subtitles from.
169
+ */
170
+ setTrackByUrl(e) {
171
+ this.sendMessage("setTrackByUrl", { url: e });
172
+ }
173
+ /**
174
+ * Overwrites the current subtitle content.
175
+ * @param {String} content Content of the ASS file.
176
+ */
177
+ setTrack(e) {
178
+ this.sendMessage("setTrack", { content: e });
179
+ }
180
+ /**
181
+ * Free currently used subtitle track.
182
+ */
282
183
  freeTrack() {
283
184
  this.sendMessage("freeTrack");
284
185
  }
285
- setIsPaused(isPaused) {
286
- this.sendMessage("video", { isPaused });
287
- }
288
- setRate(rate) {
289
- this.sendMessage("video", { rate });
290
- }
291
- setCurrentTime(isPaused, currentTime, rate) {
292
- this.sendMessage("video", { isPaused, currentTime, rate });
293
- }
294
- createEvent(event) {
295
- this.sendMessage("createEvent", { event });
296
- }
297
- setEvent(event, index) {
298
- this.sendMessage("setEvent", { event, index });
299
- }
300
- removeEvent(index) {
301
- this.sendMessage("removeEvent", { index });
302
- }
303
- getEvents(callback) {
186
+ /**
187
+ * Sets the playback state of the media.
188
+ * @param {Boolean} isPaused Pause/Play subtitle playback.
189
+ */
190
+ setIsPaused(e) {
191
+ this.sendMessage("video", { isPaused: e });
192
+ }
193
+ /**
194
+ * Sets the playback rate of the media [speed multiplier].
195
+ * @param {Number} rate Playback rate.
196
+ */
197
+ setRate(e) {
198
+ this.sendMessage("video", { rate: e });
199
+ }
200
+ /**
201
+ * Sets the current time, playback state and rate of the subtitles.
202
+ * @param {Boolean} [isPaused] Pause/Play subtitle playback.
203
+ * @param {Number} [currentTime] Time in seconds.
204
+ * @param {Number} [rate] Playback rate.
205
+ */
206
+ setCurrentTime(e, t, s) {
207
+ this.sendMessage("video", { isPaused: e, currentTime: t, rate: s });
208
+ }
209
+ /**
210
+ * @typedef {Object} ASS_Event
211
+ * @property {Number} Start Start Time of the Event, in 0:00:00:00 format ie. Hrs:Mins:Secs:hundredths. This is the time elapsed during script playback at which the text will appear onscreen. Note that there is a single digit for the hours!
212
+ * @property {Number} Duration End Time of the Event, in 0:00:00:00 format ie. Hrs:Mins:Secs:hundredths. This is the time elapsed during script playback at which the text will disappear offscreen. Note that there is a single digit for the hours!
213
+ * @property {String} Style Style name. If it is "Default", then your own *Default style will be subtituted.
214
+ * @property {String} Name Character name. This is the name of the character who speaks the dialogue. It is for information only, to make the script is easier to follow when editing/timing.
215
+ * @property {Number} MarginL 4-figure Left Margin override. The values are in pixels. All zeroes means the default margins defined by the style are used.
216
+ * @property {Number} MarginR 4-figure Right Margin override. The values are in pixels. All zeroes means the default margins defined by the style are used.
217
+ * @property {Number} MarginV 4-figure Bottom Margin override. The values are in pixels. All zeroes means the default margins defined by the style are used.
218
+ * @property {String} Effect Transition Effect. This is either empty, or contains information for one of the three transition effects implemented in SSA v4.x
219
+ * @property {String} Text Subtitle Text. This is the actual text which will be displayed as a subtitle onscreen. Everything after the 9th comma is treated as the subtitle text, so it can include commas.
220
+ * @property {Number} ReadOrder Number in order of which to read this event.
221
+ * @property {Number} Layer Z-index overlap in which to render this event.
222
+ * @property {Number} _index (Internal) index of the event.
223
+ */
224
+ /**
225
+ * Create a new ASS event directly.
226
+ * @param {ASS_Event} event
227
+ */
228
+ createEvent(e) {
229
+ this.sendMessage("createEvent", { event: e });
230
+ }
231
+ /**
232
+ * Overwrite the data of the event with the specified index.
233
+ * @param {ASS_Event} event
234
+ * @param {Number} index
235
+ */
236
+ setEvent(e, t) {
237
+ this.sendMessage("setEvent", { event: e, index: t });
238
+ }
239
+ /**
240
+ * Remove the event with the specified index.
241
+ * @param {Number} index
242
+ */
243
+ removeEvent(e) {
244
+ this.sendMessage("removeEvent", { index: e });
245
+ }
246
+ /**
247
+ * Get all ASS events.
248
+ * @param {function(Error|null, ASS_Event)} callback Function to callback when worker returns the events.
249
+ */
250
+ getEvents(e) {
304
251
  this._fetchFromWorker({
305
252
  target: "getEvents"
306
- }, (err, { events }) => {
307
- callback(err, events);
253
+ }, (t, { events: s }) => {
254
+ e(t, s);
308
255
  });
309
256
  }
310
- createStyle(style) {
311
- this.sendMessage("createStyle", { style });
312
- }
313
- setStyle(event, index) {
314
- this.sendMessage("setStyle", { event, index });
315
- }
316
- removeStyle(index) {
317
- this.sendMessage("removeStyle", { index });
318
- }
319
- getStyles(callback) {
257
+ /**
258
+ * @typedef {Object} ASS_Style
259
+ * @property {String} Name The name of the Style. Case sensitive. Cannot include commas.
260
+ * @property {String} FontName The fontname as used by Windows. Case-sensitive.
261
+ * @property {Number} FontSize Font size.
262
+ * @property {Number} PrimaryColour A long integer BGR (blue-green-red) value. ie. the byte order in the hexadecimal equivelent of this number is BBGGRR
263
+ * @property {Number} SecondaryColour A long integer BGR (blue-green-red) value. ie. the byte order in the hexadecimal equivelent of this number is BBGGRR
264
+ * @property {Number} OutlineColour A long integer BGR (blue-green-red) value. ie. the byte order in the hexadecimal equivelent of this number is BBGGRR
265
+ * @property {Number} BackColour This is the colour of the subtitle outline or shadow, if these are used. A long integer BGR (blue-green-red) value. ie. the byte order in the hexadecimal equivelent of this number is BBGGRR.
266
+ * @property {Number} Bold This defines whether text is bold (true) or not (false). -1 is True, 0 is False. This is independant of the Italic attribute - you can have have text which is both bold and italic.
267
+ * @property {Number} Italic Italic. This defines whether text is italic (true) or not (false). -1 is True, 0 is False. This is independant of the bold attribute - you can have have text which is both bold and italic.
268
+ * @property {Number} Underline -1 or 0
269
+ * @property {Number} StrikeOut -1 or 0
270
+ * @property {Number} ScaleX Modifies the width of the font. [percent]
271
+ * @property {Number} ScaleY Modifies the height of the font. [percent]
272
+ * @property {Number} Spacing Extra space between characters. [pixels]
273
+ * @property {Number} Angle The origin of the rotation is defined by the alignment. Can be a floating point number. [degrees]
274
+ * @property {Number} BorderStyle 1=Outline + drop shadow, 3=Opaque box
275
+ * @property {Number} Outline If BorderStyle is 1, then this specifies the width of the outline around the text, in pixels. Values may be 0, 1, 2, 3 or 4.
276
+ * @property {Number} Shadow If BorderStyle is 1, then this specifies the depth of the drop shadow behind the text, in pixels. Values may be 0, 1, 2, 3 or 4. Drop shadow is always used in addition to an outline - SSA will force an outline of 1 pixel if no outline width is given.
277
+ * @property {Number} Alignment This sets how text is "justified" within the Left/Right onscreen margins, and also the vertical placing. Values may be 1=Left, 2=Centered, 3=Right. Add 4 to the value for a "Toptitle". Add 8 to the value for a "Midtitle". eg. 5 = left-justified toptitle
278
+ * @property {Number} MarginL This defines the Left Margin in pixels. It is the distance from the left-hand edge of the screen.The three onscreen margins (MarginL, MarginR, MarginV) define areas in which the subtitle text will be displayed.
279
+ * @property {Number} MarginR This defines the Right Margin in pixels. It is the distance from the right-hand edge of the screen. The three onscreen margins (MarginL, MarginR, MarginV) define areas in which the subtitle text will be displayed.
280
+ * @property {Number} MarginV This defines the vertical Left Margin in pixels. For a subtitle, it is the distance from the bottom of the screen. For a toptitle, it is the distance from the top of the screen. For a midtitle, the value is ignored - the text will be vertically centred.
281
+ * @property {Number} Encoding This specifies the font character set or encoding and on multi-lingual Windows installations it provides access to characters used in multiple than one languages. It is usually 0 (zero) for English (Western, ANSI) Windows.
282
+ * @property {Number} treat_fontname_as_pattern
283
+ * @property {Number} Blur
284
+ * @property {Number} Justify
285
+ */
286
+ /**
287
+ * Create a new ASS style directly.
288
+ * @param {ASS_Style} event
289
+ */
290
+ createStyle(e) {
291
+ this.sendMessage("createStyle", { style: e });
292
+ }
293
+ /**
294
+ * Overwrite the data of the style with the specified index.
295
+ * @param {ASS_Style} event
296
+ * @param {Number} index
297
+ */
298
+ setStyle(e, t) {
299
+ this.sendMessage("setStyle", { event: e, index: t });
300
+ }
301
+ /**
302
+ * Remove the style with the specified index.
303
+ * @param {Number} index
304
+ */
305
+ removeStyle(e) {
306
+ this.sendMessage("removeStyle", { index: e });
307
+ }
308
+ /**
309
+ * Get all ASS styles.
310
+ * @param {function(Error|null, ASS_Style)} callback Function to callback when worker returns the styles.
311
+ */
312
+ getStyles(e) {
320
313
  this._fetchFromWorker({
321
314
  target: "getStyles"
322
- }, (err, { styles }) => {
323
- callback(err, styles);
315
+ }, (t, { styles: s }) => {
316
+ e(t, s);
324
317
  });
325
318
  }
326
- addFont(font) {
327
- this.sendMessage("addFont", { font });
319
+ /**
320
+ * Adds a font to the renderer.
321
+ * @param {String|Uint8Array} font Font to add.
322
+ */
323
+ addFont(e) {
324
+ this.sendMessage("addFont", { font: e });
328
325
  }
329
- _sendLocalFont(name) {
326
+ _sendLocalFont(e) {
330
327
  try {
331
- queryLocalFonts().then((fontData) => {
332
- const font = fontData == null ? void 0 : fontData.find((obj) => obj.fullName.toLowerCase() === name);
333
- if (font) {
334
- font.blob().then((blob) => {
335
- blob.arrayBuffer().then((buffer) => {
336
- this.addFont(new Uint8Array(buffer));
337
- });
328
+ queryLocalFonts().then((t) => {
329
+ const s = t == null ? void 0 : t.find((a) => a.fullName.toLowerCase() === e);
330
+ s && s.blob().then((a) => {
331
+ a.arrayBuffer().then((n) => {
332
+ this.addFont(new Uint8Array(n));
338
333
  });
339
- }
334
+ });
340
335
  });
341
- } catch (e) {
342
- console.warn("Local fonts API:", e);
336
+ } catch (t) {
337
+ console.warn("Local fonts API:", t);
343
338
  }
344
339
  }
345
- _getLocalFont({ font }) {
346
- var _a;
340
+ _getLocalFont({ font: e }) {
341
+ var t;
347
342
  try {
348
- if ((_a = navigator == null ? void 0 : navigator.permissions) == null ? void 0 : _a.query) {
349
- navigator.permissions.query({ name: "local-fonts" }).then((permission) => {
350
- if (permission.state === "granted") {
351
- this._sendLocalFont(font);
352
- }
353
- });
354
- } else {
355
- this._sendLocalFont(font);
356
- }
357
- } catch (e) {
358
- console.warn("Local fonts API:", e);
343
+ (t = navigator == null ? void 0 : navigator.permissions) != null && t.query ? navigator.permissions.query({ name: "local-fonts" }).then((s) => {
344
+ s.state === "granted" && this._sendLocalFont(e);
345
+ }) : this._sendLocalFont(e);
346
+ } catch (s) {
347
+ console.warn("Local fonts API:", s);
359
348
  }
360
349
  }
361
350
  _unbusy() {
362
- if (this._lastDemandTime) {
363
- this._demandRender(this._lastDemandTime);
364
- } else {
365
- this.busy = false;
366
- }
351
+ this._lastDemandTime ? this._demandRender(this._lastDemandTime) : this.busy = !1;
367
352
  }
368
- _handleRVFC(now, { mediaTime, width, height }) {
353
+ _handleRVFC(e, { mediaTime: t, width: s, height: a }) {
369
354
  if (this._destroyed)
370
355
  return null;
371
- if (this.busy) {
372
- this._lastDemandTime = { mediaTime, width, height };
373
- } else {
374
- this.busy = true;
375
- this._demandRender({ mediaTime, width, height });
376
- }
377
- this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
378
- }
379
- _demandRender({ mediaTime, width, height }) {
380
- this._lastDemandTime = null;
381
- if (width !== this._videoWidth || height !== this._videoHeight) {
382
- this._videoWidth = width;
383
- this._videoHeight = height;
384
- this.resize();
385
- }
386
- this.sendMessage("demand", { time: mediaTime + this.timeOffset });
356
+ this.busy ? this._lastDemandTime = { mediaTime: t, width: s, height: a } : (this.busy = !0, this._demandRender({ mediaTime: t, width: s, height: a })), this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
387
357
  }
388
- _render({ images, async, times, width, height }) {
358
+ _demandRender({ mediaTime: e, width: t, height: s }) {
359
+ this._lastDemandTime = null, (t !== this._videoWidth || s !== this._videoHeight) && (this._videoWidth = t, this._videoHeight = s, this.resize()), this.sendMessage("demand", { time: e + this.timeOffset });
360
+ }
361
+ _render({ images: e, async: t, times: s, width: a, height: n }) {
389
362
  this._unbusy();
390
- const drawStartTime = Date.now();
391
- if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
392
- this._canvasctrl.width = width;
393
- this._canvasctrl.height = height;
394
- }
395
- this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
396
- for (const image of images) {
397
- if (image.image) {
398
- if (async) {
399
- this._ctx.drawImage(image.image, image.x, image.y);
400
- image.image.close();
401
- } else {
402
- this._bufferCanvas.width = image.w;
403
- this._bufferCanvas.height = image.h;
404
- this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(image.image)), image.w, image.h), 0, 0);
405
- this._ctx.drawImage(this._bufferCanvas, image.x, image.y);
406
- }
407
- }
408
- }
363
+ const r = Date.now();
364
+ (this._canvasctrl.width !== a || this._canvasctrl.height !== n) && (this._canvasctrl.width = a, this._canvasctrl.height = n), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
365
+ for (const i of e)
366
+ i.image && (t ? (this._ctx.drawImage(i.image, i.x, i.y), i.image.close()) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
409
367
  if (this.debug) {
410
- times.drawTime = Date.now() - drawStartTime;
411
- let total = 0;
412
- for (const key in times)
413
- total += times[key];
414
- console.log("Bitmaps: " + images.length + " Total: " + Math.round(total) + "ms", times);
368
+ s.drawTime = Date.now() - r;
369
+ let i = 0;
370
+ for (const o in s)
371
+ i += s[o];
372
+ console.log("Bitmaps: " + e.length + " Total: " + Math.round(i) + "ms", s);
415
373
  }
416
374
  }
417
- _fixAlpha(uint8) {
418
- if (_JASSUB._hasAlphaBug) {
419
- for (let j = 3; j < uint8.length; j += 4) {
420
- uint8[j] = uint8[j] > 1 ? uint8[j] : 1;
421
- }
422
- }
423
- return uint8;
375
+ _fixAlpha(e) {
376
+ if (h._hasAlphaBug)
377
+ for (let t = 3; t < e.length; t += 4)
378
+ e[t] = e[t] > 1 ? e[t] : 1;
379
+ return e;
424
380
  }
425
381
  _ready() {
426
- this._init();
427
- this.dispatchEvent(new CustomEvent("ready"));
428
- }
429
- async sendMessage(target, data = {}, transferable) {
430
- await this._loaded;
431
- if (transferable) {
432
- this._worker.postMessage({
433
- target,
434
- transferable,
435
- ...data
436
- }, [...transferable]);
437
- } else {
438
- this._worker.postMessage({
439
- target,
440
- ...data
441
- });
442
- }
382
+ this._init(), this.dispatchEvent(new CustomEvent("ready"));
383
+ }
384
+ /**
385
+ * Send data and execute function in the worker.
386
+ * @param {String} target Target function.
387
+ * @param {Object} [data] Data for function.
388
+ * @param {Transferable[]} [transferable] Array of transferables.
389
+ */
390
+ async sendMessage(e, t = {}, s) {
391
+ await this._loaded, s ? this._worker.postMessage({
392
+ target: e,
393
+ transferable: s,
394
+ ...t
395
+ }, [...s]) : this._worker.postMessage({
396
+ target: e,
397
+ ...t
398
+ });
443
399
  }
444
- _fetchFromWorker(workerOptions, callback) {
400
+ _fetchFromWorker(e, t) {
445
401
  try {
446
- const target = workerOptions.target;
447
- const timeout = setTimeout(() => {
448
- reject(new Error("Error: Timeout while try to fetch " + target));
449
- }, 5e3);
450
- const resolve = ({ data }) => {
451
- if (data.target === target) {
452
- callback(null, data);
453
- this._worker.removeEventListener("message", resolve);
454
- this._worker.removeEventListener("error", reject);
455
- clearTimeout(timeout);
456
- }
402
+ const s = e.target, a = setTimeout(() => {
403
+ r(new Error("Error: Timeout while try to fetch " + s));
404
+ }, 5e3), n = ({ data: i }) => {
405
+ i.target === s && (t(null, i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", r), clearTimeout(a));
406
+ }, r = (i) => {
407
+ t(i), this._worker.removeEventListener("message", n), this._worker.removeEventListener("error", r), clearTimeout(a);
457
408
  };
458
- const reject = (event) => {
459
- callback(event);
460
- this._worker.removeEventListener("message", resolve);
461
- this._worker.removeEventListener("error", reject);
462
- clearTimeout(timeout);
463
- };
464
- this._worker.addEventListener("message", resolve);
465
- this._worker.addEventListener("error", reject);
466
- this._worker.postMessage(workerOptions);
467
- } catch (error) {
468
- this._error(error);
409
+ this._worker.addEventListener("message", n), this._worker.addEventListener("error", r), this._worker.postMessage(e);
410
+ } catch (s) {
411
+ this._error(s);
469
412
  }
470
413
  }
471
- _console({ content, command }) {
472
- console[command].apply(console, JSON.parse(content));
414
+ _console({ content: e, command: t }) {
415
+ console[t].apply(console, JSON.parse(e));
473
416
  }
474
- _onmessage({ data }) {
475
- if (this["_" + data.target])
476
- this["_" + data.target](data);
417
+ _onmessage({ data: e }) {
418
+ this["_" + e.target] && this["_" + e.target](e);
477
419
  }
478
- _error(err) {
479
- this.dispatchEvent(err instanceof ErrorEvent ? new ErrorEvent(err.type, err) : new ErrorEvent("error", { cause: err instanceof Error ? err.cause : err }));
480
- if (!(err instanceof Error)) {
481
- if (err instanceof ErrorEvent) {
482
- err = err.error;
483
- } else {
484
- err = new Error("error", { cause: err });
485
- }
486
- }
487
- console.error(err);
420
+ _error(e) {
421
+ 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 });
422
+ this.dispatchEvent(s), console.error(t);
488
423
  }
489
424
  _removeListeners() {
490
- if (this._video) {
491
- if (this._ro)
492
- this._ro.unobserve(this._video);
493
- this._video.removeEventListener("timeupdate", this._boundTimeUpdate);
494
- this._video.removeEventListener("progress", this._boundTimeUpdate);
495
- this._video.removeEventListener("waiting", this._boundTimeUpdate);
496
- this._video.removeEventListener("seeking", this._boundTimeUpdate);
497
- this._video.removeEventListener("playing", this._boundTimeUpdate);
498
- this._video.removeEventListener("ratechange", this._boundSetRate);
499
- this._video.removeEventListener("resize", this._boundResize);
500
- }
425
+ this._video && (this._ro && this._ro.unobserve(this._video), 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));
501
426
  }
502
- destroy(err) {
503
- if (err)
504
- this._error(err);
505
- if (this._video && this._canvasParent)
506
- this._video.parentNode.removeChild(this._canvasParent);
507
- this._destroyed = true;
508
- this._removeListeners();
509
- this.sendMessage("destroy");
510
- this._worker.terminate();
427
+ /**
428
+ * Destroy the object, worker, listeners and all data.
429
+ * @param {String} [err] Error to throw when destroying.
430
+ */
431
+ destroy(e) {
432
+ e && this._error(e), this._video && this._canvasParent && this._video.parentNode.removeChild(this._canvasParent), this._destroyed = !0, this._removeListeners(), this.sendMessage("destroy"), this._worker.terminate();
511
433
  }
512
434
  };
513
- let JASSUB = _JASSUB;
514
- __publicField(JASSUB, "_supportsWebAssembly", null);
515
- __publicField(JASSUB, "_hasAlphaBug", null);
516
- export { JASSUB as default };
435
+ let _ = h;
436
+ // test support for WASM, ImageData, alphaBug, but only once, on init so it doesn't run when first running the page
437
+ v(_, "_supportsWebAssembly", null), v(_, "_hasAlphaBug", null);
438
+ export {
439
+ _ as default
440
+ };