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