@therealtinhtute/baroiplayer 1.0.1 → 1.0.3

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.
Files changed (73) hide show
  1. package/dist/context/media.js +2 -0
  2. package/dist/context/media.js.map +1 -0
  3. package/dist/context/media.mjs +15 -0
  4. package/dist/context/media.mjs.map +1 -0
  5. package/dist/context/store.js +2 -0
  6. package/dist/context/store.js.map +1 -0
  7. package/dist/context/store.mjs +5 -0
  8. package/dist/context/store.mjs.map +1 -0
  9. package/dist/context-Af84FynT.js +1179 -0
  10. package/dist/context-Af84FynT.js.map +1 -0
  11. package/dist/context-CwZnPdz0.cjs +23 -0
  12. package/dist/context-CwZnPdz0.cjs.map +1 -0
  13. package/dist/core-events-B5W_j8yU.js +480 -0
  14. package/dist/core-events-B5W_j8yU.js.map +1 -0
  15. package/dist/core-events-CN0-Vhhq.cjs +2 -0
  16. package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
  17. package/dist/core-plugins-Bq9KLany.js +696 -0
  18. package/dist/core-plugins-Bq9KLany.js.map +1 -0
  19. package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
  20. package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
  21. package/dist/core.js +37 -0
  22. package/dist/core.js.map +1 -0
  23. package/dist/core.mjs +1217 -0
  24. package/dist/core.mjs.map +1 -0
  25. package/dist/enhanced-components-CXnYiOt6.cjs +2 -0
  26. package/dist/enhanced-components-CXnYiOt6.cjs.map +1 -0
  27. package/dist/enhanced-components-Da0TSvKe.js +1073 -0
  28. package/dist/enhanced-components-Da0TSvKe.js.map +1 -0
  29. package/dist/hooks-BhW_i-9L.js +2013 -0
  30. package/dist/hooks-BhW_i-9L.js.map +1 -0
  31. package/dist/hooks-DTXeB5Z-.cjs +4 -0
  32. package/dist/hooks-DTXeB5Z-.cjs.map +1 -0
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js.map +1 -0
  35. package/dist/index.mjs.map +1 -0
  36. package/dist/minimal-components-B0bILe18.js +2002 -0
  37. package/dist/minimal-components-B0bILe18.js.map +1 -0
  38. package/dist/minimal-components-BsqodtY8.cjs +2 -0
  39. package/dist/minimal-components-BsqodtY8.cjs.map +1 -0
  40. package/dist/minimal-components.css +589 -0
  41. package/dist/mona-loading.gif +0 -0
  42. package/dist/performance-monitor--rzKTlbj.js +302 -0
  43. package/dist/performance-monitor--rzKTlbj.js.map +1 -0
  44. package/dist/performance-monitor-cjIvZE2D.cjs +2 -0
  45. package/dist/performance-monitor-cjIvZE2D.cjs.map +1 -0
  46. package/dist/src/components/AnimateLoading.tsx +1 -1
  47. package/dist/src/components/enhanced/debug-panel.tsx +1 -1
  48. package/dist/src/components/media-player.tsx +2 -2
  49. package/dist/src/components/ui/media-resource-preloader.tsx +9 -11
  50. package/dist/src/components/ui/seek-bar.tsx +1 -1
  51. package/dist/src/core/plugins/enhanced-plugin-system.ts +14 -8
  52. package/dist/src/core/providers/enhanced-hls-provider.ts +22 -53
  53. package/dist/src/hooks/use-enhanced-media-player.ts +19 -2
  54. package/dist/src/types/index.ts +40 -5
  55. package/dist/styles/minimal-player.css +589 -0
  56. package/dist/utils-Db13763z.cjs +9 -0
  57. package/dist/utils-Db13763z.cjs.map +1 -0
  58. package/dist/utils-nTO4AnHo.js +2809 -0
  59. package/dist/utils-nTO4AnHo.js.map +1 -0
  60. package/dist/utils.js +2 -0
  61. package/dist/utils.js.map +1 -0
  62. package/dist/utils.mjs +7 -0
  63. package/dist/utils.mjs.map +1 -0
  64. package/package.json +3 -1
  65. package/src/components/AnimateLoading.tsx +1 -1
  66. package/src/components/enhanced/debug-panel.tsx +1 -1
  67. package/src/components/media-player.tsx +2 -2
  68. package/src/components/ui/media-resource-preloader.tsx +9 -11
  69. package/src/components/ui/seek-bar.tsx +1 -1
  70. package/src/core/plugins/enhanced-plugin-system.ts +14 -8
  71. package/src/core/providers/enhanced-hls-provider.ts +22 -53
  72. package/src/hooks/use-enhanced-media-player.ts +19 -2
  73. package/src/types/index.ts +40 -5
