@obipascal/player 1.0.7 → 1.0.9

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.
@@ -1,28 +1,36 @@
1
- var V = Object.defineProperty;
2
- var N = (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) => N(c, typeof t != "symbol" ? t + "" : t, e);
1
+ var H = Object.defineProperty;
2
+ var V = (c, t, e) => t in c ? H(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
3
+ var s = (c, t, e) => V(c, typeof t != "symbol" ? t + "" : t, e);
4
4
  import p from "hls.js";
5
- import { jsx as B } from "react/jsx-runtime";
6
- import * as R from "react";
7
- import { useRef as y, useEffect as f, useState as b } from "react";
8
- class _ {
5
+ import { jsx as A } from "react/jsx-runtime";
6
+ import * as F from "react";
7
+ import { useRef as b, useEffect as E, useState as k } from "react";
8
+ class N {
9
9
  constructor(t) {
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
- var e;
21
- this.config = t, this.sessionId = (t == null ? void 0 : t.sessionId) || this.generateSessionId(), this.sessionStartTime = Date.now(), (e = this.config) != null && e.enabled && this.trackEvent("session_start", this.getSessionData());
10
+ s(this, "config");
11
+ s(this, "sessionId");
12
+ s(this, "events", []);
13
+ s(this, "sessionStartTime");
14
+ s(this, "playbackStartTime", null);
15
+ s(this, "totalPlayTime", 0);
16
+ s(this, "totalBufferTime", 0);
17
+ s(this, "bufferStartTime", null);
18
+ s(this, "rebufferCount", 0);
19
+ s(this, "seekCount", 0);
20
+ s(this, "webSocket", null);
21
+ s(this, "socketIO", null);
22
+ s(this, "wsReconnectTimeout", null);
23
+ s(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
- var s;
25
- if (!((s = this.config) != null && s.enabled)) return;
32
+ var n;
33
+ if (!((n = this.config) != null && n.enabled)) return;
26
34
  const i = {
27
35
  eventType: t,
28
36
  timestamp: Date.now(),
@@ -34,7 +42,7 @@ class _ {
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 _ {
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,47 +190,47 @@ class _ {
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 Q {
196
+ class W {
123
197
  constructor(t, e) {
124
- r(this, "container");
125
- r(this, "player");
126
- r(this, "controlsContainer");
127
- r(this, "progressContainer");
128
- r(this, "progressBar");
129
- r(this, "playButton");
130
- r(this, "skipBackwardButton");
131
- r(this, "skipForwardButton");
132
- r(this, "volumeButton");
133
- r(this, "volumeContainer");
134
- r(this, "fullscreenButton");
135
- r(this, "pipButton");
136
- r(this, "settingsButton");
198
+ s(this, "container");
199
+ s(this, "player");
200
+ s(this, "controlsContainer");
201
+ s(this, "progressContainer");
202
+ s(this, "progressBar");
203
+ s(this, "playButton");
204
+ s(this, "skipBackwardButton");
205
+ s(this, "skipForwardButton");
206
+ s(this, "volumeButton");
207
+ s(this, "volumeContainer");
208
+ s(this, "fullscreenButton");
209
+ s(this, "pipButton");
210
+ s(this, "settingsButton");
137
211
  // private timeDisplay: HTMLElement
138
- r(this, "volumeSlider");
139
- r(this, "progressInput");
212
+ s(this, "volumeSlider");
213
+ s(this, "progressInput");
140
214
  // private controlsVisible = true
141
- r(this, "hideControlsTimeout", null);
142
- r(this, "stickyControls", !1);
143
- r(this, "isVolumeSliderActive", !1);
215
+ s(this, "hideControlsTimeout", null);
216
+ s(this, "stickyControls", !1);
217
+ s(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", s = e.accentColor || "#2563eb", n = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", a = e.controlsBackground || "linear-gradient(to top, rgba(0,0,0,0.8), transparent)", o = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", u = e.borderRadius || "4px", m = document.createElement("style");
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", r = 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: ${n};
228
+ font-family: ${o};
155
229
  overflow: hidden;
156
230
  --primary-color: ${i};
157
- --accent-color: ${s};
158
- --controls-bg: ${a};
159
- --button-hover: ${o};
231
+ --accent-color: ${n};
232
+ --controls-bg: ${r};
233
+ --button-hover: ${a};
160
234
  --progress-height: ${l};
161
235
  --border-radius: ${u};
162
236
  }
@@ -729,11 +803,11 @@ class Q {
729
803
  }), this.skipForwardButton.addEventListener("click", () => {
730
804
  this.player.skipForward(10);
731
805
  }), this.progressInput.addEventListener("input", (i) => {
732
- const s = i.target, n = parseFloat(s.value), a = this.player.getState(), o = n / 100 * a.duration;
733
- this.player.seek(o);
806
+ const n = i.target, o = parseFloat(n.value), r = this.player.getState(), a = o / 100 * r.duration;
807
+ this.player.seek(a);
734
808
  }), this.volumeSlider.addEventListener("input", (i) => {
735
- const s = i.target, n = parseFloat(s.value) / 100;
736
- this.player.setVolume(n);
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", () => {
@@ -760,10 +834,10 @@ class Q {
760
834
  });
761
835
  const t = this.controlsContainer.querySelectorAll(".wontum-tab");
762
836
  t.forEach((i) => {
763
- i.addEventListener("click", (s) => {
764
- const n = s.currentTarget, a = n.getAttribute("data-tab");
765
- t.forEach((u) => u.classList.remove("active")), n.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((u) => u.classList.remove("active"));
766
- const l = this.controlsContainer.querySelector(`[data-panel="${a}"]`);
837
+ i.addEventListener("click", (n) => {
838
+ const o = n.currentTarget, r = 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="${r}"]`);
767
841
  l == null || l.classList.add("active");
768
842
  });
769
843
  }), this.player.getVideoElement().addEventListener("click", () => {
@@ -782,11 +856,11 @@ class Q {
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 n = e / i.duration * 100;
786
- this.progressBar.style.width = `${n}%`, this.progressInput.value = n.toString();
859
+ const o = e / i.duration * 100;
860
+ this.progressBar.style.width = `${o}%`, this.progressInput.value = o.toString();
787
861
  }
788
- const s = this.controlsContainer.querySelector(".wontum-current-time");
789
- s.textContent = this.formatTime(e);
862
+ const n = this.controlsContainer.querySelector(".wontum-current-time");
863
+ n.textContent = this.formatTime(e);
790
864
  }), this.player.on("loadedmetadata", (t) => {
791
865
  const { duration: e } = t.data, i = this.controlsContainer.querySelector(".wontum-duration");
792
866
  i.textContent = this.formatTime(e), t.data.qualities && this.updateQualityMenu(t.data.qualities);
@@ -807,35 +881,35 @@ class Q {
807
881
  t.innerHTML = '<div class="wontum-subtitle-option">No subtitles available</div>';
808
882
  return;
809
883
  }
810
- const i = e.findIndex((s) => s.mode === "showing");
884
+ const i = e.findIndex((n) => n.mode === "showing");
811
885
  t.innerHTML = `
812
886
  <div class="wontum-subtitle-option ${i === -1 ? "active" : ""}" data-track="-1">Off</div>
813
887
  ${e.map(
814
- (s, n) => `
815
- <div class="wontum-subtitle-option ${n === i ? "active" : ""}" data-track="${n}">
816
- ${s.label || s.language || `Track ${n + 1}`}
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
- `, t.querySelectorAll(".wontum-subtitle-option").forEach((s) => {
821
- s.addEventListener("click", (n) => {
822
- const a = n.target, o = parseInt(a.dataset.track || "-1");
823
- o === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(o), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), a.classList.add("active");
894
+ `, t.querySelectorAll(".wontum-subtitle-option").forEach((n) => {
895
+ n.addEventListener("click", (o) => {
896
+ const r = o.target, a = parseInt(r.dataset.track || "-1");
897
+ a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), r.classList.add("active");
824
898
  });
825
899
  });
826
900
  }
827
901
  updateSpeedMenu() {
828
- const t = this.controlsContainer.querySelector(".wontum-speed-menu"), i = this.player.getState().playbackRate || 1, s = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
829
- t.innerHTML = s.map(
830
- (n) => `
831
- <div class="wontum-speed-option ${i === n ? "active" : ""}" data-speed="${n}">
832
- ${n === 1 ? "Normal" : n + "x"}
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];
903
+ t.innerHTML = n.map(
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((n) => {
836
- n.addEventListener("click", (a) => {
837
- const o = a.target, l = parseFloat(o.dataset.speed || "1");
838
- this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), o.classList.add("active");
909
+ ).join(""), t.querySelectorAll(".wontum-speed-option").forEach((o) => {
910
+ o.addEventListener("click", (r) => {
911
+ const a = r.target, l = parseFloat(a.dataset.speed || "1");
912
+ this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), a.classList.add("active");
839
913
  });
840
914
  });
841
915
  }
@@ -861,14 +935,14 @@ class Q {
861
935
  e.innerHTML = `
862
936
  <div class="wontum-quality-option active" data-quality="-1">Auto</div>
863
937
  ${i.map(
864
- (s, n) => `
865
- <div class="wontum-quality-option" data-quality="${n}">${s.name}</div>
938
+ (n, o) => `
939
+ <div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
866
940
  `
867
941
  ).join("")}
868
- `, e.querySelectorAll(".wontum-quality-option").forEach((s) => {
869
- s.addEventListener("click", (n) => {
870
- const a = n.target, o = parseInt(a.dataset.quality || "-1");
871
- this.player.setQuality(o), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), a.classList.add("active");
942
+ `, e.querySelectorAll(".wontum-quality-option").forEach((n) => {
943
+ n.addEventListener("click", (o) => {
944
+ const r = o.target, a = parseInt(r.dataset.quality || "-1");
945
+ this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), r.classList.add("active");
872
946
  });
873
947
  });
874
948
  }
@@ -933,11 +1007,11 @@ class Q {
933
1007
  this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
934
1008
  }
935
1009
  }
936
- class j {
1010
+ class _ {
937
1011
  constructor(t) {
938
- r(this, "config");
939
- r(this, "urlCache", /* @__PURE__ */ new Map());
940
- r(this, "signedUrls", /* @__PURE__ */ new Set());
1012
+ s(this, "config");
1013
+ s(this, "urlCache", /* @__PURE__ */ new Map());
1014
+ s(this, "signedUrls", /* @__PURE__ */ new Set());
941
1015
  this.config = t;
942
1016
  }
943
1017
  /**
@@ -955,7 +1029,7 @@ class j {
955
1029
  return !1;
956
1030
  try {
957
1031
  const i = new URL(t);
958
- return this.config.cloudFrontDomains.some((s) => i.hostname.includes(s));
1032
+ return this.config.cloudFrontDomains.some((n) => i.hostname.includes(n));
959
1033
  } catch {
960
1034
  return !1;
961
1035
  }
@@ -971,20 +1045,20 @@ class j {
971
1045
  * The endpoint should set signed cookies and return the URL
972
1046
  */
973
1047
  async signCloudFrontUrl(t, e = 0) {
974
- var n, a;
1048
+ var o, r;
975
1049
  if (this.signedUrls.has(t))
976
1050
  return t;
977
- if ((n = this.config) != null && n.signUrl)
1051
+ if ((o = this.config) != null && o.signUrl)
978
1052
  try {
979
- const o = await this.config.signUrl(t);
980
- return this.signedUrls.add(t), o;
981
- } catch (o) {
982
- const l = (o == null ? void 0 : o.name) === "AbortError" || ((a = o == null ? void 0 : o.message) == null ? void 0 : a.includes("aborted"));
1053
+ const a = await this.config.signUrl(t);
1054
+ return this.signedUrls.add(t), a;
1055
+ } catch (a) {
1056
+ const l = (a == null ? void 0 : a.name) === "AbortError" || ((r = a == null ? void 0 : a.message) == null ? void 0 : r.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
- throw console.error("Failed to sign CloudFront URL:", o), l ? new Error(
1059
+ throw console.error("Failed to sign CloudFront URL:", a), l ? new Error(
986
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."
987
- ) : new Error(`Failed to sign CloudFront URL: ${(o == null ? void 0 : o.message) || "Unknown error"}`);
1061
+ ) : new Error(`Failed to sign CloudFront URL: ${(a == null ? void 0 : a.message) || "Unknown error"}`);
988
1062
  }
989
1063
  return console.warn("No signUrl function provided. CloudFront cookies may not be set."), t;
990
1064
  }
@@ -1004,19 +1078,19 @@ class j {
1004
1078
  * Get presigned URL from cache or generate new one
1005
1079
  */
1006
1080
  async getPresignedUrl(t) {
1007
- var s;
1081
+ var n;
1008
1082
  const e = this.extractS3Key(t), i = this.urlCache.get(e);
1009
1083
  if (i && i.expiresAt > Date.now())
1010
1084
  return i.url;
1011
- if ((s = this.config) != null && s.getPresignedUrl)
1085
+ if ((n = this.config) != null && n.getPresignedUrl)
1012
1086
  try {
1013
- const n = await this.config.getPresignedUrl(e);
1087
+ const o = await this.config.getPresignedUrl(e);
1014
1088
  return this.urlCache.set(e, {
1015
- url: n,
1089
+ url: o,
1016
1090
  expiresAt: Date.now() + 50 * 60 * 1e3
1017
- }), n;
1018
- } catch (n) {
1019
- throw console.error("Failed to generate presigned URL:", n), new Error("Failed to generate presigned URL for S3 object");
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
  }
@@ -1032,8 +1106,8 @@ class j {
1032
1106
  static parseS3Uri(t) {
1033
1107
  if (!t.startsWith("s3://"))
1034
1108
  return null;
1035
- const e = t.replace("s3://", "").split("/"), i = e[0], s = e.slice(1).join("/");
1036
- return { bucket: i, key: s };
1109
+ const e = t.replace("s3://", "").split("/"), i = e[0], n = e.slice(1).join("/");
1110
+ return { bucket: i, key: n };
1037
1111
  }
1038
1112
  /**
1039
1113
  * Clear URL cache and signed URLs
@@ -1042,18 +1116,18 @@ class j {
1042
1116
  this.urlCache.clear(), this.signedUrls.clear();
1043
1117
  }
1044
1118
  }
1045
- class A {
1119
+ class $ {
1046
1120
  constructor(t) {
1047
- r(this, "container");
1048
- r(this, "videoElement");
1049
- r(this, "hls", null);
1050
- r(this, "config");
1051
- r(this, "eventListeners", /* @__PURE__ */ new Map());
1052
- r(this, "analytics");
1053
- r(this, "s3Handler");
1054
- r(this, "uiController");
1055
- r(this, "qualities", []);
1056
- r(this, "state", {
1121
+ s(this, "container");
1122
+ s(this, "videoElement");
1123
+ s(this, "hls", null);
1124
+ s(this, "config");
1125
+ s(this, "eventListeners", /* @__PURE__ */ new Map());
1126
+ s(this, "analytics");
1127
+ s(this, "s3Handler");
1128
+ s(this, "uiController");
1129
+ s(this, "qualities", []);
1130
+ s(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 _(t.analytics), this.s3Handler = new j(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);
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,22 +1213,22 @@ class A {
1139
1213
  try {
1140
1214
  const i = await this.s3Handler.processUrl(t);
1141
1215
  if (p.isSupported()) {
1142
- const s = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, n = {
1216
+ const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
1143
1217
  ...this.config.hlsConfig,
1144
- xhrSetup: (a, o) => {
1218
+ xhrSetup: (r, a) => {
1145
1219
  var l;
1146
- s && (a.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(a, o);
1220
+ n && (r.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(r, a);
1147
1221
  }
1148
1222
  };
1149
- this.hls = new p(n), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (a, o) => {
1150
- const l = this.extractQualities(o.levels);
1223
+ this.hls = new p(o), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (r, a) => {
1224
+ const l = this.extractQualities(a.levels);
1151
1225
  this.qualities = l;
1152
- }), this.hls.on(p.Events.LEVEL_SWITCHED, (a, o) => {
1226
+ }), this.hls.on(p.Events.LEVEL_SWITCHED, (r, a) => {
1153
1227
  var u;
1154
- const l = (u = this.hls) == null ? void 0 : u.levels[o.level];
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, (a, o) => {
1157
- o.fatal && this.handleHlsError(o);
1230
+ }), this.hls.on(p.Events.ERROR, (r, a) => {
1231
+ a.fatal && this.handleHlsError(a);
1158
1232
  });
1159
1233
  } else if (this.videoElement.canPlayType("application/vnd.apple.mpegurl"))
1160
1234
  this.videoElement.src = i;
@@ -1307,128 +1381,296 @@ class A {
1307
1381
  (i = this.eventListeners.get(t)) == null || i.delete(e);
1308
1382
  }
1309
1383
  emit(t, e) {
1310
- var s;
1384
+ var n;
1311
1385
  const i = {
1312
1386
  type: t,
1313
1387
  data: e,
1314
1388
  timestamp: Date.now()
1315
1389
  };
1316
- (s = this.eventListeners.get(t)) == null || s.forEach((n) => {
1317
- n(i);
1390
+ (n = this.eventListeners.get(t)) == null || n.forEach((o) => {
1391
+ o(i);
1318
1392
  });
1319
1393
  }
1320
1394
  destroy() {
1321
1395
  this.hls && (this.hls.destroy(), this.hls = null), this.uiController.destroy(), this.videoElement.remove(), this.eventListeners.clear(), this.analytics.destroy();
1322
1396
  }
1323
1397
  }
1398
+ class G {
1399
+ constructor(t) {
1400
+ s(this, "file");
1401
+ s(this, "videoElement", null);
1402
+ s(this, "info", null);
1403
+ if (!this.isVideoFile(t))
1404
+ throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
1405
+ this.file = t;
1406
+ }
1407
+ /**
1408
+ * Check if the file is a valid video file
1409
+ */
1410
+ isVideoFile(t) {
1411
+ if (t.type.startsWith("video/"))
1412
+ return !0;
1413
+ const e = [".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".m4v", ".3gp", ".ts", ".m3u8"], i = t.name.toLowerCase();
1414
+ return e.some((n) => i.endsWith(n));
1415
+ }
1416
+ /**
1417
+ * Extract video metadata
1418
+ */
1419
+ async extract() {
1420
+ return new Promise((t, e) => {
1421
+ try {
1422
+ this.videoElement = document.createElement("video"), this.videoElement.preload = "metadata", this.videoElement.muted = !0;
1423
+ const i = URL.createObjectURL(this.file);
1424
+ this.videoElement.onloadedmetadata = () => {
1425
+ try {
1426
+ if (!this.videoElement) {
1427
+ e(new Error("Video element not initialized"));
1428
+ return;
1429
+ }
1430
+ const n = this.videoElement.videoWidth, o = this.videoElement.videoHeight, r = this.videoElement.duration, a = this.calculateAspectRatio(n, o), l = this.file.size, u = this.formatBytes(l), m = this.formatDuration(r), g = this.getFileExtension(this.file.name), v = r > 0 ? Math.round(l * 8 / r / 1e3) : void 0;
1431
+ this.info = {
1432
+ width: n,
1433
+ height: o,
1434
+ aspectRatio: a,
1435
+ size: l,
1436
+ sizeInBytes: l,
1437
+ // raw value alias
1438
+ sizeFormatted: u,
1439
+ duration: r,
1440
+ durationInSeconds: r,
1441
+ // raw value alias
1442
+ durationFormatted: m,
1443
+ mimeType: this.file.type || "video/unknown",
1444
+ fileName: this.file.name,
1445
+ fileExtension: g,
1446
+ bitrate: v
1447
+ }, URL.revokeObjectURL(i), this.videoElement.remove(), t(this.info);
1448
+ } catch (n) {
1449
+ URL.revokeObjectURL(i), e(n);
1450
+ }
1451
+ }, this.videoElement.onerror = () => {
1452
+ URL.revokeObjectURL(i), e(new Error(`Failed to load video file: ${this.file.name}`));
1453
+ }, this.videoElement.src = i;
1454
+ } catch (i) {
1455
+ e(i);
1456
+ }
1457
+ });
1458
+ }
1459
+ /**
1460
+ * Calculate aspect ratio (e.g., "16:9", "4:3")
1461
+ */
1462
+ calculateAspectRatio(t, e) {
1463
+ const i = this.getGCD(t, e), n = t / i, o = e / i, r = n / o;
1464
+ return Math.abs(r - 16 / 9) < 0.01 ? "16:9" : Math.abs(r - 4 / 3) < 0.01 ? "4:3" : Math.abs(r - 21 / 9) < 0.01 ? "21:9" : Math.abs(r - 1) < 0.01 ? "1:1" : `${n}:${o}`;
1465
+ }
1466
+ /**
1467
+ * Get Greatest Common Divisor
1468
+ */
1469
+ getGCD(t, e) {
1470
+ return e === 0 ? t : this.getGCD(e, t % e);
1471
+ }
1472
+ /**
1473
+ * Format bytes to human-readable size
1474
+ */
1475
+ formatBytes(t) {
1476
+ if (t === 0) return "0 Bytes";
1477
+ const e = 1024, i = ["Bytes", "KB", "MB", "GB", "TB"], n = Math.floor(Math.log(t) / Math.log(e));
1478
+ return `${parseFloat((t / Math.pow(e, n)).toFixed(2))} ${i[n]}`;
1479
+ }
1480
+ /**
1481
+ * Format duration to HH:MM:SS
1482
+ */
1483
+ formatDuration(t) {
1484
+ if (!isFinite(t) || t < 0) return "00:00";
1485
+ const e = Math.floor(t / 3600), i = Math.floor(t % 3600 / 60), n = Math.floor(t % 60);
1486
+ return e > 0 ? `${e.toString().padStart(2, "0")}:${i.toString().padStart(2, "0")}:${n.toString().padStart(2, "0")}` : `${i.toString().padStart(2, "0")}:${n.toString().padStart(2, "0")}`;
1487
+ }
1488
+ /**
1489
+ * Get file extension
1490
+ */
1491
+ getFileExtension(t) {
1492
+ const e = t.split(".");
1493
+ return e.length > 1 ? `.${e[e.length - 1].toLowerCase()}` : "";
1494
+ }
1495
+ // Getter properties for convenience
1496
+ get width() {
1497
+ var t;
1498
+ return ((t = this.info) == null ? void 0 : t.width) || 0;
1499
+ }
1500
+ get height() {
1501
+ var t;
1502
+ return ((t = this.info) == null ? void 0 : t.height) || 0;
1503
+ }
1504
+ get aspectRatio() {
1505
+ var t;
1506
+ return ((t = this.info) == null ? void 0 : t.aspectRatio) || "unknown";
1507
+ }
1508
+ get size() {
1509
+ var t;
1510
+ return ((t = this.info) == null ? void 0 : t.size) || 0;
1511
+ }
1512
+ get sizeInBytes() {
1513
+ var t;
1514
+ return ((t = this.info) == null ? void 0 : t.sizeInBytes) || 0;
1515
+ }
1516
+ get sizeFormatted() {
1517
+ var t;
1518
+ return ((t = this.info) == null ? void 0 : t.sizeFormatted) || "0 Bytes";
1519
+ }
1520
+ get duration() {
1521
+ var t;
1522
+ return ((t = this.info) == null ? void 0 : t.duration) || 0;
1523
+ }
1524
+ get durationInSeconds() {
1525
+ var t;
1526
+ return ((t = this.info) == null ? void 0 : t.durationInSeconds) || 0;
1527
+ }
1528
+ get durationFormatted() {
1529
+ var t;
1530
+ return ((t = this.info) == null ? void 0 : t.durationFormatted) || "00:00";
1531
+ }
1532
+ get mimeType() {
1533
+ var t;
1534
+ return ((t = this.info) == null ? void 0 : t.mimeType) || this.file.type || "video/unknown";
1535
+ }
1536
+ get fileName() {
1537
+ return this.file.name;
1538
+ }
1539
+ get fileExtension() {
1540
+ var t;
1541
+ return ((t = this.info) == null ? void 0 : t.fileExtension) || "";
1542
+ }
1543
+ get bitrate() {
1544
+ var t;
1545
+ return (t = this.info) == null ? void 0 : t.bitrate;
1546
+ }
1547
+ get quality() {
1548
+ if (!this.info) return "unknown";
1549
+ const t = this.info.height;
1550
+ return t >= 2160 ? "4K (2160p)" : t >= 1440 ? "2K (1440p)" : t >= 1080 ? "Full HD (1080p)" : t >= 720 ? "HD (720p)" : t >= 480 ? "SD (480p)" : t >= 360 ? "360p" : "Low Quality";
1551
+ }
1552
+ /**
1553
+ * Get all information as object
1554
+ */
1555
+ getInfo() {
1556
+ return this.info;
1557
+ }
1558
+ /**
1559
+ * Clean up resources
1560
+ */
1561
+ destroy() {
1562
+ this.videoElement && (this.videoElement.remove(), this.videoElement = null), this.info = null;
1563
+ }
1564
+ }
1324
1565
  const K = (c) => {
1325
1566
  const {
1326
1567
  src: t,
1327
1568
  autoplay: e,
1328
1569
  muted: i,
1329
- controls: s = !0,
1330
- poster: n,
1331
- preload: a,
1332
- theme: o,
1570
+ controls: n = !0,
1571
+ poster: o,
1572
+ preload: r,
1573
+ theme: a,
1333
1574
  s3Config: l,
1334
1575
  analytics: u,
1335
1576
  hlsConfig: m,
1336
- subtitles: $,
1337
- stickyControls: z,
1338
- onReady: k,
1339
- onPlay: E,
1340
- onPause: x,
1341
- onEnded: S,
1342
- onTimeUpdate: C,
1343
- onVolumeChange: L,
1344
- onError: T,
1345
- onLoadedMetadata: q,
1577
+ subtitles: g,
1578
+ stickyControls: v,
1579
+ onReady: S,
1580
+ onPlay: x,
1581
+ onPause: C,
1582
+ onEnded: L,
1583
+ onTimeUpdate: T,
1584
+ onVolumeChange: I,
1585
+ onError: M,
1586
+ onLoadedMetadata: R,
1346
1587
  onQualityChange: P,
1347
- style: U,
1348
- className: H,
1349
- width: g = "100%",
1350
- height: v = "500px"
1351
- } = c, w = y(null), I = y(null);
1352
- return f(() => {
1588
+ style: D,
1589
+ className: O,
1590
+ width: f = "100%",
1591
+ height: y = "500px"
1592
+ } = c, w = b(null), q = b(null);
1593
+ return E(() => {
1353
1594
  if (!w.current) return;
1354
- const D = {
1595
+ const U = {
1355
1596
  src: t,
1356
1597
  container: w.current,
1357
1598
  autoplay: e,
1358
1599
  muted: i,
1359
- controls: s,
1360
- poster: n,
1361
- preload: a,
1362
- theme: o,
1600
+ controls: n,
1601
+ poster: o,
1602
+ preload: r,
1603
+ theme: a,
1363
1604
  s3Config: l,
1364
1605
  analytics: u,
1365
1606
  hlsConfig: m,
1366
- subtitles: $,
1367
- stickyControls: z
1368
- }, d = new A(D);
1369
- return I.current = d, E && d.on("play", E), x && d.on("pause", x), S && d.on("ended", S), T && d.on("error", (h) => {
1370
- var M;
1371
- return T((M = h.data) == null ? void 0 : M.error);
1372
- }), q && d.on("loadedmetadata", q), P && d.on("qualitychange", (h) => P(h.data.level)), C && d.on("timeupdate", (h) => C(h.data.currentTime)), L && d.on("volumechange", (h) => L(h.data.volume, h.data.muted)), k && k(d), () => {
1373
- d.destroy(), I.current = null;
1607
+ subtitles: g,
1608
+ stickyControls: v
1609
+ }, d = new $(U);
1610
+ return q.current = d, x && d.on("play", x), C && d.on("pause", C), L && d.on("ended", L), M && d.on("error", (h) => {
1611
+ var B;
1612
+ return M((B = h.data) == null ? void 0 : B.error);
1613
+ }), R && d.on("loadedmetadata", R), P && d.on("qualitychange", (h) => P(h.data.level)), T && d.on("timeupdate", (h) => T(h.data.currentTime)), I && d.on("volumechange", (h) => I(h.data.volume, h.data.muted)), S && S(d), () => {
1614
+ d.destroy(), q.current = null;
1374
1615
  };
1375
- }, [t]), /* @__PURE__ */ B(
1616
+ }, [t]), /* @__PURE__ */ A(
1376
1617
  "div",
1377
1618
  {
1378
1619
  ref: w,
1379
- className: H,
1620
+ className: O,
1380
1621
  style: {
1381
- width: typeof g == "number" ? `${g}px` : g,
1382
- height: typeof v == "number" ? `${v}px` : v,
1383
- ...U
1622
+ width: typeof f == "number" ? `${f}px` : f,
1623
+ height: typeof y == "number" ? `${y}px` : y,
1624
+ ...D
1384
1625
  }
1385
1626
  }
1386
1627
  );
1387
- }, G = (c) => {
1388
- const [t, e] = b(null), [i, s] = b(null), n = y(null);
1389
- return f(() => {
1390
- if (!n.current) return;
1391
- const a = new A({
1628
+ }, J = (c) => {
1629
+ const [t, e] = k(null), [i, n] = k(null), o = b(null);
1630
+ return E(() => {
1631
+ if (!o.current) return;
1632
+ const r = new $({
1392
1633
  ...c,
1393
- container: n.current
1634
+ container: o.current
1394
1635
  });
1395
- e(a);
1396
- const o = () => {
1397
- s(a.getState());
1636
+ e(r);
1637
+ const a = () => {
1638
+ n(r.getState());
1398
1639
  };
1399
- return a.on("play", o), a.on("pause", o), a.on("timeupdate", o), a.on("volumechange", o), a.on("loadedmetadata", o), () => {
1400
- a.destroy();
1640
+ return r.on("play", a), r.on("pause", a), r.on("timeupdate", a), r.on("volumechange", a), r.on("loadedmetadata", a), () => {
1641
+ r.destroy();
1401
1642
  };
1402
1643
  }, [c.src]), {
1403
- containerRef: n,
1644
+ containerRef: o,
1404
1645
  player: t,
1405
1646
  state: i
1406
1647
  };
1407
- }, F = R.createContext({
1648
+ }, z = F.createContext({
1408
1649
  player: null,
1409
1650
  state: null
1410
- }), J = (c) => {
1411
- const { player: t, children: e } = c, [i, s] = b(t.getState());
1412
- return f(() => {
1413
- const n = () => {
1414
- s(t.getState());
1651
+ }), Z = (c) => {
1652
+ const { player: t, children: e } = c, [i, n] = k(t.getState());
1653
+ return E(() => {
1654
+ const o = () => {
1655
+ n(t.getState());
1415
1656
  };
1416
- return t.on("play", n), t.on("pause", n), t.on("timeupdate", n), t.on("volumechange", n), t.on("loadedmetadata", n), () => {
1657
+ return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
1417
1658
  };
1418
- }, [t]), /* @__PURE__ */ B(F.Provider, { value: { player: t, state: i }, children: e });
1419
- }, Z = () => {
1420
- const c = R.useContext(F);
1659
+ }, [t]), /* @__PURE__ */ A(z.Provider, { value: { player: t, state: i }, children: e });
1660
+ }, tt = () => {
1661
+ const c = F.useContext(z);
1421
1662
  if (!c.player)
1422
1663
  throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
1423
1664
  return c;
1424
1665
  };
1425
1666
  export {
1426
- _ as Analytics,
1427
- j as S3Handler,
1428
- Q as UIController,
1429
- A as WontumPlayer,
1430
- J as WontumPlayerProvider,
1667
+ N as Analytics,
1668
+ _ as S3Handler,
1669
+ W as UIController,
1670
+ G as WontumFileInfo,
1671
+ $ as WontumPlayer,
1672
+ Z as WontumPlayerProvider,
1431
1673
  K as WontumPlayerReact,
1432
- G as useWontumPlayer,
1433
- Z as useWontumPlayerContext
1674
+ J as useWontumPlayer,
1675
+ tt as useWontumPlayerContext
1434
1676
  };