@therealtinhtute/baroiplayer 1.2.1 → 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 (302) hide show
  1. package/README.md +90 -71
  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 +1 -41
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +750 -5640
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -114
  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 -1
  78. package/dist/context/media.mjs +0 -3
  79. package/dist/context/store.js +0 -1
  80. package/dist/context/store.mjs +0 -3
  81. package/dist/context-Bzd5QCKM.cjs +0 -7
  82. package/dist/context-Bzd5QCKM.cjs.map +0 -1
  83. package/dist/context-DD_SH4tT.js +0 -1053
  84. package/dist/context-DD_SH4tT.js.map +0 -1
  85. package/dist/core-events-BRnLMB7s.cjs +0 -2
  86. package/dist/core-events-BRnLMB7s.cjs.map +0 -1
  87. package/dist/core-events-v_mKdj5p.js +0 -417
  88. package/dist/core-events-v_mKdj5p.js.map +0 -1
  89. package/dist/core-plugins-CMBv-yVh.cjs +0 -2
  90. package/dist/core-plugins-CMBv-yVh.cjs.map +0 -1
  91. package/dist/core-plugins-CqCxLkbd.js +0 -754
  92. package/dist/core-plugins-CqCxLkbd.js.map +0 -1
  93. package/dist/core.js +0 -15
  94. package/dist/core.js.map +0 -1
  95. package/dist/core.mjs +0 -960
  96. package/dist/core.mjs.map +0 -1
  97. package/dist/enhanced-components-BwjBqSA1.js +0 -2858
  98. package/dist/enhanced-components-BwjBqSA1.js.map +0 -1
  99. package/dist/enhanced-components-C-ka-XLp.cjs +0 -2
  100. package/dist/enhanced-components-C-ka-XLp.cjs.map +0 -1
  101. package/dist/hooks-B-IIWPJr.js +0 -1842
  102. package/dist/hooks-B-IIWPJr.js.map +0 -1
  103. package/dist/hooks-DcHzmBwA.cjs +0 -4
  104. package/dist/hooks-DcHzmBwA.cjs.map +0 -1
  105. package/dist/minimal-components-BYsMQde5.js +0 -1610
  106. package/dist/minimal-components-BYsMQde5.js.map +0 -1
  107. package/dist/minimal-components-CsxQbDp7.cjs +0 -2
  108. package/dist/minimal-components-CsxQbDp7.cjs.map +0 -1
  109. package/dist/minimal-components.css +0 -1
  110. package/dist/mona-loading.gif +0 -0
  111. package/dist/performance-monitor-DCSijLJg.js +0 -312
  112. package/dist/performance-monitor-DCSijLJg.js.map +0 -1
  113. package/dist/performance-monitor-wNFKmqMr.cjs +0 -2
  114. package/dist/performance-monitor-wNFKmqMr.cjs.map +0 -1
  115. package/dist/rolldown-runtime-BmowowmI.js +0 -14
  116. package/dist/rolldown-runtime-mLOUI7ql.cjs +0 -1
  117. package/dist/utils-D2gQ7c2R.js +0 -64
  118. package/dist/utils-D2gQ7c2R.js.map +0 -1
  119. package/dist/utils-DJaAwiZ9.cjs +0 -2
  120. package/dist/utils-DJaAwiZ9.cjs.map +0 -1
  121. package/dist/utils.js +0 -1
  122. package/dist/utils.mjs +0 -3
  123. package/src/adapters/videojs-adapter.tsx +0 -470
  124. package/src/assets/mona-loading.gif +0 -0
  125. package/src/components/AnimateLoading.tsx +0 -111
  126. package/src/components/LoadingState.tsx +0 -239
  127. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  128. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  129. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  130. package/src/components/audio-player.tsx +0 -85
  131. package/src/components/basic/index.ts +0 -37
  132. package/src/components/enhanced/advanced-features.tsx +0 -311
  133. package/src/components/enhanced/debug-panel.tsx +0 -448
  134. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  135. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  136. package/src/components/enhanced/error-handling.tsx +0 -338
  137. package/src/components/enhanced/index.ts +0 -39
  138. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  139. package/src/components/examples/basic-video-player.tsx +0 -50
  140. package/src/components/examples/custom-controls-example.tsx +0 -63
  141. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  142. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  143. package/src/components/examples/loading-states-demo.tsx +0 -141
  144. package/src/components/examples/react-19-demo.tsx +0 -349
  145. package/src/components/examples/volume-orientation-demo.tsx +0 -105
  146. package/src/components/icon-demo.tsx +0 -196
  147. package/src/components/legacy.tsx +0 -87
  148. package/src/components/media-metadata-display.tsx +0 -99
  149. package/src/components/media-player-audio.tsx +0 -39
  150. package/src/components/media-player-controls.tsx +0 -223
  151. package/src/components/media-player-error.tsx +0 -163
  152. package/src/components/media-player-fullscreen.tsx +0 -109
  153. package/src/components/media-player-hls.tsx +0 -111
  154. package/src/components/media-player-loading.tsx +0 -76
  155. package/src/components/media-player-play.tsx +0 -75
  156. package/src/components/media-player-root.tsx +0 -338
  157. package/src/components/media-player-seek.tsx +0 -168
  158. package/src/components/media-player-time.tsx +0 -99
  159. package/src/components/media-player-tooltip.tsx +0 -58
  160. package/src/components/media-player-video.tsx +0 -54
  161. package/src/components/media-player-volume.tsx +0 -155
  162. package/src/components/media-player.tsx +0 -292
  163. package/src/components/media-suspense.tsx +0 -344
  164. package/src/components/player-settings-form.tsx +0 -158
  165. package/src/components/react-player-wrapper.tsx +0 -651
  166. package/src/components/simple-video-player.tsx +0 -62
  167. package/src/components/ui/blur-poster.tsx +0 -96
  168. package/src/components/ui/empty-state.tsx +0 -91
  169. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  170. package/src/components/ui/error-state.tsx +0 -124
  171. package/src/components/ui/fullscreen-button.tsx +0 -81
  172. package/src/components/ui/loading-skeleton.tsx +0 -107
  173. package/src/components/ui/media-resource-preloader.tsx +0 -458
  174. package/src/components/ui/offline-message.tsx +0 -98
  175. package/src/components/ui/play-button.tsx +0 -99
  176. package/src/components/ui/seek-bar.tsx +0 -191
  177. package/src/components/ui/time-display.tsx +0 -61
  178. package/src/components/ui/volume-control.tsx +0 -190
  179. package/src/components/unified/base-media-player.tsx +0 -252
  180. package/src/components/unified/media-player.tsx +0 -75
  181. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  182. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  183. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  184. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  185. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  186. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  187. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  188. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  189. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  190. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  191. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  192. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  193. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  194. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  195. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  196. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  197. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  198. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  199. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  200. package/src/components/variants/minimal/components/VideoElement.tsx +0 -35
  201. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  202. package/src/components/variants/minimal/index.ts +0 -23
  203. package/src/components/video-player.tsx +0 -100
  204. package/src/context/__tests__/media-store.test.ts +0 -509
  205. package/src/context/error-handling.ts +0 -398
  206. package/src/context/media-context.tsx +0 -254
  207. package/src/context/media-provider.tsx +0 -264
  208. package/src/context/media-store.ts +0 -387
  209. package/src/context/persistence.ts +0 -462
  210. package/src/core/events/event-system.ts +0 -448
  211. package/src/core/events/hooks.ts +0 -325
  212. package/src/core/events/index.ts +0 -22
  213. package/src/core/events/middleware.ts +0 -286
  214. package/src/core/index.ts +0 -22
  215. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  216. package/src/core/performance/cicd.ts +0 -98
  217. package/src/core/performance/index.ts +0 -38
  218. package/src/core/performance/media-loading-optimizer.ts +0 -545
  219. package/src/core/performance/performance-budgets.ts +0 -437
  220. package/src/core/performance/performance-monitor.tsx +0 -488
  221. package/src/core/performance/performance-testing.ts +0 -461
  222. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  223. package/src/core/plugins/base-plugin.ts +0 -225
  224. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  225. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  226. package/src/core/plugins/index.ts +0 -39
  227. package/src/core/plugins/registry.ts +0 -546
  228. package/src/core/plugins/types.ts +0 -169
  229. package/src/core/plugins/utils.ts +0 -317
  230. package/src/core/progressive-loading.tsx +0 -331
  231. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  232. package/src/core/providers/lazy-provider.tsx +0 -14
  233. package/src/core/providers/service-provider.tsx +0 -164
  234. package/src/core/utils.tsx +0 -34
  235. package/src/features/media-session/media-session-manager.ts +0 -411
  236. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  237. package/src/features/playlist/playlist-manager.ts +0 -626
  238. package/src/features/subtitles/subtitle-manager.ts +0 -435
  239. package/src/features/subtitles/subtitle-parser.ts +0 -284
  240. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  241. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  242. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  243. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  244. package/src/hooks/accessibility/index.ts +0 -27
  245. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  246. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  247. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  248. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  249. package/src/hooks/core/index.ts +0 -47
  250. package/src/hooks/legacy.ts +0 -21
  251. package/src/hooks/use-buffer-health.ts +0 -218
  252. package/src/hooks/use-enhanced-media-player.ts +0 -575
  253. package/src/hooks/use-focus-trap.tsx +0 -162
  254. package/src/hooks/use-intelligent-preloading.ts +0 -387
  255. package/src/hooks/use-keyboard-controls.ts +0 -115
  256. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  257. package/src/hooks/use-media-actions.ts +0 -184
  258. package/src/hooks/use-media-metadata.ts +0 -91
  259. package/src/hooks/use-media-optimistic.ts +0 -264
  260. package/src/hooks/use-media-player.ts +0 -343
  261. package/src/hooks/use-media-state.ts +0 -194
  262. package/src/hooks/use-memory-optimization.ts +0 -360
  263. package/src/hooks/use-network-status.ts +0 -124
  264. package/src/hooks/use-optimistic-controls.ts +0 -95
  265. package/src/hooks/use-optimized-media.ts +0 -283
  266. package/src/hooks/use-smart-preload.ts +0 -229
  267. package/src/hooks/use-touch-gestures.ts +0 -461
  268. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  269. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  270. package/src/hooks/useMediaControls.ts +0 -52
  271. package/src/hooks/useScreenshot.ts +0 -77
  272. package/src/hooks/useSubtitles.ts +0 -91
  273. package/src/hooks/useVideoPlayer.ts +0 -278
  274. package/src/icons/components/FullscreenIcon.tsx +0 -36
  275. package/src/icons/components/SettingsIcon.tsx +0 -37
  276. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  277. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  278. package/src/icons/components/media/PauseIcon.tsx +0 -38
  279. package/src/icons/components/media/PlayIcon.tsx +0 -37
  280. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  281. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  282. package/src/icons/index.ts +0 -56
  283. package/src/icons/provider.tsx +0 -58
  284. package/src/icons/types.ts +0 -60
  285. package/src/index-enhanced.ts +0 -35
  286. package/src/index-legacy.ts +0 -324
  287. package/src/index.css +0 -102
  288. package/src/lib/__tests__/async-utils.test.ts +0 -291
  289. package/src/lib/async-utils.ts +0 -194
  290. package/src/lib/deprecation.ts +0 -51
  291. package/src/lib/format-time.ts +0 -37
  292. package/src/lib/index.ts +0 -4
  293. package/src/lib/utils.ts +0 -6
  294. package/src/styles/globals.css +0 -462
  295. package/src/styles/minimal-player.css +0 -621
  296. package/src/styles/pixel-art.css +0 -41
  297. package/src/styles/videojs.css +0 -100
  298. package/src/types/assets.d.ts +0 -29
  299. package/src/types/events.ts +0 -47
  300. package/src/types/formats.ts +0 -79
  301. package/src/types/index.ts +0 -203
  302. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,435 +0,0 @@
