@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,106 +0,0 @@
1
- import { useCallback, useEffect } from "react"
2
- import type { VideoControls } from "./useVideoPlayer"
3
-
4
- interface UseKeyboardShortcutsProps {
5
- videoControls: VideoControls
6
- toggleSubtitles: () => void
7
- takeScreenshot: (ctrlKey?: boolean) => void
8
- duration: number
9
- }
10
-
11
- /**
12
- * Safely sets currentTime on a video element, ensuring the value is finite
13
- */
14
- function safeSetCurrentTime(video: HTMLVideoElement, time: number): boolean {
15
- if (!Number.isFinite(time)) {
16
- console.warn(`Attempted to set non-finite currentTime: ${time}`)
17
- return false
18
- }
19
-
20
- if (time < 0) {
21
- console.warn(`Attempted to set negative currentTime: ${time}`)
22
- return false
23
- }
24
-
25
- try {
26
- video.currentTime = time
27
- return true
28
- } catch (error) {
29
- console.error(`Failed to set currentTime to ${time}:`, error)
30
- return false
31
- }
32
- }
33
-
34
- export function useKeyboardShortcuts({
35
- videoControls,
36
- toggleSubtitles,
37
- takeScreenshot,
38
- duration
39
- }: UseKeyboardShortcutsProps) {
40
- const handleKeyDown = (e: KeyboardEvent) => {
41
- const video = document.querySelector("video")
42
- if (!video) return
43
-
44
- switch (e.key.toLowerCase()) {
45
- case " ":
46
- case "k":
47
- e.preventDefault()
48
- videoControls.togglePlay()
49
- break
50
- case "j":
51
- e.preventDefault()
52
- videoControls.seekBackward()
53
- break
54
- case "l":
55
- e.preventDefault()
56
- videoControls.seekForward()
57
- break
58
- case "arrowleft":
59
- e.preventDefault()
60
- const currentTime = Number.isFinite(video.currentTime) ? video.currentTime : 0
61
- const newTimeLeft = Math.max(0, currentTime - 5)
62
- safeSetCurrentTime(video, newTimeLeft)
63
- break
64
- case "arrowright":
65
- e.preventDefault()
66
- const validDuration = Number.isFinite(duration) && duration > 0 ? duration : Number.isFinite(video.duration) ? video.duration : 0
67
- if (validDuration === 0) {
68
- console.warn("Cannot seek: duration is not available")
69
- break
70
- }
71
- const currentTimeRight = Number.isFinite(video.currentTime) ? video.currentTime : 0
72
- const newTimeRight = Math.min(validDuration, currentTimeRight + 5)
73
- safeSetCurrentTime(video, newTimeRight)
74
- break
75
- case "arrowup":
76
- e.preventDefault()
77
- video.volume = Math.min(1, video.volume + 0.1)
78
- break
79
- case "arrowdown":
80
- e.preventDefault()
81
- video.volume = Math.max(0, video.volume - 0.1)
82
- break
83
- case "m":
84
- e.preventDefault()
85
- videoControls.toggleMute()
86
- break
87
- case "f":
88
- e.preventDefault()
89
- videoControls.toggleFullscreen()
90
- break
91
- case "c":
92
- e.preventDefault()
93
- toggleSubtitles()
94
- break
95
- case "s":
96
- e.preventDefault()
97
- takeScreenshot(e.ctrlKey || e.metaKey)
98
- break
99
- }
100
- }
101
-
102
- useEffect(() => {
103
- document.addEventListener("keydown", handleKeyDown)
104
- return () => document.removeEventListener("keydown", handleKeyDown)
105
- }, [handleKeyDown])
106
- }
@@ -1,52 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react"
2
-
3
- export function useMediaControls(isPlaying: boolean, showSettings: boolean) {
4
- const [controlsVisible, setControlsVisible] = useState(true)
5
- const [showVolumeSlider, setShowVolumeSlider] = useState(false)
6
- const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null)
7
-
8
- const showControls = () => {
9
- setControlsVisible(true)
10
- if (hideTimeoutRef.current) {
11
- clearTimeout(hideTimeoutRef.current)
12
- }
13
-
14
- if (isPlaying && !showSettings) {
15
- hideTimeoutRef.current = setTimeout(() => {
16
- setControlsVisible(false)
17
- }, 3000)
18
- }
19
- }
20
-
21
- const handleMouseMove = () => {
22
- showControls()
23
- }
24
-
25
- const handleMouseEnter = () => {
26
- setControlsVisible(true)
27
- }
28
-
29
- const handleMouseLeave = () => {
30
- if (isPlaying) {
31
- setControlsVisible(false)
32
- }
33
- }
34
-
35
- useEffect(() => {
36
- showControls()
37
- return () => {
38
- if (hideTimeoutRef.current) {
39
- clearTimeout(hideTimeoutRef.current)
40
- }
41
- }
42
- }, [showControls])
43
-
44
- return {
45
- controlsVisible,
46
- showVolumeSlider,
47
- setShowVolumeSlider,
48
- handleMouseMove,
49
- handleMouseEnter,
50
- handleMouseLeave
51
- }
52
- }
@@ -1,61 +0,0 @@
1
- import { useCallback } from "react"
2
-
3
- export function useScreenshot(videoRef: React.RefObject<HTMLVideoElement | null>) {
4
- const takeScreenshot = (ctrlKey: boolean = false) => {
5
- if (!videoRef.current) return
6
-
7
- const video = videoRef.current
8
- const canvas = document.createElement("canvas")
9
- canvas.width = video.videoWidth
10
- canvas.height = video.videoHeight
11
- const ctx = canvas.getContext("2d")
12
- if (!ctx) return
13
-
14
- try {
15
- // Draw the video frame to canvas
16
- ctx.drawImage(video, 0, 0)
17
-
18
- // Try to export the canvas
19
- canvas.toBlob((blob) => {
20
- if (!blob) {
21
- console.error("Failed to create blob from canvas")
22
- return
23
- }
24
-
25
- if (ctrlKey) {
26
- // Copy to clipboard
27
- if (navigator.clipboard && window.ClipboardItem) {
28
- const item = new ClipboardItem({ "image/png": blob })
29
- navigator.clipboard.write([item]).catch((err) => {
30
- console.error("Failed to copy to clipboard:", err)
31
- })
32
- } else {
33
- console.warn("Clipboard API not supported")
34
- }
35
- } else {
36
- // Download
37
- const url = URL.createObjectURL(blob)
38
- const a = document.createElement("a")
39
- a.href = url
40
- a.download = `screenshot-${Date.now()}.png`
41
- a.click()
42
- URL.revokeObjectURL(url)
43
- }
44
- }, "image/png")
45
- } catch (error) {
46
- if (error instanceof Error && error.message.includes("tainted")) {
47
- console.error(
48
- "Canvas is tainted - video source may not have proper CORS headers. Try setting crossOrigin='anonymous' on the video element."
49
- )
50
- alert(
51
- "Screenshot failed: The video source doesn't allow screenshots due to CORS policy. Please ensure the video server includes proper CORS headers or set crossOrigin='anonymous' on the video player."
52
- )
53
- } else {
54
- console.error("Screenshot failed:", error)
55
- alert("Screenshot failed: " + (error instanceof Error ? error.message : "Unknown error"))
56
- }
57
- }
58
- }
59
-
60
- return { takeScreenshot }
61
- }
@@ -1,91 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react"
2
-
3
- interface SubtitleCue {
4
- start: number
5
- end: number
6
- text: string
7
- }
8
-
9
- export function useSubtitles(subtitleSrc?: string) {
10
- const [subtitlesEnabled, setSubtitlesEnabled] = useState(false)
11
- const [subtitleCues, setSubtitleCues] = useState<SubtitleCue[]>([])
12
- const [currentSubtitle, setCurrentSubtitle] = useState("")
13
-
14
- const parseVTTTime = (timeStr: string): number => {
15
- const parts = timeStr.split(":")
16
- const seconds = parts[2] ? parseFloat(parts[2]) : 0
17
- const minutes = parts[1] ? parseInt(parts[1], 10) * 60 : 0
18
- const hours = parts[0] ? parseInt(parts[0], 10) * 3600 : 0
19
- return hours + minutes + seconds
20
- }
21
-
22
- const loadSubtitles = async (url: string) => {
23
- try {
24
- const response = await fetch(url)
25
- const text = await response.text()
26
-
27
- const cues: SubtitleCue[] = []
28
- const lines = text.split("\n")
29
- let i = 0
30
-
31
- while (i < lines.length) {
32
- if (lines[i]?.includes("-->")) {
33
- const [startStr, endStr] = (lines[i] || "").split("-->").map((s) => s.trim())
34
- const start = parseVTTTime(startStr || "")
35
- const end = parseVTTTime(endStr || "")
36
-
37
- i++
38
- let subtitleText = ""
39
- while (i < lines.length && lines[i]?.trim() !== "") {
40
- subtitleText += (subtitleText ? " " : "") + lines[i]?.trim()
41
- i++
42
- }
43
-
44
- if (subtitleText) {
45
- cues.push({ start, end, text: subtitleText })
46
- }
47
- }
48
- i++
49
- }
50
-
51
- setSubtitleCues(cues)
52
- } catch (error) {
53
- console.error("Failed to load subtitles:", error)
54
- }
55
- }
56
-
57
- const getCurrentSubtitle = (currentTime: number) => {
58
- if (!subtitlesEnabled || subtitleCues.length === 0) return ""
59
-
60
- const currentCue = subtitleCues.find(
61
- (cue) => currentTime >= cue.start && currentTime <= cue.end
62
- )
63
- return currentCue?.text || ""
64
- }
65
-
66
- const toggleSubtitles = () => {
67
- setSubtitlesEnabled((prev) => {
68
- const newEnabled = !prev
69
- if (newEnabled && subtitleSrc && subtitleCues.length === 0) {
70
- loadSubtitles(subtitleSrc)
71
- } else if (!newEnabled) {
72
- setCurrentSubtitle("")
73
- }
74
- return newEnabled
75
- })
76
- }
77
-
78
- useEffect(() => {
79
- if (!subtitlesEnabled) {
80
- setCurrentSubtitle("")
81
- }
82
- }, [subtitlesEnabled])
83
-
84
- return {
85
- subtitlesEnabled,
86
- currentSubtitle,
87
- toggleSubtitles,
88
- getCurrentSubtitle,
89
- setCurrentSubtitle
90
- }
91
- }
@@ -1,278 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react"
2
-
3
- export interface BufferedRange {
4
- start: number
5
- end: number
6
- percentage: number
7
- }
8
-
9
- export interface VideoState {
10
- isPlaying: boolean
11
- currentTime: number
12
- duration: number
13
- volume: number
14
- isMuted: boolean
15
- isFullscreen: boolean
16
- isLoading: boolean
17
- isSeeking: boolean
18
- isBuffering: boolean
19
- bufferedRanges: BufferedRange[]
20
- }
21
-
22
- export interface VideoControls {
23
- togglePlay: () => void
24
- seekForward: (seconds?: number) => void
25
- seekBackward: (seconds?: number) => void
26
- toggleMute: () => void
27
- setVolume: (volume: number) => void
28
- toggleFullscreen: () => void
29
- seekTo: (time: number) => void
30
- }
31
-
32
- /**
33
- * Safely sets currentTime on a video element, ensuring the value is finite
34
- * @param video - The video element
35
- * @param time - The desired time value
36
- * @returns true if successfully set, false otherwise
37
- */
38
- function safeSetCurrentTime(video: HTMLVideoElement, time: number): boolean {
39
- if (!Number.isFinite(time)) {
40
- console.warn(`Attempted to set non-finite currentTime: ${time}`)
41
- return false
42
- }
43
-
44
- if (time < 0) {
45
- console.warn(`Attempted to set negative currentTime: ${time}`)
46
- return false
47
- }
48
-
49
- try {
50
- video.currentTime = time
51
- return true
52
- } catch (error) {
53
- console.error(`Failed to set currentTime to ${time}:`, error)
54
- return false
55
- }
56
- }
57
-
58
- export function useVideoPlayer(containerRef: React.RefObject<HTMLDivElement | null>) {
59
- const videoRef = useRef<HTMLVideoElement>(null)
60
- const [state, setState] = useState<VideoState>({
61
- isPlaying: false,
62
- currentTime: 0,
63
- duration: 0,
64
- volume: 1,
65
- isMuted: false,
66
- isFullscreen: false,
67
- isLoading: true,
68
- isSeeking: false,
69
- isBuffering: false,
70
- bufferedRanges: []
71
- })
72
-
73
- useEffect(() => {
74
- const video = videoRef.current
75
- if (!video) return
76
-
77
- const handleTimeUpdate = () => {
78
- setState((prev) => ({ ...prev, currentTime: video.currentTime }))
79
- }
80
-
81
- const handleLoadedMetadata = () => {
82
- setState((prev) => ({ ...prev, duration: video.duration }))
83
- }
84
-
85
- const handlePlay = () => {
86
- setState((prev) => ({ ...prev, isPlaying: true, isBuffering: false }))
87
- }
88
-
89
- const handlePause = () => {
90
- setState((prev) => ({ ...prev, isPlaying: false }))
91
- }
92
-
93
- const handleVolumeChange = () => {
94
- setState((prev) => ({
95
- ...prev,
96
- volume: video.volume,
97
- isMuted: video.muted
98
- }))
99
- }
100
-
101
- // Loading state handlers
102
- const handleLoadStart = () => {
103
- setState((prev) => ({ ...prev, isLoading: true }))
104
- }
105
-
106
- const handleLoadedData = () => {
107
- setState((prev) => ({ ...prev, isLoading: false }))
108
- }
109
-
110
- // Seeking state handlers
111
- const handleSeeking = () => {
112
- setState((prev) => ({ ...prev, isSeeking: true }))
113
- }
114
-
115
- const handleSeeked = () => {
116
- setState((prev) => ({ ...prev, isSeeking: false }))
117
- }
118
-
119
- // Buffering state handlers
120
- const handleWaiting = () => {
121
- setState((prev) => ({ ...prev, isBuffering: true }))
122
- }
123
-
124
- const handlePlaying = () => {
125
- setState((prev) => ({ ...prev, isBuffering: false, isLoading: false }))
126
- }
127
-
128
- const handleCanPlay = () => {
129
- setState((prev) => ({ ...prev, isLoading: false, isBuffering: false }))
130
- }
131
-
132
- // Progress handler for buffered ranges
133
- const handleProgress = () => {
134
- if (!video.buffered || video.buffered.length === 0 || video.duration === 0) {
135
- setState((prev) => ({ ...prev, bufferedRanges: [] }))
136
- return
137
- }
138
-
139
- const ranges: BufferedRange[] = []
140
- for (let i = 0; i < video.buffered.length; i++) {
141
- const start = video.buffered.start(i)
142
- const end = video.buffered.end(i)
143
- ranges.push({
144
- start,
145
- end,
146
- percentage: ((end - start) / video.duration) * 100
147
- })
148
- }
149
- setState((prev) => ({ ...prev, bufferedRanges: ranges }))
150
- }
151
-
152
- video.addEventListener("timeupdate", handleTimeUpdate)
153
- video.addEventListener("loadedmetadata", handleLoadedMetadata)
154
- video.addEventListener("play", handlePlay)
155
- video.addEventListener("pause", handlePause)
156
- video.addEventListener("volumechange", handleVolumeChange)
157
- video.addEventListener("loadstart", handleLoadStart)
158
- video.addEventListener("loadeddata", handleLoadedData)
159
- video.addEventListener("seeking", handleSeeking)
160
- video.addEventListener("seeked", handleSeeked)
161
- video.addEventListener("waiting", handleWaiting)
162
- video.addEventListener("playing", handlePlaying)
163
- video.addEventListener("canplay", handleCanPlay)
164
- video.addEventListener("progress", handleProgress)
165
-
166
- return () => {
167
- video.removeEventListener("timeupdate", handleTimeUpdate)
168
- video.removeEventListener("loadedmetadata", handleLoadedMetadata)
169
- video.removeEventListener("play", handlePlay)
170
- video.removeEventListener("pause", handlePause)
171
- video.removeEventListener("volumechange", handleVolumeChange)
172
- video.removeEventListener("loadstart", handleLoadStart)
173
- video.removeEventListener("loadeddata", handleLoadedData)
174
- video.removeEventListener("seeking", handleSeeking)
175
- video.removeEventListener("seeked", handleSeeked)
176
- video.removeEventListener("waiting", handleWaiting)
177
- video.removeEventListener("playing", handlePlaying)
178
- video.removeEventListener("canplay", handleCanPlay)
179
- video.removeEventListener("progress", handleProgress)
180
- }
181
- }, [])
182
-
183
- const togglePlay = () => {
184
- const video = videoRef.current
185
- if (!video) return
186
-
187
- if (state.isPlaying) {
188
- video.pause()
189
- } else {
190
- video.play()
191
- }
192
- }
193
-
194
- const seekForward = (seconds = 10) => {
195
- const video = videoRef.current
196
- if (!video) return
197
-
198
- const duration = Number.isFinite(video.duration) ? video.duration : Number.isFinite(state.duration) ? state.duration : 0
199
- if (duration === 0) {
200
- console.warn("Cannot seek forward: duration is not available")
201
- return
202
- }
203
-
204
- const currentTime = Number.isFinite(video.currentTime) ? video.currentTime : 0
205
- const newTime = Math.min(duration, currentTime + seconds)
206
- safeSetCurrentTime(video, newTime)
207
- }
208
-
209
- const seekBackward = (seconds = 10) => {
210
- const video = videoRef.current
211
- if (!video) return
212
-
213
- const currentTime = Number.isFinite(video.currentTime) ? video.currentTime : 0
214
- const newTime = Math.max(0, currentTime - seconds)
215
- safeSetCurrentTime(video, newTime)
216
- }
217
-
218
- const toggleMute = () => {
219
- const video = videoRef.current
220
- if (!video) return
221
- video.muted = !state.isMuted
222
- }
223
-
224
- const setVolume = (volume: number) => {
225
- const video = videoRef.current
226
- if (!video) return
227
- video.volume = volume
228
- if (volume > 0 && state.isMuted) {
229
- video.muted = false
230
- }
231
- }
232
-
233
- const toggleFullscreen = () => {
234
- const container = containerRef.current
235
- if (!container) return
236
-
237
- if (!state.isFullscreen) {
238
- if (container.requestFullscreen) {
239
- container.requestFullscreen()
240
- }
241
- } else {
242
- if (document.exitFullscreen) {
243
- document.exitFullscreen()
244
- }
245
- }
246
- setState((prev) => ({ ...prev, isFullscreen: !prev.isFullscreen }))
247
- }
248
-
249
- const seekTo = (time: number) => {
250
- const video = videoRef.current
251
- if (!video) return
252
-
253
- const duration = Number.isFinite(video.duration) ? video.duration : Number.isFinite(state.duration) ? state.duration : 0
254
- if (duration === 0) {
255
- console.warn("Cannot seek: duration is not available")
256
- return
257
- }
258
-
259
- const clampedTime = Math.max(0, Math.min(duration, time))
260
- safeSetCurrentTime(video, clampedTime)
261
- }
262
-
263
- const controls: VideoControls = {
264
- togglePlay,
265
- seekForward,
266
- seekBackward,
267
- toggleMute,
268
- setVolume,
269
- toggleFullscreen,
270
- seekTo
271
- }
272
-
273
- return {
274
- videoRef,
275
- state,
276
- controls
277
- }
278
- }
@@ -1,36 +0,0 @@
1
- import { useCustomIcon, useIconTheme } from "../provider"
2
- import type { IconProps } from "../types"
3
-
4
- export function FullscreenIcon(props: IconProps) {
5
- const theme = useIconTheme()
6
- const customIcon = useCustomIcon("fullscreen")
7
-
8
- if (customIcon) {
9
- return customIcon(props)
10
- }
11
-
12
- const {
13
- size = theme.size,
14
- color = theme.color,
15
- strokeWidth = theme.strokeWidth,
16
- className = theme.className,
17
- ...rest
18
- } = props
19
-
20
- return (
21
- <svg
22
- width={size}
23
- height={size}
24
- viewBox="0 0 24 24"
25
- fill="none"
26
- stroke={color}
27
- strokeWidth={strokeWidth}
28
- strokeLinecap="round"
29
- strokeLinejoin="round"
30
- className={className}
31
- aria-hidden="true"
32
- {...rest}>
33
- <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
34
- </svg>
35
- )
36
- }
@@ -1,37 +0,0 @@
1
- import { useCustomIcon, useIconTheme } from "../provider"
2
- import type { IconProps } from "../types"
3
-
4
- export function SettingsIcon(props: IconProps) {
5
- const theme = useIconTheme()
6
- const customIcon = useCustomIcon("settings")
7
-
8
- if (customIcon) {
9
- return customIcon(props)
10
- }
11
-
12
- const {
13
- size = theme.size,
14
- color = theme.color,
15
- strokeWidth = theme.strokeWidth,
16
- className = theme.className,
17
- ...rest
18
- } = props
19
-
20
- return (
21
- <svg
22
- width={size}
23
- height={size}
24
- viewBox="0 0 24 24"
25
- fill="none"
26
- stroke={color}
27
- strokeWidth={strokeWidth}
28
- strokeLinecap="round"
29
- strokeLinejoin="round"
30
- className={className}
31
- aria-hidden="true"
32
- {...rest}>
33
- <circle cx="12" cy="12" r="3" />
34
- <path d="M12 1v6m0 6v6m11-7h-6m-6 0H1m10.5-4A1.5 1.5 0 0 1 15 12a1.5 1.5 0 0 1-3.5 0 1.5 1.5 0 0 1 3.5 0Z" />
35
- </svg>
36
- )
37
- }
@@ -1,27 +0,0 @@
1
- import { useCustomIcon, useIconTheme } from "../../provider"
2
- import type { IconProps } from "../../types"
3
-
4
- export function LoadingIcon(props: IconProps) {
5
- const theme = useIconTheme()
6
- const customIcon = useCustomIcon("loading")
7
-
8
- if (customIcon) {
9
- return customIcon(props)
10
- }
11
-
12
- const { size = theme.size, color = theme.color, className = theme.className, ...rest } = props
13
-
14
- return (
15
- <svg
16
- width={size}
17
- height={size}
18
- viewBox="0 0 24 24"
19
- fill="none"
20
- className={`animate-spin ${className || ""}`}
21
- aria-hidden="true"
22
- {...rest}>
23
- <circle cx="12" cy="12" r="10" stroke={color} strokeWidth="4" strokeOpacity="0.25" />
24
- <path fill={color} d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
25
- </svg>
26
- )
27
- }