@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,190 @@
1
+ "use client"
2
+
3
+ import { useCallback, useState, useActionState, useOptimistic } from "react"
4
+ import type { MediaPlayerState } from "../types/index"
5
+ import { useMediaStore, useMediaSelector } from "../context/media-context"
6
+ import { useMediaOptimistic } from "./use-media-optimistic"
7
+ import { useMediaActions } from "./use-media-actions"
8
+ import type { EnhancedMediaStore } from "../context/media-store"
9
+
10
+ // Legacy hook for backward compatibility
11
+ export function useMediaState() {
12
+ const [state, setState] = useState<MediaPlayerState>({
13
+ isPlaying: false,
14
+ currentTime: 0,
15
+ duration: 0,
16
+ volume: 1,
17
+ isMuted: false,
18
+ isLoading: false,
19
+ isFullscreen: false,
20
+ error: null,
21
+ buffered: null
22
+ })
23
+
24
+ const updateState = (updates: Partial<MediaPlayerState>) => {
25
+ setState((prev: MediaPlayerState) => ({ ...prev, ...updates }))
26
+ }
27
+
28
+ const setPlaying = (isPlaying: boolean) => {
29
+ updateState({ isPlaying })
30
+ }
31
+
32
+ const setCurrentTime = (currentTime: number) => {
33
+ updateState({ currentTime })
34
+ }
35
+
36
+ const setDuration = (duration: number) => {
37
+ updateState({ duration })
38
+ }
39
+
40
+ const setVolume = (volume: number) => {
41
+ updateState({ volume: Math.max(0, Math.min(1, volume)) })
42
+ }
43
+
44
+ const setMuted = (isMuted: boolean) => {
45
+ updateState({ isMuted })
46
+ }
47
+
48
+ const setLoading = (isLoading: boolean) => {
49
+ updateState({ isLoading })
50
+ }
51
+
52
+ const setFullscreen = (isFullscreen: boolean) => {
53
+ updateState({ isFullscreen })
54
+ }
55
+
56
+ const setError = (error: string | null) => {
57
+ updateState({ error })
58
+ }
59
+
60
+ const setBuffered = (buffered: TimeRanges | null) => {
61
+ updateState({ buffered })
62
+ }
63
+
64
+ return {
65
+ state,
66
+ updateState,
67
+ setPlaying,
68
+ setCurrentTime,
69
+ setDuration,
70
+ setVolume,
71
+ setMuted,
72
+ setLoading,
73
+ setFullscreen,
74
+ setError,
75
+ setBuffered
76
+ }
77
+ }
78
+
79
+ // React 19 enhanced media state hook
80
+ export function useEnhancedMediaState() {
81
+ const store = useMediaStore()
82
+
83
+ // Check if this is an enhanced store
84
+ const isEnhanced = 'getOptimisticState' in store
85
+
86
+ if (!isEnhanced) {
87
+ // Fall back to regular media state if not enhanced
88
+ return useMediaState() as any
89
+ }
90
+
91
+ // Cast to enhanced store type
92
+ const enhancedStore = store as unknown as EnhancedMediaStore
93
+
94
+ // Use React 19 optimistic updates
95
+ const optimisticState = useMediaOptimistic(enhancedStore)
96
+
97
+ // Get action handlers with React 19 features
98
+ const actions = useMediaActions(enhancedStore)
99
+
100
+ return {
101
+ // State (optimistic values for immediate UI feedback)
102
+ state: optimisticState.state,
103
+ actualState: optimisticState.actualState,
104
+
105
+ // Individual state selectors
106
+ isPlaying: optimisticState.isPlaying,
107
+ currentTime: optimisticState.currentTime,
108
+ duration: optimisticState.state.duration,
109
+ volume: optimisticState.volume,
110
+ isMuted: optimisticState.isMuted,
111
+ isLoading: optimisticState.isBuffering,
112
+ isFullscreen: optimisticState.isFullscreen,
113
+ error: optimisticState.state.error,
114
+ buffered: optimisticState.state.buffered,
115
+
116
+ // Computed values
117
+ progress: optimisticState.progress,
118
+ formattedTime: optimisticState.formattedTime,
119
+ formattedDuration: optimisticState.formattedDuration,
120
+
121
+ // Actions with optimistic updates
122
+ actions,
123
+
124
+ // Action state for loading/error handling
125
+ isActionLoading: actions.isLoading,
126
+ actionError: actions.errorMessage,
127
+ retryLastAction: actions.retryLastAction,
128
+
129
+ // Legacy compatibility methods
130
+ updateState: (updates: Partial<MediaPlayerState>) => {
131
+ // Map legacy updates to new actions
132
+ if ('isPlaying' in updates) {
133
+ updates.isPlaying ? actions.play() : actions.pause()
134
+ }
135
+ if ('currentTime' in updates) {
136
+ actions.setCurrentTime(updates.currentTime!)
137
+ }
138
+ if ('duration' in updates) {
139
+ actions.setDuration(updates.duration!)
140
+ }
141
+ if ('volume' in updates) {
142
+ actions.setVolume(updates.volume!)
143
+ }
144
+ if ('isMuted' in updates) {
145
+ updates.isMuted ? actions.mute() : actions.unmute()
146
+ }
147
+ if ('isLoading' in updates) {
148
+ actions.setLoading(updates.isLoading!)
149
+ }
150
+ if ('isFullscreen' in updates) {
151
+ updates.isFullscreen ? actions.enterFullscreen() : actions.exitFullscreen()
152
+ }
153
+ if ('error' in updates) {
154
+ actions.setError(updates.error ?? null)
155
+ }
156
+ if ('buffered' in updates) {
157
+ actions.setBuffered(updates.buffered ?? null)
158
+ }
159
+ },
160
+
161
+ // Individual action methods for legacy compatibility
162
+ setPlaying: (isPlaying: boolean) => {
163
+ isPlaying ? actions.play(true) : actions.pause(true) // Use optimistic updates
164
+ },
165
+ setCurrentTime: (time: number) => actions.setCurrentTime(time),
166
+ setDuration: (duration: number) => actions.setDuration(duration),
167
+ setVolume: (volume: number) => actions.setVolume(volume, true),
168
+ setMuted: (muted: boolean) => {
169
+ muted ? actions.mute(true) : actions.unmute(true)
170
+ },
171
+ setLoading: (loading: boolean) => actions.setLoading(loading),
172
+ setFullscreen: (fullscreen: boolean) => {
173
+ fullscreen ? actions.enterFullscreen(true) : actions.exitFullscreen(true)
174
+ },
175
+ setError: (error: string | null) => actions.setError(error),
176
+ setBuffered: (buffered: TimeRanges | null) => actions.setBuffered(buffered)
177
+ }
178
+ }
179
+
180
+ // Hook that automatically chooses between legacy and enhanced based on context availability
181
+ export function useAdaptiveMediaState() {
182
+ try {
183
+ // Try to use the enhanced version if MediaStore context is available
184
+ return useEnhancedMediaState()
185
+ } catch (error) {
186
+ // Fall back to legacy version if not in MediaProvider context
187
+ console.warn('MediaStore context not available, using legacy state management')
188
+ return useMediaState()
189
+ }
190
+ }
@@ -0,0 +1,358 @@
1
+ "use client"
2
+
3
+ import React, { useEffect, useRef, useCallback, useMemo } from "react"
4
+
5
+ // Memory optimization hook for media players
6
+ export function useMemoryOptimization(options: {
7
+ maxMemoryUsage?: number // in MB
8
+ cleanupInterval?: number // in ms
9
+ enableGC?: boolean
10
+ monitorMemory?: boolean
11
+ } = {}) {
12
+ const {
13
+ maxMemoryUsage = 100, // 100MB default
14
+ cleanupInterval = 30000, // 30 seconds default
15
+ enableGC = true,
16
+ monitorMemory = true
17
+ } = options
18
+
19
+ const cleanupTimeoutRef = useRef<NodeJS.Timeout>()
20
+ const observersRef = useRef<Set<MutationObserver>>(new Set())
21
+ const eventListenersRef = useRef<Map<Element, Array<{ event: string; handler: EventListener }>>>(new Map())
22
+ const intervalRefs = useRef<Set<NodeJS.Timeout>>(new Set())
23
+ const animationFrameRefs = useRef<Set<number>>(new Set())
24
+
25
+ // Get current memory usage
26
+ const getMemoryUsage = useCallback(() => {
27
+ if (typeof window === 'undefined' || !('memory' in performance)) {
28
+ return { used: 0, total: 0, limit: 0 }
29
+ }
30
+
31
+ const memory = (performance as any).memory
32
+ return {
33
+ used: memory.usedJSHeapSize,
34
+ total: memory.totalJSHeapSize,
35
+ limit: memory.jsHeapSizeLimit
36
+ }
37
+ }, [])
38
+
39
+ // Memory monitoring state
40
+ const [memoryStats, setMemoryStats] = React.useState({
41
+ used: 0,
42
+ total: 0,
43
+ limit: 0,
44
+ usage: 0,
45
+ isHighUsage: false
46
+ })
47
+
48
+ // Memory monitoring
49
+ useEffect(() => {
50
+ if (!monitorMemory) return
51
+
52
+ const checkMemory = () => {
53
+ const memory = getMemoryUsage()
54
+ const usage = (memory.used / 1024 / 1024) // Convert to MB
55
+ const isHighUsage = usage > maxMemoryUsage
56
+
57
+ setMemoryStats({
58
+ ...memory,
59
+ usage,
60
+ isHighUsage
61
+ })
62
+
63
+ // Trigger cleanup if memory usage is high
64
+ if (isHighUsage && enableGC) {
65
+ performCleanup()
66
+ }
67
+ }
68
+
69
+ checkMemory()
70
+ const interval = setInterval(checkMemory, cleanupInterval)
71
+ intervalRefs.current.add(interval)
72
+
73
+ return () => {
74
+ clearInterval(interval)
75
+ intervalRefs.current.delete(interval)
76
+ }
77
+ }, [monitorMemory, getMemoryUsage, maxMemoryUsage, enableGC, cleanupInterval])
78
+
79
+ // Cleanup function
80
+ const performCleanup = useCallback(() => {
81
+ // Clear all timeouts
82
+ intervalRefs.current.forEach(timeout => {
83
+ clearTimeout(timeout)
84
+ })
85
+ intervalRefs.current.clear()
86
+
87
+ // Cancel all animation frames
88
+ animationFrameRefs.current.forEach(frameId => {
89
+ cancelAnimationFrame(frameId)
90
+ })
91
+ animationFrameRefs.current.clear()
92
+
93
+ // Disconnect all observers
94
+ observersRef.current.forEach(observer => {
95
+ observer.disconnect()
96
+ })
97
+ observersRef.current.clear()
98
+
99
+ // Remove all event listeners
100
+ eventListenersRef.current.forEach((listeners, element) => {
101
+ listeners.forEach(({ event, handler }) => {
102
+ element.removeEventListener(event, handler)
103
+ })
104
+ })
105
+ eventListenersRef.current.clear()
106
+
107
+ // Trigger garbage collection if available
108
+ if (enableGC && 'gc' in window) {
109
+ (window as any).gc()
110
+ }
111
+ }, [enableGC])
112
+
113
+ // Safe event listener management
114
+ const addEventListener = useCallback((
115
+ element: Element,
116
+ event: string,
117
+ handler: EventListener,
118
+ options?: AddEventListenerOptions
119
+ ) => {
120
+ element.addEventListener(event, handler, options)
121
+
122
+ if (!eventListenersRef.current.has(element)) {
123
+ eventListenersRef.current.set(element, [])
124
+ }
125
+ eventListenersRef.current.get(element)!.push({ event, handler })
126
+
127
+ // Return cleanup function
128
+ return () => {
129
+ element.removeEventListener(event, handler)
130
+ const listeners = eventListenersRef.current.get(element)
131
+ if (listeners) {
132
+ const index = listeners.findIndex(l => l.event === event && l.handler === handler)
133
+ if (index > -1) {
134
+ listeners.splice(index, 1)
135
+ }
136
+ if (listeners.length === 0) {
137
+ eventListenersRef.current.delete(element)
138
+ }
139
+ }
140
+ }
141
+ }, [])
142
+
143
+ // Safe interval management
144
+ const setInterval = useCallback((callback: () => void, delay: number) => {
145
+ const timeoutId = setInterval(callback, delay)
146
+ intervalRefs.current.add(timeoutId)
147
+
148
+ return () => {
149
+ clearInterval(timeoutId)
150
+ intervalRefs.current.delete(timeoutId)
151
+ }
152
+ }, [])
153
+
154
+ // Safe timeout management
155
+ const setTimeout = useCallback((callback: () => void, delay: number) => {
156
+ const timeoutId = setTimeout(callback, delay)
157
+ intervalRefs.current.add(timeoutId)
158
+
159
+ return () => {
160
+ clearTimeout(timeoutId)
161
+ intervalRefs.current.delete(timeoutId)
162
+ }
163
+ }, [])
164
+
165
+ // Safe animation frame management
166
+ const requestAnimationFrame = useCallback((callback: FrameRequestCallback) => {
167
+ const frameId = requestAnimationFrame(callback)
168
+ animationFrameRefs.current.add(frameId)
169
+
170
+ return () => {
171
+ cancelAnimationFrame(frameId)
172
+ animationFrameRefs.current.delete(frameId)
173
+ }
174
+ }, [])
175
+
176
+ // Safe observer management
177
+ const addObserver = useCallback((observer: MutationObserver) => {
178
+ observersRef.current.add(observer)
179
+
180
+ return () => {
181
+ observer.disconnect()
182
+ observersRef.current.delete(observer)
183
+ }
184
+ }, [])
185
+
186
+ // Cleanup on unmount
187
+ useEffect(() => {
188
+ return () => {
189
+ performCleanup()
190
+ }
191
+ }, [performCleanup])
192
+
193
+ return {
194
+ // Memory stats
195
+ memoryStats,
196
+ getMemoryUsage,
197
+
198
+ // Cleanup functions
199
+ performCleanup,
200
+
201
+ // Safe API functions
202
+ addEventListener,
203
+ setInterval,
204
+ setTimeout,
205
+ requestAnimationFrame,
206
+ addObserver,
207
+
208
+ // Utilities
209
+ formatBytes: (bytes: number) => {
210
+ if (bytes === 0) return '0 Bytes'
211
+ const k = 1024
212
+ const sizes = ['Bytes', 'KB', 'MB', 'GB']
213
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
214
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
215
+ }
216
+ }
217
+ }
218
+
219
+ // Resource cleanup hook for media elements
220
+ export function useMediaResourceCleanup(mediaRef: React.RefObject<HTMLVideoElement | HTMLAudioElement>) {
221
+ const { addEventListener, performCleanup } = useMemoryOptimization()
222
+
223
+ // Track resource cleanup
224
+ const cleanupResources = useCallback(() => {
225
+ const media = mediaRef.current
226
+ if (!media) return
227
+
228
+ // Stop media playback
229
+ if (!media.paused) {
230
+ _media.pause()
231
+ }
232
+
233
+ // Clear source
234
+ if (media.src) {
235
+ media.src = ''
236
+ media.load()
237
+ }
238
+
239
+ // Remove source elements
240
+ while (media.firstChild) {
241
+ media.removeChild(media.firstChild)
242
+ }
243
+
244
+ // Clear any pending seeks
245
+ media.currentTime = 0
246
+
247
+ // Clear buffered data
248
+ if ('clearBuffered' in media) {
249
+ (media as any).clearBuffered()
250
+ }
251
+ }, [mediaRef])
252
+
253
+ // Enhanced event listener registration
254
+ const registerMediaEventListener = useCallback((
255
+ event: string,
256
+ handler: EventListener,
257
+ options?: AddEventListenerOptions
258
+ ) => {
259
+ const media = mediaRef.current
260
+ if (!media) return () => {}
261
+
262
+ return addEventListener(media, event, handler, options)
263
+ }, [mediaRef, addEventListener])
264
+
265
+ // Cleanup on unmount
266
+ useEffect(() => {
267
+ return cleanupResources
268
+ }, [cleanupResources])
269
+
270
+ return {
271
+ cleanupResources,
272
+ registerMediaEventListener
273
+ }
274
+ }
275
+
276
+ // Performance monitoring hook
277
+ export function usePerformanceMonitoring() {
278
+ const [metrics, setMetrics] = React.useState({
279
+ fps: 0,
280
+ frameDrops: 0,
281
+ longTasks: 0,
282
+ totalLongTaskDuration: 0
283
+ })
284
+
285
+ const frameCountRef = useRef(0)
286
+ const lastFrameTimeRef = useRef(performance.now())
287
+ const longTaskObserverRef = useRef<PerformanceObserver>()
288
+
289
+ // FPS monitoring
290
+ useEffect(() => {
291
+ let rafId: number
292
+
293
+ const measureFrame = () => {
294
+ frameCountRef.current++
295
+ const now = performance.now()
296
+
297
+ // Calculate FPS every second
298
+ if (now - lastFrameTimeRef.current >= 1000) {
299
+ const fps = Math.round((frameCountRef.current * 1000) / (now - lastFrameTimeRef.current))
300
+ const expectedFrames = Math.round((now - lastFrameTimeRef.current) / 16.67) // 60fps
301
+ const frameDrops = Math.max(0, expectedFrames - frameCountRef.current)
302
+
303
+ setMetrics(prev => ({
304
+ ...prev,
305
+ fps,
306
+ frameDrops: prev.frameDrops + frameDrops
307
+ }))
308
+
309
+ frameCountRef.current = 0
310
+ lastFrameTimeRef.current = now
311
+ }
312
+
313
+ rafId = requestAnimationFrame(measureFrame)
314
+ }
315
+
316
+ rafId = requestAnimationFrame(measureFrame)
317
+
318
+ return () => {
319
+ cancelAnimationFrame(rafId)
320
+ }
321
+ }, [])
322
+
323
+ // Long task monitoring
324
+ useEffect(() => {
325
+ if (!('PerformanceObserver' in window)) return
326
+
327
+ try {
328
+ const observer = new PerformanceObserver((list) => {
329
+ for (const entry of list.getEntries()) {
330
+ if (entry.duration > 50) { // Long task threshold
331
+ setMetrics(prev => ({
332
+ ...prev,
333
+ longTasks: prev.longTasks + 1,
334
+ totalLongTaskDuration: prev.totalLongTaskDuration + entry.duration
335
+ }))
336
+ }
337
+ }
338
+ })
339
+
340
+ observer.observe({ entryTypes: ['longtask'] })
341
+ longTaskObserverRef.current = observer
342
+
343
+ return () => {
344
+ observer.disconnect()
345
+ }
346
+ } catch (error) {
347
+ console.warn('Long task monitoring not supported:', error)
348
+ }
349
+ }, [])
350
+
351
+ return {
352
+ ...metrics,
353
+ averageLongTaskDuration: metrics.longTasks > 0
354
+ ? metrics.totalLongTaskDuration / metrics.longTasks
355
+ : 0,
356
+ isPerformanceGood: metrics.fps >= 50 && metrics.frameDrops < 5
357
+ }
358
+ }
@@ -0,0 +1,92 @@
1
+ import { useOptimistic, useTransition } from 'react'
2
+
3
+ export interface MediaState {
4
+ isPlaying: boolean
5
+ volume: number
6
+ currentTime: number
7
+ playbackRate: number
8
+ }
9
+
10
+ export function useOptimisticMediaState(initialState: MediaState, mediaElement?: HTMLMediaElement | null) {
11
+ const [isPending, startTransition] = useTransition()
12
+
13
+ // Optimistic state for each property
14
+ const [optimisticPlaying, setOptimisticPlaying] = useOptimistic(
15
+ initialState.isPlaying,
16
+ (_, value: boolean) => value
17
+ )
18
+
19
+ const [optimisticVolume, setOptimisticVolume] = useOptimistic(
20
+ initialState.volume,
21
+ (_, value: number) => value
22
+ )
23
+
24
+ const [optimisticTime, setOptimisticTime] = useOptimistic(
25
+ initialState.currentTime,
26
+ (_, value: number) => value
27
+ )
28
+
29
+ const [optimisticRate, setOptimisticRate] = useOptimistic(
30
+ initialState.playbackRate,
31
+ (_, value: number) => value
32
+ )
33
+
34
+ // Wrapped actions with optimistic updates
35
+ const actions = {
36
+ togglePlay: async () => {
37
+ const newState = !optimisticPlaying
38
+ setOptimisticPlaying(newState)
39
+
40
+ startTransition(async () => {
41
+ if (mediaElement) {
42
+ if (newState) {
43
+ await mediaElement.play()
44
+ } else {
45
+ mediaElement.pause()
46
+ }
47
+ }
48
+ })
49
+ },
50
+
51
+ setVolume: async (volume: number) => {
52
+ setOptimisticVolume(volume)
53
+
54
+ startTransition(async () => {
55
+ if (mediaElement) {
56
+ mediaElement.volume = volume
57
+ }
58
+ })
59
+ },
60
+
61
+ seek: async (time: number) => {
62
+ setOptimisticTime(time)
63
+
64
+ startTransition(async () => {
65
+ if (mediaElement) {
66
+ mediaElement.currentTime = time
67
+ }
68
+ })
69
+ },
70
+
71
+ setPlaybackRate: async (rate: number) => {
72
+ setOptimisticRate(rate)
73
+
74
+ startTransition(async () => {
75
+ if (mediaElement) {
76
+ mediaElement.playbackRate = rate
77
+ }
78
+ })
79
+ }
80
+ }
81
+
82
+ return {
83
+ state: {
84
+ isPlaying: optimisticPlaying,
85
+ volume: optimisticVolume,
86
+ currentTime: optimisticTime,
87
+ playbackRate: optimisticRate
88
+ },
89
+ actions,
90
+ isPending
91
+ }
92
+ }