@obipascal/player 1.0.10 → 1.0.12
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 +197 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/player.d.ts +6 -0
- package/dist/src/react.d.ts +56 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/wontum-player.cjs.js +18 -18
- package/dist/wontum-player.esm.js +418 -312
- 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 E, useEffect as
|
|
8
|
-
class
|
|
1
|
+
var _ = Object.defineProperty;
|
|
2
|
+
var j = (u, t, e) => t in u ? _(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
|
+
var a = (u, t, e) => j(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import y from "hls.js";
|
|
5
|
+
import { jsx as $ } from "react/jsx-runtime";
|
|
6
|
+
import * as z from "react";
|
|
7
|
+
import { useRef as E, useEffect as S, useState as v, useCallback as L } from "react";
|
|
8
|
+
class O {
|
|
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 Q {
|
|
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() {
|
|
@@ -1004,14 +1004,14 @@ class W {
|
|
|
1004
1004
|
return '<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>';
|
|
1005
1005
|
}
|
|
1006
1006
|
destroy() {
|
|
1007
|
-
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
1007
|
+
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer && this.controlsContainer.remove(), this.progressContainer && this.progressContainer.remove();
|
|
1008
1008
|
}
|
|
1009
1009
|
}
|
|
1010
|
-
class
|
|
1010
|
+
class Y {
|
|
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 D {
|
|
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 O(t.analytics), this.s3Handler = new Y(t.s3Config), this.videoElement = this.createVideoElement(), this.container.appendChild(this.videoElement), this.uiController = new Q(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 (y.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 y(o), this.hls.loadSource(n), this.hls.attachMedia(this.videoElement), this.hls.on(y.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(y.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(y.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 y.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 y.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,38 @@ 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
|
+
/**
|
|
1395
|
+
* Update video source without recreating the entire player
|
|
1396
|
+
* This is more efficient than destroying and recreating the player
|
|
1397
|
+
* @param src - New video source URL
|
|
1398
|
+
*/
|
|
1399
|
+
async updateSource(t) {
|
|
1400
|
+
this.pause(), this.state.currentTime = 0, this.state.ended = !1, this.state.buffering = !1, this.hls && (this.hls.destroy(), this.hls = null), this.config.src = t, await this.loadSource(t), this.emit("sourcechange", { src: t });
|
|
1401
|
+
}
|
|
1394
1402
|
destroy() {
|
|
1395
1403
|
this.hls && (this.hls.destroy(), this.hls = null), this.uiController.destroy(), this.videoElement.remove(), this.eventListeners.clear(), this.analytics.destroy();
|
|
1396
1404
|
}
|
|
1397
1405
|
}
|
|
1398
|
-
class
|
|
1406
|
+
class X {
|
|
1399
1407
|
constructor(t) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1408
|
+
a(this, "file");
|
|
1409
|
+
a(this, "videoElement", null);
|
|
1410
|
+
a(this, "audioContext", null);
|
|
1411
|
+
a(this, "info", null);
|
|
1404
1412
|
if (!this.isVideoFile(t))
|
|
1405
1413
|
throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
|
|
1406
1414
|
this.file = t;
|
|
@@ -1411,8 +1419,8 @@ class G {
|
|
|
1411
1419
|
isVideoFile(t) {
|
|
1412
1420
|
if (t.type.startsWith("video/"))
|
|
1413
1421
|
return !0;
|
|
1414
|
-
const e = [".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".m4v", ".3gp", ".ts", ".m3u8"],
|
|
1415
|
-
return e.some((
|
|
1422
|
+
const e = [".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".m4v", ".3gp", ".ts", ".m3u8"], n = t.name.toLowerCase();
|
|
1423
|
+
return e.some((i) => n.endsWith(i));
|
|
1416
1424
|
}
|
|
1417
1425
|
/**
|
|
1418
1426
|
* Extract video metadata
|
|
@@ -1421,42 +1429,42 @@ class G {
|
|
|
1421
1429
|
return new Promise((t, e) => {
|
|
1422
1430
|
try {
|
|
1423
1431
|
this.videoElement = document.createElement("video"), this.videoElement.preload = "metadata", this.videoElement.muted = !0;
|
|
1424
|
-
const
|
|
1432
|
+
const n = URL.createObjectURL(this.file);
|
|
1425
1433
|
this.videoElement.onloadedmetadata = async () => {
|
|
1426
1434
|
try {
|
|
1427
1435
|
if (!this.videoElement) {
|
|
1428
1436
|
e(new Error("Video element not initialized"));
|
|
1429
1437
|
return;
|
|
1430
1438
|
}
|
|
1431
|
-
const
|
|
1439
|
+
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, b = await this.detectFrameRate(), w = await this.detectAudioInfo(n);
|
|
1432
1440
|
this.info = {
|
|
1433
|
-
width:
|
|
1441
|
+
width: i,
|
|
1434
1442
|
height: o,
|
|
1435
|
-
aspectRatio:
|
|
1443
|
+
aspectRatio: r,
|
|
1436
1444
|
size: l,
|
|
1437
1445
|
sizeInBytes: l,
|
|
1438
1446
|
// raw value alias
|
|
1439
|
-
sizeFormatted:
|
|
1447
|
+
sizeFormatted: c,
|
|
1440
1448
|
duration: s,
|
|
1441
1449
|
durationInSeconds: s,
|
|
1442
1450
|
// raw value alias
|
|
1443
|
-
durationFormatted:
|
|
1451
|
+
durationFormatted: d,
|
|
1444
1452
|
mimeType: this.file.type || "video/unknown",
|
|
1445
1453
|
fileName: this.file.name,
|
|
1446
|
-
fileExtension:
|
|
1447
|
-
bitrate:
|
|
1448
|
-
frameRate:
|
|
1449
|
-
audioChannels:
|
|
1450
|
-
hasAudio:
|
|
1451
|
-
}, URL.revokeObjectURL(
|
|
1452
|
-
} catch (
|
|
1453
|
-
URL.revokeObjectURL(
|
|
1454
|
+
fileExtension: m,
|
|
1455
|
+
bitrate: h,
|
|
1456
|
+
frameRate: b,
|
|
1457
|
+
audioChannels: w.channels,
|
|
1458
|
+
hasAudio: w.hasAudio
|
|
1459
|
+
}, URL.revokeObjectURL(n), this.videoElement.remove(), t(this.info);
|
|
1460
|
+
} catch (i) {
|
|
1461
|
+
URL.revokeObjectURL(n), e(i);
|
|
1454
1462
|
}
|
|
1455
1463
|
}, this.videoElement.onerror = () => {
|
|
1456
|
-
URL.revokeObjectURL(
|
|
1457
|
-
}, this.videoElement.src =
|
|
1458
|
-
} catch (
|
|
1459
|
-
e(
|
|
1464
|
+
URL.revokeObjectURL(n), e(new Error(`Failed to load video file: ${this.file.name}`));
|
|
1465
|
+
}, this.videoElement.src = n;
|
|
1466
|
+
} catch (n) {
|
|
1467
|
+
e(n);
|
|
1460
1468
|
}
|
|
1461
1469
|
});
|
|
1462
1470
|
}
|
|
@@ -1464,8 +1472,8 @@ class G {
|
|
|
1464
1472
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
1465
1473
|
*/
|
|
1466
1474
|
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" : `${
|
|
1475
|
+
const n = this.getGCD(t, e), i = t / n, o = e / n, s = i / o;
|
|
1476
|
+
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
1477
|
}
|
|
1470
1478
|
/**
|
|
1471
1479
|
* Detect frame rate by analyzing video playback
|
|
@@ -1474,19 +1482,19 @@ class G {
|
|
|
1474
1482
|
if (this.videoElement)
|
|
1475
1483
|
try {
|
|
1476
1484
|
return "requestVideoFrameCallback" in this.videoElement ? new Promise((t) => {
|
|
1477
|
-
let e = 0,
|
|
1478
|
-
const
|
|
1485
|
+
let e = 0, n = 0;
|
|
1486
|
+
const i = 10, o = (s, r) => {
|
|
1479
1487
|
if (!this.videoElement) {
|
|
1480
1488
|
t(void 0);
|
|
1481
1489
|
return;
|
|
1482
1490
|
}
|
|
1483
1491
|
if (e++, e === 1)
|
|
1484
|
-
|
|
1485
|
-
else if (e <
|
|
1492
|
+
n = s, this.videoElement.requestVideoFrameCallback(o);
|
|
1493
|
+
else if (e < i)
|
|
1486
1494
|
this.videoElement.requestVideoFrameCallback(o);
|
|
1487
1495
|
else {
|
|
1488
|
-
const l = (s -
|
|
1489
|
-
t(
|
|
1496
|
+
const l = (s - n) / 1e3, c = Math.round((e - 1) / l);
|
|
1497
|
+
t(c);
|
|
1490
1498
|
}
|
|
1491
1499
|
};
|
|
1492
1500
|
this.videoElement ? (this.videoElement.currentTime = 1, this.videoElement.play().catch(() => t(void 0)), this.videoElement.requestVideoFrameCallback(o)) : t(void 0);
|
|
@@ -1505,10 +1513,10 @@ class G {
|
|
|
1505
1513
|
if (!(this.videoElement.mozHasAudio || (this.videoElement.webkitAudioDecodedByteCount ?? 0) > 0 || (((e = this.videoElement.audioTracks) == null ? void 0 : e.length) ?? 0) > 0))
|
|
1506
1514
|
return { hasAudio: !1 };
|
|
1507
1515
|
try {
|
|
1508
|
-
const
|
|
1509
|
-
if (!
|
|
1516
|
+
const i = window.AudioContext || window.webkitAudioContext;
|
|
1517
|
+
if (!i)
|
|
1510
1518
|
return { hasAudio: !0 };
|
|
1511
|
-
this.audioContext = new
|
|
1519
|
+
this.audioContext = new i();
|
|
1512
1520
|
const o = this.audioContext.createMediaElementSource(this.videoElement), s = this.audioContext.createAnalyser();
|
|
1513
1521
|
return o.connect(s), s.connect(this.audioContext.destination), { hasAudio: !0, channels: o.channelCount };
|
|
1514
1522
|
} catch {
|
|
@@ -1529,16 +1537,16 @@ class G {
|
|
|
1529
1537
|
*/
|
|
1530
1538
|
formatBytes(t) {
|
|
1531
1539
|
if (t === 0) return "0 Bytes";
|
|
1532
|
-
const e = 1024,
|
|
1533
|
-
return `${parseFloat((t / Math.pow(e,
|
|
1540
|
+
const e = 1024, n = ["Bytes", "KB", "MB", "GB", "TB"], i = Math.floor(Math.log(t) / Math.log(e));
|
|
1541
|
+
return `${parseFloat((t / Math.pow(e, i)).toFixed(2))} ${n[i]}`;
|
|
1534
1542
|
}
|
|
1535
1543
|
/**
|
|
1536
1544
|
* Format duration to HH:MM:SS
|
|
1537
1545
|
*/
|
|
1538
1546
|
formatDuration(t) {
|
|
1539
1547
|
if (!isFinite(t) || t < 0) return "00:00";
|
|
1540
|
-
const e = Math.floor(t / 3600),
|
|
1541
|
-
return e > 0 ? `${e.toString().padStart(2, "0")}:${
|
|
1548
|
+
const e = Math.floor(t / 3600), n = Math.floor(t % 3600 / 60), i = Math.floor(t % 60);
|
|
1549
|
+
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
1550
|
}
|
|
1543
1551
|
/**
|
|
1544
1552
|
* Get file extension
|
|
@@ -1630,115 +1638,213 @@ class G {
|
|
|
1630
1638
|
}), this.audioContext = null), this.info = null;
|
|
1631
1639
|
}
|
|
1632
1640
|
}
|
|
1633
|
-
const
|
|
1641
|
+
const tt = (u) => {
|
|
1634
1642
|
const {
|
|
1635
1643
|
src: t,
|
|
1636
1644
|
autoplay: e,
|
|
1637
|
-
muted:
|
|
1638
|
-
controls:
|
|
1645
|
+
muted: n,
|
|
1646
|
+
controls: i = !0,
|
|
1639
1647
|
poster: o,
|
|
1640
1648
|
preload: s,
|
|
1641
|
-
theme:
|
|
1649
|
+
theme: r,
|
|
1642
1650
|
s3Config: l,
|
|
1643
|
-
analytics:
|
|
1644
|
-
hlsConfig:
|
|
1645
|
-
subtitles:
|
|
1646
|
-
stickyControls:
|
|
1647
|
-
onReady:
|
|
1648
|
-
onPlay:
|
|
1649
|
-
onPause:
|
|
1650
|
-
onEnded:
|
|
1651
|
-
onTimeUpdate:
|
|
1652
|
-
onVolumeChange:
|
|
1653
|
-
onError:
|
|
1654
|
-
onLoadedMetadata:
|
|
1655
|
-
onQualityChange:
|
|
1656
|
-
style:
|
|
1657
|
-
className:
|
|
1658
|
-
width:
|
|
1659
|
-
height:
|
|
1660
|
-
} =
|
|
1661
|
-
return
|
|
1662
|
-
if (!
|
|
1663
|
-
|
|
1651
|
+
analytics: c,
|
|
1652
|
+
hlsConfig: d,
|
|
1653
|
+
subtitles: m,
|
|
1654
|
+
stickyControls: h,
|
|
1655
|
+
onReady: b,
|
|
1656
|
+
onPlay: w,
|
|
1657
|
+
onPause: I,
|
|
1658
|
+
onEnded: T,
|
|
1659
|
+
onTimeUpdate: A,
|
|
1660
|
+
onVolumeChange: R,
|
|
1661
|
+
onError: M,
|
|
1662
|
+
onLoadedMetadata: q,
|
|
1663
|
+
onQualityChange: F,
|
|
1664
|
+
style: V,
|
|
1665
|
+
className: H,
|
|
1666
|
+
width: P = "100%",
|
|
1667
|
+
height: B = "500px"
|
|
1668
|
+
} = u, f = E(null), x = E(null);
|
|
1669
|
+
return S(() => {
|
|
1670
|
+
if (!f.current) return;
|
|
1671
|
+
if (f.current) {
|
|
1672
|
+
const g = f.current.querySelectorAll(".wontum-player-video"), C = f.current.querySelectorAll(".wontum-controls"), W = f.current.querySelectorAll(".wontum-progress-container");
|
|
1673
|
+
g.forEach((k) => k.remove()), C.forEach((k) => k.remove()), W.forEach((k) => k.remove());
|
|
1674
|
+
}
|
|
1675
|
+
const N = {
|
|
1664
1676
|
src: t,
|
|
1665
|
-
container:
|
|
1677
|
+
container: f.current,
|
|
1666
1678
|
autoplay: e,
|
|
1667
|
-
muted:
|
|
1668
|
-
controls:
|
|
1679
|
+
muted: n,
|
|
1680
|
+
controls: i,
|
|
1669
1681
|
poster: o,
|
|
1670
1682
|
preload: s,
|
|
1671
|
-
theme:
|
|
1683
|
+
theme: r,
|
|
1672
1684
|
s3Config: l,
|
|
1673
|
-
analytics:
|
|
1674
|
-
hlsConfig:
|
|
1675
|
-
subtitles:
|
|
1676
|
-
stickyControls:
|
|
1677
|
-
},
|
|
1678
|
-
return
|
|
1679
|
-
var
|
|
1680
|
-
return
|
|
1681
|
-
}),
|
|
1682
|
-
|
|
1685
|
+
analytics: c,
|
|
1686
|
+
hlsConfig: d,
|
|
1687
|
+
subtitles: m,
|
|
1688
|
+
stickyControls: h
|
|
1689
|
+
}, p = new D(N);
|
|
1690
|
+
return x.current = p, w && p.on("play", w), I && p.on("pause", I), T && p.on("ended", T), M && p.on("error", (g) => {
|
|
1691
|
+
var C;
|
|
1692
|
+
return M((C = g.data) == null ? void 0 : C.error);
|
|
1693
|
+
}), q && p.on("loadedmetadata", q), F && p.on("qualitychange", (g) => F(g.data.level)), A && p.on("timeupdate", (g) => A(g.data.currentTime)), R && p.on("volumechange", (g) => R(g.data.volume, g.data.muted)), b && b(p), () => {
|
|
1694
|
+
x.current && (x.current.destroy(), x.current = null);
|
|
1683
1695
|
};
|
|
1684
|
-
}, [
|
|
1696
|
+
}, [
|
|
1697
|
+
t,
|
|
1698
|
+
e,
|
|
1699
|
+
n,
|
|
1700
|
+
i,
|
|
1701
|
+
o,
|
|
1702
|
+
s,
|
|
1703
|
+
r,
|
|
1704
|
+
l,
|
|
1705
|
+
c,
|
|
1706
|
+
d,
|
|
1707
|
+
m,
|
|
1708
|
+
h,
|
|
1709
|
+
w,
|
|
1710
|
+
I,
|
|
1711
|
+
T,
|
|
1712
|
+
M,
|
|
1713
|
+
q,
|
|
1714
|
+
F,
|
|
1715
|
+
A,
|
|
1716
|
+
R,
|
|
1717
|
+
b
|
|
1718
|
+
]), /* @__PURE__ */ $(
|
|
1685
1719
|
"div",
|
|
1686
1720
|
{
|
|
1687
|
-
ref:
|
|
1688
|
-
className:
|
|
1721
|
+
ref: f,
|
|
1722
|
+
className: H,
|
|
1689
1723
|
style: {
|
|
1690
|
-
width: typeof
|
|
1691
|
-
height: typeof
|
|
1692
|
-
...
|
|
1724
|
+
width: typeof P == "number" ? `${P}px` : P,
|
|
1725
|
+
height: typeof B == "number" ? `${B}px` : B,
|
|
1726
|
+
...V
|
|
1693
1727
|
}
|
|
1694
1728
|
}
|
|
1695
1729
|
);
|
|
1696
|
-
},
|
|
1697
|
-
const [t, e] =
|
|
1698
|
-
return
|
|
1730
|
+
}, et = (u) => {
|
|
1731
|
+
const [t, e] = v(null), [n, i] = v(null), o = E(null);
|
|
1732
|
+
return S(() => {
|
|
1699
1733
|
if (!o.current) return;
|
|
1700
|
-
const s = new
|
|
1701
|
-
...
|
|
1734
|
+
const s = new D({
|
|
1735
|
+
...u,
|
|
1702
1736
|
container: o.current
|
|
1703
1737
|
});
|
|
1704
1738
|
e(s);
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1739
|
+
const r = () => {
|
|
1740
|
+
i(s.getState());
|
|
1707
1741
|
};
|
|
1708
|
-
return s.on("play",
|
|
1742
|
+
return s.on("play", r), s.on("pause", r), s.on("timeupdate", r), s.on("volumechange", r), s.on("loadedmetadata", r), () => {
|
|
1709
1743
|
s.destroy();
|
|
1710
1744
|
};
|
|
1711
|
-
}, [
|
|
1745
|
+
}, [u.src]), {
|
|
1712
1746
|
containerRef: o,
|
|
1713
1747
|
player: t,
|
|
1714
|
-
state:
|
|
1748
|
+
state: n
|
|
1715
1749
|
};
|
|
1716
|
-
},
|
|
1750
|
+
}, U = z.createContext({
|
|
1717
1751
|
player: null,
|
|
1718
1752
|
state: null
|
|
1719
|
-
}),
|
|
1720
|
-
const { player: t, children: e } =
|
|
1721
|
-
return
|
|
1753
|
+
}), nt = (u) => {
|
|
1754
|
+
const { player: t, children: e } = u, [n, i] = v(t.getState());
|
|
1755
|
+
return S(() => {
|
|
1722
1756
|
const o = () => {
|
|
1723
|
-
|
|
1757
|
+
i(t.getState());
|
|
1724
1758
|
};
|
|
1725
1759
|
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1726
1760
|
};
|
|
1727
|
-
}, [t]), /* @__PURE__ */
|
|
1728
|
-
},
|
|
1729
|
-
const
|
|
1730
|
-
if (!
|
|
1761
|
+
}, [t]), /* @__PURE__ */ $(U.Provider, { value: { player: t, state: n }, children: e });
|
|
1762
|
+
}, it = () => {
|
|
1763
|
+
const u = z.useContext(U);
|
|
1764
|
+
if (!u.player)
|
|
1731
1765
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1732
|
-
return
|
|
1766
|
+
return u;
|
|
1767
|
+
}, ot = (u) => {
|
|
1768
|
+
const [t, e] = v(null), [n, i] = v(!1), [o, s] = v(null), r = E(null), l = L(async () => {
|
|
1769
|
+
if (!u) {
|
|
1770
|
+
e(null), s(null), i(!1);
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
i(!0), s(null);
|
|
1774
|
+
try {
|
|
1775
|
+
r.current && (r.current.destroy(), r.current = null);
|
|
1776
|
+
const c = new X(u);
|
|
1777
|
+
r.current = c;
|
|
1778
|
+
const d = await c.extract();
|
|
1779
|
+
e(d), s(null);
|
|
1780
|
+
} catch (c) {
|
|
1781
|
+
const d = c instanceof Error ? c.message : "Failed to extract video information";
|
|
1782
|
+
s(d), e(null);
|
|
1783
|
+
} finally {
|
|
1784
|
+
i(!1);
|
|
1785
|
+
}
|
|
1786
|
+
}, [u]);
|
|
1787
|
+
return S(() => (l(), () => {
|
|
1788
|
+
r.current && (r.current.destroy(), r.current = null);
|
|
1789
|
+
}), [l]), { info: t, loading: n, error: o, refetch: l };
|
|
1790
|
+
}, st = (u) => {
|
|
1791
|
+
const t = E(null), [e, n] = v(!1), [i, o] = v("");
|
|
1792
|
+
S(() => {
|
|
1793
|
+
const c = new O(u);
|
|
1794
|
+
if (t.current = c, o(c.getMetrics().sessionId), u != null && u.webSocket) {
|
|
1795
|
+
const d = setInterval(() => {
|
|
1796
|
+
if (!t.current) {
|
|
1797
|
+
n(!1);
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
const m = u.webSocket;
|
|
1801
|
+
if (m && "type" in m && m.type === "websocket") {
|
|
1802
|
+
const h = t.current.webSocket;
|
|
1803
|
+
n((h == null ? void 0 : h.readyState) === WebSocket.OPEN);
|
|
1804
|
+
} else if (m && "type" in m && m.type === "socket.io") {
|
|
1805
|
+
const h = t.current.socketIO;
|
|
1806
|
+
n((h == null ? void 0 : h.connected) ?? !1);
|
|
1807
|
+
} else if (m) {
|
|
1808
|
+
const h = t.current.webSocket;
|
|
1809
|
+
n((h == null ? void 0 : h.readyState) === WebSocket.OPEN);
|
|
1810
|
+
}
|
|
1811
|
+
}, 1e3);
|
|
1812
|
+
return () => {
|
|
1813
|
+
clearInterval(d), t.current && (t.current.destroy(), t.current = null);
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
return () => {
|
|
1817
|
+
t.current && (t.current.destroy(), t.current = null);
|
|
1818
|
+
};
|
|
1819
|
+
}, [u]);
|
|
1820
|
+
const s = L((c, d) => {
|
|
1821
|
+
var m;
|
|
1822
|
+
(m = t.current) == null || m.trackEvent(c, d);
|
|
1823
|
+
}, []), r = L(() => {
|
|
1824
|
+
var c;
|
|
1825
|
+
return ((c = t.current) == null ? void 0 : c.getEvents()) ?? [];
|
|
1826
|
+
}, []), l = L(() => {
|
|
1827
|
+
var c;
|
|
1828
|
+
return ((c = t.current) == null ? void 0 : c.getMetrics()) ?? {};
|
|
1829
|
+
}, []);
|
|
1830
|
+
return {
|
|
1831
|
+
trackEvent: s,
|
|
1832
|
+
getEvents: r,
|
|
1833
|
+
getMetrics: l,
|
|
1834
|
+
connected: e,
|
|
1835
|
+
sessionId: i
|
|
1836
|
+
};
|
|
1733
1837
|
};
|
|
1734
1838
|
export {
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1839
|
+
O as Analytics,
|
|
1840
|
+
Y as S3Handler,
|
|
1841
|
+
Q as UIController,
|
|
1842
|
+
X as WontumFileInfo,
|
|
1843
|
+
D as WontumPlayer,
|
|
1844
|
+
nt as WontumPlayerProvider,
|
|
1845
|
+
tt as WontumPlayerReact,
|
|
1846
|
+
st as useAnalytics,
|
|
1847
|
+
ot as useVideoFileInfo,
|
|
1848
|
+
et as useWontumPlayer,
|
|
1849
|
+
it as useWontumPlayerContext
|
|
1744
1850
|
};
|