@obipascal/player 1.0.8 → 1.0.10
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 +319 -1
- package/dist/src/analytics.d.ts +8 -0
- package/dist/src/file-info.d.ts +23 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/types.d.ts +47 -1
- package/dist/wontum-player.cjs.js +16 -16
- package/dist/wontum-player.esm.js +309 -167
- package/package.json +6 -1
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
var V = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var
|
|
2
|
+
var H = (c, t, e) => t in c ? V(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
|
|
3
|
+
var r = (c, t, e) => H(c, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import p from "hls.js";
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
7
|
-
import { useRef as
|
|
8
|
-
class
|
|
5
|
+
import { jsx as P } from "react/jsx-runtime";
|
|
6
|
+
import * as B from "react";
|
|
7
|
+
import { useRef as E, useEffect as x, useState as S } from "react";
|
|
8
|
+
class N {
|
|
9
9
|
constructor(t) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
r(this, "config");
|
|
11
|
+
r(this, "sessionId");
|
|
12
|
+
r(this, "events", []);
|
|
13
|
+
r(this, "sessionStartTime");
|
|
14
|
+
r(this, "playbackStartTime", null);
|
|
15
|
+
r(this, "totalPlayTime", 0);
|
|
16
|
+
r(this, "totalBufferTime", 0);
|
|
17
|
+
r(this, "bufferStartTime", null);
|
|
18
|
+
r(this, "rebufferCount", 0);
|
|
19
|
+
r(this, "seekCount", 0);
|
|
20
|
+
r(this, "webSocket", null);
|
|
21
|
+
r(this, "socketIO", null);
|
|
22
|
+
r(this, "wsReconnectTimeout", null);
|
|
23
|
+
r(this, "isDestroyed", !1);
|
|
24
|
+
var e, i;
|
|
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 n = this.config.webSocket;
|
|
27
|
+
"type" in n ? n.type === "socket.io" ? this.initializeSocketIO() : this.initializeWebSocket() : this.initializeWebSocket();
|
|
28
|
+
}
|
|
29
|
+
(i = this.config) != null && i.enabled && this.trackEvent("session_start", this.getSessionData());
|
|
22
30
|
}
|
|
23
31
|
trackEvent(t, e = {}) {
|
|
24
32
|
var n;
|
|
@@ -34,7 +42,7 @@ class W {
|
|
|
34
42
|
...this.getQoEMetrics()
|
|
35
43
|
}
|
|
36
44
|
};
|
|
37
|
-
this.events.push(i), this.updateMetrics(t, e), this.config.endpoint && this.sendEvent(i), process.env.NODE_ENV === "development" && console.log("[Analytics]", t, i.data);
|
|
45
|
+
this.events.push(i), this.updateMetrics(t, e), this.webSocket && this.webSocket.readyState === WebSocket.OPEN && this.sendToWebSocket(i), this.socketIO && this.socketIO.connected && this.sendToSocketIO(i), this.config.endpoint && this.sendEvent(i), process.env.NODE_ENV === "development" && console.log("[Analytics]", t, i.data);
|
|
38
46
|
}
|
|
39
47
|
updateMetrics(t, e) {
|
|
40
48
|
switch (t) {
|
|
@@ -104,6 +112,72 @@ class W {
|
|
|
104
112
|
generateSessionId() {
|
|
105
113
|
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
106
114
|
}
|
|
115
|
+
async initializeSocketIO() {
|
|
116
|
+
var e;
|
|
117
|
+
if (!((e = this.config) != null && e.webSocket) || !("type" in this.config.webSocket)) return;
|
|
118
|
+
const t = this.config.webSocket;
|
|
119
|
+
if (t.type === "socket.io")
|
|
120
|
+
try {
|
|
121
|
+
if (typeof t.connection == "string") {
|
|
122
|
+
const n = (await import("socket.io-client")).default;
|
|
123
|
+
this.socketIO = n(t.connection, t.options || {});
|
|
124
|
+
} else
|
|
125
|
+
this.socketIO = t.connection;
|
|
126
|
+
if (!this.socketIO) return;
|
|
127
|
+
this.socketIO.on("connect", () => {
|
|
128
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Connected"), t.onConnect && t.onConnect();
|
|
129
|
+
}), this.socketIO.on("connect_error", (i) => {
|
|
130
|
+
console.error("[Analytics Socket.IO] Connection error:", i), t.onError && t.onError(i);
|
|
131
|
+
}), this.socketIO.on("disconnect", (i) => {
|
|
132
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Disconnected:", i), t.onDisconnect && t.onDisconnect(i);
|
|
133
|
+
}), this.socketIO.on("error", (i) => {
|
|
134
|
+
console.error("[Analytics Socket.IO] Error:", i), t.onError && t.onError(i);
|
|
135
|
+
});
|
|
136
|
+
} catch (i) {
|
|
137
|
+
console.error("[Analytics Socket.IO] Failed to initialize:", i);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
sendToSocketIO(t) {
|
|
141
|
+
var e;
|
|
142
|
+
if (!(!this.socketIO || !this.socketIO.connected))
|
|
143
|
+
try {
|
|
144
|
+
const i = (e = this.config) == null ? void 0 : e.webSocket, n = i != null && i.transform ? i.transform(t) : t, o = (i == null ? void 0 : i.eventName) || "analytics";
|
|
145
|
+
this.socketIO.emit(o, n), process.env.NODE_ENV === "development" && console.log(`[Analytics Socket.IO] Emitted (${o}):`, t.eventType);
|
|
146
|
+
} catch (i) {
|
|
147
|
+
console.error("[Analytics Socket.IO] Failed to emit event:", i);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
initializeWebSocket() {
|
|
151
|
+
var e;
|
|
152
|
+
if (!((e = this.config) != null && e.webSocket)) return;
|
|
153
|
+
const t = this.config.webSocket;
|
|
154
|
+
try {
|
|
155
|
+
typeof t.connection == "string" ? this.webSocket = new WebSocket(t.connection) : this.webSocket = t.connection, this.webSocket.onopen = (i) => {
|
|
156
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Connected"), t.onOpen && t.onOpen(i);
|
|
157
|
+
}, this.webSocket.onerror = (i) => {
|
|
158
|
+
console.error("[Analytics WebSocket] Error:", i), t.onError && t.onError(i);
|
|
159
|
+
}, this.webSocket.onclose = (i) => {
|
|
160
|
+
if (process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Disconnected"), t.onClose && t.onClose(i), t.autoReconnect !== !1 && !this.isDestroyed) {
|
|
161
|
+
const o = t.reconnectDelay || 3e3;
|
|
162
|
+
process.env.NODE_ENV === "development" && console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`), this.wsReconnectTimeout = window.setTimeout(() => {
|
|
163
|
+
this.initializeWebSocket();
|
|
164
|
+
}, o);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
} catch (i) {
|
|
168
|
+
console.error("[Analytics WebSocket] Failed to initialize:", i);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
sendToWebSocket(t) {
|
|
172
|
+
var e;
|
|
173
|
+
if (!(!this.webSocket || this.webSocket.readyState !== WebSocket.OPEN))
|
|
174
|
+
try {
|
|
175
|
+
const i = (e = this.config) == null ? void 0 : e.webSocket, n = i != null && i.transform ? i.transform(t) : t;
|
|
176
|
+
this.webSocket.send(JSON.stringify(n)), process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Sent:", t.eventType);
|
|
177
|
+
} catch (i) {
|
|
178
|
+
console.error("[Analytics WebSocket] Failed to send event:", i);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
107
181
|
getEvents() {
|
|
108
182
|
return [...this.events];
|
|
109
183
|
}
|
|
@@ -116,46 +190,46 @@ class W {
|
|
|
116
190
|
}
|
|
117
191
|
destroy() {
|
|
118
192
|
var t;
|
|
119
|
-
(t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.events = [];
|
|
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 = [];
|
|
120
194
|
}
|
|
121
195
|
}
|
|
122
|
-
class
|
|
196
|
+
class W {
|
|
123
197
|
constructor(t, e) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
198
|
+
r(this, "container");
|
|
199
|
+
r(this, "player");
|
|
200
|
+
r(this, "controlsContainer");
|
|
201
|
+
r(this, "progressContainer");
|
|
202
|
+
r(this, "progressBar");
|
|
203
|
+
r(this, "playButton");
|
|
204
|
+
r(this, "skipBackwardButton");
|
|
205
|
+
r(this, "skipForwardButton");
|
|
206
|
+
r(this, "volumeButton");
|
|
207
|
+
r(this, "volumeContainer");
|
|
208
|
+
r(this, "fullscreenButton");
|
|
209
|
+
r(this, "pipButton");
|
|
210
|
+
r(this, "settingsButton");
|
|
137
211
|
// private timeDisplay: HTMLElement
|
|
138
|
-
|
|
139
|
-
|
|
212
|
+
r(this, "volumeSlider");
|
|
213
|
+
r(this, "progressInput");
|
|
140
214
|
// private controlsVisible = true
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
215
|
+
r(this, "hideControlsTimeout", null);
|
|
216
|
+
r(this, "stickyControls", !1);
|
|
217
|
+
r(this, "isVolumeSliderActive", !1);
|
|
144
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();
|
|
145
219
|
}
|
|
146
220
|
injectStyles() {
|
|
147
221
|
const t = "wontum-player-styles";
|
|
148
222
|
if (document.getElementById(t)) return;
|
|
149
|
-
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = e.accentColor || "#2563eb",
|
|
223
|
+
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = 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)", a = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", u = e.borderRadius || "4px", m = document.createElement("style");
|
|
150
224
|
m.id = t, m.textContent = `
|
|
151
225
|
.wontum-player-container {
|
|
152
226
|
position: relative;
|
|
153
227
|
background: #000;
|
|
154
|
-
font-family: ${
|
|
228
|
+
font-family: ${o};
|
|
155
229
|
overflow: hidden;
|
|
156
230
|
--primary-color: ${i};
|
|
157
231
|
--accent-color: ${n};
|
|
158
|
-
--controls-bg: ${
|
|
232
|
+
--controls-bg: ${s};
|
|
159
233
|
--button-hover: ${a};
|
|
160
234
|
--progress-height: ${l};
|
|
161
235
|
--border-radius: ${u};
|
|
@@ -729,11 +803,11 @@ class j {
|
|
|
729
803
|
}), this.skipForwardButton.addEventListener("click", () => {
|
|
730
804
|
this.player.skipForward(10);
|
|
731
805
|
}), this.progressInput.addEventListener("input", (i) => {
|
|
732
|
-
const n = i.target,
|
|
806
|
+
const n = i.target, o = parseFloat(n.value), s = this.player.getState(), a = o / 100 * s.duration;
|
|
733
807
|
this.player.seek(a);
|
|
734
808
|
}), this.volumeSlider.addEventListener("input", (i) => {
|
|
735
|
-
const n = i.target,
|
|
736
|
-
this.player.setVolume(
|
|
809
|
+
const n = i.target, o = parseFloat(n.value) / 100;
|
|
810
|
+
this.player.setVolume(o);
|
|
737
811
|
}), this.volumeButton.addEventListener("click", () => {
|
|
738
812
|
this.player.getState().muted ? this.player.unmute() : this.player.mute();
|
|
739
813
|
}), this.volumeContainer.addEventListener("mouseenter", () => {
|
|
@@ -761,9 +835,9 @@ class j {
|
|
|
761
835
|
const t = this.controlsContainer.querySelectorAll(".wontum-tab");
|
|
762
836
|
t.forEach((i) => {
|
|
763
837
|
i.addEventListener("click", (n) => {
|
|
764
|
-
const
|
|
765
|
-
t.forEach((u) => u.classList.remove("active")),
|
|
766
|
-
const l = this.controlsContainer.querySelector(`[data-panel="${
|
|
838
|
+
const o = n.currentTarget, s = o.getAttribute("data-tab");
|
|
839
|
+
t.forEach((u) => u.classList.remove("active")), o.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((u) => u.classList.remove("active"));
|
|
840
|
+
const l = this.controlsContainer.querySelector(`[data-panel="${s}"]`);
|
|
767
841
|
l == null || l.classList.add("active");
|
|
768
842
|
});
|
|
769
843
|
}), this.player.getVideoElement().addEventListener("click", () => {
|
|
@@ -782,8 +856,8 @@ class j {
|
|
|
782
856
|
}), this.player.on("timeupdate", (t) => {
|
|
783
857
|
const { currentTime: e } = t.data, i = this.player.getState();
|
|
784
858
|
if (i.duration > 0) {
|
|
785
|
-
const
|
|
786
|
-
this.progressBar.style.width = `${
|
|
859
|
+
const o = e / i.duration * 100;
|
|
860
|
+
this.progressBar.style.width = `${o}%`, this.progressInput.value = o.toString();
|
|
787
861
|
}
|
|
788
862
|
const n = this.controlsContainer.querySelector(".wontum-current-time");
|
|
789
863
|
n.textContent = this.formatTime(e);
|
|
@@ -811,30 +885,30 @@ class j {
|
|
|
811
885
|
t.innerHTML = `
|
|
812
886
|
<div class="wontum-subtitle-option ${i === -1 ? "active" : ""}" data-track="-1">Off</div>
|
|
813
887
|
${e.map(
|
|
814
|
-
(n,
|
|
815
|
-
<div class="wontum-subtitle-option ${
|
|
816
|
-
${n.label || n.language || `Track ${
|
|
888
|
+
(n, o) => `
|
|
889
|
+
<div class="wontum-subtitle-option ${o === i ? "active" : ""}" data-track="${o}">
|
|
890
|
+
${n.label || n.language || `Track ${o + 1}`}
|
|
817
891
|
</div>
|
|
818
892
|
`
|
|
819
893
|
).join("")}
|
|
820
894
|
`, t.querySelectorAll(".wontum-subtitle-option").forEach((n) => {
|
|
821
|
-
n.addEventListener("click", (
|
|
822
|
-
const
|
|
823
|
-
a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")),
|
|
895
|
+
n.addEventListener("click", (o) => {
|
|
896
|
+
const s = o.target, a = parseInt(s.dataset.track || "-1");
|
|
897
|
+
a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
824
898
|
});
|
|
825
899
|
});
|
|
826
900
|
}
|
|
827
901
|
updateSpeedMenu() {
|
|
828
902
|
const t = this.controlsContainer.querySelector(".wontum-speed-menu"), i = this.player.getState().playbackRate || 1, n = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
829
903
|
t.innerHTML = n.map(
|
|
830
|
-
(
|
|
831
|
-
<div class="wontum-speed-option ${i ===
|
|
832
|
-
${
|
|
904
|
+
(o) => `
|
|
905
|
+
<div class="wontum-speed-option ${i === o ? "active" : ""}" data-speed="${o}">
|
|
906
|
+
${o === 1 ? "Normal" : o + "x"}
|
|
833
907
|
</div>
|
|
834
908
|
`
|
|
835
|
-
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((
|
|
836
|
-
|
|
837
|
-
const a =
|
|
909
|
+
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((o) => {
|
|
910
|
+
o.addEventListener("click", (s) => {
|
|
911
|
+
const a = s.target, l = parseFloat(a.dataset.speed || "1");
|
|
838
912
|
this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), a.classList.add("active");
|
|
839
913
|
});
|
|
840
914
|
});
|
|
@@ -861,14 +935,14 @@ class j {
|
|
|
861
935
|
e.innerHTML = `
|
|
862
936
|
<div class="wontum-quality-option active" data-quality="-1">Auto</div>
|
|
863
937
|
${i.map(
|
|
864
|
-
(n,
|
|
865
|
-
<div class="wontum-quality-option" data-quality="${
|
|
938
|
+
(n, o) => `
|
|
939
|
+
<div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
|
|
866
940
|
`
|
|
867
941
|
).join("")}
|
|
868
942
|
`, e.querySelectorAll(".wontum-quality-option").forEach((n) => {
|
|
869
|
-
n.addEventListener("click", (
|
|
870
|
-
const
|
|
871
|
-
this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")),
|
|
943
|
+
n.addEventListener("click", (o) => {
|
|
944
|
+
const s = o.target, a = parseInt(s.dataset.quality || "-1");
|
|
945
|
+
this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
872
946
|
});
|
|
873
947
|
});
|
|
874
948
|
}
|
|
@@ -933,11 +1007,11 @@ class j {
|
|
|
933
1007
|
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
934
1008
|
}
|
|
935
1009
|
}
|
|
936
|
-
class
|
|
1010
|
+
class _ {
|
|
937
1011
|
constructor(t) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1012
|
+
r(this, "config");
|
|
1013
|
+
r(this, "urlCache", /* @__PURE__ */ new Map());
|
|
1014
|
+
r(this, "signedUrls", /* @__PURE__ */ new Set());
|
|
941
1015
|
this.config = t;
|
|
942
1016
|
}
|
|
943
1017
|
/**
|
|
@@ -971,15 +1045,15 @@ class Q {
|
|
|
971
1045
|
* The endpoint should set signed cookies and return the URL
|
|
972
1046
|
*/
|
|
973
1047
|
async signCloudFrontUrl(t, e = 0) {
|
|
974
|
-
var
|
|
1048
|
+
var o, s;
|
|
975
1049
|
if (this.signedUrls.has(t))
|
|
976
1050
|
return t;
|
|
977
|
-
if ((
|
|
1051
|
+
if ((o = this.config) != null && o.signUrl)
|
|
978
1052
|
try {
|
|
979
1053
|
const a = await this.config.signUrl(t);
|
|
980
1054
|
return this.signedUrls.add(t), a;
|
|
981
1055
|
} catch (a) {
|
|
982
|
-
const l = (a == null ? void 0 : a.name) === "AbortError" || ((
|
|
1056
|
+
const l = (a == null ? void 0 : a.name) === "AbortError" || ((s = a == null ? void 0 : a.message) == null ? void 0 : s.includes("aborted"));
|
|
983
1057
|
if (l && e < 2)
|
|
984
1058
|
return console.warn(`Sign URL aborted, retrying (${e + 1}/2)...`), await new Promise((u) => setTimeout(u, 300)), this.signCloudFrontUrl(t, e + 1);
|
|
985
1059
|
throw console.error("Failed to sign CloudFront URL:", a), l ? new Error(
|
|
@@ -1010,13 +1084,13 @@ class Q {
|
|
|
1010
1084
|
return i.url;
|
|
1011
1085
|
if ((n = this.config) != null && n.getPresignedUrl)
|
|
1012
1086
|
try {
|
|
1013
|
-
const
|
|
1087
|
+
const o = await this.config.getPresignedUrl(e);
|
|
1014
1088
|
return this.urlCache.set(e, {
|
|
1015
|
-
url:
|
|
1089
|
+
url: o,
|
|
1016
1090
|
expiresAt: Date.now() + 50 * 60 * 1e3
|
|
1017
|
-
}),
|
|
1018
|
-
} catch (
|
|
1019
|
-
throw console.error("Failed to generate presigned URL:",
|
|
1091
|
+
}), o;
|
|
1092
|
+
} catch (o) {
|
|
1093
|
+
throw console.error("Failed to generate presigned URL:", o), new Error("Failed to generate presigned URL for S3 object");
|
|
1020
1094
|
}
|
|
1021
1095
|
return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"), t;
|
|
1022
1096
|
}
|
|
@@ -1042,18 +1116,18 @@ class Q {
|
|
|
1042
1116
|
this.urlCache.clear(), this.signedUrls.clear();
|
|
1043
1117
|
}
|
|
1044
1118
|
}
|
|
1045
|
-
class
|
|
1119
|
+
class $ {
|
|
1046
1120
|
constructor(t) {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1121
|
+
r(this, "container");
|
|
1122
|
+
r(this, "videoElement");
|
|
1123
|
+
r(this, "hls", null);
|
|
1124
|
+
r(this, "config");
|
|
1125
|
+
r(this, "eventListeners", /* @__PURE__ */ new Map());
|
|
1126
|
+
r(this, "analytics");
|
|
1127
|
+
r(this, "s3Handler");
|
|
1128
|
+
r(this, "uiController");
|
|
1129
|
+
r(this, "qualities", []);
|
|
1130
|
+
r(this, "state", {
|
|
1057
1131
|
playing: !1,
|
|
1058
1132
|
paused: !0,
|
|
1059
1133
|
ended: !1,
|
|
@@ -1069,7 +1143,7 @@ class A {
|
|
|
1069
1143
|
});
|
|
1070
1144
|
if (this.config = t, this.container = typeof t.container == "string" ? document.querySelector(t.container) : t.container, !this.container)
|
|
1071
1145
|
throw new Error("Container element not found");
|
|
1072
|
-
this.analytics = new
|
|
1146
|
+
this.analytics = new N(t.analytics), this.s3Handler = new _(t.s3Config), this.videoElement = this.createVideoElement(), this.container.appendChild(this.videoElement), this.uiController = new W(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);
|
|
1073
1147
|
}
|
|
1074
1148
|
addSubtitleTracks(t) {
|
|
1075
1149
|
t.forEach((e) => {
|
|
@@ -1139,21 +1213,21 @@ class A {
|
|
|
1139
1213
|
try {
|
|
1140
1214
|
const i = await this.s3Handler.processUrl(t);
|
|
1141
1215
|
if (p.isSupported()) {
|
|
1142
|
-
const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1,
|
|
1216
|
+
const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
|
|
1143
1217
|
...this.config.hlsConfig,
|
|
1144
|
-
xhrSetup: (
|
|
1218
|
+
xhrSetup: (s, a) => {
|
|
1145
1219
|
var l;
|
|
1146
|
-
n && (
|
|
1220
|
+
n && (s.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(s, a);
|
|
1147
1221
|
}
|
|
1148
1222
|
};
|
|
1149
|
-
this.hls = new p(
|
|
1223
|
+
this.hls = new p(o), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (s, a) => {
|
|
1150
1224
|
const l = this.extractQualities(a.levels);
|
|
1151
1225
|
this.qualities = l;
|
|
1152
|
-
}), this.hls.on(p.Events.LEVEL_SWITCHED, (
|
|
1226
|
+
}), this.hls.on(p.Events.LEVEL_SWITCHED, (s, a) => {
|
|
1153
1227
|
var u;
|
|
1154
1228
|
const l = (u = this.hls) == null ? void 0 : u.levels[a.level];
|
|
1155
1229
|
l && (this.state.quality = `${l.height}p`, this.emit("qualitychange", { quality: this.state.quality }));
|
|
1156
|
-
}), this.hls.on(p.Events.ERROR, (
|
|
1230
|
+
}), this.hls.on(p.Events.ERROR, (s, a) => {
|
|
1157
1231
|
a.fatal && this.handleHlsError(a);
|
|
1158
1232
|
});
|
|
1159
1233
|
} else if (this.videoElement.canPlayType("application/vnd.apple.mpegurl"))
|
|
@@ -1313,8 +1387,8 @@ class A {
|
|
|
1313
1387
|
data: e,
|
|
1314
1388
|
timestamp: Date.now()
|
|
1315
1389
|
};
|
|
1316
|
-
(n = this.eventListeners.get(t)) == null || n.forEach((
|
|
1317
|
-
|
|
1390
|
+
(n = this.eventListeners.get(t)) == null || n.forEach((o) => {
|
|
1391
|
+
o(i);
|
|
1318
1392
|
});
|
|
1319
1393
|
}
|
|
1320
1394
|
destroy() {
|
|
@@ -1323,9 +1397,10 @@ class A {
|
|
|
1323
1397
|
}
|
|
1324
1398
|
class G {
|
|
1325
1399
|
constructor(t) {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1400
|
+
r(this, "file");
|
|
1401
|
+
r(this, "videoElement", null);
|
|
1402
|
+
r(this, "audioContext", null);
|
|
1403
|
+
r(this, "info", null);
|
|
1329
1404
|
if (!this.isVideoFile(t))
|
|
1330
1405
|
throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
|
|
1331
1406
|
this.file = t;
|
|
@@ -1347,29 +1422,32 @@ class G {
|
|
|
1347
1422
|
try {
|
|
1348
1423
|
this.videoElement = document.createElement("video"), this.videoElement.preload = "metadata", this.videoElement.muted = !0;
|
|
1349
1424
|
const i = URL.createObjectURL(this.file);
|
|
1350
|
-
this.videoElement.onloadedmetadata = () => {
|
|
1425
|
+
this.videoElement.onloadedmetadata = async () => {
|
|
1351
1426
|
try {
|
|
1352
1427
|
if (!this.videoElement) {
|
|
1353
1428
|
e(new Error("Video element not initialized"));
|
|
1354
1429
|
return;
|
|
1355
1430
|
}
|
|
1356
|
-
const n = this.videoElement.videoWidth,
|
|
1431
|
+
const n = this.videoElement.videoWidth, o = this.videoElement.videoHeight, s = this.videoElement.duration, a = this.calculateAspectRatio(n, o), l = this.file.size, u = this.formatBytes(l), m = this.formatDuration(s), f = this.getFileExtension(this.file.name), y = s > 0 ? Math.round(l * 8 / s / 1e3) : void 0, v = await this.detectFrameRate(), g = await this.detectAudioInfo(i);
|
|
1357
1432
|
this.info = {
|
|
1358
1433
|
width: n,
|
|
1359
|
-
height:
|
|
1434
|
+
height: o,
|
|
1360
1435
|
aspectRatio: a,
|
|
1361
1436
|
size: l,
|
|
1362
1437
|
sizeInBytes: l,
|
|
1363
1438
|
// raw value alias
|
|
1364
1439
|
sizeFormatted: u,
|
|
1365
|
-
duration:
|
|
1366
|
-
durationInSeconds:
|
|
1440
|
+
duration: s,
|
|
1441
|
+
durationInSeconds: s,
|
|
1367
1442
|
// raw value alias
|
|
1368
1443
|
durationFormatted: m,
|
|
1369
1444
|
mimeType: this.file.type || "video/unknown",
|
|
1370
1445
|
fileName: this.file.name,
|
|
1371
|
-
fileExtension:
|
|
1372
|
-
bitrate:
|
|
1446
|
+
fileExtension: f,
|
|
1447
|
+
bitrate: y,
|
|
1448
|
+
frameRate: v,
|
|
1449
|
+
audioChannels: g.channels,
|
|
1450
|
+
hasAudio: g.hasAudio
|
|
1373
1451
|
}, URL.revokeObjectURL(i), this.videoElement.remove(), t(this.info);
|
|
1374
1452
|
} catch (n) {
|
|
1375
1453
|
URL.revokeObjectURL(i), e(n);
|
|
@@ -1386,8 +1464,59 @@ class G {
|
|
|
1386
1464
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
1387
1465
|
*/
|
|
1388
1466
|
calculateAspectRatio(t, e) {
|
|
1389
|
-
const i = this.getGCD(t, e), n = t / i,
|
|
1390
|
-
return Math.abs(
|
|
1467
|
+
const i = this.getGCD(t, e), n = t / i, o = e / i, s = n / 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" : `${n}:${o}`;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Detect frame rate by analyzing video playback
|
|
1472
|
+
*/
|
|
1473
|
+
async detectFrameRate() {
|
|
1474
|
+
if (this.videoElement)
|
|
1475
|
+
try {
|
|
1476
|
+
return "requestVideoFrameCallback" in this.videoElement ? new Promise((t) => {
|
|
1477
|
+
let e = 0, i = 0;
|
|
1478
|
+
const n = 10, o = (s, a) => {
|
|
1479
|
+
if (!this.videoElement) {
|
|
1480
|
+
t(void 0);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (e++, e === 1)
|
|
1484
|
+
i = s, this.videoElement.requestVideoFrameCallback(o);
|
|
1485
|
+
else if (e < n)
|
|
1486
|
+
this.videoElement.requestVideoFrameCallback(o);
|
|
1487
|
+
else {
|
|
1488
|
+
const l = (s - i) / 1e3, u = Math.round((e - 1) / l);
|
|
1489
|
+
t(u);
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
this.videoElement ? (this.videoElement.currentTime = 1, this.videoElement.play().catch(() => t(void 0)), this.videoElement.requestVideoFrameCallback(o)) : t(void 0);
|
|
1493
|
+
}) : void 0;
|
|
1494
|
+
} catch {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Detect audio channel information using Web Audio API
|
|
1500
|
+
*/
|
|
1501
|
+
async detectAudioInfo(t) {
|
|
1502
|
+
var e;
|
|
1503
|
+
if (!this.videoElement) return { hasAudio: !1 };
|
|
1504
|
+
try {
|
|
1505
|
+
if (!(this.videoElement.mozHasAudio || (this.videoElement.webkitAudioDecodedByteCount ?? 0) > 0 || (((e = this.videoElement.audioTracks) == null ? void 0 : e.length) ?? 0) > 0))
|
|
1506
|
+
return { hasAudio: !1 };
|
|
1507
|
+
try {
|
|
1508
|
+
const n = window.AudioContext || window.webkitAudioContext;
|
|
1509
|
+
if (!n)
|
|
1510
|
+
return { hasAudio: !0 };
|
|
1511
|
+
this.audioContext = new n();
|
|
1512
|
+
const o = this.audioContext.createMediaElementSource(this.videoElement), s = this.audioContext.createAnalyser();
|
|
1513
|
+
return o.connect(s), s.connect(this.audioContext.destination), { hasAudio: !0, channels: o.channelCount };
|
|
1514
|
+
} catch {
|
|
1515
|
+
return { hasAudio: !0 };
|
|
1516
|
+
}
|
|
1517
|
+
} catch {
|
|
1518
|
+
return { hasAudio: !1 };
|
|
1519
|
+
}
|
|
1391
1520
|
}
|
|
1392
1521
|
/**
|
|
1393
1522
|
* Get Greatest Common Divisor
|
|
@@ -1470,6 +1599,18 @@ class G {
|
|
|
1470
1599
|
var t;
|
|
1471
1600
|
return (t = this.info) == null ? void 0 : t.bitrate;
|
|
1472
1601
|
}
|
|
1602
|
+
get frameRate() {
|
|
1603
|
+
var t;
|
|
1604
|
+
return (t = this.info) == null ? void 0 : t.frameRate;
|
|
1605
|
+
}
|
|
1606
|
+
get audioChannels() {
|
|
1607
|
+
var t;
|
|
1608
|
+
return (t = this.info) == null ? void 0 : t.audioChannels;
|
|
1609
|
+
}
|
|
1610
|
+
get hasAudio() {
|
|
1611
|
+
var t;
|
|
1612
|
+
return ((t = this.info) == null ? void 0 : t.hasAudio) || !1;
|
|
1613
|
+
}
|
|
1473
1614
|
get quality() {
|
|
1474
1615
|
if (!this.info) return "unknown";
|
|
1475
1616
|
const t = this.info.height;
|
|
@@ -1485,7 +1626,8 @@ class G {
|
|
|
1485
1626
|
* Clean up resources
|
|
1486
1627
|
*/
|
|
1487
1628
|
destroy() {
|
|
1488
|
-
this.videoElement && (this.videoElement.remove(), this.videoElement = null), this.
|
|
1629
|
+
this.videoElement && (this.videoElement.pause(), this.videoElement.remove(), this.videoElement = null), this.audioContext && (this.audioContext.close().catch(() => {
|
|
1630
|
+
}), this.audioContext = null), this.info = null;
|
|
1489
1631
|
}
|
|
1490
1632
|
}
|
|
1491
1633
|
const K = (c) => {
|
|
@@ -1494,107 +1636,107 @@ const K = (c) => {
|
|
|
1494
1636
|
autoplay: e,
|
|
1495
1637
|
muted: i,
|
|
1496
1638
|
controls: n = !0,
|
|
1497
|
-
poster:
|
|
1498
|
-
preload:
|
|
1639
|
+
poster: o,
|
|
1640
|
+
preload: s,
|
|
1499
1641
|
theme: a,
|
|
1500
1642
|
s3Config: l,
|
|
1501
1643
|
analytics: u,
|
|
1502
1644
|
hlsConfig: m,
|
|
1503
|
-
subtitles:
|
|
1504
|
-
stickyControls:
|
|
1505
|
-
onReady:
|
|
1506
|
-
onPlay:
|
|
1645
|
+
subtitles: f,
|
|
1646
|
+
stickyControls: y,
|
|
1647
|
+
onReady: v,
|
|
1648
|
+
onPlay: g,
|
|
1507
1649
|
onPause: C,
|
|
1508
1650
|
onEnded: L,
|
|
1509
1651
|
onTimeUpdate: T,
|
|
1510
1652
|
onVolumeChange: I,
|
|
1511
|
-
onError:
|
|
1512
|
-
onLoadedMetadata:
|
|
1513
|
-
onQualityChange:
|
|
1514
|
-
style:
|
|
1515
|
-
className:
|
|
1516
|
-
width:
|
|
1517
|
-
height:
|
|
1518
|
-
} = c,
|
|
1519
|
-
return
|
|
1520
|
-
if (!
|
|
1521
|
-
const
|
|
1653
|
+
onError: A,
|
|
1654
|
+
onLoadedMetadata: R,
|
|
1655
|
+
onQualityChange: M,
|
|
1656
|
+
style: D,
|
|
1657
|
+
className: O,
|
|
1658
|
+
width: w = "100%",
|
|
1659
|
+
height: b = "500px"
|
|
1660
|
+
} = c, k = E(null), q = E(null);
|
|
1661
|
+
return x(() => {
|
|
1662
|
+
if (!k.current) return;
|
|
1663
|
+
const U = {
|
|
1522
1664
|
src: t,
|
|
1523
|
-
container:
|
|
1665
|
+
container: k.current,
|
|
1524
1666
|
autoplay: e,
|
|
1525
1667
|
muted: i,
|
|
1526
1668
|
controls: n,
|
|
1527
|
-
poster:
|
|
1528
|
-
preload:
|
|
1669
|
+
poster: o,
|
|
1670
|
+
preload: s,
|
|
1529
1671
|
theme: a,
|
|
1530
1672
|
s3Config: l,
|
|
1531
1673
|
analytics: u,
|
|
1532
1674
|
hlsConfig: m,
|
|
1533
|
-
subtitles:
|
|
1534
|
-
stickyControls:
|
|
1535
|
-
}, d = new
|
|
1536
|
-
return
|
|
1537
|
-
var
|
|
1538
|
-
return
|
|
1539
|
-
}),
|
|
1540
|
-
d.destroy(),
|
|
1675
|
+
subtitles: f,
|
|
1676
|
+
stickyControls: y
|
|
1677
|
+
}, d = new $(U);
|
|
1678
|
+
return q.current = d, g && d.on("play", g), C && d.on("pause", C), L && d.on("ended", L), A && d.on("error", (h) => {
|
|
1679
|
+
var F;
|
|
1680
|
+
return A((F = h.data) == null ? void 0 : F.error);
|
|
1681
|
+
}), R && d.on("loadedmetadata", R), M && d.on("qualitychange", (h) => M(h.data.level)), T && d.on("timeupdate", (h) => T(h.data.currentTime)), I && d.on("volumechange", (h) => I(h.data.volume, h.data.muted)), v && v(d), () => {
|
|
1682
|
+
d.destroy(), q.current = null;
|
|
1541
1683
|
};
|
|
1542
|
-
}, [t]), /* @__PURE__ */
|
|
1684
|
+
}, [t]), /* @__PURE__ */ P(
|
|
1543
1685
|
"div",
|
|
1544
1686
|
{
|
|
1545
|
-
ref:
|
|
1546
|
-
className:
|
|
1687
|
+
ref: k,
|
|
1688
|
+
className: O,
|
|
1547
1689
|
style: {
|
|
1548
|
-
width: typeof
|
|
1549
|
-
height: typeof
|
|
1550
|
-
...
|
|
1690
|
+
width: typeof w == "number" ? `${w}px` : w,
|
|
1691
|
+
height: typeof b == "number" ? `${b}px` : b,
|
|
1692
|
+
...D
|
|
1551
1693
|
}
|
|
1552
1694
|
}
|
|
1553
1695
|
);
|
|
1554
1696
|
}, J = (c) => {
|
|
1555
|
-
const [t, e] =
|
|
1556
|
-
return
|
|
1557
|
-
if (!
|
|
1558
|
-
const
|
|
1697
|
+
const [t, e] = S(null), [i, n] = S(null), o = E(null);
|
|
1698
|
+
return x(() => {
|
|
1699
|
+
if (!o.current) return;
|
|
1700
|
+
const s = new $({
|
|
1559
1701
|
...c,
|
|
1560
|
-
container:
|
|
1702
|
+
container: o.current
|
|
1561
1703
|
});
|
|
1562
|
-
e(
|
|
1704
|
+
e(s);
|
|
1563
1705
|
const a = () => {
|
|
1564
|
-
n(
|
|
1706
|
+
n(s.getState());
|
|
1565
1707
|
};
|
|
1566
|
-
return
|
|
1567
|
-
|
|
1708
|
+
return s.on("play", a), s.on("pause", a), s.on("timeupdate", a), s.on("volumechange", a), s.on("loadedmetadata", a), () => {
|
|
1709
|
+
s.destroy();
|
|
1568
1710
|
};
|
|
1569
1711
|
}, [c.src]), {
|
|
1570
|
-
containerRef:
|
|
1712
|
+
containerRef: o,
|
|
1571
1713
|
player: t,
|
|
1572
1714
|
state: i
|
|
1573
1715
|
};
|
|
1574
|
-
}, z =
|
|
1716
|
+
}, z = B.createContext({
|
|
1575
1717
|
player: null,
|
|
1576
1718
|
state: null
|
|
1577
1719
|
}), Z = (c) => {
|
|
1578
|
-
const { player: t, children: e } = c, [i, n] =
|
|
1579
|
-
return
|
|
1580
|
-
const
|
|
1720
|
+
const { player: t, children: e } = c, [i, n] = S(t.getState());
|
|
1721
|
+
return x(() => {
|
|
1722
|
+
const o = () => {
|
|
1581
1723
|
n(t.getState());
|
|
1582
1724
|
};
|
|
1583
|
-
return t.on("play",
|
|
1725
|
+
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1584
1726
|
};
|
|
1585
|
-
}, [t]), /* @__PURE__ */
|
|
1727
|
+
}, [t]), /* @__PURE__ */ P(z.Provider, { value: { player: t, state: i }, children: e });
|
|
1586
1728
|
}, tt = () => {
|
|
1587
|
-
const c =
|
|
1729
|
+
const c = B.useContext(z);
|
|
1588
1730
|
if (!c.player)
|
|
1589
1731
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1590
1732
|
return c;
|
|
1591
1733
|
};
|
|
1592
1734
|
export {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1735
|
+
N as Analytics,
|
|
1736
|
+
_ as S3Handler,
|
|
1737
|
+
W as UIController,
|
|
1596
1738
|
G as WontumFileInfo,
|
|
1597
|
-
|
|
1739
|
+
$ as WontumPlayer,
|
|
1598
1740
|
Z as WontumPlayerProvider,
|
|
1599
1741
|
K as WontumPlayerReact,
|
|
1600
1742
|
J as useWontumPlayer,
|