@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,398 +0,0 @@
1
- "use client"
2
-
3
- import React from "react"
4
- import type { MediaActionType } from "./media-context"
5
- import type { OptimisticMediaAction } from "./media-store"
6
-
7
- // Error types specific to media operations
8
- export enum MediaErrorType {
9
- NETWORK_ERROR = "NETWORK_ERROR",
10
- PLAYBACK_ERROR = "PLAYBACK_ERROR",
11
- PERMISSION_ERROR = "PERMISSION_ERROR",
12
- NOT_SUPPORTED_ERROR = "NOT_SUPPORTED_ERROR",
13
- TIMEOUT_ERROR = "TIMEOUT_ERROR",
14
- UNKNOWN_ERROR = "UNKNOWN_ERROR"
15
- }
16
-
17
- // Enhanced error interface
18
- export interface MediaError {
19
- type: MediaErrorType
20
- message: string
21
- action?: OptimisticMediaAction
22
- timestamp: number
23
- retryable: boolean
24
- retryCount: number
25
- originalError?: Error
26
- }
27
-
28
- // Retry configuration
29
- export interface RetryConfig {
30
- maxRetries: number
31
- baseDelay: number // milliseconds
32
- maxDelay: number // milliseconds
33
- exponentialBackoff: boolean
34
- retryableErrors: MediaErrorType[]
35
- retryableActions: MediaActionType[]
36
- }
37
-
38
- // Default retry configuration
39
- const DEFAULT_RETRY_CONFIG: RetryConfig = {
40
- maxRetries: 3,
41
- baseDelay: 1000,
42
- maxDelay: 10000,
43
- exponentialBackoff: true,
44
- retryableErrors: [MediaErrorType.NETWORK_ERROR, MediaErrorType.TIMEOUT_ERROR],
45
- retryableActions: ["PLAY", "PAUSE", "SEEK", "SET_VOLUME", "ENTER_FULLSCREEN", "EXIT_FULLSCREEN"]
46
- }
47
-
48
- // Error recovery strategies
49
- export interface ErrorRecoveryStrategy {
50
- canRecover(error: MediaError): boolean
51
- recover(error: MediaError): Promise<void>
52
- }
53
-
54
- // Network error recovery
55
- class NetworkErrorRecovery implements ErrorRecoveryStrategy {
56
- canRecover(error: MediaError): boolean {
57
- return error.type === MediaErrorType.NETWORK_ERROR && error.retryCount < 3
58
- }
59
-
60
- async recover(error: MediaError): Promise<void> {
61
- // Wait for network to become available
62
- if (navigator.onLine === false) {
63
- await new Promise((resolve) => {
64
- const handleOnline = () => {
65
- window.removeEventListener("online", handleOnline)
66
- resolve(void 0)
67
- }
68
- window.addEventListener("online", handleOnline)
69
- })
70
- }
71
-
72
- // Additional delay for network stability
73
- await new Promise((resolve) => setTimeout(resolve, 2000))
74
- }
75
- }
76
-
77
- // Playback error recovery
78
- class PlaybackErrorRecovery implements ErrorRecoveryStrategy {
79
- canRecover(error: MediaError): boolean {
80
- return error.type === MediaErrorType.PLAYBACK_ERROR && error.retryCount < 2
81
- }
82
-
83
- async recover(error: MediaError): Promise<void> {
84
- // Try to reload the media element
85
- const mediaElement = document.querySelector("video, audio") as HTMLMediaElement
86
- if (mediaElement) {
87
- mediaElement.load()
88
- await new Promise((resolve) => {
89
- const handleCanPlay = () => {
90
- mediaElement.removeEventListener("canplay", handleCanPlay)
91
- resolve(void 0)
92
- }
93
- mediaElement.addEventListener("canplay", handleCanPlay)
94
- })
95
- }
96
- }
97
- }
98
-
99
- // Permission error recovery (for fullscreen, etc.)
100
- class PermissionErrorRecovery implements ErrorRecoveryStrategy {
101
- canRecover(error: MediaError): boolean {
102
- return (
103
- error.type === MediaErrorType.PERMISSION_ERROR && error.action?.type === "ENTER_FULLSCREEN"
104
- )
105
- }
106
-
107
- async recover(error: MediaError): Promise<void> {
108
- // Request user interaction for fullscreen
109
- console.warn("Fullscreen requires user interaction")
110
- // In a real implementation, you might show a message to the user
111
- }
112
- }
113
-
114
- // Error handler class
115
- export class MediaErrorHandler {
116
- private config: RetryConfig
117
- private recoveryStrategies: ErrorRecoveryStrategy[]
118
- private errorQueue: Map<string, MediaError> = new Map()
119
- private listeners: Set<(error: MediaError) => void> = new Set()
120
-
121
- constructor(config: Partial<RetryConfig> = {}, recoveryStrategies: ErrorRecoveryStrategy[] = []) {
122
- this.config = { ...DEFAULT_RETRY_CONFIG, ...config }
123
- this.recoveryStrategies = [
124
- new NetworkErrorRecovery(),
125
- new PlaybackErrorRecovery(),
126
- new PermissionErrorRecovery(),
127
- ...recoveryStrategies
128
- ]
129
- }
130
-
131
- // Create a media error from a generic error
132
- createMediaError(error: unknown, action?: OptimisticMediaAction, retryCount = 0): MediaError {
133
- const timestamp = Date.now()
134
-
135
- if (error instanceof Error) {
136
- const errorType = this.categorizeError(error, action)
137
- return {
138
- type: errorType,
139
- message: error.message,
140
- action,
141
- timestamp,
142
- retryable: this.isRetryable(errorType, action),
143
- retryCount,
144
- originalError: error
145
- }
146
- }
147
-
148
- return {
149
- type: MediaErrorType.UNKNOWN_ERROR,
150
- message: typeof error === "string" ? error : "Unknown error occurred",
151
- action,
152
- timestamp,
153
- retryable: this.isRetryable(MediaErrorType.UNKNOWN_ERROR, action),
154
- retryCount
155
- }
156
- }
157
-
158
- // Categorize errors based on error properties and action context
159
- private categorizeError(error: Error, action?: OptimisticMediaAction): MediaErrorType {
160
- const message = error.message.toLowerCase()
161
-
162
- // Network-related errors
163
- if (
164
- message.includes("network") ||
165
- message.includes("fetch") ||
166
- message.includes("connection") ||
167
- error.name === "NetworkError"
168
- ) {
169
- return MediaErrorType.NETWORK_ERROR
170
- }
171
-
172
- // Permission errors
173
- if (
174
- message.includes("permission") ||
175
- message.includes("denied") ||
176
- message.includes("fullscreen") ||
177
- error.name === "NotAllowedError"
178
- ) {
179
- return MediaErrorType.PERMISSION_ERROR
180
- }
181
-
182
- // Playback errors
183
- if (
184
- message.includes("decode") ||
185
- message.includes("format") ||
186
- message.includes("codec") ||
187
- action?.type === "PLAY"
188
- ) {
189
- return MediaErrorType.PLAYBACK_ERROR
190
- }
191
-
192
- // Timeout errors
193
- if (message.includes("timeout") || error.name === "TimeoutError") {
194
- return MediaErrorType.TIMEOUT_ERROR
195
- }
196
-
197
- // Not supported errors
198
- if (
199
- message.includes("not supported") ||
200
- message.includes("unsupported") ||
201
- error.name === "NotSupportedError"
202
- ) {
203
- return MediaErrorType.NOT_SUPPORTED_ERROR
204
- }
205
-
206
- return MediaErrorType.UNKNOWN_ERROR
207
- }
208
-
209
- // Check if an error/action combination is retryable
210
- private isRetryable(errorType: MediaErrorType, action?: OptimisticMediaAction): boolean {
211
- const errorRetryable = this.config.retryableErrors.includes(errorType)
212
- const actionRetryable = !action || this.config.retryableActions.includes(action.type)
213
- return errorRetryable && actionRetryable
214
- }
215
-
216
- // Calculate retry delay with exponential backoff
217
- private calculateRetryDelay(retryCount: number): number {
218
- if (!this.config.exponentialBackoff) {
219
- return this.config.baseDelay
220
- }
221
-
222
- const delay = this.config.baseDelay * Math.pow(2, retryCount)
223
- return Math.min(delay, this.config.maxDelay)
224
- }
225
-
226
- // Handle an error with automatic retry logic
227
- async handleError(
228
- error: unknown,
229
- action?: OptimisticMediaAction,
230
- retryCallback?: (action: OptimisticMediaAction) => Promise<void>
231
- ): Promise<MediaError> {
232
- const mediaError = this.createMediaError(error, action, action?.retryCount || 0)
233
- const errorId = `${action?.type}-${mediaError.timestamp}`
234
-
235
- // Store error for tracking
236
- this.errorQueue.set(errorId, mediaError)
237
-
238
- // Notify listeners
239
- this.listeners.forEach((listener) => listener(mediaError))
240
-
241
- // Try recovery strategies
242
- for (const strategy of this.recoveryStrategies) {
243
- if (strategy.canRecover(mediaError)) {
244
- try {
245
- await strategy.recover(mediaError)
246
- break
247
- } catch (recoveryError) {
248
- console.warn("Recovery strategy failed:", recoveryError)
249
- }
250
- }
251
- }
252
-
253
- // Retry if possible
254
- if (
255
- mediaError.retryable &&
256
- mediaError.retryCount < this.config.maxRetries &&
257
- retryCallback &&
258
- action
259
- ) {
260
- const delay = this.calculateRetryDelay(mediaError.retryCount)
261
- console.log(
262
- `Retrying action ${action.type} in ${delay}ms (attempt ${mediaError.retryCount + 1}/${this.config.maxRetries})`
263
- )
264
-
265
- setTimeout(async () => {
266
- try {
267
- await retryCallback({
268
- ...action,
269
- retryCount: mediaError.retryCount + 1
270
- })
271
-
272
- // Remove from error queue on successful retry
273
- this.errorQueue.delete(errorId)
274
- } catch (retryError) {
275
- // Handle retry failure
276
- await this.handleError(
277
- retryError,
278
- {
279
- ...action,
280
- retryCount: mediaError.retryCount + 1
281
- },
282
- retryCallback
283
- )
284
- }
285
- }, delay)
286
- }
287
-
288
- return mediaError
289
- }
290
-
291
- // Subscribe to error events
292
- subscribe(listener: (error: MediaError) => void): () => void {
293
- this.listeners.add(listener)
294
- return () => this.listeners.delete(listener)
295
- }
296
-
297
- // Get current errors
298
- getErrors(): MediaError[] {
299
- return Array.from(this.errorQueue.values())
300
- }
301
-
302
- // Clear specific error
303
- clearError(errorId: string): void {
304
- this.errorQueue.delete(errorId)
305
- }
306
-
307
- // Clear all errors
308
- clearAllErrors(): void {
309
- this.errorQueue.clear()
310
- }
311
-
312
- // Get error statistics
313
- getErrorStats(): {
314
- totalErrors: number
315
- errorsByType: Record<MediaErrorType, number>
316
- retryableErrors: number
317
- recentErrors: MediaError[]
318
- } {
319
- const errors = this.getErrors()
320
- const now = Date.now()
321
- const recentThreshold = 5 * 60 * 1000 // 5 minutes
322
-
323
- const errorsByType = errors.reduce(
324
- (acc, error) => {
325
- acc[error.type] = (acc[error.type] || 0) + 1
326
- return acc
327
- },
328
- {} as Record<MediaErrorType, number>
329
- )
330
-
331
- const retryableErrors = errors.filter((e) => e.retryable).length
332
- const recentErrors = errors.filter((e) => now - e.timestamp < recentThreshold)
333
-
334
- return {
335
- totalErrors: errors.length,
336
- errorsByType,
337
- retryableErrors,
338
- recentErrors
339
- }
340
- }
341
- }
342
-
343
- // Hook for using error handling in components
344
- export function useMediaErrorHandler(config?: Partial<RetryConfig>) {
345
- const [handler] = React.useState(() => new MediaErrorHandler(config))
346
- const [errors, setErrors] = React.useState<MediaError[]>([])
347
-
348
- React.useEffect(() => {
349
- const unsubscribe = handler.subscribe((error) => {
350
- setErrors((current) => [...current, error])
351
- })
352
-
353
- return unsubscribe
354
- }, [handler])
355
-
356
- const clearError = React.useCallback(
357
- (errorId: string) => {
358
- handler.clearError(errorId)
359
- setErrors((current) => current.filter((e) => `${e.action?.type}-${e.timestamp}` !== errorId))
360
- },
361
- [handler]
362
- )
363
-
364
- const clearAllErrors = React.useCallback(() => {
365
- handler.clearAllErrors()
366
- setErrors([])
367
- }, [handler])
368
-
369
- return {
370
- handler,
371
- errors,
372
- clearError,
373
- clearAllErrors,
374
- errorStats: handler.getErrorStats()
375
- }
376
- }
377
-
378
- // Hook for error boundaries
379
- export function useMediaErrorBoundary() {
380
- const [error, setError] = React.useState<MediaError | null>(null)
381
-
382
- const resetError = React.useCallback(() => {
383
- setError(null)
384
- }, [])
385
-
386
- const captureError = React.useCallback((error: unknown, action?: OptimisticMediaAction) => {
387
- const handler = new MediaErrorHandler()
388
- const mediaError = handler.createMediaError(error, action)
389
- setError(mediaError)
390
- }, [])
391
-
392
- return {
393
- error,
394
- hasError: !!error,
395
- resetError,
396
- captureError
397
- }
398
- }
@@ -1,254 +0,0 @@
1
- "use client"
2
-
3
- import React from "react"
4
-
5
- // Media action types
6
- export const MediaActionTypes = {
7
- PLAY: "PLAY",
8
- PAUSE: "PAUSE",
9
- SEEK: "SEEK",
10
- SET_VOLUME: "SET_VOLUME",
11
- MUTE: "MUTE",
12
- UNMUTE: "UNMUTE",
13
- TOGGLE_MUTE: "TOGGLE_MUTE",
14
- SET_DURATION: "SET_DURATION",
15
- SET_CURRENT_TIME: "SET_CURRENT_TIME",
16
- SET_BUFFERED: "SET_BUFFERED",
17
- SET_LOADING: "SET_LOADING",
18
- SET_ERROR: "SET_ERROR",
19
- ENTER_FULLSCREEN: "ENTER_FULLSCREEN",
20
- EXIT_FULLSCREEN: "EXIT_FULLSCREEN",
21
- ENTER_PIP: "ENTER_PIP",
22
- EXIT_PIP: "EXIT_PIP",
23
- SET_PLAYBACK_RATE: "SET_PLAYBACK_RATE",
24
- SET_SUBTITLE_TRACK: "SET_SUBTITLE_TRACK",
25
- SET_RENDITION: "SET_RENDITION",
26
- TOGGLE_SUBTITLES: "TOGGLE_SUBTITLES",
27
- PREVIEW_TIME: "PREVIEW_TIME",
28
- CLEAR_PREVIEW: "CLEAR_PREVIEW",
29
- // New actions for Video.js adapter
30
- SET_BUFFERING: "SET_BUFFERING",
31
- SET_QUALITY_LEVEL: "SET_QUALITY_LEVEL",
32
- SET_BANDWIDTH_ESTIMATE: "SET_BANDWIDTH_ESTIMATE",
33
- SET_ACTIVE_TEXT_TRACKS: "SET_ACTIVE_TEXT_TRACKS"
34
- } as const
35
-
36
- export type MediaActionType = (typeof MediaActionTypes)[keyof typeof MediaActionTypes]
37
-
38
- // Media state interface
39
- export interface MediaState {
40
- // Playback state
41
- isPlaying: boolean
42
- currentTime: number
43
- duration: number
44
- buffered: TimeRanges | null
45
- isLoading: boolean
46
- isBuffering: boolean
47
- error: string | null
48
-
49
- // Audio state
50
- volume: number
51
- isMuted: boolean
52
-
53
- // Video state
54
- isFullscreen: boolean
55
- isPictureInPicture: boolean
56
-
57
- // Advanced features
58
- playbackRate: number
59
- subtitlesShowing: boolean
60
- selectedSubtitleTrack: TextTrack | null
61
- selectedRendition: string | null
62
- qualityLevel: number
63
- bandwidthEstimate: number
64
- activeTextTracks: any[]
65
-
66
- // Preview state (for seek preview)
67
- previewTime: number | null
68
- previewImage: string | null
69
- previewCoords: { x: number; y: number; width: number; height: number } | null
70
-
71
- // Media lists
72
- subtitlesList: TextTrack[]
73
- renditionList: Array<{ id: string; label: string; width?: number; height?: number }>
74
- }
75
-
76
- // Media action interface
77
- export interface MediaAction {
78
- type: MediaActionType
79
- detail?: any
80
- }
81
-
82
- // Media context interface
83
- export interface MediaContextValue {
84
- mediaId: string
85
- labelId: string
86
- descriptionId: string
87
- dir?: "ltr" | "rtl"
88
- rootRef: React.RefObject<HTMLDivElement | null>
89
- mediaRef: React.RefObject<HTMLVideoElement | HTMLAudioElement | null>
90
- portalContainer?: HTMLElement
91
- tooltipDelayDuration: number
92
- tooltipSideOffset: number
93
- disabled: boolean
94
- isVideo: boolean
95
- withoutTooltip: boolean
96
- }
97
-
98
- // Store interface for internal state management
99
- export interface MediaStore {
100
- subscribe: (callback: () => void) => () => void
101
- getState: () => MediaState
102
- setState: (updates: Partial<MediaState>) => void
103
- dispatch: (action: MediaAction) => void
104
- }
105
-
106
- // Create the media context
107
- export const MediaContext = React.createContext<MediaContextValue | null>(null)
108
-
109
- // Hook to use media context
110
- export function useMediaContext() {
111
- const context = React.useContext(MediaContext)
112
- if (!context) {
113
- throw new Error("useMediaContext must be used within a MediaPlayer")
114
- }
115
- return context
116
- }
117
-
118
- // Store context for state management
119
- export const MediaStoreContext = React.createContext<MediaStore | null>(null)
120
-
121
- // Hook to use media store
122
- export function useMediaStore() {
123
- const store = React.useContext(MediaStoreContext)
124
- if (!store) {
125
- throw new Error("useMediaStore must be used within a MediaPlayer")
126
- }
127
- return store
128
- }
129
-
130
- // Shallow comparison for selector optimization
131
- function shallowEqual(prev: unknown, next: unknown): boolean {
132
- if (Object.is(prev, next)) return true
133
-
134
- if (typeof prev !== "object" || prev === null || typeof next !== "object" || next === null) {
135
- return false
136
- }
137
-
138
- const prevKeys = Object.keys(prev as object)
139
- const nextKeys = Object.keys(next as object)
140
-
141
- if (prevKeys.length !== nextKeys.length) return false
142
-
143
- for (const key of prevKeys) {
144
- if (!nextKeys.includes(key)) return false
145
-
146
- const prevValue = (prev as Record<string, unknown>)[key]
147
- const nextValue = (next as Record<string, unknown>)[key]
148
-
149
- if (!Object.is(prevValue, nextValue)) return false
150
- }
151
-
152
- return true
153
- }
154
-
155
- // Hook to select specific state values - React 19 optimized with shallow comparison
156
- export function useMediaSelector<T>(selector: (state: MediaState) => T): T {
157
- const store = useMediaStore()
158
-
159
- // React 19 compiler will optimize this callback
160
- const getSnapshot = () => selector(store.getState())
161
-
162
- // Track previous selected value for shallow comparison
163
- const prevRef = React.useRef<T | undefined>(undefined)
164
- const getServerSnapshot = React.useCallback(() => {
165
- const value = selector(store.getState())
166
- prevRef.current = value
167
- return value
168
- }, [selector])
169
-
170
- // Use useSyncExternalStore for subscription
171
- const selected = React.useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot)
172
-
173
- // Apply shallow comparison to prevent unnecessary re-renders
174
- React.useEffect(() => {
175
- const prev = prevRef.current
176
- if (prev !== undefined && shallowEqual(prev, selected)) {
177
- // Values are equal, no re-render needed
178
- return
179
- }
180
- prevRef.current = selected
181
- }, [selected])
182
-
183
- return selected
184
- }
185
-
186
- // Hook to get dispatch function
187
- export function useMediaDispatch() {
188
- const store = useMediaStore()
189
- return store.dispatch
190
- }
191
-
192
- // React 19 enhanced context selector with optimistic updates
193
- export function useOptimisticMediaSelector<T>(selector: (state: MediaState) => T): T {
194
- const store = useMediaStore()
195
-
196
- // Check if enhanced store is available
197
- const isEnhanced = "getOptimisticState" in store
198
-
199
- const getSnapshot = () => {
200
- if (isEnhanced) {
201
- // Use optimistic state for immediate UI feedback
202
- return selector((store as any).getOptimisticState())
203
- } else {
204
- // Fall back to regular state
205
- return selector(store.getState())
206
- }
207
- }
208
-
209
- return React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot)
210
- }
211
-
212
- // Hook for accessing React 19 enhanced features
213
- export function useMediaEnhancements() {
214
- const store = useMediaStore()
215
- const context = useMediaContext()
216
-
217
- const isEnhanced = "getOptimisticState" in store
218
- const errorHandler = "errorHandler" in context ? (context as any).errorHandler : null
219
- const isRehydrated = "isRehydrated" in context ? (context as any).isRehydrated : true
220
-
221
- return {
222
- isEnhanced,
223
- errorHandler,
224
- isRehydrated,
225
- actionsState: isEnhanced ? (store as any).getActionState() : null
226
- }
227
- }
228
-
229
- // Initial media state
230
- export const initialMediaState: MediaState = {
231
- isPlaying: false,
232
- currentTime: 0,
233
- duration: 0,
234
- buffered: null,
235
- isLoading: false,
236
- isBuffering: false,
237
- error: null,
238
- volume: 1,
239
- isMuted: false,
240
- isFullscreen: false,
241
- isPictureInPicture: false,
242
- playbackRate: 1,
243
- subtitlesShowing: false,
244
- selectedSubtitleTrack: null,
245
- selectedRendition: null,
246
- qualityLevel: -1,
247
- bandwidthEstimate: 0,
248
- activeTextTracks: [],
249
- previewTime: null,
250
- previewImage: null,
251
- previewCoords: null,
252
- subtitlesList: [],
253
- renditionList: []
254
- }