@@ -0,0 +1,2013 @@
1
+ import * as re from "react";
2
+ import N, { useEffect as q, useOptimistic as ce, useRef as W, useTransition as le, useCallback as A, useMemo as ue, useState as Q } from "react";
3
+ import { c as H, d as pe, e as j, M as K } from "./context-Af84FynT.js";
4
+ import { s as ve } from "./utils-nTO4AnHo.js";
5
+ function Ie({ enabled: e = !0, state: t, controls: n, seekStep: s = 10, volumeStep: u = 0.1 }) {
6
+ const o = (a) => {
7
+ if (!e)
8
+ return;
9
+ const d = a.target;
10
+ if (!(d.tagName === "INPUT" || d.tagName === "TEXTAREA" || d.contentEditable === "true"))
11
+ switch (a.code) {
12
+ case "Space":
13
+ case "KeyK":
14
+ a.preventDefault(), n.toggle();
15
+ break;
16
+ case "KeyM":
17
+ a.preventDefault(), n.toggleMute();
18
+ break;
19
+ case "KeyF":
20
+ a.preventDefault(), n.toggleFullscreen();
21
+ break;
22
+ case "ArrowLeft":
23
+ a.preventDefault(), n.seek(Math.max(0, t.currentTime - s));
24
+ break;
25
+ case "ArrowRight":
26
+ a.preventDefault(), n.seek(Math.min(t.duration, t.currentTime + s));
27
+ break;
28
+ case "ArrowUp":
29
+ a.preventDefault(), n.setVolume(Math.min(1, t.volume + u));
30
+ break;
31
+ case "ArrowDown":
32
+ a.preventDefault(), n.setVolume(Math.max(0, t.volume - u));
33
+ break;
34
+ case "Digit0":
35
+ case "Digit1":
36
+ case "Digit2":
37
+ case "Digit3":
38
+ case "Digit4":
39
+ case "Digit5":
40
+ case "Digit6":
41
+ case "Digit7":
42
+ case "Digit8":
43
+ case "Digit9":
44
+ a.preventDefault();
45
+ const D = parseInt(a.code.replace("Digit", ""), 10) / 10;
46
+ n.seek(t.duration * D);
47
+ break;
48
+ case "Home":
49
+ a.preventDefault(), n.seek(0);
50
+ break;
51
+ case "End":
52
+ a.preventDefault(), n.seek(t.duration);
53
+ break;
54
+ }
55
+ };
56
+ return q(() => {
57
+ if (e)
58
+ return document.addEventListener("keydown", o), () => {
59
+ document.removeEventListener("keydown", o);
60
+ };
61
+ }, [e, o]), {
62
+ handleKeyDown: o
63
+ };
64
+ }
65
+ function ye(e, t) {
66
+ if (!t.optimistic)
67
+ return e;
68
+ switch (t.type) {
69
+ case "PLAY":
70
+ return { ...e, isPlaying: !0, error: null };
71
+ case "PAUSE":
72
+ return { ...e, isPlaying: !1 };
73
+ case "SEEK":
74
+ return { ...e, currentTime: t.detail };
75
+ case "SET_VOLUME":
76
+ return { ...e, volume: Math.max(0, Math.min(1, t.detail)) };
77
+ case "MUTE":
78
+ return { ...e, isMuted: !0 };
79
+ case "UNMUTE":
80
+ return { ...e, isMuted: !1 };
81
+ case "TOGGLE_MUTE":
82
+ return { ...e, isMuted: !e.isMuted };
83
+ case "ENTER_FULLSCREEN":
84
+ return { ...e, isFullscreen: !0 };
85
+ case "EXIT_FULLSCREEN":
86
+ return { ...e, isFullscreen: !1 };
87
+ case "SET_PLAYBACK_RATE":
88
+ return { ...e, playbackRate: t.detail };
89
+ case "TOGGLE_SUBTITLES":
90
+ return { ...e, subtitlesShowing: !e.subtitlesShowing };
91
+ case "PREVIEW_TIME":
92
+ return { ...e, previewTime: t.detail };
93
+ case "CLEAR_PREVIEW":
94
+ return {
95
+ ...e,
96
+ previewTime: null,
97
+ previewImage: null,
98
+ previewCoords: null
99
+ };
100
+ default:
101
+ return e;
102
+ }
103
+ }
104
+ function Ee(e) {
105
+ const t = N.useSyncExternalStore(e.subscribe, e.getState, e.getState), [n, s] = ce(t, ye), u = N.useCallback(async (d) => {
106
+ d.optimistic && s(d), await e.dispatchOptimistic(d);
107
+ }, [e, s]), o = N.useMemo(() => ({
108
+ // Play/Pause with immediate feedback
109
+ togglePlayPause: async () => {
110
+ const d = {
111
+ type: n.isPlaying ? "PAUSE" : "PLAY",
112
+ optimistic: !0,
113
+ timestamp: Date.now()
114
+ };
115
+ await u(d);
116
+ },
117
+ // Volume control with immediate slider feedback
118
+ setVolumeOptimistic: async (d) => {
119
+ const S = {
120
+ type: "SET_VOLUME",
121
+ detail: Math.max(0, Math.min(1, d)),
122
+ optimistic: !0,
123
+ timestamp: Date.now()
124
+ };
125
+ await u(S);
126
+ },
127
+ // Seek with immediate scrub feedback
128
+ seekOptimistic: async (d) => {
129
+ const S = {
130
+ type: "SEEK",
131
+ detail: d,
132
+ optimistic: !0,
133
+ timestamp: Date.now()
134
+ };
135
+ await u(S);
136
+ },
137
+ // Mute toggle with immediate icon change
138
+ toggleMuteOptimistic: async () => {
139
+ const d = {
140
+ type: "TOGGLE_MUTE",
141
+ optimistic: !0,
142
+ timestamp: Date.now()
143
+ };
144
+ await u(d);
145
+ },
146
+ // Fullscreen toggle with immediate layout change
147
+ toggleFullscreenOptimistic: async () => {
148
+ const d = {
149
+ type: n.isFullscreen ? "EXIT_FULLSCREEN" : "ENTER_FULLSCREEN",
150
+ optimistic: !0,
151
+ timestamp: Date.now()
152
+ };
153
+ await u(d);
154
+ },
155
+ // Playback rate with immediate feedback
156
+ setPlaybackRateOptimistic: async (d) => {
157
+ const S = {
158
+ type: "SET_PLAYBACK_RATE",
159
+ detail: d,
160
+ optimistic: !0,
161
+ timestamp: Date.now()
162
+ };
163
+ await u(S);
164
+ },
165
+ // Subtitle toggle with immediate visibility change
166
+ toggleSubtitlesOptimistic: async () => {
167
+ const d = {
168
+ type: "TOGGLE_SUBTITLES",
169
+ optimistic: !0,
170
+ timestamp: Date.now()
171
+ };
172
+ await u(d);
173
+ }
174
+ }), [n, u]), a = N.useMemo(() => ({
175
+ isPlaying: n.isPlaying,
176
+ currentTime: n.currentTime,
177
+ volume: n.volume,
178
+ isMuted: n.isMuted,
179
+ isFullscreen: n.isFullscreen,
180
+ playbackRate: n.playbackRate,
181
+ subtitlesShowing: n.subtitlesShowing,
182
+ previewTime: n.previewTime,
183
+ // Computed values
184
+ progress: n.duration > 0 ? n.currentTime / n.duration : 0,
185
+ formattedTime: me(n.currentTime),
186
+ formattedDuration: me(n.duration),
187
+ // State checks
188
+ canPlay: !n.isLoading && !n.error,
189
+ hasError: !!n.error,
190
+ isBuffering: n.isLoading
191
+ }), [n]);
192
+ return {
193
+ state: n,
194
+ actualState: t,
195
+ ...a,
196
+ ...o,
197
+ dispatchOptimistic: u
198
+ };
199
+ }
200
+ function me(e) {
201
+ if (!e || !isFinite(e))
202
+ return "0:00";
203
+ const t = Math.floor(e / 60), n = Math.floor(e % 60), s = Math.floor(t / 60);
204
+ return s > 0 ? `${s}:${String(t % 60).padStart(2, "0")}:${String(n).padStart(2, "0")}` : `${t}:${String(n).padStart(2, "0")}`;
205
+ }
206
+ function $(e, t) {
207
+ return ((n, s = !1) => {
208
+ const u = {
209
+ type: e,
210
+ detail: n,
211
+ optimistic: s,
212
+ timestamp: Date.now()
213
+ };
214
+ return s ? t.dispatchOptimistic(u) : (t.dispatch(u), Promise.resolve());
215
+ });
216
+ }
217
+ function we(e) {
218
+ const [t, n] = N.useState(e.getActionState());
219
+ return N.useEffect(() => e.subscribe(() => {
220
+ const u = e.getActionState();
221
+ n((o) => JSON.stringify(o) !== JSON.stringify(u) ? u : o);
222
+ }), [e]), t;
223
+ }
224
+ function Te(e) {
225
+ const t = N.useMemo(() => ({
226
+ // Playback actions
227
+ play: $(H.PLAY, e),
228
+ pause: $(H.PAUSE, e),
229
+ seek: $(H.SEEK, e),
230
+ // Volume actions
231
+ setVolume: $(H.SET_VOLUME, e),
232
+ mute: $(H.MUTE, e),
233
+ unmute: $(H.UNMUTE, e),
234
+ toggleMute: $(H.TOGGLE_MUTE, e),
235
+ // Media state actions
236
+ setDuration: $(H.SET_DURATION, e),
237
+ setCurrentTime: $(H.SET_CURRENT_TIME, e),
238
+ setBuffered: $(H.SET_BUFFERED, e),
239
+ setLoading: $(H.SET_LOADING, e),
240
+ setError: $(H.SET_ERROR, e),
241
+ // Display actions
242
+ enterFullscreen: $(H.ENTER_FULLSCREEN, e),
243
+ exitFullscreen: $(H.EXIT_FULLSCREEN, e),
244
+ enterPiP: $(H.ENTER_PIP, e),
245
+ exitPiP: $(H.EXIT_PIP, e),
246
+ // Advanced actions
247
+ setPlaybackRate: $(H.SET_PLAYBACK_RATE, e),
248
+ setSubtitleTrack: $(H.SET_SUBTITLE_TRACK, e),
249
+ setRendition: $(H.SET_RENDITION, e),
250
+ toggleSubtitles: $(H.TOGGLE_SUBTITLES, e),
251
+ // Preview actions
252
+ previewTime: $(H.PREVIEW_TIME, e),
253
+ clearPreview: $(H.CLEAR_PREVIEW, e)
254
+ }), [e]), n = we(e), s = N.useMemo(() => ({
255
+ // These actions benefit from immediate UI feedback
256
+ togglePlayPause: async (o) => {
257
+ o ? await t.pause(!0) : await t.play(!0);
258
+ },
259
+ seekWithPreview: async (o) => {
260
+ await t.previewTime(o, !0), await t.seek(o, !0);
261
+ },
262
+ adjustVolume: async (o, a) => {
263
+ const d = Math.max(0, Math.min(1, a + o));
264
+ await t.setVolume(d, !0);
265
+ },
266
+ toggleFullscreenOptimistic: async (o) => {
267
+ o ? await t.exitFullscreen(!0) : await t.enterFullscreen(!0);
268
+ }
269
+ }), [t]), u = N.useCallback(async () => {
270
+ const { lastAction: o } = n;
271
+ o && n.error && await e.dispatchOptimistic({
272
+ ...o,
273
+ retryCount: (o.retryCount || 0) + 1
274
+ });
275
+ }, [e, n]);
276
+ return {
277
+ ...t,
278
+ ...s,
279
+ actionState: n,
280
+ retryLastAction: u,
281
+ isLoading: n.pending,
282
+ hasError: !!n.error,
283
+ errorMessage: n.error,
284
+ retryCount: n.retryCount
285
+ };
286
+ }
287
+ function Oe(e) {
288
+ const t = W(null), n = W(null), [s, u] = le(), [o, a] = le();
289
+ N.useRef(0);
290
+ const d = N.useRef(0), S = N.useRef(0);
291
+ W();
292
+ const D = W(0), R = pe(), g = "getOptimisticState" in R, r = j((i) => i.isPlaying), y = j((i) => i.currentTime), p = j((i) => i.duration), l = j((i) => i.volume), v = j((i) => i.isMuted), M = j((i) => i.isLoading), h = j((i) => i.isBuffering), c = j((i) => i.error), T = j((i) => i.buffered), E = j((i) => i.isFullscreen), b = R, w = g ? Ee(b) : null, m = g ? Te(b) : null, [z, F] = N.useState({
293
+ frameRate: 0,
294
+ averageRenderTime: 0,
295
+ droppedFrames: 0,
296
+ bufferHealth: 0
297
+ }), [O, P] = ce(l, (i, k) => Math.max(0, Math.min(1, k)));
298
+ ce(y, (i, k) => Math.max(0, Math.min(p || 0, k))), q(() => {
299
+ const i = t.current;
300
+ if (!i)
301
+ return;
302
+ const k = {
303
+ volume: e.volume,
304
+ muted: e.muted,
305
+ autoplay: e.autoPlay,
306
+ loop: e.loop,
307
+ preload: e.preload,
308
+ crossOrigin: e.crossOrigin
309
+ };
310
+ Object.entries(k).forEach(([B, Y]) => {
311
+ Y !== void 0 && (i[B] = Y);
312
+ }), i.setAttribute("preload", e.preloadStrategy === "eager" ? "auto" : "metadata"), e.bufferingStrategy === "aggressive" && i.setAttribute("buffered", "auto"), i instanceof HTMLVideoElement && (i.style.willChange = "transform", i.style.transform = "translateZ(0)");
313
+ }, [
314
+ e.volume,
315
+ e.muted,
316
+ e.autoPlay,
317
+ e.loop,
318
+ e.preload,
319
+ e.crossOrigin,
320
+ e.preloadStrategy,
321
+ e.bufferingStrategy
322
+ ]);
323
+ const L = A(() => {
324
+ const i = t.current;
325
+ if (!i)
326
+ return;
327
+ const k = performance.now();
328
+ if (e.enableTimeUpdateThrottling !== !1) {
329
+ if (k - D.current < (e.timeUpdateThrottleMs || 100))
330
+ return;
331
+ D.current = k;
332
+ }
333
+ u(() => {
334
+ g && m && m.setCurrentTime(i.currentTime);
335
+ });
336
+ }, [e.enableTimeUpdateThrottling, e.timeUpdateThrottleMs, g, m]), I = A(() => {
337
+ u(() => {
338
+ g && m && m.play(!0);
339
+ }), e.onPlay?.();
340
+ }, [g, m, e.onPlay]), U = A(() => {
341
+ u(() => {
342
+ g && m && m.pause(!0);
343
+ }), e.onPause?.();
344
+ }, [g, m, e.onPause]), _ = A(() => {
345
+ const i = t.current;
346
+ i && u(() => {
347
+ g && m && (m.setVolume(i.volume, !0), i.muted ? m.mute(!0) : m.unmute(!0));
348
+ });
349
+ }, [g, m]), C = A(() => {
350
+ a(() => {
351
+ });
352
+ }, []), ee = A(() => {
353
+ }, []), f = A(() => {
354
+ const i = t.current;
355
+ i && u(() => {
356
+ g && m && m.setBuffered(i.buffered);
357
+ });
358
+ }, [g, m]), V = A(() => {
359
+ const i = performance.now();
360
+ if (i - S.current > 0 && (d.current++, d.current >= 60)) {
361
+ const B = Math.round(d.current * 1e3 / (i - S.current));
362
+ F((Y) => ({
363
+ ...Y,
364
+ frameRate: B,
365
+ droppedFrames: Math.max(0, 60 - B)
366
+ })), d.current = 0, S.current = i;
367
+ }
368
+ }, []);
369
+ q(() => {
370
+ const i = t.current;
371
+ if (!i)
372
+ return;
373
+ const k = [
374
+ { event: "timeupdate", handler: L, passive: !0 },
375
+ { event: "play", handler: I },
376
+ { event: "pause", handler: U },
377
+ { event: "volumechange", handler: _ },
378
+ { event: "seeking", handler: C },
379
+ { event: "seeked", handler: ee },
380
+ { event: "progress", handler: f, passive: !0 },
381
+ { event: "loadedmetadata", handler: () => V() },
382
+ { event: "loadeddata", handler: () => V() }
383
+ ];
384
+ k.forEach(({ event: te, handler: ne, passive: ie }) => {
385
+ const oe = ie ? { passive: !0 } : {};
386
+ i.addEventListener(te, ne, oe);
387
+ });
388
+ let B;
389
+ const Y = () => {
390
+ V(), B = requestAnimationFrame(Y);
391
+ };
392
+ return e.enablePerformanceMonitoring && Y(), () => {
393
+ k.forEach(({ event: te, handler: ne }) => {
394
+ i.removeEventListener(te, ne);
395
+ }), B && cancelAnimationFrame(B);
396
+ };
397
+ }, [
398
+ L,
399
+ I,
400
+ U,
401
+ _,
402
+ C,
403
+ ee,
404
+ f,
405
+ V,
406
+ e.enablePerformanceMonitoring
407
+ ]);
408
+ const se = ue(() => {
409
+ const i = async () => {
410
+ const x = t.current;
411
+ if (x)
412
+ if (g && m)
413
+ await m.play(!0);
414
+ else
415
+ try {
416
+ await x.play();
417
+ } catch (X) {
418
+ console.error("Failed to play media:", X);
419
+ }
420
+ }, k = () => {
421
+ const x = t.current;
422
+ x && (g && m ? m.pause(!0) : x.pause());
423
+ };
424
+ return {
425
+ play: i,
426
+ pause: k,
427
+ toggle: () => {
428
+ r ? k() : i();
429
+ },
430
+ seek: (x) => {
431
+ const X = t.current;
432
+ if (!X)
433
+ return;
434
+ const Z = Math.max(0, Math.min(x, p || 0));
435
+ g && m ? a(() => {
436
+ m.seek(Z, !0);
437
+ }) : X.currentTime = Z;
438
+ },
439
+ setVolume: (x) => {
440
+ const X = t.current;
441
+ if (!X)
442
+ return;
443
+ const Z = Math.max(0, Math.min(1, x));
444
+ g && m ? (P(Z), u(() => {
445
+ m.setVolume(Z, !0);
446
+ })) : X.volume = Z;
447
+ },
448
+ toggleMute: () => {
449
+ const x = t.current;
450
+ x && (g && m ? m.toggleMute(!0) : x.muted = !x.muted);
451
+ },
452
+ enterFullscreen: async () => {
453
+ const x = n.current;
454
+ if (!(!x || !document.fullscreenEnabled))
455
+ try {
456
+ await x.requestFullscreen(), g && m && m.enterFullscreen(!0);
457
+ } catch (X) {
458
+ console.error("Failed to enter fullscreen:", X);
459
+ }
460
+ },
461
+ exitFullscreen: async () => {
462
+ if (document.fullscreenElement)
463
+ try {
464
+ await document.exitFullscreen(), g && m && m.exitFullscreen(!0);
465
+ } catch (x) {
466
+ console.error("Failed to exit fullscreen:", x);
467
+ }
468
+ }
469
+ };
470
+ }, [
471
+ r,
472
+ p,
473
+ g,
474
+ m,
475
+ u,
476
+ a,
477
+ P
478
+ ]), ae = ue(() => ({
479
+ isPlaying: w?.isPlaying ?? r,
480
+ currentTime: w?.currentTime ?? y,
481
+ duration: w?.duration ?? p,
482
+ volume: w?.volume ?? O,
483
+ isMuted: w?.isMuted ?? v,
484
+ isLoading: w?.isBuffering ?? M,
485
+ isBuffering: w?.isBuffering ?? h,
486
+ error: w?.error ?? c,
487
+ buffered: w?.buffered ?? T,
488
+ isFullscreen: w?.isFullscreen ?? E,
489
+ progress: p > 0 ? y / p : 0,
490
+ isTransitioning: s || o,
491
+ canPlay: !M && !h && !c
492
+ }), [
493
+ w,
494
+ r,
495
+ y,
496
+ p,
497
+ O,
498
+ v,
499
+ M,
500
+ h,
501
+ c,
502
+ T,
503
+ E,
504
+ s,
505
+ o
506
+ ]);
507
+ return {
508
+ // Refs
509
+ mediaRef: t,
510
+ containerRef: n,
511
+ // State
512
+ state: ae,
513
+ actualState: w?.actualState,
514
+ // Controls
515
+ controls: se,
516
+ // Performance metrics
517
+ performanceMetrics: z,
518
+ isTransitioning: s || o,
519
+ // Enhanced features
520
+ actions: w?.actions,
521
+ actionState: w?.actionState,
522
+ // Optimistic features
523
+ optimisticState: w,
524
+ isEnhanced: g
525
+ };
526
+ }
527
+ function Ue(e = {}) {
528
+ const {
529
+ maxMemoryUsage: t = 100,
530
+ // 100MB default
531
+ cleanupInterval: n = 3e4,
532
+ // 30 seconds default
533
+ enableGC: s = !0,
534
+ monitorMemory: u = !0
535
+ } = e;
536
+ W();
537
+ const o = W(/* @__PURE__ */ new Set()), a = W(/* @__PURE__ */ new Map()), d = W(/* @__PURE__ */ new Set()), S = W(/* @__PURE__ */ new Set()), D = A(() => {
538
+ if (typeof window > "u" || !("memory" in performance))
539
+ return { used: 0, total: 0, limit: 0 };
540
+ const h = performance.memory;
541
+ return {
542
+ used: h.usedJSHeapSize,
543
+ total: h.totalJSHeapSize,
544
+ limit: h.jsHeapSizeLimit
545
+ };
546
+ }, []), [R, g] = N.useState({
547
+ used: 0,
548
+ total: 0,
549
+ limit: 0,
550
+ usage: 0,
551
+ isHighUsage: !1
552
+ });
553
+ q(() => {
554
+ if (!u)
555
+ return;
556
+ const h = () => {
557
+ const T = D(), E = T.used / 1024 / 1024, b = E > t;
558
+ g({
559
+ ...T,
560
+ usage: E,
561
+ isHighUsage: b
562
+ }), b && s && r();
563
+ };
564
+ h();
565
+ const c = p(h, n);
566
+ return d.current.add(c), () => {
567
+ clearInterval(c), d.current.delete(c);
568
+ };
569
+ }, [u, D, t, s, n]);
570
+ const r = A(() => {
571
+ d.current.forEach((h) => {
572
+ clearTimeout(h);
573
+ }), d.current.clear(), S.current.forEach((h) => {
574
+ cancelAnimationFrame(h);
575
+ }), S.current.clear(), o.current.forEach((h) => {
576
+ h.disconnect();
577
+ }), o.current.clear(), a.current.forEach((h, c) => {
578
+ h.forEach(({ event: T, handler: E }) => {
579
+ c.removeEventListener(T, E);
580
+ });
581
+ }), a.current.clear(), s && "gc" in window && window.gc();
582
+ }, [s]), y = A((h, c, T, E) => (h.addEventListener(c, T, E), a.current.has(h) || a.current.set(h, []), a.current.get(h).push({ event: c, handler: T }), () => {
583
+ h.removeEventListener(c, T);
584
+ const b = a.current.get(h);
585
+ if (b) {
586
+ const w = b.findIndex((m) => m.event === c && m.handler === T);
587
+ w > -1 && b.splice(w, 1), b.length === 0 && a.current.delete(h);
588
+ }
589
+ }), []), p = A((h, c) => {
590
+ const T = p(h, c);
591
+ return d.current.add(T), () => {
592
+ clearInterval(T), d.current.delete(T);
593
+ };
594
+ }, []), l = A((h, c) => {
595
+ const T = l(h, c);
596
+ return d.current.add(T), () => {
597
+ clearTimeout(T), d.current.delete(T);
598
+ };
599
+ }, []), v = A((h) => {
600
+ const c = v(h);
601
+ return S.current.add(c), () => {
602
+ cancelAnimationFrame(c), S.current.delete(c);
603
+ };
604
+ }, []), M = A((h) => (o.current.add(h), () => {
605
+ h.disconnect(), o.current.delete(h);
606
+ }), []);
607
+ return q(() => () => {
608
+ r();
609
+ }, [r]), {
610
+ // Memory stats
611
+ memoryStats: R,
612
+ getMemoryUsage: D,
613
+ // Cleanup functions
614
+ performCleanup: r,
615
+ // Safe API functions
616
+ addEventListener: y,
617
+ setInterval: p,
618
+ setTimeout: l,
619
+ requestAnimationFrame: v,
620
+ addObserver: M,
621
+ // Utilities
622
+ formatBytes: (h) => {
623
+ if (h === 0)
624
+ return "0 Bytes";
625
+ const c = 1024, T = ["Bytes", "KB", "MB", "GB"], E = Math.floor(Math.log(h) / Math.log(c));
626
+ return parseFloat((h / Math.pow(c, E)).toFixed(2)) + " " + T[E];
627
+ }
628
+ };
629
+ }
630
+ function be({
631
+ enabled: e = !0,
632
+ state: t,
633
+ controls: n,
634
+ seekStep: s = 10,
635
+ volumeStep: u = 0.1
636
+ }) {
637
+ const o = (a) => {
638
+ if (!e) return;
639
+ const d = a.target;
640
+ if (!(d.tagName === "INPUT" || d.tagName === "TEXTAREA" || d.contentEditable === "true"))
641
+ switch (a.code) {
642
+ case "Space":
643
+ case "KeyK":
644
+ a.preventDefault(), n.toggle();
645
+ break;
646
+ case "KeyM":
647
+ a.preventDefault(), n.toggleMute();
648
+ break;
649
+ case "KeyF":
650
+ a.preventDefault(), n.toggleFullscreen();
651
+ break;
652
+ case "ArrowLeft":
653
+ a.preventDefault(), n.seek(Math.max(0, t.currentTime - s));
654
+ break;
655
+ case "ArrowRight":
656
+ a.preventDefault(), n.seek(Math.min(t.duration, t.currentTime + s));
657
+ break;
658
+ case "ArrowUp":
659
+ a.preventDefault(), n.setVolume(Math.min(1, t.volume + u));
660
+ break;
661
+ case "ArrowDown":
662
+ a.preventDefault(), n.setVolume(Math.max(0, t.volume - u));
663
+ break;
664
+ case "Digit0":
665
+ case "Digit1":
666
+ case "Digit2":
667
+ case "Digit3":
668
+ case "Digit4":
669
+ case "Digit5":
670
+ case "Digit6":
671
+ case "Digit7":
672
+ case "Digit8":
673
+ case "Digit9":
674
+ a.preventDefault();
675
+ const D = parseInt(a.code.replace("Digit", ""), 10) / 10;
676
+ n.seek(t.duration * D);
677
+ break;
678
+ case "Home":
679
+ a.preventDefault(), n.seek(0);
680
+ break;
681
+ case "End":
682
+ a.preventDefault(), n.seek(t.duration);
683
+ break;
684
+ }
685
+ };
686
+ return q(() => {
687
+ if (e)
688
+ return document.addEventListener("keydown", o), () => {
689
+ document.removeEventListener("keydown", o);
690
+ };
691
+ }, [e, o]), {
692
+ handleKeyDown: o
693
+ };
694
+ }
695
+ const Ve = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
696
+ __proto__: null,
697
+ useKeyboardControls: be
698
+ }, Symbol.toStringTag, { value: "Module" }));
699
+ function G(e, t) {
700
+ return ((n, s = !1) => {
701
+ const u = {
702
+ type: e,
703
+ detail: n,
704
+ optimistic: s,
705
+ timestamp: Date.now()
706
+ };
707
+ return s ? t.dispatchOptimistic(u) : (t.dispatch(u), Promise.resolve());
708
+ });
709
+ }
710
+ function Se(e) {
711
+ const [t, n] = N.useState(e.getActionState());
712
+ return N.useEffect(() => e.subscribe(() => {
713
+ const u = e.getActionState();
714
+ n(
715
+ (o) => JSON.stringify(o) !== JSON.stringify(u) ? u : o
716
+ );
717
+ }), [e]), t;
718
+ }
719
+ function _e(e) {
720
+ const t = N.useMemo(() => ({
721
+ // Playback actions
722
+ play: G(K.PLAY, e),
723
+ pause: G(K.PAUSE, e),
724
+ seek: G(K.SEEK, e),
725
+ // Volume actions
726
+ setVolume: G(K.SET_VOLUME, e),
727
+ mute: G(K.MUTE, e),
728
+ unmute: G(K.UNMUTE, e),
729
+ toggleMute: G(K.TOGGLE_MUTE, e),
730
+ // Media state actions
731
+ setDuration: G(K.SET_DURATION, e),
732
+ setCurrentTime: G(K.SET_CURRENT_TIME, e),
733
+ setBuffered: G(K.SET_BUFFERED, e),
734
+ setLoading: G(K.SET_LOADING, e),
735
+ setError: G(K.SET_ERROR, e),
736
+ // Display actions
737
+ enterFullscreen: G(K.ENTER_FULLSCREEN, e),
738
+ exitFullscreen: G(K.EXIT_FULLSCREEN, e),
739
+ enterPiP: G(K.ENTER_PIP, e),
740
+ exitPiP: G(K.EXIT_PIP, e),
741
+ // Advanced actions
742
+ setPlaybackRate: G(K.SET_PLAYBACK_RATE, e),
743
+ setSubtitleTrack: G(K.SET_SUBTITLE_TRACK, e),
744
+ setRendition: G(K.SET_RENDITION, e),
745
+ toggleSubtitles: G(K.TOGGLE_SUBTITLES, e),
746
+ // Preview actions
747
+ previewTime: G(K.PREVIEW_TIME, e),
748
+ clearPreview: G(K.CLEAR_PREVIEW, e)
749
+ }), [e]), n = Se(e), s = N.useMemo(() => ({
750
+ // These actions benefit from immediate UI feedback
751
+ togglePlayPause: async (o) => {
752
+ o ? await t.pause(!0) : await t.play(!0);
753
+ },
754
+ seekWithPreview: async (o) => {
755
+ await t.previewTime(o, !0), await t.seek(o, !0);
756
+ },
757
+ adjustVolume: async (o, a) => {
758
+ const d = Math.max(0, Math.min(1, a + o));
759
+ await t.setVolume(d, !0);
760
+ },
761
+ toggleFullscreenOptimistic: async (o) => {
762
+ o ? await t.exitFullscreen(!0) : await t.enterFullscreen(!0);
763
+ }
764
+ }), [t]), u = N.useCallback(async () => {
765
+ const { lastAction: o } = n;
766
+ o && n.error && await e.dispatchOptimistic({
767
+ ...o,
768
+ retryCount: (o.retryCount || 0) + 1
769
+ });
770
+ }, [e, n]);
771
+ return {
772
+ ...t,
773
+ ...s,
774
+ actionState: n,
775
+ retryLastAction: u,
776
+ isLoading: n.pending,
777
+ hasError: !!n.error,
778
+ errorMessage: n.error,
779
+ retryCount: n.retryCount
780
+ };
781
+ }
782
+ function Me() {
783
+ const [e, t] = Q({
784
+ isPlaying: !1,
785
+ currentTime: 0,
786
+ duration: 0,
787
+ volume: 1,
788
+ isMuted: !1,
789
+ isLoading: !1,
790
+ isFullscreen: !1,
791
+ error: null,
792
+ buffered: null
793
+ }), n = (r) => {
794
+ t((y) => ({ ...y, ...r }));
795
+ };
796
+ return {
797
+ state: e,
798
+ updateState: n,
799
+ setPlaying: (r) => {
800
+ n({ isPlaying: r });
801
+ },
802
+ setCurrentTime: (r) => {
803
+ n({ currentTime: r });
804
+ },
805
+ setDuration: (r) => {
806
+ n({ duration: r });
807
+ },
808
+ setVolume: (r) => {
809
+ n({ volume: Math.max(0, Math.min(1, r)) });
810
+ },
811
+ setMuted: (r) => {
812
+ n({ isMuted: r });
813
+ },
814
+ setLoading: (r) => {
815
+ n({ isLoading: r });
816
+ },
817
+ setFullscreen: (r) => {
818
+ n({ isFullscreen: r });
819
+ },
820
+ setError: (r) => {
821
+ n({ error: r });
822
+ },
823
+ setBuffered: (r) => {
824
+ n({ buffered: r });
825
+ }
826
+ };
827
+ }
828
+ function Le(e) {
829
+ const t = W(null), n = W(null), {
830
+ state: s,
831
+ setPlaying: u,
832
+ setCurrentTime: o,
833
+ setDuration: a,
834
+ setVolume: d,
835
+ setMuted: S,
836
+ setLoading: D,
837
+ setFullscreen: R,
838
+ setError: g,
839
+ setBuffered: r
840
+ } = Me();
841
+ q(() => {
842
+ const f = t.current;
843
+ f && (e.volume !== void 0 && (f.volume = e.volume, d(e.volume)), e.muted !== void 0 && (f.muted = e.muted, S(e.muted)), e.autoPlay !== void 0 && (f.autoplay = e.autoPlay), e.loop !== void 0 && (f.loop = e.loop), e.preload !== void 0 && (f.preload = e.preload), e.crossOrigin !== void 0 && (f.crossOrigin = e.crossOrigin));
844
+ }, [e, d, S]);
845
+ const y = () => {
846
+ u(!0), e.onPlay?.();
847
+ }, p = () => {
848
+ u(!1), e.onPause?.();
849
+ }, l = () => {
850
+ const f = t.current;
851
+ f && (o(f.currentTime), e.onTimeUpdate?.(f.currentTime));
852
+ }, v = () => {
853
+ const f = t.current;
854
+ f && (a(f.duration), e.onDurationChange?.(f.duration));
855
+ }, M = () => {
856
+ const f = t.current;
857
+ f && (d(f.volume), S(f.muted), e.onVolumeChange?.(f.volume));
858
+ }, h = () => {
859
+ D(!0), g(null), e.onLoadStart?.();
860
+ }, c = () => {
861
+ D(!1), e.onLoadedData?.();
862
+ }, T = () => {
863
+ const f = t.current;
864
+ if (!f) return;
865
+ const V = f.error?.message || "An error occurred while loading the media";
866
+ g(V), D(!1), e.onError?.(V);
867
+ }, E = () => {
868
+ u(!1), e.onEnded?.();
869
+ }, b = () => {
870
+ const f = t.current;
871
+ f && r(f.buffered);
872
+ };
873
+ q(() => {
874
+ const f = t.current;
875
+ if (f)
876
+ return f.addEventListener("play", y), f.addEventListener("pause", p), f.addEventListener("timeupdate", l), f.addEventListener("durationchange", v), f.addEventListener("volumechange", M), f.addEventListener("loadstart", h), f.addEventListener("loadeddata", c), f.addEventListener("error", T), f.addEventListener("ended", E), f.addEventListener("progress", b), () => {
877
+ f.removeEventListener("play", y), f.removeEventListener("pause", p), f.removeEventListener("timeupdate", l), f.removeEventListener("durationchange", v), f.removeEventListener("volumechange", M), f.removeEventListener("loadstart", h), f.removeEventListener("loadeddata", c), f.removeEventListener("error", T), f.removeEventListener("ended", E), f.removeEventListener("progress", b);
878
+ };
879
+ }, [
880
+ y,
881
+ p,
882
+ l,
883
+ v,
884
+ M,
885
+ h,
886
+ c,
887
+ T,
888
+ E,
889
+ b
890
+ ]);
891
+ const w = async () => {
892
+ const f = t.current;
893
+ if (f)
894
+ try {
895
+ await f.play();
896
+ } catch (V) {
897
+ console.error("Failed to play media:", V), g("Failed to play media");
898
+ }
899
+ }, m = () => {
900
+ const f = t.current;
901
+ f && f.pause();
902
+ }, z = () => {
903
+ s.isPlaying ? m() : w();
904
+ }, F = (f) => {
905
+ const V = t.current;
906
+ V && (V.currentTime = Math.max(0, Math.min(f, V.duration || 0)));
907
+ }, O = (f) => {
908
+ const V = t.current;
909
+ if (!V) return;
910
+ const se = Math.max(0, Math.min(1, f));
911
+ V.volume = se;
912
+ }, P = () => {
913
+ const f = t.current;
914
+ f && (f.muted = !0);
915
+ }, L = () => {
916
+ const f = t.current;
917
+ f && (f.muted = !1);
918
+ }, I = () => {
919
+ const f = t.current;
920
+ f && (f.muted = !f.muted);
921
+ }, U = async () => {
922
+ const f = n.current;
923
+ if (!(!f || !document.fullscreenEnabled))
924
+ try {
925
+ await f.requestFullscreen(), R(!0);
926
+ } catch (V) {
927
+ console.error("Failed to enter fullscreen:", V);
928
+ }
929
+ }, _ = async () => {
930
+ if (document.fullscreenElement)
931
+ try {
932
+ await document.exitFullscreen(), R(!1);
933
+ } catch (f) {
934
+ console.error("Failed to exit fullscreen:", f);
935
+ }
936
+ }, C = () => {
937
+ document.fullscreenElement ? _() : U();
938
+ };
939
+ return q(() => {
940
+ const f = () => {
941
+ R(!!document.fullscreenElement);
942
+ };
943
+ return document.addEventListener("fullscreenchange", f), () => {
944
+ document.removeEventListener("fullscreenchange", f);
945
+ };
946
+ }, [R]), {
947
+ state: s,
948
+ controls: {
949
+ play: w,
950
+ pause: m,
951
+ toggle: z,
952
+ seek: F,
953
+ setVolume: O,
954
+ mute: P,
955
+ unmute: L,
956
+ toggleMute: I,
957
+ enterFullscreen: U,
958
+ exitFullscreen: _,
959
+ toggleFullscreen: C
960
+ },
961
+ mediaRef: t,
962
+ containerRef: n
963
+ };
964
+ }
965
+ const J = {
966
+ mobile: 768,
967
+ desktop: 1280
968
+ };
969
+ function fe() {
970
+ if (typeof window > "u") return "unknown";
971
+ const e = window.navigator.userAgent.toLowerCase();
972
+ return /iphone|ipad|ipod/.test(e) ? "ios" : /android/.test(e) ? "android" : /windows|mac|linux/.test(e) ? "desktop" : "unknown";
973
+ }
974
+ function ge() {
975
+ return typeof window > "u" ? !1 : "ontouchstart" in window || navigator.maxTouchPoints > 0 || // @ts-ignore - for older browsers
976
+ navigator.msMaxTouchPoints > 0;
977
+ }
978
+ function he() {
979
+ return typeof window > "u" ? !1 : "vibrate" in navigator || // @ts-ignore - for newer Vibration API
980
+ "vibration" in navigator || // @ts-ignore - for iOS haptic feedback
981
+ "ondevicemotion" in window;
982
+ }
983
+ function de() {
984
+ const [e, t] = re.useState(() => {
985
+ if (typeof window > "u")
986
+ return {
987
+ isMobile: !1,
988
+ isTablet: !1,
989
+ isDesktop: !0,
990
+ isTouchDevice: !1,
991
+ platform: "unknown",
992
+ supportsHaptics: !1,
993
+ screenSize: { width: 1920, height: 1080 },
994
+ orientation: "landscape"
995
+ };
996
+ const n = window.innerWidth, s = window.innerHeight;
997
+ return {
998
+ isMobile: n < J.mobile,
999
+ isTablet: n >= J.mobile && n < J.desktop,
1000
+ isDesktop: n >= J.desktop,
1001
+ isTouchDevice: ge(),
1002
+ platform: fe(),
1003
+ supportsHaptics: he(),
1004
+ screenSize: { width: n, height: s },
1005
+ orientation: n > s ? "landscape" : "portrait"
1006
+ };
1007
+ });
1008
+ return re.useEffect(() => {
1009
+ const n = () => {
1010
+ const a = window.innerWidth, d = window.innerHeight;
1011
+ t({
1012
+ isMobile: a < J.mobile,
1013
+ isTablet: a >= J.mobile && a < J.desktop,
1014
+ isDesktop: a >= J.desktop,
1015
+ isTouchDevice: ge(),
1016
+ platform: fe(),
1017
+ supportsHaptics: he(),
1018
+ screenSize: { width: a, height: d },
1019
+ orientation: a > d ? "landscape" : "portrait"
1020
+ });
1021
+ };
1022
+ window.addEventListener("resize", n), window.addEventListener("orientationchange", n);
1023
+ const s = window.matchMedia(`(max-width: ${J.mobile - 1}px)`), u = window.matchMedia(`(min-width: ${J.mobile}px) and (max-width: ${J.desktop - 1}px)`), o = window.matchMedia(`(min-width: ${J.desktop}px)`);
1024
+ return s.addEventListener("change", n), u.addEventListener("change", n), o.addEventListener("change", n), () => {
1025
+ window.removeEventListener("resize", n), window.removeEventListener("orientationchange", n), s.removeEventListener("change", n), u.removeEventListener("change", n), o.removeEventListener("change", n);
1026
+ };
1027
+ }, []), e;
1028
+ }
1029
+ function Be() {
1030
+ const { platform: e, isMobile: t } = de();
1031
+ re.useEffect(() => {
1032
+ if (t) {
1033
+ if (e === "ios") {
1034
+ const n = (s) => {
1035
+ s.touches.length > 1 && s.preventDefault();
1036
+ };
1037
+ return document.addEventListener("touchstart", n, { passive: !1 }), document.body.style.webkitOverflowScrolling = "touch", () => {
1038
+ document.removeEventListener("touchstart", n);
1039
+ };
1040
+ }
1041
+ e === "android" && (document.body.style.touchAction = "manipulation"), document.documentElement.style.setProperty("--webkit-transform", "translateZ(0)"), document.documentElement.style.setProperty("--transform", "translateZ(0)");
1042
+ }
1043
+ }, [e, t]);
1044
+ }
1045
+ function ke() {
1046
+ const { supportsHaptics: e } = de();
1047
+ return { triggerHaptic: re.useCallback((n = "light") => {
1048
+ if (!e) return;
1049
+ const u = {
1050
+ light: [10],
1051
+ medium: [20],
1052
+ heavy: [30],
1053
+ success: [10, 10, 10],
1054
+ warning: [20, 20],
1055
+ error: [50, 20, 50]
1056
+ }[n];
1057
+ "vibrate" in navigator && navigator.vibrate(u);
1058
+ }, [e]), supportsHaptics: e };
1059
+ }
1060
+ const Pe = {
1061
+ enabledGestures: ["tap", "double-tap", "long-press", "swipe-left", "swipe-right", "swipe-up", "swipe-down", "pinch-in", "pinch-out"],
1062
+ tapThreshold: 200,
1063
+ doubleTapThreshold: 300,
1064
+ longPressThreshold: 500,
1065
+ swipeThreshold: 50,
1066
+ swipeVelocityThreshold: 0.5,
1067
+ pinchThreshold: 0.1,
1068
+ rotationThreshold: 15,
1069
+ enableHapticFeedback: !0
1070
+ };
1071
+ function Fe(e, t, n = {}) {
1072
+ const s = { ...Pe, ...n }, { isTouchDevice: u } = de(), { triggerHaptic: o } = ke(), a = re.useRef({
1073
+ isTracking: !1,
1074
+ touches: [],
1075
+ startTouches: []
1076
+ }), d = (p) => ({
1077
+ id: p.identifier,
1078
+ x: p.clientX,
1079
+ y: p.clientY,
1080
+ timestamp: Date.now()
1081
+ }), S = (p, l) => Math.sqrt(Math.pow(l.x - p.x, 2) + Math.pow(l.y - p.y, 2)), D = (p, l) => {
1082
+ const v = Math.max(l.timestamp - p.timestamp, 1);
1083
+ return {
1084
+ x: (l.x - p.x) / v,
1085
+ y: (l.y - p.y) / v
1086
+ };
1087
+ }, R = (p, l, v, M = {}) => ({
1088
+ type: p,
1089
+ startPoint: { x: l.x, y: l.y },
1090
+ currentPoint: { x: v.x, y: v.y },
1091
+ duration: v.timestamp - l.timestamp,
1092
+ target: e.current,
1093
+ preventDefault: () => {
1094
+ },
1095
+ ...M
1096
+ }), g = re.useCallback((p) => {
1097
+ if (!s.enabledGestures.length) return;
1098
+ const l = Array.from(p.touches).map(d), v = a.current;
1099
+ v.isTracking = !0, v.touches = l, v.startTouches = [...l], v.longPressTimer && clearTimeout(v.longPressTimer), l.length === 1 && s.enabledGestures.includes("long-press") && (v.longPressTimer = setTimeout(() => {
1100
+ if (v.touches.length === 1 && l[0]) {
1101
+ const M = R("long-press", l[0], l[0]);
1102
+ t(M), s.enableHapticFeedback && o("heavy");
1103
+ }
1104
+ }, s.longPressThreshold)), l.length === 2 && l[0] && l[1] && (v.initialDistance = S(l[0], l[1]), v.initialScale = 1, v.lastScale = 1);
1105
+ }, [s, t, o]), r = re.useCallback((p) => {
1106
+ const l = a.current;
1107
+ if (!l.isTracking) return;
1108
+ const v = Array.from(p.touches).map(d);
1109
+ if (l.touches = v, v.length === 2 && l.initialDistance && v[0] && v[1]) {
1110
+ const M = S(v[0], v[1]), h = M / l.initialDistance;
1111
+ if (Math.abs(h - (l.lastScale || 1)) > s.pinchThreshold) {
1112
+ const T = h > (l.lastScale || 1) ? "pinch-out" : "pinch-in";
1113
+ if (s.enabledGestures.includes(T)) {
1114
+ const E = {
1115
+ x: (v[0].x + v[1].x) / 2,
1116
+ y: (v[0].y + v[1].y) / 2,
1117
+ timestamp: Date.now()
1118
+ }, b = {
1119
+ x: ((l.startTouches[0]?.x ?? 0) + (l.startTouches[1]?.x ?? 0)) / 2,
1120
+ y: ((l.startTouches[0]?.y ?? 0) + (l.startTouches[1]?.y ?? 0)) / 2,
1121
+ timestamp: l.startTouches[0]?.timestamp ?? Date.now()
1122
+ }, w = R(T, b, E, {
1123
+ scale: h,
1124
+ distance: M
1125
+ });
1126
+ t(w), l.lastScale = h;
1127
+ }
1128
+ }
1129
+ }
1130
+ if (l.longPressTimer && v.length === 1 && l.startTouches[0] && v[0]) {
1131
+ const M = l.startTouches[0], h = v[0];
1132
+ S(M, h) > s.swipeThreshold && (clearTimeout(l.longPressTimer), l.longPressTimer = void 0);
1133
+ }
1134
+ }, [s, t]), y = re.useCallback((p) => {
1135
+ const l = a.current;
1136
+ if (!l.isTracking) return;
1137
+ const v = Array.from(p.changedTouches).map(d), M = Date.now();
1138
+ if (l.longPressTimer && (clearTimeout(l.longPressTimer), l.longPressTimer = void 0), l.startTouches.length === 1 && v.length === 1 && l.startTouches[0] && v[0]) {
1139
+ const h = l.startTouches[0], c = v[0], T = S(h, c), E = c.timestamp - h.timestamp;
1140
+ if (T > s.swipeThreshold) {
1141
+ const b = D(h, c), w = Math.abs(b.x), m = Math.abs(b.y);
1142
+ if (w > s.swipeVelocityThreshold || m > s.swipeVelocityThreshold) {
1143
+ let z;
1144
+ if (w > m ? z = b.x > 0 ? "swipe-right" : "swipe-left" : z = b.y > 0 ? "swipe-down" : "swipe-up", s.enabledGestures.includes(z)) {
1145
+ const F = R(z, h, c, {
1146
+ velocity: b,
1147
+ distance: T
1148
+ });
1149
+ t(F), s.enableHapticFeedback && o("light");
1150
+ }
1151
+ }
1152
+ } else if (E < s.tapThreshold && T < s.swipeThreshold)
1153
+ if (l.lastTap && M - l.lastTap.timestamp < s.doubleTapThreshold && S({ ...l.lastTap.point }, c) < s.swipeThreshold) {
1154
+ if (s.enabledGestures.includes("double-tap")) {
1155
+ const b = R("double-tap", h, c);
1156
+ t(b), s.enableHapticFeedback && o("medium");
1157
+ }
1158
+ l.lastTap = void 0;
1159
+ } else {
1160
+ if (s.enabledGestures.includes("tap")) {
1161
+ const b = R("tap", h, c);
1162
+ t(b), s.enableHapticFeedback && o("light");
1163
+ }
1164
+ l.lastTap = {
1165
+ timestamp: M,
1166
+ point: { x: c.x, y: c.y }
1167
+ };
1168
+ }
1169
+ }
1170
+ p.touches.length === 0 && (l.isTracking = !1, l.touches = [], l.startTouches = [], l.initialDistance = void 0, l.initialScale = void 0, l.lastScale = void 0);
1171
+ }, [s, t, o]);
1172
+ return re.useEffect(() => {
1173
+ const p = e.current;
1174
+ if (!(!p || !u))
1175
+ return p.addEventListener("touchstart", g, { passive: !1 }), p.addEventListener("touchmove", r, { passive: !1 }), p.addEventListener("touchend", y, { passive: !1 }), p.addEventListener("touchcancel", y, { passive: !1 }), () => {
1176
+ p.removeEventListener("touchstart", g), p.removeEventListener("touchmove", r), p.removeEventListener("touchend", y), p.removeEventListener("touchcancel", y);
1177
+ };
1178
+ }, [g, r, y, u]), {
1179
+ isGestureEnabled: u && s.enabledGestures.length > 0
1180
+ };
1181
+ }
1182
+ function Ne(e, t) {
1183
+ const n = re.useCallback((u) => {
1184
+ const { type: o, distance: a, scale: d } = u;
1185
+ switch (o) {
1186
+ case "double-tap":
1187
+ t.onPlayPause?.();
1188
+ break;
1189
+ case "swipe-left":
1190
+ const S = Math.min((a || 0) / 10, 30);
1191
+ t.onSeek?.("backward", S);
1192
+ break;
1193
+ case "swipe-right":
1194
+ const D = Math.min((a || 0) / 10, 30);
1195
+ t.onSeek?.("forward", D);
1196
+ break;
1197
+ case "swipe-up":
1198
+ if (u.startPoint.x > (e.current?.clientWidth || 0) / 2) {
1199
+ const R = Math.min((a || 0) / 100, 0.2);
1200
+ t.onVolumeChange?.("up", R);
1201
+ }
1202
+ break;
1203
+ case "swipe-down":
1204
+ if (u.startPoint.x > (e.current?.clientWidth || 0) / 2) {
1205
+ const R = Math.min((a || 0) / 100, 0.2);
1206
+ t.onVolumeChange?.("down", R);
1207
+ }
1208
+ break;
1209
+ case "pinch-out":
1210
+ t.onZoom?.(d || 1);
1211
+ break;
1212
+ case "pinch-in":
1213
+ t.onZoom?.(d || 1);
1214
+ break;
1215
+ case "long-press":
1216
+ t.onToggleFullscreen?.();
1217
+ break;
1218
+ }
1219
+ }, [t, e]);
1220
+ return Fe(e, n, {
1221
+ enabledGestures: ["tap", "double-tap", "long-press", "swipe-left", "swipe-right", "swipe-up", "swipe-down", "pinch-in", "pinch-out"],
1222
+ enableHapticFeedback: !0,
1223
+ swipeThreshold: 30,
1224
+ swipeVelocityThreshold: 0.3
1225
+ });
1226
+ }
1227
+ function He(e) {
1228
+ const t = W(null), [n, s] = Q({
1229
+ isPlaying: !1,
1230
+ currentTime: 0,
1231
+ duration: 0,
1232
+ volume: 1,
1233
+ isMuted: !1,
1234
+ isFullscreen: !1,
1235
+ isLoading: !0,
1236
+ isSeeking: !1,
1237
+ isBuffering: !1,
1238
+ bufferedRanges: []
1239
+ });
1240
+ return q(() => {
1241
+ const r = t.current;
1242
+ if (!r) return;
1243
+ const y = () => {
1244
+ s((F) => ({ ...F, currentTime: r.currentTime }));
1245
+ }, p = () => {
1246
+ s((F) => ({ ...F, duration: r.duration }));
1247
+ }, l = () => {
1248
+ s((F) => ({ ...F, isPlaying: !0, isBuffering: !1 }));
1249
+ }, v = () => {
1250
+ s((F) => ({ ...F, isPlaying: !1 }));
1251
+ }, M = () => {
1252
+ s((F) => ({
1253
+ ...F,
1254
+ volume: r.volume,
1255
+ isMuted: r.muted
1256
+ }));
1257
+ }, h = () => {
1258
+ s((F) => ({ ...F, isLoading: !0 }));
1259
+ }, c = () => {
1260
+ s((F) => ({ ...F, isLoading: !1 }));
1261
+ }, T = () => {
1262
+ s((F) => ({ ...F, isSeeking: !0 }));
1263
+ }, E = () => {
1264
+ s((F) => ({ ...F, isSeeking: !1 }));
1265
+ }, b = () => {
1266
+ s((F) => ({ ...F, isBuffering: !0 }));
1267
+ }, w = () => {
1268
+ s((F) => ({ ...F, isBuffering: !1, isLoading: !1 }));
1269
+ }, m = () => {
1270
+ s((F) => ({ ...F, isLoading: !1, isBuffering: !1 }));
1271
+ }, z = () => {
1272
+ if (!r.buffered || r.buffered.length === 0 || r.duration === 0) {
1273
+ s((O) => ({ ...O, bufferedRanges: [] }));
1274
+ return;
1275
+ }
1276
+ const F = [];
1277
+ for (let O = 0; O < r.buffered.length; O++) {
1278
+ const P = r.buffered.start(O), L = r.buffered.end(O);
1279
+ F.push({
1280
+ start: P,
1281
+ end: L,
1282
+ percentage: (L - P) / r.duration * 100
1283
+ });
1284
+ }
1285
+ s((O) => ({ ...O, bufferedRanges: F }));
1286
+ };
1287
+ return r.addEventListener("timeupdate", y), r.addEventListener("loadedmetadata", p), r.addEventListener("play", l), r.addEventListener("pause", v), r.addEventListener("volumechange", M), r.addEventListener("loadstart", h), r.addEventListener("loadeddata", c), r.addEventListener("seeking", T), r.addEventListener("seeked", E), r.addEventListener("waiting", b), r.addEventListener("playing", w), r.addEventListener("canplay", m), r.addEventListener("progress", z), () => {
1288
+ r.removeEventListener("timeupdate", y), r.removeEventListener("loadedmetadata", p), r.removeEventListener("play", l), r.removeEventListener("pause", v), r.removeEventListener("volumechange", M), r.removeEventListener("loadstart", h), r.removeEventListener("loadeddata", c), r.removeEventListener("seeking", T), r.removeEventListener("seeked", E), r.removeEventListener("waiting", b), r.removeEventListener("playing", w), r.removeEventListener("canplay", m), r.removeEventListener("progress", z);
1289
+ };
1290
+ }, []), {
1291
+ videoRef: t,
1292
+ state: n,
1293
+ controls: {
1294
+ togglePlay: () => {
1295
+ const r = t.current;
1296
+ r && (n.isPlaying ? r.pause() : r.play());
1297
+ },
1298
+ seekForward: (r = 10) => {
1299
+ const y = t.current;
1300
+ y && (y.currentTime = Math.min(n.duration, y.currentTime + r));
1301
+ },
1302
+ seekBackward: (r = 10) => {
1303
+ const y = t.current;
1304
+ y && (y.currentTime = Math.max(0, y.currentTime - r));
1305
+ },
1306
+ toggleMute: () => {
1307
+ const r = t.current;
1308
+ r && (r.muted = !n.isMuted);
1309
+ },
1310
+ setVolume: (r) => {
1311
+ const y = t.current;
1312
+ y && (y.volume = r, r > 0 && n.isMuted && (y.muted = !1));
1313
+ },
1314
+ toggleFullscreen: () => {
1315
+ const r = e.current;
1316
+ r && (n.isFullscreen ? document.exitFullscreen && document.exitFullscreen() : r.requestFullscreen && r.requestFullscreen(), s((y) => ({ ...y, isFullscreen: !y.isFullscreen })));
1317
+ },
1318
+ seekTo: (r) => {
1319
+ const y = t.current;
1320
+ !y || n.duration === 0 || (y.currentTime = Math.max(0, Math.min(n.duration, r)));
1321
+ }
1322
+ }
1323
+ };
1324
+ }
1325
+ function De({
1326
+ subtitleSrc: e,
1327
+ subtitleTracks: t = [],
1328
+ defaultFontSize: n = "medium",
1329
+ onLoadError: s
1330
+ } = {}) {
1331
+ const [u, o] = Q(!1), [a, d] = Q([]), [S, D] = Q(""), [R, g] = Q(null), [r, y] = Q(n), [p, l] = Q(null), [v, M] = Q(!1), h = {
1332
+ small: "text-sm",
1333
+ medium: "text-base",
1334
+ large: "text-lg"
1335
+ }, c = !!(e || t && t.length > 0), T = (P) => {
1336
+ const L = P.split(":"), I = L[2] ? parseFloat(L[2]) : 0, U = L[1] ? parseInt(L[1], 10) * 60 : 0;
1337
+ return (L[0] ? parseInt(L[0], 10) * 3600 : 0) + U + I;
1338
+ }, E = (P) => {
1339
+ const [L, I] = P.split(","), U = (L || "").split(":"), _ = I ? parseInt(I, 10) / 1e3 : 0, C = U[2] ? parseInt(U[2], 10) : 0, ee = U[1] ? parseInt(U[1], 10) * 60 : 0;
1340
+ return (U[0] ? parseInt(U[0], 10) * 3600 : 0) + ee + C + _;
1341
+ }, b = async (P) => {
1342
+ M(!0), l(null);
1343
+ try {
1344
+ const L = await fetch(P);
1345
+ if (!L.ok)
1346
+ throw new Error(`Failed to load subtitles: ${L.status} ${L.statusText}`);
1347
+ const I = await L.text(), U = [], _ = I.split(`
1348
+ `);
1349
+ let C = 0;
1350
+ const ee = I.includes("WEBVTT") || P.endsWith(".vtt"), f = P.endsWith(".srt") || /^\d+$/.test(_[0]?.trim() || "");
1351
+ if (ee)
1352
+ for (; C < _.length; ) {
1353
+ if (_[C]?.includes("-->")) {
1354
+ const [V, se] = (_[C] || "").split("-->").map((B) => B.trim()), ae = T(V || ""), i = T(se || "");
1355
+ C++;
1356
+ let k = "";
1357
+ for (; C < _.length && _[C]?.trim() !== ""; )
1358
+ k += (k ? " " : "") + _[C]?.trim(), C++;
1359
+ k && U.push({ start: ae, end: i, text: k });
1360
+ }
1361
+ C++;
1362
+ }
1363
+ else if (f)
1364
+ for (; C < _.length; ) {
1365
+ if (/^\d+$/.test(_[C]?.trim() || "") && (C++, _[C]?.includes("-->"))) {
1366
+ const [V, se] = (_[C] || "").split("-->").map((B) => B.trim()), ae = E(V || ""), i = E(se || "");
1367
+ C++;
1368
+ let k = "";
1369
+ for (; C < _.length && _[C]?.trim() !== ""; )
1370
+ k += (k ? " " : "") + _[C]?.trim(), C++;
1371
+ k && U.push({ start: ae, end: i, text: k });
1372
+ }
1373
+ C++;
1374
+ }
1375
+ else
1376
+ throw new Error("Unsupported subtitle format. Only VTT and SRT are supported.");
1377
+ if (U.length === 0)
1378
+ throw new Error("No subtitle cues found in file");
1379
+ d(U), M(!1);
1380
+ } catch (L) {
1381
+ const I = L instanceof Error ? L : new Error("Failed to load subtitles");
1382
+ console.error("Failed to load subtitles:", I), l(I), M(!1), d([]), s?.(I);
1383
+ }
1384
+ }, w = (P) => !u || a.length === 0 ? "" : a.find(
1385
+ (I) => P >= I.start && P <= I.end
1386
+ )?.text || "", m = () => {
1387
+ o((P) => {
1388
+ const L = !P;
1389
+ if (L && !p) {
1390
+ if (a.length === 0 && !v) {
1391
+ const I = e || t[0]?.src;
1392
+ I && (b(I), t[0] && g(t[0].id));
1393
+ }
1394
+ } else L || D("");
1395
+ return L;
1396
+ });
1397
+ }, z = (P) => {
1398
+ if (!P) {
1399
+ o(!1), g(null), D("");
1400
+ return;
1401
+ }
1402
+ const L = t.find((I) => I.id === P);
1403
+ L?.src && (g(P), b(L.src), o(!0));
1404
+ }, F = (P) => {
1405
+ y(P);
1406
+ }, O = {
1407
+ fontSize: h[r],
1408
+ className: `${h[r]} font-medium`
1409
+ };
1410
+ return q(() => {
1411
+ u || D("");
1412
+ }, [u]), q(() => {
1413
+ }, []), {
1414
+ // State
1415
+ subtitlesEnabled: u,
1416
+ currentSubtitle: S,
1417
+ subtitleCues: a,
1418
+ currentTrackId: R,
1419
+ fontSize: r,
1420
+ loadError: p,
1421
+ isLoading: v,
1422
+ hasSubtitles: c,
1423
+ // Actions
1424
+ toggleSubtitles: m,
1425
+ selectSubtitleTrack: z,
1426
+ changeSubtitleFontSize: F,
1427
+ setCurrentSubtitle: D,
1428
+ // Utilities
1429
+ getCurrentSubtitle: w,
1430
+ getSubtitleStyles: O,
1431
+ // Track info
1432
+ availableTracks: t
1433
+ };
1434
+ }
1435
+ const Ke = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1436
+ __proto__: null,
1437
+ useEnhancedSubtitles: De
1438
+ }, Symbol.toStringTag, { value: "Module" }));
1439
+ function $e(e, t) {
1440
+ const [n, s] = Q(!0), [u, o] = Q(!1), a = W(null), d = () => {
1441
+ s(!0), a.current && clearTimeout(a.current), e && !t && (a.current = setTimeout(() => {
1442
+ s(!1);
1443
+ }, 3e3));
1444
+ }, S = () => {
1445
+ d();
1446
+ }, D = () => {
1447
+ s(!0);
1448
+ }, R = () => {
1449
+ e && s(!1);
1450
+ };
1451
+ return q(() => (d(), () => {
1452
+ a.current && clearTimeout(a.current);
1453
+ }), [d]), {
1454
+ controlsVisible: n,
1455
+ showVolumeSlider: u,
1456
+ setShowVolumeSlider: o,
1457
+ handleMouseMove: S,
1458
+ handleMouseEnter: D,
1459
+ handleMouseLeave: R
1460
+ };
1461
+ }
1462
+ function Ge({
1463
+ videoControls: e,
1464
+ toggleSubtitles: t,
1465
+ takeScreenshot: n,
1466
+ duration: s
1467
+ }) {
1468
+ const u = (o) => {
1469
+ const a = document.querySelector("video");
1470
+ if (a)
1471
+ switch (o.key.toLowerCase()) {
1472
+ case " ":
1473
+ case "k":
1474
+ o.preventDefault(), e.togglePlay();
1475
+ break;
1476
+ case "j":
1477
+ o.preventDefault(), e.seekBackward();
1478
+ break;
1479
+ case "l":
1480
+ o.preventDefault(), e.seekForward();
1481
+ break;
1482
+ case "arrowleft":
1483
+ o.preventDefault(), a.currentTime = Math.max(0, a.currentTime - 5);
1484
+ break;
1485
+ case "arrowright":
1486
+ o.preventDefault(), a.currentTime = Math.min(s, a.currentTime + 5);
1487
+ break;
1488
+ case "arrowup":
1489
+ o.preventDefault(), a.volume = Math.min(1, a.volume + 0.1);
1490
+ break;
1491
+ case "arrowdown":
1492
+ o.preventDefault(), a.volume = Math.max(0, a.volume - 0.1);
1493
+ break;
1494
+ case "m":
1495
+ o.preventDefault(), e.toggleMute();
1496
+ break;
1497
+ case "f":
1498
+ o.preventDefault(), e.toggleFullscreen();
1499
+ break;
1500
+ case "c":
1501
+ o.preventDefault(), t();
1502
+ break;
1503
+ case "s":
1504
+ o.preventDefault(), n(o.ctrlKey || o.metaKey);
1505
+ break;
1506
+ }
1507
+ };
1508
+ q(() => (document.addEventListener("keydown", u), () => document.removeEventListener("keydown", u)), [u]);
1509
+ }
1510
+ function ze(e) {
1511
+ return { takeScreenshot: (n = !1) => {
1512
+ if (!e.current) return;
1513
+ const s = e.current, u = document.createElement("canvas");
1514
+ u.width = s.videoWidth, u.height = s.videoHeight;
1515
+ const o = u.getContext("2d");
1516
+ if (o)
1517
+ try {
1518
+ o.drawImage(s, 0, 0), u.toBlob((a) => {
1519
+ if (!a) {
1520
+ console.error("Failed to create blob from canvas");
1521
+ return;
1522
+ }
1523
+ if (n)
1524
+ if (navigator.clipboard && window.ClipboardItem) {
1525
+ const d = new ClipboardItem({ "image/png": a });
1526
+ navigator.clipboard.write([d]).catch((S) => {
1527
+ console.error("Failed to copy to clipboard:", S);
1528
+ });
1529
+ } else
1530
+ console.warn("Clipboard API not supported");
1531
+ else {
1532
+ const d = URL.createObjectURL(a), S = document.createElement("a");
1533
+ S.href = d, S.download = `screenshot-${Date.now()}.png`, S.click(), URL.revokeObjectURL(d);
1534
+ }
1535
+ }, "image/png");
1536
+ } catch (a) {
1537
+ a instanceof Error && a.message.includes("tainted") ? (console.error("Canvas is tainted - video source may not have proper CORS headers. Try setting crossOrigin='anonymous' on the video element."), alert("Screenshot failed: The video source doesn't allow screenshots due to CORS policy. Please ensure the video server includes proper CORS headers or set crossOrigin='anonymous' on the video player.")) : (console.error("Screenshot failed:", a), alert("Screenshot failed: " + (a instanceof Error ? a.message : "Unknown error")));
1538
+ }
1539
+ } };
1540
+ }
1541
+ function We(e) {
1542
+ const t = W(null), n = W(null), [s, u] = le(), [o, a] = le();
1543
+ N.useRef(0);
1544
+ const d = N.useRef(0), S = N.useRef(0);
1545
+ W(void 0);
1546
+ const D = W(0), R = pe(), g = "getOptimisticState" in R, r = j((i) => i.isPlaying), y = j((i) => i.currentTime), p = j((i) => i.duration), l = j((i) => i.volume), v = j((i) => i.isMuted), M = j((i) => i.isLoading), h = j((i) => i.isBuffering), c = j((i) => i.error), T = j((i) => i.buffered), E = j((i) => i.isFullscreen), b = R, w = g ? Ee(b) : null, m = g ? Te(b) : null, [z, F] = N.useState({
1547
+ frameRate: 0,
1548
+ averageRenderTime: 0,
1549
+ droppedFrames: 0,
1550
+ bufferHealth: 0
1551
+ }), [O, P] = ce(l, (i, k) => Math.max(0, Math.min(1, k)));
1552
+ ce(y, (i, k) => Math.max(0, Math.min(p || 0, k))), q(() => {
1553
+ const i = t.current;
1554
+ if (!i) return;
1555
+ const k = {
1556
+ volume: e.volume,
1557
+ muted: e.muted,
1558
+ autoplay: e.autoPlay,
1559
+ loop: e.loop,
1560
+ preload: e.preload,
1561
+ crossOrigin: e.crossOrigin
1562
+ };
1563
+ Object.entries(k).forEach(([B, Y]) => {
1564
+ Y !== void 0 && (i[B] = Y);
1565
+ }), i.setAttribute("preload", e.preloadStrategy === "eager" ? "auto" : "metadata"), e.bufferingStrategy === "aggressive" && i.setAttribute("buffered", "auto"), i instanceof HTMLVideoElement && (i.style.willChange = "transform", i.style.transform = "translateZ(0)");
1566
+ }, [
1567
+ e.volume,
1568
+ e.muted,
1569
+ e.autoPlay,
1570
+ e.loop,
1571
+ e.preload,
1572
+ e.crossOrigin,
1573
+ e.preloadStrategy,
1574
+ e.bufferingStrategy
1575
+ ]);
1576
+ const L = A(() => {
1577
+ const i = t.current;
1578
+ if (!i) return;
1579
+ const k = performance.now();
1580
+ if (e.enableTimeUpdateThrottling !== !1) {
1581
+ if (k - D.current < (e.timeUpdateThrottleMs || 100))
1582
+ return;
1583
+ D.current = k;
1584
+ }
1585
+ u(() => {
1586
+ g && m && m.setCurrentTime(i.currentTime);
1587
+ });
1588
+ }, [e.enableTimeUpdateThrottling, e.timeUpdateThrottleMs, g, m]), I = A(() => {
1589
+ u(() => {
1590
+ g && m && m.play(!0);
1591
+ }), e.onPlay?.();
1592
+ }, [g, m, e.onPlay]), U = A(() => {
1593
+ u(() => {
1594
+ g && m && m.pause(!0);
1595
+ }), e.onPause?.();
1596
+ }, [g, m, e.onPause]), _ = A(() => {
1597
+ const i = t.current;
1598
+ i && u(() => {
1599
+ g && m && (m.setVolume(i.volume, !0), i.muted ? m.mute(!0) : m.unmute(!0));
1600
+ });
1601
+ }, [g, m]), C = A(() => {
1602
+ a(() => {
1603
+ });
1604
+ }, []), ee = A(() => {
1605
+ }, []), f = A(() => {
1606
+ const i = t.current;
1607
+ i && u(() => {
1608
+ g && m && m.setBuffered(i.buffered);
1609
+ });
1610
+ }, [g, m]), V = A(() => {
1611
+ const i = performance.now();
1612
+ if (i - S.current > 0 && (d.current++, d.current >= 60)) {
1613
+ const B = Math.round(d.current * 1e3 / (i - S.current));
1614
+ F((Y) => ({
1615
+ ...Y,
1616
+ frameRate: B,
1617
+ droppedFrames: Math.max(0, 60 - B)
1618
+ })), d.current = 0, S.current = i;
1619
+ }
1620
+ }, []);
1621
+ q(() => {
1622
+ const i = t.current;
1623
+ if (!i) return;
1624
+ const k = [
1625
+ { event: "timeupdate", handler: L, passive: !0 },
1626
+ { event: "play", handler: I },
1627
+ { event: "pause", handler: U },
1628
+ { event: "volumechange", handler: _ },
1629
+ { event: "seeking", handler: C },
1630
+ { event: "seeked", handler: ee },
1631
+ { event: "progress", handler: f, passive: !0 },
1632
+ { event: "loadedmetadata", handler: () => V() },
1633
+ { event: "loadeddata", handler: () => V() }
1634
+ ];
1635
+ k.forEach(({ event: te, handler: ne, passive: ie }) => {
1636
+ const oe = ie ? { passive: !0 } : {};
1637
+ i.addEventListener(te, ne, oe);
1638
+ });
1639
+ let B;
1640
+ const Y = () => {
1641
+ V(), B = requestAnimationFrame(Y);
1642
+ };
1643
+ return e.enablePerformanceMonitoring && Y(), () => {
1644
+ k.forEach(({ event: te, handler: ne }) => {
1645
+ i.removeEventListener(te, ne);
1646
+ }), B && cancelAnimationFrame(B);
1647
+ };
1648
+ }, [
1649
+ L,
1650
+ I,
1651
+ U,
1652
+ _,
1653
+ C,
1654
+ ee,
1655
+ f,
1656
+ V,
1657
+ e.enablePerformanceMonitoring
1658
+ ]);
1659
+ const se = ue(() => {
1660
+ const i = async () => {
1661
+ const x = t.current;
1662
+ if (x)
1663
+ if (g && m)
1664
+ await m.play(!0);
1665
+ else
1666
+ try {
1667
+ await x.play();
1668
+ } catch (X) {
1669
+ console.error("Failed to play media:", X);
1670
+ }
1671
+ }, k = () => {
1672
+ const x = t.current;
1673
+ x && (g && m ? m.pause(!0) : x.pause());
1674
+ }, B = () => {
1675
+ r ? k() : i();
1676
+ }, Y = (x) => {
1677
+ const X = t.current;
1678
+ if (!X) return;
1679
+ const Z = Math.max(0, Math.min(x, p || 0));
1680
+ g && m ? a(() => {
1681
+ m.seek(Z, !0);
1682
+ }) : X.currentTime = Z;
1683
+ }, te = (x) => {
1684
+ const X = t.current;
1685
+ if (!X) return;
1686
+ const Z = Math.max(0, Math.min(1, x));
1687
+ g && m ? (P(Z), u(() => {
1688
+ m.setVolume(Z, !0);
1689
+ })) : X.volume = Z;
1690
+ }, ne = () => {
1691
+ const x = t.current;
1692
+ x && (g && m ? m.toggleMute(!0) : x.muted = !x.muted);
1693
+ }, ie = async () => {
1694
+ const x = n.current;
1695
+ if (!(!x || !document.fullscreenEnabled))
1696
+ try {
1697
+ await x.requestFullscreen(), g && m && m.enterFullscreen(!0);
1698
+ } catch (X) {
1699
+ console.error("Failed to enter fullscreen:", X);
1700
+ }
1701
+ }, oe = async () => {
1702
+ if (document.fullscreenElement)
1703
+ try {
1704
+ await document.exitFullscreen(), g && m && m.exitFullscreen(!0);
1705
+ } catch (x) {
1706
+ console.error("Failed to exit fullscreen:", x);
1707
+ }
1708
+ };
1709
+ return {
1710
+ play: i,
1711
+ pause: k,
1712
+ toggle: B,
1713
+ seek: Y,
1714
+ setVolume: te,
1715
+ toggleMute: ne,
1716
+ enterFullscreen: ie,
1717
+ exitFullscreen: oe,
1718
+ toggleFullscreen: () => {
1719
+ document.fullscreenElement ? oe() : ie();
1720
+ }
1721
+ };
1722
+ }, [
1723
+ r,
1724
+ p,
1725
+ g,
1726
+ m,
1727
+ u,
1728
+ a,
1729
+ P
1730
+ ]), ae = ue(() => ({
1731
+ isPlaying: w?.isPlaying ?? r,
1732
+ currentTime: w?.currentTime ?? y,
1733
+ duration: w?.duration ?? p,
1734
+ volume: w?.volume ?? O,
1735
+ isMuted: w?.isMuted ?? v,
1736
+ isLoading: w?.isBuffering ?? M,
1737
+ isBuffering: w?.isBuffering ?? h,
1738
+ error: w?.error ?? c,
1739
+ buffered: w?.buffered ?? T,
1740
+ isFullscreen: w?.isFullscreen ?? E,
1741
+ progress: p > 0 ? y / p : 0,
1742
+ isTransitioning: s || o,
1743
+ canPlay: !M && !h && !c
1744
+ }), [
1745
+ w,
1746
+ r,
1747
+ y,
1748
+ p,
1749
+ O,
1750
+ v,
1751
+ M,
1752
+ h,
1753
+ c,
1754
+ T,
1755
+ E,
1756
+ s,
1757
+ o
1758
+ ]);
1759
+ return {
1760
+ // Refs
1761
+ mediaRef: t,
1762
+ containerRef: n,
1763
+ // State
1764
+ state: ae,
1765
+ actualState: w?.actualState,
1766
+ // Controls
1767
+ controls: se,
1768
+ // Performance metrics
1769
+ performanceMetrics: z,
1770
+ isTransitioning: s || o,
1771
+ // Enhanced features
1772
+ actions: w?.actions,
1773
+ actionState: w?.actionState,
1774
+ // Optimistic features
1775
+ optimisticState: w,
1776
+ isEnhanced: g
1777
+ };
1778
+ }
1779
+ const je = (e, t = {}) => {
1780
+ const {
1781
+ trackUserBehavior: n = !0,
1782
+ adaptToNetwork: s = !0,
1783
+ strategy: u = "balanced",
1784
+ maxPreloadItems: o = 3,
1785
+ preloadRadius: a = 2
1786
+ } = t, d = W({
1787
+ mouseMovements: 0,
1788
+ scrollEvents: 0,
1789
+ keyPresses: 0,
1790
+ focusEvents: 0,
1791
+ timeOnPage: 0,
1792
+ engagementScore: 0,
1793
+ lastInteraction: Date.now()
1794
+ }), S = W(null), D = W(/* @__PURE__ */ new Set()), R = W([]), g = A(() => {
1795
+ const c = d.current, T = Math.min(c.timeOnPage / 6e4, 1), E = Math.min(
1796
+ (c.mouseMovements + c.scrollEvents + c.keyPresses) / 100,
1797
+ 1
1798
+ );
1799
+ return (T * 0.4 + E * 0.6) * 100;
1800
+ }, []), r = A((c, T = 1) => {
1801
+ const E = d.current;
1802
+ E[c] = typeof E[c] == "number" ? E[c] + T : Date.now(), E.engagementScore = g(), E.lastInteraction = Date.now();
1803
+ }, [g]), y = A(() => {
1804
+ if (!S.current || !s)
1805
+ return { type: "unknown", downlink: 10, effectiveType: "4g", saveData: !1 };
1806
+ const c = S.current;
1807
+ return {
1808
+ type: c.type,
1809
+ downlink: c.downlink || 10,
1810
+ effectiveType: c.effectiveType || "4g",
1811
+ saveData: c.saveData || !1,
1812
+ rtt: c.rtt || 100
1813
+ };
1814
+ }, [s]), p = A((c, T, E = 0) => {
1815
+ if (D.current.has(c.src))
1816
+ return { shouldPreload: !1, priority: "low", reason: "Already preloaded" };
1817
+ const b = Math.abs(T - E);
1818
+ if (b > a)
1819
+ return { shouldPreload: !1, priority: "low", reason: "Outside preload radius" };
1820
+ const w = d.current, m = y(), z = w.engagementScore, F = Date.now() - w.lastInteraction;
1821
+ if (m.saveData)
1822
+ return { shouldPreload: !1, priority: "low", reason: "Data saver mode" };
1823
+ let O = !1, P = "medium", L = "";
1824
+ switch (u) {
1825
+ case "conservative":
1826
+ O = z > 70 && m.effectiveType !== "2g" && b === 1, P = O ? "medium" : "low", L = O ? "High engagement and optimal network" : "Conservative strategy";
1827
+ break;
1828
+ case "aggressive":
1829
+ O = z > 30 && m.effectiveType !== "slow-2g", P = z > 70 ? "high" : z > 50 ? "medium" : "low", L = O ? "Aggressive preloading" : "Low engagement";
1830
+ break;
1831
+ case "balanced":
1832
+ default:
1833
+ const I = m.effectiveType === "4g" ? 1 : m.effectiveType === "3g" ? 0.7 : 0.3, U = z * I;
1834
+ O = U > 40 && b <= 2, P = U > 70 ? "high" : U > 55 ? "medium" : "low", L = O ? `Balanced: score ${U.toFixed(1)}` : "Low adjusted score";
1835
+ break;
1836
+ }
1837
+ return O && ((c.type === "hls" || c.type === "m3u8") && (P = P === "low" ? "medium" : "high"), F < 5e3 && (P = "high", L += " + Recent interaction"), (c.type === "mp4" || c.type === "webm") && (P = P === "low" ? "medium" : P)), { shouldPreload: O, priority: P, reason: L };
1838
+ }, [u, a, y, g]), l = A(async (c, T) => {
1839
+ try {
1840
+ const E = document.createElement("link");
1841
+ switch (E.rel = "preload", E.href = c.src, c.type) {
1842
+ case "hls":
1843
+ case "m3u8":
1844
+ E.as = "fetch";
1845
+ break;
1846
+ case "mp4":
1847
+ case "webm":
1848
+ E.as = "video";
1849
+ break;
1850
+ case "mp3":
1851
+ case "wav":
1852
+ case "ogg":
1853
+ E.as = "audio";
1854
+ break;
1855
+ default:
1856
+ E.as = "fetch";
1857
+ }
1858
+ E.crossOrigin = "anonymous", document.head.appendChild(E), D.current.add(c.src), console.debug(`Preloaded: ${c.src} (${T})`), setTimeout(() => {
1859
+ document.head.contains(E) && document.head.removeChild(E);
1860
+ }, 3e4);
1861
+ } catch (E) {
1862
+ console.warn("Failed to preload source:", c.src, E);
1863
+ }
1864
+ }, []), v = A(() => {
1865
+ if (R.current.length === 0) return;
1866
+ const T = [...R.current].sort((E, b) => b.priority - E.priority).slice(0, o);
1867
+ R.current = [], T.forEach(({ source: E, priority: b }) => {
1868
+ l(E, b);
1869
+ });
1870
+ }, [o, l]), M = A((c = 0) => {
1871
+ R.current = [], e.forEach((T, E) => {
1872
+ const b = p(T, E, c);
1873
+ if (b.shouldPreload) {
1874
+ const w = b.priority === "high" ? 3 : b.priority === "medium" ? 2 : 1;
1875
+ R.current.push({ source: T, priority: w });
1876
+ }
1877
+ }), v();
1878
+ }, [e, p, v]);
1879
+ return q(() => {
1880
+ if (!n) return;
1881
+ const c = () => r("mouseMovements"), T = () => r("scrollEvents"), E = () => r("keyPresses"), b = () => r("focusEvents");
1882
+ document.addEventListener("mousemove", c, { passive: !0 }), document.addEventListener("scroll", T, { passive: !0 }), document.addEventListener("keydown", E, { passive: !0 }), document.addEventListener("focusin", b, { passive: !0 });
1883
+ const w = setInterval(() => {
1884
+ r("timeOnPage", 1);
1885
+ }, 1e3);
1886
+ return () => {
1887
+ document.removeEventListener("mousemove", c), document.removeEventListener("scroll", T), document.removeEventListener("keydown", E), document.removeEventListener("focusin", b), clearInterval(w);
1888
+ };
1889
+ }, [n, r]), q(() => {
1890
+ if (!s || !("connection" in navigator)) return;
1891
+ const c = navigator.connection;
1892
+ S.current = c;
1893
+ const T = () => {
1894
+ M();
1895
+ };
1896
+ return c.addEventListener("change", T), () => {
1897
+ c.removeEventListener("change", T);
1898
+ };
1899
+ }, [s, M]), q(() => {
1900
+ M();
1901
+ }, [M]), ue(() => ({
1902
+ /**
1903
+ * Manually trigger preloading for specific index
1904
+ */
1905
+ preloadAtIndex: (c) => {
1906
+ M(c);
1907
+ },
1908
+ /**
1909
+ * Get current user behavior data
1910
+ */
1911
+ getUserBehavior: () => ({ ...d.current }),
1912
+ /**
1913
+ * Get current network conditions
1914
+ */
1915
+ getNetworkConditions: y,
1916
+ /**
1917
+ * Clear preloaded items cache
1918
+ */
1919
+ clearCache: () => {
1920
+ D.current.clear();
1921
+ },
1922
+ /**
1923
+ * Get preloading statistics
1924
+ */
1925
+ getStats: () => ({
1926
+ preloadedItems: D.current.size,
1927
+ engagementScore: d.current.engagementScore,
1928
+ queueLength: R.current.length,
1929
+ maxPreloadItems: o
1930
+ })
1931
+ }), [M, y, o]);
1932
+ };
1933
+ function Re(e) {
1934
+ const [t, n] = Q(!1), [s, u] = Q([]), [o, a] = Q(""), d = (g) => {
1935
+ const r = g.split(":"), y = r[2] ? parseFloat(r[2]) : 0, p = r[1] ? parseInt(r[1], 10) * 60 : 0;
1936
+ return (r[0] ? parseInt(r[0], 10) * 3600 : 0) + p + y;
1937
+ }, S = async (g) => {
1938
+ try {
1939
+ const y = await (await fetch(g)).text(), p = [], l = y.split(`
1940
+ `);
1941
+ let v = 0;
1942
+ for (; v < l.length; ) {
1943
+ if (l[v]?.includes("-->")) {
1944
+ const [M, h] = (l[v] || "").split("-->").map((b) => b.trim()), c = d(M || ""), T = d(h || "");
1945
+ v++;
1946
+ let E = "";
1947
+ for (; v < l.length && l[v]?.trim() !== ""; )
1948
+ E += (E ? " " : "") + l[v]?.trim(), v++;
1949
+ E && p.push({ start: c, end: T, text: E });
1950
+ }
1951
+ v++;
1952
+ }
1953
+ u(p);
1954
+ } catch (r) {
1955
+ console.error("Failed to load subtitles:", r);
1956
+ }
1957
+ }, D = (g) => !t || s.length === 0 ? "" : s.find(
1958
+ (y) => g >= y.start && g <= y.end
1959
+ )?.text || "", R = () => {
1960
+ n((g) => {
1961
+ const r = !g;
1962
+ return r && e && s.length === 0 ? S(e) : r || a(""), r;
1963
+ });
1964
+ };
1965
+ return q(() => {
1966
+ t || a("");
1967
+ }, [t]), {
1968
+ subtitlesEnabled: t,
1969
+ currentSubtitle: o,
1970
+ toggleSubtitles: R,
1971
+ getCurrentSubtitle: D,
1972
+ setCurrentSubtitle: a
1973
+ };
1974
+ }
1975
+ function qe(e) {
1976
+ return ve(
1977
+ "useVideoPlayer",
1978
+ "useMediaPlayer (the primary media player hook)"
1979
+ ), Le(e);
1980
+ }
1981
+ function Xe(e) {
1982
+ return ve(
1983
+ "useEnhancedSubtitles",
1984
+ "useSubtitles (the current subtitle hook)"
1985
+ ), Re(e);
1986
+ }
1987
+ export {
1988
+ Be as a,
1989
+ Ne as b,
1990
+ He as c,
1991
+ De as d,
1992
+ $e as e,
1993
+ Ge as f,
1994
+ ze as g,
1995
+ Oe as h,
1996
+ Ue as i,
1997
+ Ie as j,
1998
+ Le as k,
1999
+ be as l,
2000
+ Me as m,
2001
+ We as n,
2002
+ _e as o,
2003
+ Se as p,
2004
+ je as q,
2005
+ Fe as r,
2006
+ Re as s,
2007
+ qe as t,
2008
+ de as u,
2009
+ Xe as v,
2010
+ Ve as w,
2011
+ Ke as x
2012
+ };
2013
+ //# sourceMappingURL=hooks-BhW_i-9L.js.map