@therealtinhtute/baroiplayer 1.2.0 → 2.0.0-beta.1

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 (305) hide show
  1. package/README.md +91 -73
  2. package/dist/components/icons/index.d.ts +36 -0
  3. package/dist/components/icons/index.d.ts.map +1 -0
  4. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
  5. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
  6. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
  7. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
  8. package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
  9. package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
  10. package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
  11. package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
  12. package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
  13. package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
  14. package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
  15. package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
  16. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
  17. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
  18. package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
  19. package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
  20. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
  21. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
  22. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
  23. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
  24. package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
  25. package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
  26. package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
  27. package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
  28. package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
  29. package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
  30. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
  31. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
  32. package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
  33. package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
  34. package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
  35. package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
  36. package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
  37. package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
  38. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
  39. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
  40. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
  41. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
  42. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
  43. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
  44. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
  45. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
  46. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
  47. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
  48. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
  49. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
  50. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
  51. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
  52. package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
  53. package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
  54. package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
  55. package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
  56. package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
  57. package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
  58. package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
  59. package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +2 -112
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +786 -6271
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -108
  69. package/src/components/variants/gradient/gradient-audio.tsx +47 -0
  70. package/src/components/variants/gradient/gradient-controls.tsx +254 -0
  71. package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
  72. package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
  73. package/src/components/variants/gradient/gradient-skin.css +211 -0
  74. package/src/components/variants/gradient/gradient-video.tsx +70 -0
  75. package/src/index.ts +5 -198
  76. package/src/test/accessibility-utils.ts +0 -59
  77. package/dist/context/media.js +0 -2
  78. package/dist/context/media.js.map +0 -1
  79. package/dist/context/media.mjs +0 -15
  80. package/dist/context/media.mjs.map +0 -1
  81. package/dist/context/store.js +0 -2
  82. package/dist/context/store.js.map +0 -1
  83. package/dist/context/store.mjs +0 -5
  84. package/dist/context/store.mjs.map +0 -1
  85. package/dist/context-BYwDoSRX.js +0 -1172
  86. package/dist/context-BYwDoSRX.js.map +0 -1
  87. package/dist/context-eNS62_ac.cjs +0 -23
  88. package/dist/context-eNS62_ac.cjs.map +0 -1
  89. package/dist/core-events-B1iM2F46.cjs +0 -2
  90. package/dist/core-events-B1iM2F46.cjs.map +0 -1
  91. package/dist/core-events-DunPHKRE.js +0 -484
  92. package/dist/core-events-DunPHKRE.js.map +0 -1
  93. package/dist/core-plugins-By-4-kGs.cjs +0 -2
  94. package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
  95. package/dist/core-plugins-DSBWcTuX.js +0 -821
  96. package/dist/core-plugins-DSBWcTuX.js.map +0 -1
  97. package/dist/core.js +0 -37
  98. package/dist/core.js.map +0 -1
  99. package/dist/core.mjs +0 -1233
  100. package/dist/core.mjs.map +0 -1
  101. package/dist/enhanced-components-B_l3cist.js +0 -1142
  102. package/dist/enhanced-components-B_l3cist.js.map +0 -1
  103. package/dist/enhanced-components-BspFs9OO.cjs +0 -2
  104. package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
  105. package/dist/hooks-BXwI8QG6.cjs +0 -4
  106. package/dist/hooks-BXwI8QG6.cjs.map +0 -1
  107. package/dist/hooks-Bpi-jDiO.js +0 -1816
  108. package/dist/hooks-Bpi-jDiO.js.map +0 -1
  109. package/dist/minimal-components-C4z900Ro.js +0 -1926
  110. package/dist/minimal-components-C4z900Ro.js.map +0 -1
  111. package/dist/minimal-components-v4qBp6jv.cjs +0 -2
  112. package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
  113. package/dist/minimal-components.css +0 -1
  114. package/dist/mona-loading.gif +0 -0
  115. package/dist/performance-monitor-C5k6FDXw.js +0 -301
  116. package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
  117. package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
  118. package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
  119. package/dist/utils-CFOue_9K.cjs +0 -9
  120. package/dist/utils-CFOue_9K.cjs.map +0 -1
  121. package/dist/utils-Dzpl2ArK.js +0 -2844
  122. package/dist/utils-Dzpl2ArK.js.map +0 -1
  123. package/dist/utils.js +0 -2
  124. package/dist/utils.js.map +0 -1
  125. package/dist/utils.mjs +0 -11
  126. package/dist/utils.mjs.map +0 -1
  127. package/src/adapters/videojs-adapter.tsx +0 -470
  128. package/src/assets/mona-loading.gif +0 -0
  129. package/src/components/AnimateLoading.tsx +0 -107
  130. package/src/components/LoadingState.tsx +0 -239
  131. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  132. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  133. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  134. package/src/components/audio-player.tsx +0 -85
  135. package/src/components/basic/index.ts +0 -37
  136. package/src/components/enhanced/advanced-features.tsx +0 -311
  137. package/src/components/enhanced/debug-panel.tsx +0 -448
  138. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  139. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  140. package/src/components/enhanced/error-handling.tsx +0 -338
  141. package/src/components/enhanced/index.ts +0 -39
  142. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  143. package/src/components/examples/basic-video-player.tsx +0 -50
  144. package/src/components/examples/custom-controls-example.tsx +0 -63
  145. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  146. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  147. package/src/components/examples/loading-states-demo.tsx +0 -142
  148. package/src/components/examples/react-19-demo.tsx +0 -353
  149. package/src/components/examples/volume-orientation-demo.tsx +0 -106
  150. package/src/components/icon-demo.tsx +0 -196
  151. package/src/components/legacy.tsx +0 -87
  152. package/src/components/media-metadata-display.tsx +0 -99
  153. package/src/components/media-player-audio.tsx +0 -39
  154. package/src/components/media-player-controls.tsx +0 -223
  155. package/src/components/media-player-error.tsx +0 -163
  156. package/src/components/media-player-fullscreen.tsx +0 -109
  157. package/src/components/media-player-hls.tsx +0 -111
  158. package/src/components/media-player-loading.tsx +0 -76
  159. package/src/components/media-player-play.tsx +0 -75
  160. package/src/components/media-player-root.tsx +0 -338
  161. package/src/components/media-player-seek.tsx +0 -168
  162. package/src/components/media-player-time.tsx +0 -99
  163. package/src/components/media-player-tooltip.tsx +0 -58
  164. package/src/components/media-player-video.tsx +0 -54
  165. package/src/components/media-player-volume.tsx +0 -155
  166. package/src/components/media-player.tsx +0 -292
  167. package/src/components/media-suspense.tsx +0 -344
  168. package/src/components/player-settings-form.tsx +0 -158
  169. package/src/components/react-player-wrapper.tsx +0 -651
  170. package/src/components/simple-video-player.tsx +0 -62
  171. package/src/components/ui/blur-poster.tsx +0 -93
  172. package/src/components/ui/empty-state.tsx +0 -91
  173. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  174. package/src/components/ui/error-state.tsx +0 -124
  175. package/src/components/ui/fullscreen-button.tsx +0 -81
  176. package/src/components/ui/loading-skeleton.tsx +0 -107
  177. package/src/components/ui/media-resource-preloader.tsx +0 -458
  178. package/src/components/ui/offline-message.tsx +0 -98
  179. package/src/components/ui/play-button.tsx +0 -99
  180. package/src/components/ui/seek-bar.tsx +0 -191
  181. package/src/components/ui/time-display.tsx +0 -61
  182. package/src/components/ui/volume-control.tsx +0 -190
  183. package/src/components/unified/base-media-player.tsx +0 -252
  184. package/src/components/unified/media-player.tsx +0 -75
  185. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  186. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  187. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  188. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  189. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  190. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  191. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  192. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  193. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  194. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  195. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  196. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  197. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  198. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  199. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  200. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  201. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  202. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  203. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  204. package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
  205. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  206. package/src/components/variants/minimal/index.ts +0 -23
  207. package/src/components/video-player.tsx +0 -100
  208. package/src/context/__tests__/media-store.test.ts +0 -509
  209. package/src/context/error-handling.ts +0 -398
  210. package/src/context/media-context.tsx +0 -254
  211. package/src/context/media-provider.tsx +0 -264
  212. package/src/context/media-store.ts +0 -387
  213. package/src/context/persistence.ts +0 -462
  214. package/src/core/events/event-system.ts +0 -448
  215. package/src/core/events/hooks.ts +0 -325
  216. package/src/core/events/index.ts +0 -22
  217. package/src/core/events/middleware.ts +0 -286
  218. package/src/core/index.ts +0 -22
  219. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  220. package/src/core/performance/cicd.ts +0 -98
  221. package/src/core/performance/index.ts +0 -38
  222. package/src/core/performance/media-loading-optimizer.ts +0 -544
  223. package/src/core/performance/performance-budgets.ts +0 -437
  224. package/src/core/performance/performance-monitor.tsx +0 -488
  225. package/src/core/performance/performance-testing.ts +0 -461
  226. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  227. package/src/core/plugins/base-plugin.ts +0 -225
  228. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  229. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  230. package/src/core/plugins/index.ts +0 -39
  231. package/src/core/plugins/registry.ts +0 -546
  232. package/src/core/plugins/types.ts +0 -169
  233. package/src/core/plugins/utils.ts +0 -317
  234. package/src/core/progressive-loading.tsx +0 -331
  235. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  236. package/src/core/providers/lazy-provider.tsx +0 -14
  237. package/src/core/providers/service-provider.tsx +0 -164
  238. package/src/core/utils.tsx +0 -34
  239. package/src/features/media-session/media-session-manager.ts +0 -411
  240. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  241. package/src/features/playlist/playlist-manager.ts +0 -626
  242. package/src/features/subtitles/subtitle-manager.ts +0 -435
  243. package/src/features/subtitles/subtitle-parser.ts +0 -284
  244. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  245. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  246. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  247. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  248. package/src/hooks/accessibility/index.ts +0 -27
  249. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  250. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  251. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  252. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  253. package/src/hooks/core/index.ts +0 -47
  254. package/src/hooks/legacy.ts +0 -21
  255. package/src/hooks/use-buffer-health.ts +0 -218
  256. package/src/hooks/use-enhanced-media-player.ts +0 -575
  257. package/src/hooks/use-focus-trap.tsx +0 -162
  258. package/src/hooks/use-intelligent-preloading.ts +0 -387
  259. package/src/hooks/use-keyboard-controls.ts +0 -115
  260. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  261. package/src/hooks/use-media-actions.ts +0 -184
  262. package/src/hooks/use-media-metadata.ts +0 -91
  263. package/src/hooks/use-media-optimistic.ts +0 -264
  264. package/src/hooks/use-media-player.ts +0 -343
  265. package/src/hooks/use-media-state.ts +0 -194
  266. package/src/hooks/use-memory-optimization.ts +0 -360
  267. package/src/hooks/use-network-status.ts +0 -124
  268. package/src/hooks/use-optimistic-controls.ts +0 -95
  269. package/src/hooks/use-optimized-media.ts +0 -283
  270. package/src/hooks/use-smart-preload.ts +0 -229
  271. package/src/hooks/use-touch-gestures.ts +0 -461
  272. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  273. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  274. package/src/hooks/useMediaControls.ts +0 -52
  275. package/src/hooks/useScreenshot.ts +0 -61
  276. package/src/hooks/useSubtitles.ts +0 -91
  277. package/src/hooks/useVideoPlayer.ts +0 -278
  278. package/src/icons/components/FullscreenIcon.tsx +0 -36
  279. package/src/icons/components/SettingsIcon.tsx +0 -37
  280. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  281. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  282. package/src/icons/components/media/PauseIcon.tsx +0 -38
  283. package/src/icons/components/media/PlayIcon.tsx +0 -37
  284. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  285. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  286. package/src/icons/index.ts +0 -56
  287. package/src/icons/provider.tsx +0 -58
  288. package/src/icons/types.ts +0 -60
  289. package/src/index-enhanced.ts +0 -35
  290. package/src/index-legacy.ts +0 -324
  291. package/src/index.css +0 -102
  292. package/src/lib/__tests__/async-utils.test.ts +0 -291
  293. package/src/lib/async-utils.ts +0 -194
  294. package/src/lib/deprecation.ts +0 -51
  295. package/src/lib/format-time.ts +0 -37
  296. package/src/lib/index.ts +0 -4
  297. package/src/lib/utils.ts +0 -6
  298. package/src/styles/globals.css +0 -462
  299. package/src/styles/minimal-player.css +0 -621
  300. package/src/styles/pixel-art.css +0 -41
  301. package/src/styles/videojs.css +0 -100
  302. package/src/types/events.ts +0 -47
  303. package/src/types/formats.ts +0 -79
  304. package/src/types/index.ts +0 -203
  305. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,575 +0,0 @@
