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