1
- import { type ParsedSubtitles, type SubtitleCue, SubtitleParser } from "./subtitle-parser"
2
-
3
- export interface SubtitleTrack {
4
- id: string
5
- url: string
6
- label: string
7
- language: string
8
- isDefault?: boolean
9
- format?: "vtt" | "srt"
10
- parsedSubtitles?: ParsedSubtitles
11
- loadingState?: "idle" | "loading" | "loaded" | "error"
12
- error?: string
13
- }
14
-
15
- export interface SubtitleStyle {
16
- fontSize?: number
17
- fontFamily?: string
18
- color?: string
19
- backgroundColor?: string
20
- borderColor?: string
21
- borderWidth?: number
22
- opacity?: number
23
- position?: "top" | "center" | "bottom"
24
- alignment?: "left" | "center" | "right"
25
- shadow?: boolean
26
- }
27
-
28
- export interface SubtitleManagerOptions {
29
- tracks?: SubtitleTrack[]
30
- defaultStyle?: SubtitleStyle
31
- enabledByDefault?: boolean
32
- preloadTracks?: boolean
33
- }
34
-
35
- export class SubtitleManager {
36
- private tracks: Map<string, SubtitleTrack> = new Map()
37
- private activeTrackId: string | null = null
38
- private currentCues: SubtitleCue[] = []
39
- private isEnabled: boolean = false
40
- private style: SubtitleStyle
41
- private eventListeners: Map<string, Set<Function>> = new Map()
42
-
43
- constructor(options: SubtitleManagerOptions = {}) {
44
- this.style = {
45
- fontSize: 16,
46
- fontFamily: "Arial, sans-serif",
47
- color: "#ffffff",
48
- backgroundColor: "rgba(0, 0, 0, 0.7)",
49
- borderColor: "#000000",
50
- borderWidth: 1,
51
- opacity: 1,
52
- position: "bottom",
53
- alignment: "center",
54
- shadow: true,
55
- ...options.defaultStyle
56
- }
57
-
58
- this.isEnabled = options.enabledByDefault ?? false
59
-
60
- if (options.tracks) {
61
- this.addTracks(options.tracks)
62
-
63
- if (options.preloadTracks) {
64
- this.preloadAllTracks()
65
- }
66
- }
67
- }
68
-
69
- /**
70
- * Add multiple subtitle tracks
71
- */
72
- addTracks(tracks: SubtitleTrack[]): void {
73
- tracks.forEach((track) => this.addTrack(track))
74
- }
75
-
76
- /**
77
- * Add a single subtitle track
78
- */
79
- addTrack(track: SubtitleTrack): void {
80
- const trackWithDefaults: SubtitleTrack = {
81
- ...track,
82
- loadingState: "idle",
83
- format: track.format || this.detectFormat(track.url)
84
- }
85
-
86
- this.tracks.set(track.id, trackWithDefaults)
87
- this.emit("trackAdded", trackWithDefaults)
88
-
89
- // Set as active if it's the default track and no track is currently active
90
- if (track.isDefault && !this.activeTrackId) {
91
- this.setActiveTrack(track.id)
92
- }
93
- }
94
-
95
- /**
96
- * Remove a subtitle track
97
- */
98
- removeTrack(trackId: string): void {
99
- const track = this.tracks.get(trackId)
100
- if (track) {
101
- this.tracks.delete(trackId)
102
-
103
- if (this.activeTrackId === trackId) {
104
- this.activeTrackId = null
105
- this.currentCues = []
106
- this.emit("cuesChanged", [])
107
- }
108
-
109
- this.emit("trackRemoved", track)
110
- }
111
- }
112
-
113
- /**
114
- * Get all available tracks
115
- */
116
- getTracks(): SubtitleTrack[] {
117
- return Array.from(this.tracks.values())
118
- }
119
-
120
- /**
121
- * Get a specific track by ID
122
- */
123
- getTrack(trackId: string): SubtitleTrack | undefined {
124
- return this.tracks.get(trackId)
125
- }
126
-
127
- /**
128
- * Set the active subtitle track
129
- */
130
- async setActiveTrack(trackId: string | null): Promise<void> {
131
- this.activeTrackId = trackId
132
- this.currentCues = []
133
-
134
- if (trackId) {
135
- const track = this.tracks.get(trackId)
136
- if (track && !track.parsedSubtitles && track.loadingState === "idle") {
137
- await this.loadTrack(trackId)
138
- }
139
- }
140
-
141
- this.emit("activeTrackChanged", trackId)
142
- this.emit("cuesChanged", [])
143
- }
144
-
145
- /**
146
- * Get the currently active track
147
- */
148
- getActiveTrack(): SubtitleTrack | null {
149
- return this.activeTrackId ? this.tracks.get(this.activeTrackId) || null : null
150
- }
151
-
152
- /**
153
- * Enable or disable subtitles
154
- */
155
- setEnabled(enabled: boolean): void {
156
- this.isEnabled = enabled
157
-
158
- if (!enabled) {
159
- this.currentCues = []
160
- this.emit("cuesChanged", [])
161
- }
162
-
163
- this.emit("enabledChanged", enabled)
164
- }
165
-
166
- /**
167
- * Check if subtitles are enabled
168
- */
169
- isSubtitlesEnabled(): boolean {
170
- return this.isEnabled
171
- }
172
-
173
- /**
174
- * Update subtitle styling
175
- */
176
- updateStyle(newStyle: Partial<SubtitleStyle>): void {
177
- this.style = { ...this.style, ...newStyle }
178
- this.emit("styleChanged", this.style)
179
- }
180
-
181
- /**
182
- * Get current subtitle style
183
- */
184
- getStyle(): SubtitleStyle {
185
- return { ...this.style }
186
- }
187
-
188
- /**
189
- * Update current time and get active cues
190
- */
191
- updateTime(currentTime: number): SubtitleCue[] {
192
- if (!this.isEnabled || !this.activeTrackId) {
193
- if (this.currentCues.length > 0) {
194
- this.currentCues = []
195
- this.emit("cuesChanged", [])
196
- }
197
- return []
198
- }
199
-
200
- const activeTrack = this.tracks.get(this.activeTrackId)
201
- if (!activeTrack?.parsedSubtitles) {
202
- if (this.currentCues.length > 0) {
203
- this.currentCues = []
204
- this.emit("cuesChanged", [])
205
- }
206
- return []
207
- }
208
-
209
- const activeCues = SubtitleParser.getActiveCues(activeTrack.parsedSubtitles.cues, currentTime)
210
-
211
- // Check if cues have changed
212
- const cuesChanged =
213
- activeCues.length !== this.currentCues.length ||
214
- activeCues.some(
215
- (cue, index) => !this.currentCues[index] || cue.id !== this.currentCues[index].id
216
- )
217
-
218
- if (cuesChanged) {
219
- this.currentCues = activeCues
220
- this.emit("cuesChanged", activeCues)
221
- }
222
-
223
- return activeCues
224
- }
225
-
226
- /**
227
- * Get current active cues
228
- */
229
- getCurrentCues(): SubtitleCue[] {
230
- return [...this.currentCues]
231
- }
232
-
233
- /**
234
- * Load a subtitle track
235
- */
236
- async loadTrack(trackId: string): Promise<void> {
237
- const track = this.tracks.get(trackId)
238
- if (!track || track.loadingState === "loading" || track.loadingState === "loaded") {
239
- return
240
- }
241
-
242
- // Update loading state
243
- track.loadingState = "loading"
244
- this.emit("trackLoadingStateChanged", { trackId, state: "loading" })
245
-
246
- try {
247
- const response = await fetch(track.url)
248
- if (!response.ok) {
249
- throw new Error(`Failed to fetch subtitles: ${response.status} ${response.statusText}`)
250
- }
251
-
252
- const content = await response.text()
253
- const format = track.format || SubtitleParser.detectFormat(content)
254
-
255
- if (format === "unknown") {
256
- throw new Error("Unsupported subtitle format")
257
- }
258
-
259
- const parsedSubtitles = SubtitleParser.parse(content, format)
260
- track.parsedSubtitles = parsedSubtitles
261
- track.loadingState = "loaded"
262
- track.format = format
263
-
264
- this.emit("trackLoadingStateChanged", { trackId, state: "loaded" })
265
- this.emit("trackLoaded", track)
266
- } catch (error) {
267
- track.loadingState = "error"
268
- track.error = error instanceof Error ? error.message : "Unknown error"
269
-
270
- this.emit("trackLoadingStateChanged", { trackId, state: "error", error: track.error })
271
- this.emit("trackError", { trackId, error: track.error })
272
- }
273
- }
274
-
275
- /**
276
- * Preload all available tracks
277
- */
278
- async preloadAllTracks(): Promise<void> {
279
- const loadPromises = Array.from(this.tracks.keys()).map((trackId) => this.loadTrack(trackId))
280
-
281
- await Promise.allSettled(loadPromises)
282
- }
283
-
284
- /**
285
- * Search for cues containing text
286
- */
287
- searchCues(query: string, trackId?: string): Array<{ trackId: string; cue: SubtitleCue }> {
288
- const results: Array<{ trackId: string; cue: SubtitleCue }> = []
289
- const searchTracks = trackId ? [trackId] : Array.from(this.tracks.keys())
290
-
291
- for (const id of searchTracks) {
292
- const track = this.tracks.get(id)
293
- if (!track?.parsedSubtitles) continue
294
-
295
- for (const cue of track.parsedSubtitles.cues) {
296
- const cleanText = SubtitleParser.cleanText(cue.text).toLowerCase()
297
- if (cleanText.includes(query.toLowerCase())) {
298
- results.push({ trackId: id, cue })
299
- }
300
- }
301
- }
302
-
303
- return results
304
- }
305
-
306
- /**
307
- * Export subtitles in a specific format
308
- */
309
- exportSubtitles(trackId: string, format: "vtt" | "srt"): string | null {
310
- const track = this.tracks.get(trackId)
311
- if (!track?.parsedSubtitles) return null
312
-
313
- const { cues, metadata } = track.parsedSubtitles
314
-
315
- if (format === "vtt") {
316
- return this.exportAsVTT(cues, metadata)
317
- } else {
318
- return this.exportAsSRT(cues)
319
- }
320
- }
321
-
322
- /**
323
- * Event system methods
324
- */
325
- on(event: string, callback: Function): () => void {
326
- if (!this.eventListeners.has(event)) {
327
- this.eventListeners.set(event, new Set())
328
- }
329
-
330
- this.eventListeners.get(event)!.add(callback)
331
-
332
- return () => {
333
- const listeners = this.eventListeners.get(event)
334
- if (listeners) {
335
- listeners.delete(callback)
336
- }
337
- }
338
- }
339
-
340
- private emit(event: string, data?: any): void {
341
- const listeners = this.eventListeners.get(event)
342
- if (listeners) {
343
- listeners.forEach((callback) => callback(data))
344
- }
345
- }
346
-
347
- /**
348
- * Detect subtitle format from URL extension
349
- */
350
- private detectFormat(url: string): "vtt" | "srt" {
351
- const extension = url.split(".").pop()?.toLowerCase()
352
- return extension === "srt" ? "srt" : "vtt"
353
- }
354
-
355
- /**
356
- * Export cues as WebVTT format
357
- */
358
- private exportAsVTT(cues: SubtitleCue[], metadata?: any): string {
359
- let output = "WEBVTT\n\n"
360
-
361
- if (metadata) {
362
- Object.entries(metadata).forEach(([key, value]) => {
363
- output += `${key}: ${value}\n`
364
- })
365
- output += "\n"
366
- }
367
-
368
- cues.forEach((cue, index) => {
369
- if (cue.id) {
370
- output += `${cue.id}\n`
371
- }
372
-
373
- const startTime = this.formatTime(cue.startTime, "vtt")
374
- const endTime = this.formatTime(cue.endTime, "vtt")
375
-
376
- output += `${startTime} --> ${endTime}`
377
-
378
- if (cue.settings) {
379
- const settings: string[] = []
380
- Object.entries(cue.settings).forEach(([key, value]) => {
381
- settings.push(`${key}:${value}`)
382
- })
383
- if (settings.length > 0) {
384
- output += ` ${settings.join(" ")}`
385
- }
386
- }
387
-
388
- output += `\n${cue.text}\n\n`
389
- })
390
-
391
- return output
392
- }
393
-
394
- /**
395
- * Export cues as SRT format
396
- */
397
- private exportAsSRT(cues: SubtitleCue[]): string {
398
- let output = ""
399
-
400
- cues.forEach((cue, index) => {
401
- const startTime = this.formatTime(cue.startTime, "srt")
402
- const endTime = this.formatTime(cue.endTime, "srt")
403
-
404
- output += `${index + 1}\n`
405
- output += `${startTime} --> ${endTime}\n`
406
- output += `${cue.text}\n\n`
407
- })
408
-
409
- return output
410
- }
411
-
412
- /**
413
- * Format time for different subtitle formats
414
- */
415
- private formatTime(seconds: number, format: "vtt" | "srt"): string {
416
- const hours = Math.floor(seconds / 3600)
417
- const minutes = Math.floor((seconds % 3600) / 60)
418
- const secs = Math.floor(seconds % 60)
419
- const milliseconds = Math.floor((seconds % 1) * 1000)
420
-
421
- const separator = format === "srt" ? "," : "."
422
-
423
- return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}${separator}${milliseconds.toString().padStart(3, "0")}`
424
- }
425
-
426
- /**
427
- * Cleanup resources
428
- */
429
- destroy(): void {
430
- this.tracks.clear()
431
- this.eventListeners.clear()
432
- this.activeTrackId = null
433
- this.currentCues = []
434
- }
435
- }
@@ -1,284 +0,0 @@
1
- export interface SubtitleCue {
2
- id?: string
3
- startTime: number
4
- endTime: number
5
- text: string
6
- settings?: {
7
- line?: number | "auto"
8
- position?: number
9
- size?: number
10
- align?: "start" | "center" | "end"
11
- vertical?: "rl" | "lr"
12
- }
13
- }
14
-
15
- export interface ParsedSubtitles {
16
- cues: SubtitleCue[]
17
- metadata?: {
18
- title?: string
19
- language?: string
20
- description?: string
21
- }
22
- }
23
-
24
- export class SubtitleParser {
25
- /**
26
- * Parse subtitle content based on format
27
- */
28
- static parse(content: string, format: "vtt" | "srt"): ParsedSubtitles {
29
- switch (format) {
30
- case "vtt":
31
- return this.parseVTT(content)
32
- case "srt":
33
- return this.parseSRT(content)
34
- default:
35
- throw new Error(`Unsupported subtitle format: ${format}`)
36
- }
37
- }
38
-
39
- /**
40
- * Auto-detect subtitle format from content
41
- */
42
- static detectFormat(content: string): "vtt" | "srt" | "unknown" {
43
- const trimmedContent = content.trim()
44
-
45
- if (trimmedContent.startsWith("WEBVTT")) {
46
- return "vtt"
47
- }
48
-
49
- // Check for SRT pattern (number, timestamp, text)
50
- const srtPattern = /^\d+\s*\n\d{2}:\d{2}:\d{2},\d{3}\s*-->\s*\d{2}:\d{2}:\d{2},\d{3}/m
51
- if (srtPattern.test(trimmedContent)) {
52
- return "srt"
53
- }
54
-
55
- return "unknown"
56
- }
57
-
58
- /**
59
- * Parse WebVTT format
60
- */
61
- private static parseVTT(content: string): ParsedSubtitles {
62
- const lines = content.split("\n")
63
- const cues: SubtitleCue[] = []
64
- const metadata: any = {}
65
-
66
- let i = 0
67
-
68
- // Skip WEBVTT header and metadata
69
- if (lines[0]?.startsWith("WEBVTT")) {
70
- i = 1
71
- // Parse metadata in header
72
- while (i < lines.length && lines[i]?.trim() !== "") {
73
- const line = lines[i]?.trim() || ""
74
- if (line.includes(":")) {
75
- const [key, value] = line.split(":").map((s) => s.trim())
76
- if (key && value) {
77
- metadata[key.toLowerCase()] = value
78
- }
79
- }
80
- i++
81
- }
82
- }
83
-
84
- // Parse cues
85
- while (i < lines.length) {
86
- // Skip empty lines
87
- if (!lines[i]?.trim()) {
88
- i++
89
- continue
90
- }
91
-
92
- let cueId: string | undefined
93
- let timingLine: string
94
-
95
- // Check if this line is a timing line or cue identifier
96
- const isTimingLine = lines[i]?.includes("-->")
97
- if (isTimingLine) {
98
- timingLine = lines[i] || ""
99
- i++
100
- } else {
101
- // This is a cue identifier
102
- cueId = lines[i]?.trim()
103
- i++
104
- timingLine = lines[i] || ""
105
- i++
106
- }
107
-
108
- // Parse timing line
109
- const timing = this.parseVTTTiming(timingLine)
110
- if (!timing) {
111
- i++
112
- continue
113
- }
114
-
115
- // Collect cue text
116
- const textLines: string[] = []
117
- while (i < lines.length && lines[i]?.trim() !== "") {
118
- const line = lines[i]
119
- if (line) textLines.push(line)
120
- i++
121
- }
122
-
123
- if (textLines.length > 0) {
124
- cues.push({
125
- id: cueId,
126
- startTime: timing.start,
127
- endTime: timing.end,
128
- text: textLines.join("\n"),
129
- settings: timing.settings
130
- })
131
- }
132
-
133
- i++
134
- }
135
-
136
- return { cues, metadata }
137
- }
138
-
139
- /**
140
- * Parse SRT format
141
- */
142
- private static parseSRT(content: string): ParsedSubtitles {
143
- const cues: SubtitleCue[] = []
144
- const blocks = content.split(/\n\s*\n/).filter((block) => block.trim())
145
-
146
- for (const block of blocks) {
147
- const lines = block
148
- .split("\n")
149
- .map((line) => line.trim())
150
- .filter((line) => line)
151
- if (lines.length < 3) continue
152
-
153
- const id = lines[0]
154
- const timingLine = lines[1] || ""
155
- const textLines = lines.slice(2)
156
-
157
- const timing = this.parseSRTTiming(timingLine)
158
- if (!timing) continue
159
-
160
- cues.push({
161
- id,
162
- startTime: timing.start,
163
- endTime: timing.end,
164
- text: textLines.join("\n")
165
- })
166
- }
167
-
168
- return { cues }
169
- }
170
-
171
- /**
172
- * Parse VTT timing line with settings
173
- */
174
- private static parseVTTTiming(timingLine: string): {
175
- start: number
176
- end: number
177
- settings?: SubtitleCue["settings"]
178
- } | null {
179
- const parts = timingLine.split(/\s+/)
180
- const arrowIndex = parts.findIndex((part) => part === "-->")
181
-
182
- if (arrowIndex === -1 || arrowIndex === 0 || arrowIndex === parts.length - 1) {
183
- return null
184
- }
185
-
186
- const startTime = this.parseTimeString(parts[arrowIndex - 1] || "")
187
- const endTime = this.parseTimeString(parts[arrowIndex + 1] || "")
188
-
189
- if (startTime === null || endTime === null) {
190
- return null
191
- }
192
-
193
- // Parse cue settings
194
- const settings: SubtitleCue["settings"] = {}
195
- const settingsParts = parts.slice(arrowIndex + 2)
196
-
197
- for (const setting of settingsParts) {
198
- const [key, value] = setting.split(":")
199
- if (!key || !value) continue
200
-
201
- switch (key) {
202
- case "line":
203
- settings.line = value === "auto" ? "auto" : parseInt(value)
204
- break
205
- case "position":
206
- settings.position = parseInt(value)
207
- break
208
- case "size":
209
- settings.size = parseInt(value)
210
- break
211
- case "align":
212
- if (["start", "center", "end"].includes(value)) {
213
- settings.align = value as "start" | "center" | "end"
214
- }
215
- break
216
- case "vertical":
217
- if (["rl", "lr"].includes(value)) {
218
- settings.vertical = value as "rl" | "lr"
219
- }
220
- break
221
- }
222
- }
223
-
224
- return {
225
- start: startTime,
226
- end: endTime,
227
- settings: Object.keys(settings).length > 0 ? settings : undefined
228
- }
229
- }
230
-
231
- /**
232
- * Parse SRT timing line
233
- */
234
- private static parseSRTTiming(timingLine: string): {
235
- start: number
236
- end: number
237
- } | null {
238
- const match = timingLine.match(/(\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3})/)
239
- if (!match) return null
240
-
241
- const startTime = this.parseTimeString(match[1]?.replace(",", ".") || "")
242
- const endTime = this.parseTimeString(match[2]?.replace(",", ".") || "")
243
-
244
- if (startTime === null || endTime === null) return null
245
-
246
- return { start: startTime, end: endTime }
247
- }
248
-
249
- /**
250
- * Parse time string to seconds
251
- */
252
- private static parseTimeString(timeStr: string): number | null {
253
- const match = timeStr.match(/(\d{2}):(\d{2}):(\d{2})\.(\d{3})/)
254
- if (!match) return null
255
-
256
- const hours = parseInt(match[1] || "0", 10)
257
- const minutes = parseInt(match[2] || "0", 10)
258
- const seconds = parseInt(match[3] || "0", 10)
259
- const milliseconds = parseInt(match[4] || "0", 10)
260
-
261
- return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000
262
- }
263
-
264
- /**
265
- * Find active cues at a given time
266
- */
267
- static getActiveCues(cues: SubtitleCue[], currentTime: number): SubtitleCue[] {
268
- return cues.filter((cue) => currentTime >= cue.startTime && currentTime <= cue.endTime)
269
- }
270
-
271
- /**
272
- * Clean subtitle text (remove HTML tags, etc.)
273
- */
274
- static cleanText(text: string): string {
275
- return text
276
- .replace(/<[^>]*>/g, "") // Remove HTML tags
277
- .replace(/&lt;/g, "<")
278
- .replace(/&gt;/g, ">")
279
- .replace(/&amp;/g, "&")
280
- .replace(/&quot;/g, '"')
281
- .replace(/&#39;/g, "'")
282
- .trim()
283
- }
284
- }