1
- "use client"
2
-
3
- import React, {
4
- useCallback,
5
- useEffect,
6
- useRef,
7
- useMemo,
8
- useTransition,
9
- useOptimistic,
10
- useActionState
11
- } from "react"
12
- import { useMediaSelector, useMediaStore } from "../context/media-context"
13
- import type { EnhancedMediaStore } from "../context/media-store"
14
- import type { MediaPlayerControls, MediaPlayerState } from "../types/index"
15
- import { useMediaActions } from "./use-media-actions"
16
- import { useMediaOptimistic } from "./use-media-optimistic"
17
-
18
- interface UseEnhancedMediaPlayerOptions {
19
- src: string | string[]
20
- autoPlay?: boolean
21
- loop?: boolean
22
- muted?: boolean
23
- volume?: number
24
- preload?: "none" | "metadata" | "auto"
25
- crossOrigin?: "anonymous" | "use-credentials"
26
- playbackRates?: number[]
27
- keyboardControls?: boolean
28
- showControls?: boolean
29
- customControls?: boolean
30
- enablePerformanceMonitoring?: boolean
31
- bufferingStrategy?: "aggressive" | "conservative" | "adaptive"
32
- // Performance optimizations
33
- enableTimeUpdateThrottling?: boolean
34
- timeUpdateThrottleMs?: number
35
- enableSeekPreview?: boolean
36
- preloadStrategy?: "eager" | "lazy" | "progressive"
37
- // Event handlers
38
- onPlay?: () => void
39
- onPause?: () => void
40
- }
41
-
42
- /**
43
- * Safely sets currentTime on a media element, ensuring the value is finite
44
- */
45
- function safeSetCurrentTime(media: HTMLVideoElement | HTMLAudioElement, time: number): boolean {
46
- if (!Number.isFinite(time)) {
47
- console.warn(`Attempted to set non-finite currentTime: ${time}`)
48
- return false
49
- }
50
-
51
- if (time < 0) {
52
- console.warn(`Attempted to set negative currentTime: ${time}`)
53
- return false
54
- }
55
-
56
- try {
57
- media.currentTime = time
58
- return true
59
- } catch (error) {
60
- console.error(`Failed to set currentTime to ${time}:`, error)
61
- return false
62
- }
63
- }
64
-
65
- // Performance-optimized media player hook with React 19 features
66
- export function useEnhancedMediaPlayer(options: UseEnhancedMediaPlayerOptions) {
67
- const mediaRef = useRef<HTMLVideoElement | HTMLAudioElement>(null)
68
- const containerRef = useRef<HTMLDivElement>(null)
69
-
70
- // React 19 concurrent features
71
- const [isPending, startTransition] = useTransition()
72
- const [isSeeking, startSeekTransition] = useTransition()
73
-
74
- // Performance monitoring
75
- const renderStartTime = React.useRef<number>(0)
76
- const frameCount = React.useRef<number>(0)
77
- const lastFrameTime = React.useRef<number>(0)
78
-
79
- // Throttled time update
80
- const timeUpdateTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
81
- const lastTimeUpdate = useRef<number>(0)
82
-
83
- // Store integration
84
- const store = useMediaStore()
85
- const isEnhanced = "getOptimisticState" in store
86
-
87
- // Select only the state we need to minimize re-renders
88
- const isPlaying = useMediaSelector((state) => state.isPlaying)
89
- const currentTime = useMediaSelector((state) => state.currentTime)
90
- const duration = useMediaSelector((state) => state.duration)
91
- const volume = useMediaSelector((state) => state.volume)
92
- const isMuted = useMediaSelector((state) => state.isMuted)
93
- const isLoading = useMediaSelector((state) => state.isLoading)
94
- const isBuffering = useMediaSelector((state) => state.isBuffering)
95
- const error = useMediaSelector((state) => state.error)
96
- const buffered = useMediaSelector((state) => state.buffered)
97
- const isFullscreen = useMediaSelector((state) => state.isFullscreen)
98
-
99
- // Enhanced features - always call hooks unconditionally
100
- const enhancedStore = store as unknown as EnhancedMediaStore
101
- const optimisticState = useMediaOptimistic(enhancedStore)
102
- const actions = useMediaActions(enhancedStore)
103
-
104
- // Performance state
105
- const [performanceMetrics, setPerformanceMetrics] = React.useState({
106
- frameRate: 0,
107
- averageRenderTime: 0,
108
- droppedFrames: 0,
109
- bufferHealth: 0
110
- })
111
-
112
- // Optimistic state updates for immediate UI feedback
113
- const [optimisticVolume, setOptimisticVolume] = useOptimistic(
114
- volume,
115
- (state, newVolume: number) => {
116
- return Math.max(0, Math.min(1, newVolume))
117
- }
118
- )
119
-
120
- const [optimisticTime, setOptimisticTime] = useOptimistic(
121
- currentTime,
122
- (state, newTime: number) => {
123
- return Math.max(0, Math.min(duration || 0, newTime))
124
- }
125
- )
126
-
127
- // Initialize media element with performance optimizations
128
- useEffect(() => {
129
- const media = mediaRef.current
130
- if (!media) return
131
-
132
- // Set initial properties
133
- const initProps = {
134
- volume: options.volume,
135
- muted: options.muted,
136
- autoplay: options.autoPlay,
137
- loop: options.loop,
138
- preload: options.preload,
139
- crossOrigin: options.crossOrigin
140
- }
141
-
142
- Object.entries(initProps).forEach(([key, value]) => {
143
- if (value !== undefined) {
144
- ;(media as any)[key] = value
145
- }
146
- })
147
-
148
- // Performance optimizations
149
- media.setAttribute("preload", options.preloadStrategy === "eager" ? "auto" : "metadata")
150
-
151
- if (options.bufferingStrategy === "aggressive") {
152
- media.setAttribute("buffered", "auto")
153
- }
154
-
155
- // Hardware acceleration
156
- if (media instanceof HTMLVideoElement) {
157
- media.style.willChange = "transform"
158
- media.style.transform = "translateZ(0)"
159
- }
160
- }, [
161
- options.volume,
162
- options.muted,
163
- options.autoPlay,
164
- options.loop,
165
- options.preload,
166
- options.crossOrigin,
167
- options.preloadStrategy,
168
- options.bufferingStrategy
169
- ])
170
-
171
- // Optimized event handlers with React 19 patterns
172
- const handleTimeUpdate = useCallback(() => {
173
- const media = mediaRef.current
174
- if (!media) return
175
-
176
- const now = performance.now()
177
-
178
- // Throttle time updates for performance
179
- if (options.enableTimeUpdateThrottling !== false) {
180
- if (now - lastTimeUpdate.current < (options.timeUpdateThrottleMs || 100)) {
181
- return
182
- }
183
- lastTimeUpdate.current = now
184
- }
185
-
186
- startTransition(() => {
187
- if (isEnhanced && actions) {
188
- actions.setCurrentTime(media.currentTime)
189
- }
190
- })
191
- }, [options.enableTimeUpdateThrottling, options.timeUpdateThrottleMs, isEnhanced, actions])
192
-
193
- const handlePlay = useCallback(() => {
194
- startTransition(() => {
195
- if (isEnhanced && actions) {
196
- actions.play(true) // Optimistic update
197
- }
198
- })
199
- options.onPlay?.()
200
- }, [isEnhanced, actions, options.onPlay])
201
-
202
- const handlePause = useCallback(() => {
203
- startTransition(() => {
204
- if (isEnhanced && actions) {
205
- actions.pause(true) // Optimistic update
206
- }
207
- })
208
- options.onPause?.()
209
- }, [isEnhanced, actions, options.onPause])
210
-
211
- const handleVolumeChange = useCallback(() => {
212
- const media = mediaRef.current
213
- if (!media) return
214
-
215
- startTransition(() => {
216
- if (isEnhanced && actions) {
217
- actions.setVolume(media.volume, true) // Optimistic update
218
- media.muted ? actions.mute(true) : actions.unmute(true)
219
- }
220
- })
221
- }, [isEnhanced, actions])
222
-
223
- const handleSeeking = useCallback(() => {
224
- startSeekTransition(() => {
225
- // Seek operations get their own transition
226
- })
227
- }, [])
228
-
229
- const handleSeeked = useCallback(() => {
230
- // Seek completed
231
- }, [])
232
-
233
- const handleProgress = useCallback(() => {
234
- const media = mediaRef.current
235
- if (!media) return
236
-
237
- startTransition(() => {
238
- if (isEnhanced && actions) {
239
- actions.setBuffered(media.buffered)
240
- }
241
- })
242
- }, [isEnhanced, actions])
243
-
244
- // Performance monitoring
245
- const measureRenderTime = useCallback(() => {
246
- const now = performance.now()
247
- const deltaTime = now - lastFrameTime.current
248
-
249
- if (deltaTime > 0) {
250
- frameCount.current++
251
-
252
- // Calculate frame rate every second
253
- if (frameCount.current >= 60) {
254
- const fps = Math.round((frameCount.current * 1000) / (now - lastFrameTime.current))
255
- setPerformanceMetrics((prev) => ({
256
- ...prev,
257
- frameRate: fps,
258
- droppedFrames: Math.max(0, 60 - fps)
259
- }))
260
- frameCount.current = 0
261
- lastFrameTime.current = now
262
- }
263
- }
264
- }, [])
265
-
266
- // Attach event listeners with performance optimization
267
- useEffect(() => {
268
- const media = mediaRef.current
269
- if (!media) return
270
-
271
- // Use passive listeners where possible for better performance
272
- const eventListeners = [
273
- { event: "timeupdate", handler: handleTimeUpdate, passive: true },
274
- { event: "play", handler: handlePlay },
275
- { event: "pause", handler: handlePause },
276
- { event: "volumechange", handler: handleVolumeChange },
277
- { event: "seeking", handler: handleSeeking },
278
- { event: "seeked", handler: handleSeeked },
279
- { event: "progress", handler: handleProgress, passive: true },
280
- { event: "loadedmetadata", handler: () => measureRenderTime() },
281
- { event: "loadeddata", handler: () => measureRenderTime() }
282
- ]
283
-
284
- eventListeners.forEach(({ event, handler, passive }) => {
285
- const options = passive ? { passive: true } : {}
286
- media.addEventListener(event, handler, options)
287
- })
288
-
289
- // Performance monitoring frame loop
290
- let rafId: number
291
- const performanceLoop = () => {
292
- measureRenderTime()
293
- rafId = requestAnimationFrame(performanceLoop)
294
- }
295
-
296
- if (options.enablePerformanceMonitoring) {
297
- performanceLoop()
298
- }
299
-
300
- return () => {
301
- eventListeners.forEach(({ event, handler }) => {
302
- media.removeEventListener(event, handler)
303
- })
304
- if (rafId) {
305
- cancelAnimationFrame(rafId)
306
- }
307
- }
308
- }, [
309
- handleTimeUpdate,
310
- handlePlay,
311
- handlePause,
312
- handleVolumeChange,
313
- handleSeeking,
314
- handleSeeked,
315
- handleProgress,
316
- measureRenderTime,
317
- options.enablePerformanceMonitoring
318
- ])
319
-
320
- // Optimized control functions with React 19 features
321
- const controls = useMemo(() => {
322
- const play = async () => {
323
- const media = mediaRef.current
324
- if (!media) return
325
-
326
- if (isEnhanced && actions) {
327
- await actions.play(true) // Optimistic
328
- } else {
329
- try {
330
- await media.play()
331
- } catch (error) {
332
- console.error("Failed to play media:", error)
333
- }
334
- }
335
- }
336
-
337
- const pause = () => {
338
- const media = mediaRef.current
339
- if (!media) return
340
-
341
- if (isEnhanced && actions) {
342
- actions.pause(true) // Optimistic
343
- } else {
344
- media.pause()
345
- }
346
- }
347
-
348
- const toggle = () => {
349
- if (isPlaying) {
350
- pause()
351
- } else {
352
- play()
353
- }
354
- }
355
-
356
- const seek = (time: number) => {
357
- const media = mediaRef.current
358
- if (!media) return
359
-
360
- const validDuration = Number.isFinite(duration) && duration > 0 ? duration : Number.isFinite(media.duration) ? media.duration : 0
361
- if (validDuration === 0) {
362
- console.warn("Cannot seek: duration is not available")
363
- return
364
- }
365
-
366
- const clampedTime = Math.max(0, Math.min(time, validDuration))
367
-
368
- if (!Number.isFinite(clampedTime)) {
369
- console.warn(`Computed non-finite seek time: ${clampedTime}`)
370
- return
371
- }
372
-
373
- if (isEnhanced && actions) {
374
- startSeekTransition(() => {
375
- actions.seek(clampedTime, true) // Optimistic
376
- })
377
- } else {
378
- safeSetCurrentTime(media, clampedTime)
379
- }
380
- }
381
-
382
- const setVolume = (volume: number) => {
383
- const media = mediaRef.current
384
- if (!media) return
385
-
386
- const clampedVolume = Math.max(0, Math.min(1, volume))
387
-
388
- if (isEnhanced && actions) {
389
- setOptimisticVolume(clampedVolume)
390
- startTransition(() => {
391
- actions.setVolume(clampedVolume, true)
392
- })
393
- } else {
394
- media.volume = clampedVolume
395
- }
396
- }
397
-
398
- const toggleMute = () => {
399
- const media = mediaRef.current
400
- if (!media) return
401
-
402
- if (isEnhanced && actions) {
403
- actions.toggleMute(true) // Optimistic
404
- } else {
405
- media.muted = !media.muted
406
- }
407
- }
408
-
409
- const enterFullscreen = async () => {
410
- const container = containerRef.current
411
- if (!container || !document.fullscreenEnabled) return
412
-
413
- try {
414
- await container.requestFullscreen()
415
- if (isEnhanced && actions) {
416
- actions.enterFullscreen(true)
417
- }
418
- } catch (error) {
419
- console.error("Failed to enter fullscreen:", error)
420
- }
421
- }
422
-
423
- const exitFullscreen = async () => {
424
- if (!document.fullscreenElement) return
425
-
426
- try {
427
- await document.exitFullscreen()
428
- if (isEnhanced && actions) {
429
- actions.exitFullscreen(true)
430
- }
431
- } catch (error) {
432
- console.error("Failed to exit fullscreen:", error)
433
- }
434
- }
435
-
436
- const mute = () => {
437
- const media = mediaRef.current
438
- if (!media) return
439
-
440
- if (isEnhanced && actions) {
441
- actions.mute(true)
442
- } else {
443
- media.muted = true
444
- }
445
- }
446
-
447
- const unmute = () => {
448
- const media = mediaRef.current
449
- if (!media) return
450
-
451
- if (isEnhanced && actions) {
452
- actions.unmute(true)
453
- } else {
454
- media.muted = false
455
- }
456
- }
457
-
458
- const toggleFullscreen = async () => {
459
- if (isFullscreen) {
460
- await exitFullscreen()
461
- } else {
462
- await enterFullscreen()
463
- }
464
- }
465
-
466
- const setCurrentTime = (time: number) => {
467
- const media = mediaRef.current
468
- if (!media) return
469
-
470
- const validDuration =
471
- Number.isFinite(duration) && duration > 0
472
- ? duration
473
- : Number.isFinite(media.duration)
474
- ? media.duration
475
- : 0
476
-
477
- if (validDuration === 0) {
478
- console.warn("Cannot set currentTime: duration is not available")
479
- return
480
- }
481
-
482
- const clampedTime = Math.max(0, Math.min(time, validDuration))
483
-
484
- if (!Number.isFinite(clampedTime)) {
485
- console.warn(`Computed non-finite currentTime: ${clampedTime}`)
486
- return
487
- }
488
-
489
- safeSetCurrentTime(media, clampedTime)
490
- }
491
-
492
- return {
493
- play,
494
- pause,
495
- toggle,
496
- seek,
497
- setCurrentTime,
498
- setVolume,
499
- mute,
500
- unmute,
501
- toggleMute,
502
- enterFullscreen,
503
- exitFullscreen,
504
- toggleFullscreen
505
- }
506
- }, [
507
- isPlaying,
508
- isFullscreen,
509
- duration,
510
- isEnhanced,
511
- actions,
512
- startTransition,
513
- startSeekTransition,
514
- setOptimisticVolume
515
- ])
516
-
517
- // Computed state
518
- const computedState = useMemo(
519
- () => ({
520
- isPlaying: optimisticState?.isPlaying ?? isPlaying,
521
- currentTime: optimisticState?.currentTime ?? currentTime,
522
- duration: optimisticState?.actualState?.duration ?? duration,
523
- volume: optimisticState?.volume ?? optimisticVolume,
524
- isMuted: optimisticState?.isMuted ?? isMuted,
525
- isLoading: optimisticState?.isBuffering ?? isLoading,
526
- isBuffering: optimisticState?.isBuffering ?? isBuffering,
527
- error: optimisticState?.actualState?.error ?? error,
528
- buffered: optimisticState?.actualState?.buffered ?? buffered,
529
- isFullscreen: optimisticState?.isFullscreen ?? isFullscreen,
530
- progress: duration > 0 ? currentTime / duration : 0,
531
- isTransitioning: isPending || isSeeking,
532
- canPlay: !isLoading && !isBuffering && !error
533
- }),
534
- [
535
- optimisticState,
536
- isPlaying,
537
- currentTime,
538
- duration,
539
- optimisticVolume,
540
- isMuted,
541
- isLoading,
542
- isBuffering,
543
- error,
544
- buffered,
545
- isFullscreen,
546
- isPending,
547
- isSeeking
548
- ]
549
- )
550
-
551
- return {
552
- // Refs
553
- mediaRef,
554
- containerRef,
555
-
556
- // State
557
- state: computedState,
558
- actualState: optimisticState?.actualState,
559
-
560
- // Controls
561
- controls,
562
-
563
- // Performance metrics
564
- performanceMetrics,
565
- isTransitioning: isPending || isSeeking,
566
-
567
- // Enhanced features
568
- actions: optimisticState,
569
- actionState: optimisticState,
570
-
571
- // Optimistic features
572
- optimisticState,
573
- isEnhanced
574
- }
575
- }