@obipascal/player 1.0.10 → 1.0.11
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/README.md +131 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/react.d.ts +56 -1
- package/dist/wontum-player.cjs.js +18 -18
- package/dist/wontum-player.esm.js +382 -310
- package/package.json +1 -1
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
7
|
-
import { useRef as
|
|
8
|
-
class
|
|
1
|
+
var N = Object.defineProperty;
|
|
2
|
+
var W = (u, t, e) => t in u ? N(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
|
+
var a = (u, t, e) => W(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import f from "hls.js";
|
|
5
|
+
import { jsx as B } from "react/jsx-runtime";
|
|
6
|
+
import * as $ from "react";
|
|
7
|
+
import { useRef as w, useEffect as b, useState as v, useCallback as E } from "react";
|
|
8
|
+
class z {
|
|
9
9
|
constructor(t) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
var e,
|
|
10
|
+
a(this, "config");
|
|
11
|
+
a(this, "sessionId");
|
|
12
|
+
a(this, "events", []);
|
|
13
|
+
a(this, "sessionStartTime");
|
|
14
|
+
a(this, "playbackStartTime", null);
|
|
15
|
+
a(this, "totalPlayTime", 0);
|
|
16
|
+
a(this, "totalBufferTime", 0);
|
|
17
|
+
a(this, "bufferStartTime", null);
|
|
18
|
+
a(this, "rebufferCount", 0);
|
|
19
|
+
a(this, "seekCount", 0);
|
|
20
|
+
a(this, "webSocket", null);
|
|
21
|
+
a(this, "socketIO", null);
|
|
22
|
+
a(this, "wsReconnectTimeout", null);
|
|
23
|
+
a(this, "isDestroyed", !1);
|
|
24
|
+
var e, n;
|
|
25
25
|
if (this.config = t, this.sessionId = (t == null ? void 0 : t.sessionId) || this.generateSessionId(), this.sessionStartTime = Date.now(), (e = this.config) != null && e.webSocket) {
|
|
26
|
-
const
|
|
27
|
-
"type" in
|
|
26
|
+
const i = this.config.webSocket;
|
|
27
|
+
"type" in i ? i.type === "socket.io" ? this.initializeSocketIO() : this.initializeWebSocket() : this.initializeWebSocket();
|
|
28
28
|
}
|
|
29
|
-
(
|
|
29
|
+
(n = this.config) != null && n.enabled && this.trackEvent("session_start", this.getSessionData());
|
|
30
30
|
}
|
|
31
31
|
trackEvent(t, e = {}) {
|
|
32
|
-
var
|
|
33
|
-
if (!((
|
|
34
|
-
const
|
|
32
|
+
var i;
|
|
33
|
+
if (!((i = this.config) != null && i.enabled)) return;
|
|
34
|
+
const n = {
|
|
35
35
|
eventType: t,
|
|
36
36
|
timestamp: Date.now(),
|
|
37
37
|
sessionId: this.sessionId,
|
|
@@ -42,7 +42,7 @@ class N {
|
|
|
42
42
|
...this.getQoEMetrics()
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
|
-
this.events.push(
|
|
45
|
+
this.events.push(n), this.updateMetrics(t, e), this.webSocket && this.webSocket.readyState === WebSocket.OPEN && this.sendToWebSocket(n), this.socketIO && this.socketIO.connected && this.sendToSocketIO(n), this.config.endpoint && this.sendEvent(n), process.env.NODE_ENV === "development" && console.log("[Analytics]", t, n.data);
|
|
46
46
|
}
|
|
47
47
|
updateMetrics(t, e) {
|
|
48
48
|
switch (t) {
|
|
@@ -105,8 +105,8 @@ class N {
|
|
|
105
105
|
},
|
|
106
106
|
body: JSON.stringify(t)
|
|
107
107
|
});
|
|
108
|
-
} catch (
|
|
109
|
-
console.error("Failed to send analytics event:",
|
|
108
|
+
} catch (n) {
|
|
109
|
+
console.error("Failed to send analytics event:", n);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
generateSessionId() {
|
|
@@ -119,32 +119,32 @@ class N {
|
|
|
119
119
|
if (t.type === "socket.io")
|
|
120
120
|
try {
|
|
121
121
|
if (typeof t.connection == "string") {
|
|
122
|
-
const
|
|
123
|
-
this.socketIO =
|
|
122
|
+
const i = (await import("socket.io-client")).default;
|
|
123
|
+
this.socketIO = i(t.connection, t.options || {});
|
|
124
124
|
} else
|
|
125
125
|
this.socketIO = t.connection;
|
|
126
126
|
if (!this.socketIO) return;
|
|
127
127
|
this.socketIO.on("connect", () => {
|
|
128
128
|
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Connected"), t.onConnect && t.onConnect();
|
|
129
|
-
}), this.socketIO.on("connect_error", (
|
|
130
|
-
console.error("[Analytics Socket.IO] Connection error:",
|
|
131
|
-
}), this.socketIO.on("disconnect", (
|
|
132
|
-
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Disconnected:",
|
|
133
|
-
}), this.socketIO.on("error", (
|
|
134
|
-
console.error("[Analytics Socket.IO] Error:",
|
|
129
|
+
}), this.socketIO.on("connect_error", (n) => {
|
|
130
|
+
console.error("[Analytics Socket.IO] Connection error:", n), t.onError && t.onError(n);
|
|
131
|
+
}), this.socketIO.on("disconnect", (n) => {
|
|
132
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Disconnected:", n), t.onDisconnect && t.onDisconnect(n);
|
|
133
|
+
}), this.socketIO.on("error", (n) => {
|
|
134
|
+
console.error("[Analytics Socket.IO] Error:", n), t.onError && t.onError(n);
|
|
135
135
|
});
|
|
136
|
-
} catch (
|
|
137
|
-
console.error("[Analytics Socket.IO] Failed to initialize:",
|
|
136
|
+
} catch (n) {
|
|
137
|
+
console.error("[Analytics Socket.IO] Failed to initialize:", n);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
sendToSocketIO(t) {
|
|
141
141
|
var e;
|
|
142
142
|
if (!(!this.socketIO || !this.socketIO.connected))
|
|
143
143
|
try {
|
|
144
|
-
const
|
|
145
|
-
this.socketIO.emit(o,
|
|
146
|
-
} catch (
|
|
147
|
-
console.error("[Analytics Socket.IO] Failed to emit event:",
|
|
144
|
+
const n = (e = this.config) == null ? void 0 : e.webSocket, i = n != null && n.transform ? n.transform(t) : t, o = (n == null ? void 0 : n.eventName) || "analytics";
|
|
145
|
+
this.socketIO.emit(o, i), process.env.NODE_ENV === "development" && console.log(`[Analytics Socket.IO] Emitted (${o}):`, t.eventType);
|
|
146
|
+
} catch (n) {
|
|
147
|
+
console.error("[Analytics Socket.IO] Failed to emit event:", n);
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
initializeWebSocket() {
|
|
@@ -152,30 +152,30 @@ class N {
|
|
|
152
152
|
if (!((e = this.config) != null && e.webSocket)) return;
|
|
153
153
|
const t = this.config.webSocket;
|
|
154
154
|
try {
|
|
155
|
-
typeof t.connection == "string" ? this.webSocket = new WebSocket(t.connection) : this.webSocket = t.connection, this.webSocket.onopen = (
|
|
156
|
-
process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Connected"), t.onOpen && t.onOpen(
|
|
157
|
-
}, this.webSocket.onerror = (
|
|
158
|
-
console.error("[Analytics WebSocket] Error:",
|
|
159
|
-
}, this.webSocket.onclose = (
|
|
160
|
-
if (process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Disconnected"), t.onClose && t.onClose(
|
|
155
|
+
typeof t.connection == "string" ? this.webSocket = new WebSocket(t.connection) : this.webSocket = t.connection, this.webSocket.onopen = (n) => {
|
|
156
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Connected"), t.onOpen && t.onOpen(n);
|
|
157
|
+
}, this.webSocket.onerror = (n) => {
|
|
158
|
+
console.error("[Analytics WebSocket] Error:", n), t.onError && t.onError(n);
|
|
159
|
+
}, this.webSocket.onclose = (n) => {
|
|
160
|
+
if (process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Disconnected"), t.onClose && t.onClose(n), t.autoReconnect !== !1 && !this.isDestroyed) {
|
|
161
161
|
const o = t.reconnectDelay || 3e3;
|
|
162
162
|
process.env.NODE_ENV === "development" && console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`), this.wsReconnectTimeout = window.setTimeout(() => {
|
|
163
163
|
this.initializeWebSocket();
|
|
164
164
|
}, o);
|
|
165
165
|
}
|
|
166
166
|
};
|
|
167
|
-
} catch (
|
|
168
|
-
console.error("[Analytics WebSocket] Failed to initialize:",
|
|
167
|
+
} catch (n) {
|
|
168
|
+
console.error("[Analytics WebSocket] Failed to initialize:", n);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
sendToWebSocket(t) {
|
|
172
172
|
var e;
|
|
173
173
|
if (!(!this.webSocket || this.webSocket.readyState !== WebSocket.OPEN))
|
|
174
174
|
try {
|
|
175
|
-
const
|
|
176
|
-
this.webSocket.send(JSON.stringify(
|
|
177
|
-
} catch (
|
|
178
|
-
console.error("[Analytics WebSocket] Failed to send event:",
|
|
175
|
+
const n = (e = this.config) == null ? void 0 : e.webSocket, i = n != null && n.transform ? n.transform(t) : t;
|
|
176
|
+
this.webSocket.send(JSON.stringify(i)), process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Sent:", t.eventType);
|
|
177
|
+
} catch (n) {
|
|
178
|
+
console.error("[Analytics WebSocket] Failed to send event:", n);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
getEvents() {
|
|
@@ -193,46 +193,46 @@ class N {
|
|
|
193
193
|
this.isDestroyed = !0, (t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.wsReconnectTimeout && (clearTimeout(this.wsReconnectTimeout), this.wsReconnectTimeout = null), this.webSocket && (this.webSocket.close(), this.webSocket = null), this.socketIO && (this.socketIO.removeAllListeners(), this.socketIO.disconnect(), this.socketIO = null), this.events = [];
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
class
|
|
196
|
+
class _ {
|
|
197
197
|
constructor(t, e) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
198
|
+
a(this, "container");
|
|
199
|
+
a(this, "player");
|
|
200
|
+
a(this, "controlsContainer");
|
|
201
|
+
a(this, "progressContainer");
|
|
202
|
+
a(this, "progressBar");
|
|
203
|
+
a(this, "playButton");
|
|
204
|
+
a(this, "skipBackwardButton");
|
|
205
|
+
a(this, "skipForwardButton");
|
|
206
|
+
a(this, "volumeButton");
|
|
207
|
+
a(this, "volumeContainer");
|
|
208
|
+
a(this, "fullscreenButton");
|
|
209
|
+
a(this, "pipButton");
|
|
210
|
+
a(this, "settingsButton");
|
|
211
211
|
// private timeDisplay: HTMLElement
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
a(this, "volumeSlider");
|
|
213
|
+
a(this, "progressInput");
|
|
214
214
|
// private controlsVisible = true
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
a(this, "hideControlsTimeout", null);
|
|
216
|
+
a(this, "stickyControls", !1);
|
|
217
|
+
a(this, "isVolumeSliderActive", !1);
|
|
218
218
|
this.container = t, this.player = e, this.injectStyles(), this.createProgressBar(), this.controlsContainer = this.createControls(), this.container.appendChild(this.controlsContainer), this.playButton = this.controlsContainer.querySelector(".wontum-play-btn"), this.skipBackwardButton = this.controlsContainer.querySelector(".wontum-skip-backward-btn"), this.skipForwardButton = this.controlsContainer.querySelector(".wontum-skip-forward-btn"), this.volumeButton = this.controlsContainer.querySelector(".wontum-volume-btn"), this.volumeContainer = this.controlsContainer.querySelector(".wontum-volume-container"), this.fullscreenButton = this.controlsContainer.querySelector(".wontum-fullscreen-btn"), this.pipButton = this.controlsContainer.querySelector(".wontum-pip-btn"), this.settingsButton = this.controlsContainer.querySelector(".wontum-settings-btn"), this.volumeSlider = this.controlsContainer.querySelector(".wontum-volume-slider"), this.progressInput = this.container.querySelector(".wontum-progress-input"), this.progressBar = this.container.querySelector(".wontum-progress-filled"), this.stickyControls = this.player.config.stickyControls || !1, this.stickyControls && this.controlsContainer.classList.add("sticky"), this.setupEventListeners(), this.setupPlayerEventListeners();
|
|
219
219
|
}
|
|
220
220
|
injectStyles() {
|
|
221
221
|
const t = "wontum-player-styles";
|
|
222
222
|
if (document.getElementById(t)) return;
|
|
223
|
-
const e = this.player.config.theme || {},
|
|
224
|
-
|
|
223
|
+
const e = this.player.config.theme || {}, n = e.primaryColor || "#3b82f6", i = e.accentColor || "#2563eb", o = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", s = e.controlsBackground || "linear-gradient(to top, rgba(0,0,0,0.8), transparent)", r = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", c = e.borderRadius || "4px", d = document.createElement("style");
|
|
224
|
+
d.id = t, d.textContent = `
|
|
225
225
|
.wontum-player-container {
|
|
226
226
|
position: relative;
|
|
227
227
|
background: #000;
|
|
228
228
|
font-family: ${o};
|
|
229
229
|
overflow: hidden;
|
|
230
|
-
--primary-color: ${
|
|
231
|
-
--accent-color: ${
|
|
230
|
+
--primary-color: ${n};
|
|
231
|
+
--accent-color: ${i};
|
|
232
232
|
--controls-bg: ${s};
|
|
233
|
-
--button-hover: ${
|
|
233
|
+
--button-hover: ${r};
|
|
234
234
|
--progress-height: ${l};
|
|
235
|
-
--border-radius: ${
|
|
235
|
+
--border-radius: ${c};
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
.wontum-player-video {
|
|
@@ -709,7 +709,7 @@ class W {
|
|
|
709
709
|
transform: translateY(0) !important;
|
|
710
710
|
pointer-events: all !important;
|
|
711
711
|
}
|
|
712
|
-
`, document.head.appendChild(
|
|
712
|
+
`, document.head.appendChild(d), this.container.classList.add("wontum-player-container");
|
|
713
713
|
}
|
|
714
714
|
createProgressBar() {
|
|
715
715
|
const t = document.createElement("div");
|
|
@@ -802,11 +802,11 @@ class W {
|
|
|
802
802
|
this.player.skipBackward(10);
|
|
803
803
|
}), this.skipForwardButton.addEventListener("click", () => {
|
|
804
804
|
this.player.skipForward(10);
|
|
805
|
-
}), this.progressInput.addEventListener("input", (
|
|
806
|
-
const
|
|
807
|
-
this.player.seek(
|
|
808
|
-
}), this.volumeSlider.addEventListener("input", (
|
|
809
|
-
const
|
|
805
|
+
}), this.progressInput.addEventListener("input", (n) => {
|
|
806
|
+
const i = n.target, o = parseFloat(i.value), s = this.player.getState(), r = o / 100 * s.duration;
|
|
807
|
+
this.player.seek(r);
|
|
808
|
+
}), this.volumeSlider.addEventListener("input", (n) => {
|
|
809
|
+
const i = n.target, o = parseFloat(i.value) / 100;
|
|
810
810
|
this.player.setVolume(o);
|
|
811
811
|
}), this.volumeButton.addEventListener("click", () => {
|
|
812
812
|
this.player.getState().muted ? this.player.unmute() : this.player.mute();
|
|
@@ -825,18 +825,18 @@ class W {
|
|
|
825
825
|
}), this.pipButton.addEventListener("click", async () => {
|
|
826
826
|
try {
|
|
827
827
|
await this.player.togglePictureInPicture();
|
|
828
|
-
} catch (
|
|
829
|
-
console.error("PiP error:",
|
|
828
|
+
} catch (n) {
|
|
829
|
+
console.error("PiP error:", n);
|
|
830
830
|
}
|
|
831
831
|
}), this.settingsButton.addEventListener("click", () => {
|
|
832
|
-
const
|
|
833
|
-
|
|
832
|
+
const n = this.controlsContainer.querySelector(".wontum-settings-panel");
|
|
833
|
+
n.classList.toggle("active"), n.classList.contains("active") && (this.updateSettingsMenu(), this.updateQualityMenu(), this.updateSpeedMenu(), this.updateSubtitleMenu());
|
|
834
834
|
});
|
|
835
835
|
const t = this.controlsContainer.querySelectorAll(".wontum-tab");
|
|
836
|
-
t.forEach((
|
|
837
|
-
|
|
838
|
-
const o =
|
|
839
|
-
t.forEach((
|
|
836
|
+
t.forEach((n) => {
|
|
837
|
+
n.addEventListener("click", (i) => {
|
|
838
|
+
const o = i.currentTarget, s = o.getAttribute("data-tab");
|
|
839
|
+
t.forEach((c) => c.classList.remove("active")), o.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((c) => c.classList.remove("active"));
|
|
840
840
|
const l = this.controlsContainer.querySelector(`[data-panel="${s}"]`);
|
|
841
841
|
l == null || l.classList.add("active");
|
|
842
842
|
});
|
|
@@ -854,19 +854,19 @@ class W {
|
|
|
854
854
|
}), this.player.on("pause", () => {
|
|
855
855
|
this.playButton.innerHTML = this.getPlayIcon();
|
|
856
856
|
}), this.player.on("timeupdate", (t) => {
|
|
857
|
-
const { currentTime: e } = t.data,
|
|
858
|
-
if (
|
|
859
|
-
const o = e /
|
|
857
|
+
const { currentTime: e } = t.data, n = this.player.getState();
|
|
858
|
+
if (n.duration > 0) {
|
|
859
|
+
const o = e / n.duration * 100;
|
|
860
860
|
this.progressBar.style.width = `${o}%`, this.progressInput.value = o.toString();
|
|
861
861
|
}
|
|
862
|
-
const
|
|
863
|
-
|
|
862
|
+
const i = this.controlsContainer.querySelector(".wontum-current-time");
|
|
863
|
+
i.textContent = this.formatTime(e);
|
|
864
864
|
}), this.player.on("loadedmetadata", (t) => {
|
|
865
|
-
const { duration: e } = t.data,
|
|
866
|
-
|
|
865
|
+
const { duration: e } = t.data, n = this.controlsContainer.querySelector(".wontum-duration");
|
|
866
|
+
n.textContent = this.formatTime(e), t.data.qualities && this.updateQualityMenu(t.data.qualities);
|
|
867
867
|
}), this.player.on("volumechange", (t) => {
|
|
868
|
-
const { volume: e, muted:
|
|
869
|
-
this.volumeSlider.value = (e * 100).toString(), this.volumeButton.innerHTML =
|
|
868
|
+
const { volume: e, muted: n } = t.data;
|
|
869
|
+
this.volumeSlider.value = (e * 100).toString(), this.volumeButton.innerHTML = n ? this.getMutedIcon() : this.getVolumeIcon();
|
|
870
870
|
}), this.player.on("waiting", () => {
|
|
871
871
|
const t = this.controlsContainer.querySelector(".wontum-loading");
|
|
872
872
|
t.style.display = "block";
|
|
@@ -881,35 +881,35 @@ class W {
|
|
|
881
881
|
t.innerHTML = '<div class="wontum-subtitle-option">No subtitles available</div>';
|
|
882
882
|
return;
|
|
883
883
|
}
|
|
884
|
-
const
|
|
884
|
+
const n = e.findIndex((i) => i.mode === "showing");
|
|
885
885
|
t.innerHTML = `
|
|
886
|
-
<div class="wontum-subtitle-option ${
|
|
886
|
+
<div class="wontum-subtitle-option ${n === -1 ? "active" : ""}" data-track="-1">Off</div>
|
|
887
887
|
${e.map(
|
|
888
|
-
(
|
|
889
|
-
<div class="wontum-subtitle-option ${o ===
|
|
890
|
-
${
|
|
888
|
+
(i, o) => `
|
|
889
|
+
<div class="wontum-subtitle-option ${o === n ? "active" : ""}" data-track="${o}">
|
|
890
|
+
${i.label || i.language || `Track ${o + 1}`}
|
|
891
891
|
</div>
|
|
892
892
|
`
|
|
893
893
|
).join("")}
|
|
894
|
-
`, t.querySelectorAll(".wontum-subtitle-option").forEach((
|
|
895
|
-
|
|
896
|
-
const s = o.target,
|
|
897
|
-
|
|
894
|
+
`, t.querySelectorAll(".wontum-subtitle-option").forEach((i) => {
|
|
895
|
+
i.addEventListener("click", (o) => {
|
|
896
|
+
const s = o.target, r = parseInt(s.dataset.track || "-1");
|
|
897
|
+
r === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(r), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
898
898
|
});
|
|
899
899
|
});
|
|
900
900
|
}
|
|
901
901
|
updateSpeedMenu() {
|
|
902
|
-
const t = this.controlsContainer.querySelector(".wontum-speed-menu"),
|
|
903
|
-
t.innerHTML =
|
|
902
|
+
const t = this.controlsContainer.querySelector(".wontum-speed-menu"), n = this.player.getState().playbackRate || 1, i = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
903
|
+
t.innerHTML = i.map(
|
|
904
904
|
(o) => `
|
|
905
|
-
<div class="wontum-speed-option ${
|
|
905
|
+
<div class="wontum-speed-option ${n === o ? "active" : ""}" data-speed="${o}">
|
|
906
906
|
${o === 1 ? "Normal" : o + "x"}
|
|
907
907
|
</div>
|
|
908
908
|
`
|
|
909
909
|
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((o) => {
|
|
910
910
|
o.addEventListener("click", (s) => {
|
|
911
|
-
const
|
|
912
|
-
this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((
|
|
911
|
+
const r = s.target, l = parseFloat(r.dataset.speed || "1");
|
|
912
|
+
this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((c) => c.classList.remove("active")), r.classList.add("active");
|
|
913
913
|
});
|
|
914
914
|
});
|
|
915
915
|
}
|
|
@@ -927,22 +927,22 @@ class W {
|
|
|
927
927
|
});
|
|
928
928
|
}
|
|
929
929
|
updateQualityMenu(t) {
|
|
930
|
-
const e = this.controlsContainer.querySelector(".wontum-quality-menu"),
|
|
931
|
-
if (!
|
|
930
|
+
const e = this.controlsContainer.querySelector(".wontum-quality-menu"), n = t || this.player.getQualities();
|
|
931
|
+
if (!n || n.length === 0) {
|
|
932
932
|
e.innerHTML = '<div class="wontum-quality-option">No qualities available</div>';
|
|
933
933
|
return;
|
|
934
934
|
}
|
|
935
935
|
e.innerHTML = `
|
|
936
936
|
<div class="wontum-quality-option active" data-quality="-1">Auto</div>
|
|
937
|
-
${
|
|
938
|
-
(
|
|
939
|
-
<div class="wontum-quality-option" data-quality="${o}">${
|
|
937
|
+
${n.map(
|
|
938
|
+
(i, o) => `
|
|
939
|
+
<div class="wontum-quality-option" data-quality="${o}">${i.name}</div>
|
|
940
940
|
`
|
|
941
941
|
).join("")}
|
|
942
|
-
`, e.querySelectorAll(".wontum-quality-option").forEach((
|
|
943
|
-
|
|
944
|
-
const s = o.target,
|
|
945
|
-
this.player.setQuality(
|
|
942
|
+
`, e.querySelectorAll(".wontum-quality-option").forEach((i) => {
|
|
943
|
+
i.addEventListener("click", (o) => {
|
|
944
|
+
const s = o.target, r = parseInt(s.dataset.quality || "-1");
|
|
945
|
+
this.player.setQuality(r), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
946
946
|
});
|
|
947
947
|
});
|
|
948
948
|
}
|
|
@@ -960,8 +960,8 @@ class W {
|
|
|
960
960
|
}
|
|
961
961
|
formatTime(t) {
|
|
962
962
|
if (isNaN(t)) return "0:00";
|
|
963
|
-
const e = Math.floor(t / 60),
|
|
964
|
-
return `${e}:${
|
|
963
|
+
const e = Math.floor(t / 60), n = Math.floor(t % 60);
|
|
964
|
+
return `${e}:${n.toString().padStart(2, "0")}`;
|
|
965
965
|
}
|
|
966
966
|
// SVG Icons
|
|
967
967
|
getPlayIcon() {
|
|
@@ -1007,11 +1007,11 @@ class W {
|
|
|
1007
1007
|
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
1008
1008
|
}
|
|
1009
1009
|
}
|
|
1010
|
-
class
|
|
1010
|
+
class j {
|
|
1011
1011
|
constructor(t) {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1012
|
+
a(this, "config");
|
|
1013
|
+
a(this, "urlCache", /* @__PURE__ */ new Map());
|
|
1014
|
+
a(this, "signedUrls", /* @__PURE__ */ new Set());
|
|
1015
1015
|
this.config = t;
|
|
1016
1016
|
}
|
|
1017
1017
|
/**
|
|
@@ -1028,8 +1028,8 @@ class _ {
|
|
|
1028
1028
|
if (!((e = this.config) != null && e.cloudFrontDomains) || this.config.cloudFrontDomains.length === 0)
|
|
1029
1029
|
return !1;
|
|
1030
1030
|
try {
|
|
1031
|
-
const
|
|
1032
|
-
return this.config.cloudFrontDomains.some((
|
|
1031
|
+
const n = new URL(t);
|
|
1032
|
+
return this.config.cloudFrontDomains.some((i) => n.hostname.includes(i));
|
|
1033
1033
|
} catch {
|
|
1034
1034
|
return !1;
|
|
1035
1035
|
}
|
|
@@ -1050,15 +1050,15 @@ class _ {
|
|
|
1050
1050
|
return t;
|
|
1051
1051
|
if ((o = this.config) != null && o.signUrl)
|
|
1052
1052
|
try {
|
|
1053
|
-
const
|
|
1054
|
-
return this.signedUrls.add(t),
|
|
1055
|
-
} catch (
|
|
1056
|
-
const l = (
|
|
1053
|
+
const r = await this.config.signUrl(t);
|
|
1054
|
+
return this.signedUrls.add(t), r;
|
|
1055
|
+
} catch (r) {
|
|
1056
|
+
const l = (r == null ? void 0 : r.name) === "AbortError" || ((s = r == null ? void 0 : r.message) == null ? void 0 : s.includes("aborted"));
|
|
1057
1057
|
if (l && e < 2)
|
|
1058
|
-
return console.warn(`Sign URL aborted, retrying (${e + 1}/2)...`), await new Promise((
|
|
1059
|
-
throw console.error("Failed to sign CloudFront URL:",
|
|
1058
|
+
return console.warn(`Sign URL aborted, retrying (${e + 1}/2)...`), await new Promise((c) => setTimeout(c, 300)), this.signCloudFrontUrl(t, e + 1);
|
|
1059
|
+
throw console.error("Failed to sign CloudFront URL:", r), l ? new Error(
|
|
1060
1060
|
"Failed to sign CloudFront URL: Request was aborted. If using Apollo Client or other GraphQL clients, consider moving the query outside component lifecycle or using useQuery with skip option."
|
|
1061
|
-
) : new Error(`Failed to sign CloudFront URL: ${(
|
|
1061
|
+
) : new Error(`Failed to sign CloudFront URL: ${(r == null ? void 0 : r.message) || "Unknown error"}`);
|
|
1062
1062
|
}
|
|
1063
1063
|
return console.warn("No signUrl function provided. CloudFront cookies may not be set."), t;
|
|
1064
1064
|
}
|
|
@@ -1071,18 +1071,18 @@ class _ {
|
|
|
1071
1071
|
const e = t.match(/s3[.-]([^.]+)\.amazonaws\.com\/(.+)/);
|
|
1072
1072
|
if (e)
|
|
1073
1073
|
return e[2];
|
|
1074
|
-
const
|
|
1075
|
-
return
|
|
1074
|
+
const n = t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);
|
|
1075
|
+
return n ? n[2] : t;
|
|
1076
1076
|
}
|
|
1077
1077
|
/**
|
|
1078
1078
|
* Get presigned URL from cache or generate new one
|
|
1079
1079
|
*/
|
|
1080
1080
|
async getPresignedUrl(t) {
|
|
1081
|
-
var
|
|
1082
|
-
const e = this.extractS3Key(t),
|
|
1083
|
-
if (
|
|
1084
|
-
return
|
|
1085
|
-
if ((
|
|
1081
|
+
var i;
|
|
1082
|
+
const e = this.extractS3Key(t), n = this.urlCache.get(e);
|
|
1083
|
+
if (n && n.expiresAt > Date.now())
|
|
1084
|
+
return n.url;
|
|
1085
|
+
if ((i = this.config) != null && i.getPresignedUrl)
|
|
1086
1086
|
try {
|
|
1087
1087
|
const o = await this.config.getPresignedUrl(e);
|
|
1088
1088
|
return this.urlCache.set(e, {
|
|
@@ -1097,8 +1097,8 @@ class _ {
|
|
|
1097
1097
|
/**
|
|
1098
1098
|
* Helper to construct S3 URL from bucket and key
|
|
1099
1099
|
*/
|
|
1100
|
-
static constructS3Url(t, e,
|
|
1101
|
-
return `https://${t}.s3.${
|
|
1100
|
+
static constructS3Url(t, e, n = "us-east-1") {
|
|
1101
|
+
return `https://${t}.s3.${n}.amazonaws.com/${e}`;
|
|
1102
1102
|
}
|
|
1103
1103
|
/**
|
|
1104
1104
|
* Helper to parse S3 URI (s3://bucket/key)
|
|
@@ -1106,8 +1106,8 @@ class _ {
|
|
|
1106
1106
|
static parseS3Uri(t) {
|
|
1107
1107
|
if (!t.startsWith("s3://"))
|
|
1108
1108
|
return null;
|
|
1109
|
-
const e = t.replace("s3://", "").split("/"),
|
|
1110
|
-
return { bucket:
|
|
1109
|
+
const e = t.replace("s3://", "").split("/"), n = e[0], i = e.slice(1).join("/");
|
|
1110
|
+
return { bucket: n, key: i };
|
|
1111
1111
|
}
|
|
1112
1112
|
/**
|
|
1113
1113
|
* Clear URL cache and signed URLs
|
|
@@ -1116,18 +1116,18 @@ class _ {
|
|
|
1116
1116
|
this.urlCache.clear(), this.signedUrls.clear();
|
|
1117
1117
|
}
|
|
1118
1118
|
}
|
|
1119
|
-
class
|
|
1119
|
+
class O {
|
|
1120
1120
|
constructor(t) {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1121
|
+
a(this, "container");
|
|
1122
|
+
a(this, "videoElement");
|
|
1123
|
+
a(this, "hls", null);
|
|
1124
|
+
a(this, "config");
|
|
1125
|
+
a(this, "eventListeners", /* @__PURE__ */ new Map());
|
|
1126
|
+
a(this, "analytics");
|
|
1127
|
+
a(this, "s3Handler");
|
|
1128
|
+
a(this, "uiController");
|
|
1129
|
+
a(this, "qualities", []);
|
|
1130
|
+
a(this, "state", {
|
|
1131
1131
|
playing: !1,
|
|
1132
1132
|
paused: !0,
|
|
1133
1133
|
ended: !1,
|
|
@@ -1143,12 +1143,12 @@ class $ {
|
|
|
1143
1143
|
});
|
|
1144
1144
|
if (this.config = t, this.container = typeof t.container == "string" ? document.querySelector(t.container) : t.container, !this.container)
|
|
1145
1145
|
throw new Error("Container element not found");
|
|
1146
|
-
this.analytics = new
|
|
1146
|
+
this.analytics = new z(t.analytics), this.s3Handler = new j(t.s3Config), this.videoElement = this.createVideoElement(), this.container.appendChild(this.videoElement), this.uiController = new _(this.container, this), this.setupVideoListeners(), this.loadSource(t.src), t.autoplay && (this.videoElement.autoplay = !0), t.muted && this.mute(), t.poster && (this.videoElement.poster = t.poster), t.preload && (this.videoElement.preload = t.preload), t.subtitles && this.addSubtitleTracks(t.subtitles);
|
|
1147
1147
|
}
|
|
1148
1148
|
addSubtitleTracks(t) {
|
|
1149
1149
|
t.forEach((e) => {
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1150
|
+
const n = document.createElement("track");
|
|
1151
|
+
n.kind = "subtitles", n.label = e.label, n.src = e.src, n.srclang = e.srclang, e.default && (n.default = !0), this.videoElement.appendChild(n);
|
|
1152
1152
|
});
|
|
1153
1153
|
}
|
|
1154
1154
|
createVideoElement() {
|
|
@@ -1211,31 +1211,31 @@ class $ {
|
|
|
1211
1211
|
async loadSource(t) {
|
|
1212
1212
|
var e;
|
|
1213
1213
|
try {
|
|
1214
|
-
const
|
|
1215
|
-
if (
|
|
1216
|
-
const
|
|
1214
|
+
const n = await this.s3Handler.processUrl(t);
|
|
1215
|
+
if (f.isSupported()) {
|
|
1216
|
+
const i = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
|
|
1217
1217
|
...this.config.hlsConfig,
|
|
1218
|
-
xhrSetup: (s,
|
|
1218
|
+
xhrSetup: (s, r) => {
|
|
1219
1219
|
var l;
|
|
1220
|
-
|
|
1220
|
+
i && (s.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(s, r);
|
|
1221
1221
|
}
|
|
1222
1222
|
};
|
|
1223
|
-
this.hls = new
|
|
1224
|
-
const l = this.extractQualities(
|
|
1223
|
+
this.hls = new f(o), this.hls.loadSource(n), this.hls.attachMedia(this.videoElement), this.hls.on(f.Events.MANIFEST_PARSED, (s, r) => {
|
|
1224
|
+
const l = this.extractQualities(r.levels);
|
|
1225
1225
|
this.qualities = l;
|
|
1226
|
-
}), this.hls.on(
|
|
1227
|
-
var
|
|
1228
|
-
const l = (
|
|
1226
|
+
}), this.hls.on(f.Events.LEVEL_SWITCHED, (s, r) => {
|
|
1227
|
+
var c;
|
|
1228
|
+
const l = (c = this.hls) == null ? void 0 : c.levels[r.level];
|
|
1229
1229
|
l && (this.state.quality = `${l.height}p`, this.emit("qualitychange", { quality: this.state.quality }));
|
|
1230
|
-
}), this.hls.on(
|
|
1231
|
-
|
|
1230
|
+
}), this.hls.on(f.Events.ERROR, (s, r) => {
|
|
1231
|
+
r.fatal && this.handleHlsError(r);
|
|
1232
1232
|
});
|
|
1233
1233
|
} else if (this.videoElement.canPlayType("application/vnd.apple.mpegurl"))
|
|
1234
|
-
this.videoElement.src =
|
|
1234
|
+
this.videoElement.src = n;
|
|
1235
1235
|
else
|
|
1236
1236
|
throw new Error("HLS is not supported in this browser");
|
|
1237
|
-
} catch (
|
|
1238
|
-
console.error("Failed to load video source:",
|
|
1237
|
+
} catch (n) {
|
|
1238
|
+
console.error("Failed to load video source:", n), this.emit("error", { error: n });
|
|
1239
1239
|
}
|
|
1240
1240
|
}
|
|
1241
1241
|
extractQualities(t) {
|
|
@@ -1247,13 +1247,13 @@ class $ {
|
|
|
1247
1247
|
}));
|
|
1248
1248
|
}
|
|
1249
1249
|
handleHlsError(t) {
|
|
1250
|
-
var e,
|
|
1250
|
+
var e, n;
|
|
1251
1251
|
switch (t.type) {
|
|
1252
|
-
case
|
|
1252
|
+
case f.ErrorTypes.NETWORK_ERROR:
|
|
1253
1253
|
console.error("Network error occurred"), (e = this.hls) == null || e.startLoad();
|
|
1254
1254
|
break;
|
|
1255
|
-
case
|
|
1256
|
-
console.error("Media error occurred"), (
|
|
1255
|
+
case f.ErrorTypes.MEDIA_ERROR:
|
|
1256
|
+
console.error("Media error occurred"), (n = this.hls) == null || n.recoverMediaError();
|
|
1257
1257
|
break;
|
|
1258
1258
|
default:
|
|
1259
1259
|
console.error("Fatal error occurred:", t), this.destroy();
|
|
@@ -1342,8 +1342,8 @@ class $ {
|
|
|
1342
1342
|
*/
|
|
1343
1343
|
enableSubtitles(t) {
|
|
1344
1344
|
const e = this.videoElement.textTracks;
|
|
1345
|
-
for (let
|
|
1346
|
-
e[
|
|
1345
|
+
for (let n = 0; n < e.length; n++)
|
|
1346
|
+
e[n].mode = n === t ? "showing" : "hidden";
|
|
1347
1347
|
}
|
|
1348
1348
|
/**
|
|
1349
1349
|
* Disable all subtitles
|
|
@@ -1358,7 +1358,7 @@ class $ {
|
|
|
1358
1358
|
*/
|
|
1359
1359
|
toggleSubtitles() {
|
|
1360
1360
|
const t = this.videoElement.textTracks;
|
|
1361
|
-
return Array.from(t).some((
|
|
1361
|
+
return Array.from(t).some((n) => n.mode === "showing") ? (this.disableSubtitles(), !1) : t.length > 0 ? (this.enableSubtitles(0), !0) : !1;
|
|
1362
1362
|
}
|
|
1363
1363
|
/**
|
|
1364
1364
|
* Get available subtitle tracks
|
|
@@ -1377,30 +1377,30 @@ class $ {
|
|
|
1377
1377
|
this.eventListeners.has(t) || this.eventListeners.set(t, /* @__PURE__ */ new Set()), this.eventListeners.get(t).add(e);
|
|
1378
1378
|
}
|
|
1379
1379
|
off(t, e) {
|
|
1380
|
-
var
|
|
1381
|
-
(
|
|
1380
|
+
var n;
|
|
1381
|
+
(n = this.eventListeners.get(t)) == null || n.delete(e);
|
|
1382
1382
|
}
|
|
1383
1383
|
emit(t, e) {
|
|
1384
|
-
var
|
|
1385
|
-
const
|
|
1384
|
+
var i;
|
|
1385
|
+
const n = {
|
|
1386
1386
|
type: t,
|
|
1387
1387
|
data: e,
|
|
1388
1388
|
timestamp: Date.now()
|
|
1389
1389
|
};
|
|
1390
|
-
(
|
|
1391
|
-
o(
|
|
1390
|
+
(i = this.eventListeners.get(t)) == null || i.forEach((o) => {
|
|
1391
|
+
o(n);
|
|
1392
1392
|
});
|
|
1393
1393
|
}
|
|
1394
1394
|
destroy() {
|
|
1395
1395
|
this.hls && (this.hls.destroy(), this.hls = null), this.uiController.destroy(), this.videoElement.remove(), this.eventListeners.clear(), this.analytics.destroy();
|
|
1396
1396
|
}
|
|
1397
1397
|
}
|
|
1398
|
-
class
|
|
1398
|
+
class Q {
|
|
1399
1399
|
constructor(t) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1400
|
+
a(this, "file");
|
|
1401
|
+
a(this, "videoElement", null);
|
|
1402
|
+
a(this, "audioContext", null);
|
|
1403
|
+
a(this, "info", null);
|
|
1404
1404
|
if (!this.isVideoFile(t))
|
|
1405
1405
|
throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
|
|
1406
1406
|
this.file = t;
|
|
@@ -1411,8 +1411,8 @@ class G {
|
|
|
1411
1411
|
isVideoFile(t) {
|
|
1412
1412
|
if (t.type.startsWith("video/"))
|
|
1413
1413
|
return !0;
|
|
1414
|
-
const e = [".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".m4v", ".3gp", ".ts", ".m3u8"],
|
|
1415
|
-
return e.some((
|
|
1414
|
+
const e = [".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".m4v", ".3gp", ".ts", ".m3u8"], n = t.name.toLowerCase();
|
|
1415
|
+
return e.some((i) => n.endsWith(i));
|
|
1416
1416
|
}
|
|
1417
1417
|
/**
|
|
1418
1418
|
* Extract video metadata
|
|
@@ -1421,42 +1421,42 @@ class G {
|
|
|
1421
1421
|
return new Promise((t, e) => {
|
|
1422
1422
|
try {
|
|
1423
1423
|
this.videoElement = document.createElement("video"), this.videoElement.preload = "metadata", this.videoElement.muted = !0;
|
|
1424
|
-
const
|
|
1424
|
+
const n = URL.createObjectURL(this.file);
|
|
1425
1425
|
this.videoElement.onloadedmetadata = async () => {
|
|
1426
1426
|
try {
|
|
1427
1427
|
if (!this.videoElement) {
|
|
1428
1428
|
e(new Error("Video element not initialized"));
|
|
1429
1429
|
return;
|
|
1430
1430
|
}
|
|
1431
|
-
const
|
|
1431
|
+
const i = this.videoElement.videoWidth, o = this.videoElement.videoHeight, s = this.videoElement.duration, r = this.calculateAspectRatio(i, o), l = this.file.size, c = this.formatBytes(l), d = this.formatDuration(s), m = this.getFileExtension(this.file.name), h = s > 0 ? Math.round(l * 8 / s / 1e3) : void 0, k = await this.detectFrameRate(), y = await this.detectAudioInfo(n);
|
|
1432
1432
|
this.info = {
|
|
1433
|
-
width:
|
|
1433
|
+
width: i,
|
|
1434
1434
|
height: o,
|
|
1435
|
-
aspectRatio:
|
|
1435
|
+
aspectRatio: r,
|
|
1436
1436
|
size: l,
|
|
1437
1437
|
sizeInBytes: l,
|
|
1438
1438
|
// raw value alias
|
|
1439
|
-
sizeFormatted:
|
|
1439
|
+
sizeFormatted: c,
|
|
1440
1440
|
duration: s,
|
|
1441
1441
|
durationInSeconds: s,
|
|
1442
1442
|
// raw value alias
|
|
1443
|
-
durationFormatted:
|
|
1443
|
+
durationFormatted: d,
|
|
1444
1444
|
mimeType: this.file.type || "video/unknown",
|
|
1445
1445
|
fileName: this.file.name,
|
|
1446
|
-
fileExtension:
|
|
1447
|
-
bitrate:
|
|
1448
|
-
frameRate:
|
|
1449
|
-
audioChannels:
|
|
1450
|
-
hasAudio:
|
|
1451
|
-
}, URL.revokeObjectURL(
|
|
1452
|
-
} catch (
|
|
1453
|
-
URL.revokeObjectURL(
|
|
1446
|
+
fileExtension: m,
|
|
1447
|
+
bitrate: h,
|
|
1448
|
+
frameRate: k,
|
|
1449
|
+
audioChannels: y.channels,
|
|
1450
|
+
hasAudio: y.hasAudio
|
|
1451
|
+
}, URL.revokeObjectURL(n), this.videoElement.remove(), t(this.info);
|
|
1452
|
+
} catch (i) {
|
|
1453
|
+
URL.revokeObjectURL(n), e(i);
|
|
1454
1454
|
}
|
|
1455
1455
|
}, this.videoElement.onerror = () => {
|
|
1456
|
-
URL.revokeObjectURL(
|
|
1457
|
-
}, this.videoElement.src =
|
|
1458
|
-
} catch (
|
|
1459
|
-
e(
|
|
1456
|
+
URL.revokeObjectURL(n), e(new Error(`Failed to load video file: ${this.file.name}`));
|
|
1457
|
+
}, this.videoElement.src = n;
|
|
1458
|
+
} catch (n) {
|
|
1459
|
+
e(n);
|
|
1460
1460
|
}
|
|
1461
1461
|
});
|
|
1462
1462
|
}
|
|
@@ -1464,8 +1464,8 @@ class G {
|
|
|
1464
1464
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
1465
1465
|
*/
|
|
1466
1466
|
calculateAspectRatio(t, e) {
|
|
1467
|
-
const
|
|
1468
|
-
return Math.abs(s - 16 / 9) < 0.01 ? "16:9" : Math.abs(s - 4 / 3) < 0.01 ? "4:3" : Math.abs(s - 21 / 9) < 0.01 ? "21:9" : Math.abs(s - 1) < 0.01 ? "1:1" : `${
|
|
1467
|
+
const n = this.getGCD(t, e), i = t / n, o = e / n, s = i / o;
|
|
1468
|
+
return Math.abs(s - 16 / 9) < 0.01 ? "16:9" : Math.abs(s - 4 / 3) < 0.01 ? "4:3" : Math.abs(s - 21 / 9) < 0.01 ? "21:9" : Math.abs(s - 1) < 0.01 ? "1:1" : `${i}:${o}`;
|
|
1469
1469
|
}
|
|
1470
1470
|
/**
|
|
1471
1471
|
* Detect frame rate by analyzing video playback
|
|
@@ -1474,19 +1474,19 @@ class G {
|
|
|
1474
1474
|
if (this.videoElement)
|
|
1475
1475
|
try {
|
|
1476
1476
|
return "requestVideoFrameCallback" in this.videoElement ? new Promise((t) => {
|
|
1477
|
-
let e = 0,
|
|
1478
|
-
const
|
|
1477
|
+
let e = 0, n = 0;
|
|
1478
|
+
const i = 10, o = (s, r) => {
|
|
1479
1479
|
if (!this.videoElement) {
|
|
1480
1480
|
t(void 0);
|
|
1481
1481
|
return;
|
|
1482
1482
|
}
|
|
1483
1483
|
if (e++, e === 1)
|
|
1484
|
-
|
|
1485
|
-
else if (e <
|
|
1484
|
+
n = s, this.videoElement.requestVideoFrameCallback(o);
|
|
1485
|
+
else if (e < i)
|
|
1486
1486
|
this.videoElement.requestVideoFrameCallback(o);
|
|
1487
1487
|
else {
|
|
1488
|
-
const l = (s -
|
|
1489
|
-
t(
|
|
1488
|
+
const l = (s - n) / 1e3, c = Math.round((e - 1) / l);
|
|
1489
|
+
t(c);
|
|
1490
1490
|
}
|
|
1491
1491
|
};
|
|
1492
1492
|
this.videoElement ? (this.videoElement.currentTime = 1, this.videoElement.play().catch(() => t(void 0)), this.videoElement.requestVideoFrameCallback(o)) : t(void 0);
|
|
@@ -1505,10 +1505,10 @@ class G {
|
|
|
1505
1505
|
if (!(this.videoElement.mozHasAudio || (this.videoElement.webkitAudioDecodedByteCount ?? 0) > 0 || (((e = this.videoElement.audioTracks) == null ? void 0 : e.length) ?? 0) > 0))
|
|
1506
1506
|
return { hasAudio: !1 };
|
|
1507
1507
|
try {
|
|
1508
|
-
const
|
|
1509
|
-
if (!
|
|
1508
|
+
const i = window.AudioContext || window.webkitAudioContext;
|
|
1509
|
+
if (!i)
|
|
1510
1510
|
return { hasAudio: !0 };
|
|
1511
|
-
this.audioContext = new
|
|
1511
|
+
this.audioContext = new i();
|
|
1512
1512
|
const o = this.audioContext.createMediaElementSource(this.videoElement), s = this.audioContext.createAnalyser();
|
|
1513
1513
|
return o.connect(s), s.connect(this.audioContext.destination), { hasAudio: !0, channels: o.channelCount };
|
|
1514
1514
|
} catch {
|
|
@@ -1529,16 +1529,16 @@ class G {
|
|
|
1529
1529
|
*/
|
|
1530
1530
|
formatBytes(t) {
|
|
1531
1531
|
if (t === 0) return "0 Bytes";
|
|
1532
|
-
const e = 1024,
|
|
1533
|
-
return `${parseFloat((t / Math.pow(e,
|
|
1532
|
+
const e = 1024, n = ["Bytes", "KB", "MB", "GB", "TB"], i = Math.floor(Math.log(t) / Math.log(e));
|
|
1533
|
+
return `${parseFloat((t / Math.pow(e, i)).toFixed(2))} ${n[i]}`;
|
|
1534
1534
|
}
|
|
1535
1535
|
/**
|
|
1536
1536
|
* Format duration to HH:MM:SS
|
|
1537
1537
|
*/
|
|
1538
1538
|
formatDuration(t) {
|
|
1539
1539
|
if (!isFinite(t) || t < 0) return "00:00";
|
|
1540
|
-
const e = Math.floor(t / 3600),
|
|
1541
|
-
return e > 0 ? `${e.toString().padStart(2, "0")}:${
|
|
1540
|
+
const e = Math.floor(t / 3600), n = Math.floor(t % 3600 / 60), i = Math.floor(t % 60);
|
|
1541
|
+
return e > 0 ? `${e.toString().padStart(2, "0")}:${n.toString().padStart(2, "0")}:${i.toString().padStart(2, "0")}` : `${n.toString().padStart(2, "0")}:${i.toString().padStart(2, "0")}`;
|
|
1542
1542
|
}
|
|
1543
1543
|
/**
|
|
1544
1544
|
* Get file extension
|
|
@@ -1630,115 +1630,187 @@ class G {
|
|
|
1630
1630
|
}), this.audioContext = null), this.info = null;
|
|
1631
1631
|
}
|
|
1632
1632
|
}
|
|
1633
|
-
const
|
|
1633
|
+
const J = (u) => {
|
|
1634
1634
|
const {
|
|
1635
1635
|
src: t,
|
|
1636
1636
|
autoplay: e,
|
|
1637
|
-
muted:
|
|
1638
|
-
controls:
|
|
1637
|
+
muted: n,
|
|
1638
|
+
controls: i = !0,
|
|
1639
1639
|
poster: o,
|
|
1640
1640
|
preload: s,
|
|
1641
|
-
theme:
|
|
1641
|
+
theme: r,
|
|
1642
1642
|
s3Config: l,
|
|
1643
|
-
analytics:
|
|
1644
|
-
hlsConfig:
|
|
1645
|
-
subtitles:
|
|
1646
|
-
stickyControls:
|
|
1647
|
-
onReady:
|
|
1648
|
-
onPlay:
|
|
1649
|
-
onPause:
|
|
1650
|
-
onEnded:
|
|
1643
|
+
analytics: c,
|
|
1644
|
+
hlsConfig: d,
|
|
1645
|
+
subtitles: m,
|
|
1646
|
+
stickyControls: h,
|
|
1647
|
+
onReady: k,
|
|
1648
|
+
onPlay: y,
|
|
1649
|
+
onPause: L,
|
|
1650
|
+
onEnded: I,
|
|
1651
1651
|
onTimeUpdate: T,
|
|
1652
|
-
onVolumeChange:
|
|
1653
|
-
onError:
|
|
1654
|
-
onLoadedMetadata:
|
|
1655
|
-
onQualityChange:
|
|
1656
|
-
style:
|
|
1657
|
-
className:
|
|
1658
|
-
width:
|
|
1659
|
-
height:
|
|
1660
|
-
} =
|
|
1661
|
-
return
|
|
1662
|
-
if (!
|
|
1663
|
-
const
|
|
1652
|
+
onVolumeChange: A,
|
|
1653
|
+
onError: R,
|
|
1654
|
+
onLoadedMetadata: M,
|
|
1655
|
+
onQualityChange: F,
|
|
1656
|
+
style: U,
|
|
1657
|
+
className: V,
|
|
1658
|
+
width: S = "100%",
|
|
1659
|
+
height: x = "500px"
|
|
1660
|
+
} = u, C = w(null), P = w(null);
|
|
1661
|
+
return b(() => {
|
|
1662
|
+
if (!C.current) return;
|
|
1663
|
+
const H = {
|
|
1664
1664
|
src: t,
|
|
1665
|
-
container:
|
|
1665
|
+
container: C.current,
|
|
1666
1666
|
autoplay: e,
|
|
1667
|
-
muted:
|
|
1668
|
-
controls:
|
|
1667
|
+
muted: n,
|
|
1668
|
+
controls: i,
|
|
1669
1669
|
poster: o,
|
|
1670
1670
|
preload: s,
|
|
1671
|
-
theme:
|
|
1671
|
+
theme: r,
|
|
1672
1672
|
s3Config: l,
|
|
1673
|
-
analytics:
|
|
1674
|
-
hlsConfig:
|
|
1675
|
-
subtitles:
|
|
1676
|
-
stickyControls:
|
|
1677
|
-
},
|
|
1678
|
-
return
|
|
1679
|
-
var
|
|
1680
|
-
return
|
|
1681
|
-
}),
|
|
1682
|
-
|
|
1673
|
+
analytics: c,
|
|
1674
|
+
hlsConfig: d,
|
|
1675
|
+
subtitles: m,
|
|
1676
|
+
stickyControls: h
|
|
1677
|
+
}, p = new O(H);
|
|
1678
|
+
return P.current = p, y && p.on("play", y), L && p.on("pause", L), I && p.on("ended", I), R && p.on("error", (g) => {
|
|
1679
|
+
var q;
|
|
1680
|
+
return R((q = g.data) == null ? void 0 : q.error);
|
|
1681
|
+
}), M && p.on("loadedmetadata", M), F && p.on("qualitychange", (g) => F(g.data.level)), T && p.on("timeupdate", (g) => T(g.data.currentTime)), A && p.on("volumechange", (g) => A(g.data.volume, g.data.muted)), k && k(p), () => {
|
|
1682
|
+
p.destroy(), P.current = null;
|
|
1683
1683
|
};
|
|
1684
|
-
}, [t]), /* @__PURE__ */
|
|
1684
|
+
}, [t]), /* @__PURE__ */ B(
|
|
1685
1685
|
"div",
|
|
1686
1686
|
{
|
|
1687
|
-
ref:
|
|
1688
|
-
className:
|
|
1687
|
+
ref: C,
|
|
1688
|
+
className: V,
|
|
1689
1689
|
style: {
|
|
1690
|
-
width: typeof
|
|
1691
|
-
height: typeof
|
|
1692
|
-
...
|
|
1690
|
+
width: typeof S == "number" ? `${S}px` : S,
|
|
1691
|
+
height: typeof x == "number" ? `${x}px` : x,
|
|
1692
|
+
...U
|
|
1693
1693
|
}
|
|
1694
1694
|
}
|
|
1695
1695
|
);
|
|
1696
|
-
},
|
|
1697
|
-
const [t, e] =
|
|
1698
|
-
return
|
|
1696
|
+
}, Z = (u) => {
|
|
1697
|
+
const [t, e] = v(null), [n, i] = v(null), o = w(null);
|
|
1698
|
+
return b(() => {
|
|
1699
1699
|
if (!o.current) return;
|
|
1700
|
-
const s = new
|
|
1701
|
-
...
|
|
1700
|
+
const s = new O({
|
|
1701
|
+
...u,
|
|
1702
1702
|
container: o.current
|
|
1703
1703
|
});
|
|
1704
1704
|
e(s);
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1705
|
+
const r = () => {
|
|
1706
|
+
i(s.getState());
|
|
1707
1707
|
};
|
|
1708
|
-
return s.on("play",
|
|
1708
|
+
return s.on("play", r), s.on("pause", r), s.on("timeupdate", r), s.on("volumechange", r), s.on("loadedmetadata", r), () => {
|
|
1709
1709
|
s.destroy();
|
|
1710
1710
|
};
|
|
1711
|
-
}, [
|
|
1711
|
+
}, [u.src]), {
|
|
1712
1712
|
containerRef: o,
|
|
1713
1713
|
player: t,
|
|
1714
|
-
state:
|
|
1714
|
+
state: n
|
|
1715
1715
|
};
|
|
1716
|
-
},
|
|
1716
|
+
}, D = $.createContext({
|
|
1717
1717
|
player: null,
|
|
1718
1718
|
state: null
|
|
1719
|
-
}),
|
|
1720
|
-
const { player: t, children: e } =
|
|
1721
|
-
return
|
|
1719
|
+
}), tt = (u) => {
|
|
1720
|
+
const { player: t, children: e } = u, [n, i] = v(t.getState());
|
|
1721
|
+
return b(() => {
|
|
1722
1722
|
const o = () => {
|
|
1723
|
-
|
|
1723
|
+
i(t.getState());
|
|
1724
1724
|
};
|
|
1725
1725
|
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1726
1726
|
};
|
|
1727
|
-
}, [t]), /* @__PURE__ */
|
|
1728
|
-
},
|
|
1729
|
-
const
|
|
1730
|
-
if (!
|
|
1727
|
+
}, [t]), /* @__PURE__ */ B(D.Provider, { value: { player: t, state: n }, children: e });
|
|
1728
|
+
}, et = () => {
|
|
1729
|
+
const u = $.useContext(D);
|
|
1730
|
+
if (!u.player)
|
|
1731
1731
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1732
|
-
return
|
|
1732
|
+
return u;
|
|
1733
|
+
}, nt = (u) => {
|
|
1734
|
+
const [t, e] = v(null), [n, i] = v(!1), [o, s] = v(null), r = w(null), l = E(async () => {
|
|
1735
|
+
if (!u) {
|
|
1736
|
+
e(null), s(null), i(!1);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
i(!0), s(null);
|
|
1740
|
+
try {
|
|
1741
|
+
r.current && (r.current.destroy(), r.current = null);
|
|
1742
|
+
const c = new Q(u);
|
|
1743
|
+
r.current = c;
|
|
1744
|
+
const d = await c.extract();
|
|
1745
|
+
e(d), s(null);
|
|
1746
|
+
} catch (c) {
|
|
1747
|
+
const d = c instanceof Error ? c.message : "Failed to extract video information";
|
|
1748
|
+
s(d), e(null);
|
|
1749
|
+
} finally {
|
|
1750
|
+
i(!1);
|
|
1751
|
+
}
|
|
1752
|
+
}, [u]);
|
|
1753
|
+
return b(() => (l(), () => {
|
|
1754
|
+
r.current && (r.current.destroy(), r.current = null);
|
|
1755
|
+
}), [l]), { info: t, loading: n, error: o, refetch: l };
|
|
1756
|
+
}, it = (u) => {
|
|
1757
|
+
const t = w(null), [e, n] = v(!1), [i, o] = v("");
|
|
1758
|
+
b(() => {
|
|
1759
|
+
const c = new z(u);
|
|
1760
|
+
if (t.current = c, o(c.getMetrics().sessionId), u != null && u.webSocket) {
|
|
1761
|
+
const d = setInterval(() => {
|
|
1762
|
+
if (!t.current) {
|
|
1763
|
+
n(!1);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
const m = u.webSocket;
|
|
1767
|
+
if (m && "type" in m && m.type === "websocket") {
|
|
1768
|
+
const h = t.current.webSocket;
|
|
1769
|
+
n((h == null ? void 0 : h.readyState) === WebSocket.OPEN);
|
|
1770
|
+
} else if (m && "type" in m && m.type === "socket.io") {
|
|
1771
|
+
const h = t.current.socketIO;
|
|
1772
|
+
n((h == null ? void 0 : h.connected) ?? !1);
|
|
1773
|
+
} else if (m) {
|
|
1774
|
+
const h = t.current.webSocket;
|
|
1775
|
+
n((h == null ? void 0 : h.readyState) === WebSocket.OPEN);
|
|
1776
|
+
}
|
|
1777
|
+
}, 1e3);
|
|
1778
|
+
return () => {
|
|
1779
|
+
clearInterval(d), t.current && (t.current.destroy(), t.current = null);
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
return () => {
|
|
1783
|
+
t.current && (t.current.destroy(), t.current = null);
|
|
1784
|
+
};
|
|
1785
|
+
}, [u]);
|
|
1786
|
+
const s = E((c, d) => {
|
|
1787
|
+
var m;
|
|
1788
|
+
(m = t.current) == null || m.trackEvent(c, d);
|
|
1789
|
+
}, []), r = E(() => {
|
|
1790
|
+
var c;
|
|
1791
|
+
return ((c = t.current) == null ? void 0 : c.getEvents()) ?? [];
|
|
1792
|
+
}, []), l = E(() => {
|
|
1793
|
+
var c;
|
|
1794
|
+
return ((c = t.current) == null ? void 0 : c.getMetrics()) ?? {};
|
|
1795
|
+
}, []);
|
|
1796
|
+
return {
|
|
1797
|
+
trackEvent: s,
|
|
1798
|
+
getEvents: r,
|
|
1799
|
+
getMetrics: l,
|
|
1800
|
+
connected: e,
|
|
1801
|
+
sessionId: i
|
|
1802
|
+
};
|
|
1733
1803
|
};
|
|
1734
1804
|
export {
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1805
|
+
z as Analytics,
|
|
1806
|
+
j as S3Handler,
|
|
1807
|
+
_ as UIController,
|
|
1808
|
+
Q as WontumFileInfo,
|
|
1809
|
+
O as WontumPlayer,
|
|
1810
|
+
tt as WontumPlayerProvider,
|
|
1811
|
+
J as WontumPlayerReact,
|
|
1812
|
+
it as useAnalytics,
|
|
1813
|
+
nt as useVideoFileInfo,
|
|
1814
|
+
Z as useWontumPlayer,
|
|
1815
|
+
et as useWontumPlayerContext
|
|
1744
1816
|
};
|