@therealtinhtute/baroiplayer 1.1.0 → 1.2.0

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