@therealtinhtute/baroiplayer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/context/media.js +2 -0
  4. package/dist/context/media.js.map +1 -0
  5. package/dist/context/media.mjs +15 -0
  6. package/dist/context/media.mjs.map +1 -0
  7. package/dist/context/store.js +2 -0
  8. package/dist/context/store.js.map +1 -0
  9. package/dist/context/store.mjs +5 -0
  10. package/dist/context/store.mjs.map +1 -0
  11. package/dist/context-BMteAJDN.js +1140 -0
  12. package/dist/context-BMteAJDN.js.map +1 -0
  13. package/dist/context-DCJ_scmO.cjs +23 -0
  14. package/dist/context-DCJ_scmO.cjs.map +1 -0
  15. package/dist/core-events-B5W_j8yU.js +480 -0
  16. package/dist/core-events-B5W_j8yU.js.map +1 -0
  17. package/dist/core-events-CN0-Vhhq.cjs +2 -0
  18. package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
  19. package/dist/core-plugins-Bq9KLany.js +696 -0
  20. package/dist/core-plugins-Bq9KLany.js.map +1 -0
  21. package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
  22. package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
  23. package/dist/core.js +37 -0
  24. package/dist/core.js.map +1 -0
  25. package/dist/core.mjs +1217 -0
  26. package/dist/core.mjs.map +1 -0
  27. package/dist/enhanced-components-DHv0MFvG.js +1073 -0
  28. package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
  29. package/dist/enhanced-components-DTIObgB7.cjs +2 -0
  30. package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
  31. package/dist/hooks-C_r8wexn.cjs +4 -0
  32. package/dist/hooks-C_r8wexn.cjs.map +1 -0
  33. package/dist/hooks-Da2wVXlF.js +1630 -0
  34. package/dist/hooks-Da2wVXlF.js.map +1 -0
  35. package/dist/index.css +1 -0
  36. package/dist/index.js +112 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +6126 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/minimal-components-DSq5sQpy.js +2002 -0
  41. package/dist/minimal-components-DSq5sQpy.js.map +1 -0
  42. package/dist/minimal-components-DflWiihN.cjs +2 -0
  43. package/dist/minimal-components-DflWiihN.cjs.map +1 -0
  44. package/dist/minimal-components.css +1 -0
  45. package/dist/mona-loading.gif +0 -0
  46. package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
  47. package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
  48. package/dist/performance-monitor-rMW1RgV3.js +302 -0
  49. package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
  50. package/dist/utils-BnscpYYd.js +2798 -0
  51. package/dist/utils-BnscpYYd.js.map +1 -0
  52. package/dist/utils-D_czS_0K.cjs +9 -0
  53. package/dist/utils-D_czS_0K.cjs.map +1 -0
  54. package/dist/utils.js +2 -0
  55. package/dist/utils.js.map +1 -0
  56. package/dist/utils.mjs +7 -0
  57. package/dist/utils.mjs.map +1 -0
  58. package/package.json +114 -0
  59. package/src/adapters/videojs-adapter.tsx +470 -0
  60. package/src/assets/mona-loading.gif +0 -0
  61. package/src/components/AnimateLoading.tsx +115 -0
  62. package/src/components/LoadingState.tsx +248 -0
  63. package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
  64. package/src/components/audio-player.tsx +85 -0
  65. package/src/components/basic/index.ts +37 -0
  66. package/src/components/enhanced/advanced-features.tsx +316 -0
  67. package/src/components/enhanced/debug-panel.tsx +422 -0
  68. package/src/components/enhanced/enhanced-controls.tsx +600 -0
  69. package/src/components/enhanced/enhanced-media-player.tsx +509 -0
  70. package/src/components/enhanced/error-handling.tsx +345 -0
  71. package/src/components/enhanced/index.ts +39 -0
  72. package/src/components/enhanced/media-player-enhanced.tsx +349 -0
  73. package/src/components/examples/basic-video-player.tsx +55 -0
  74. package/src/components/examples/custom-controls-example.tsx +63 -0
  75. package/src/components/examples/enhanced-controls-example.tsx +114 -0
  76. package/src/components/examples/enhanced-media-player-example.tsx +293 -0
  77. package/src/components/examples/loading-states-demo.tsx +142 -0
  78. package/src/components/examples/react-19-demo.tsx +381 -0
  79. package/src/components/examples/volume-orientation-demo.tsx +114 -0
  80. package/src/components/icon-demo.tsx +209 -0
  81. package/src/components/icons/index.tsx +166 -0
  82. package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
  83. package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
  84. package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
  85. package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
  86. package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
  87. package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
  88. package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
  89. package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
  90. package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
  91. package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
  92. package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
  93. package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
  94. package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
  95. package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
  96. package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
  97. package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
  98. package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
  99. package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
  100. package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
  101. package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
  102. package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
  103. package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
  104. package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
  105. package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
  106. package/src/components/legacy.tsx +93 -0
  107. package/src/components/media-metadata-display.tsx +100 -0
  108. package/src/components/media-player-audio.tsx +39 -0
  109. package/src/components/media-player-controls.tsx +226 -0
  110. package/src/components/media-player-error.tsx +163 -0
  111. package/src/components/media-player-fullscreen.tsx +109 -0
  112. package/src/components/media-player-hls.tsx +111 -0
  113. package/src/components/media-player-loading.tsx +76 -0
  114. package/src/components/media-player-play.tsx +75 -0
  115. package/src/components/media-player-root.tsx +340 -0
  116. package/src/components/media-player-seek.tsx +168 -0
  117. package/src/components/media-player-time.tsx +99 -0
  118. package/src/components/media-player-tooltip.tsx +58 -0
  119. package/src/components/media-player-video.tsx +39 -0
  120. package/src/components/media-player-volume.tsx +155 -0
  121. package/src/components/media-player.tsx +257 -0
  122. package/src/components/media-suspense.tsx +362 -0
  123. package/src/components/player-settings-form.tsx +163 -0
  124. package/src/components/react-player-wrapper.tsx +651 -0
  125. package/src/components/simple-video-player.tsx +60 -0
  126. package/src/components/ui/enhanced-seek-bar.tsx +235 -0
  127. package/src/components/ui/fullscreen-button.tsx +60 -0
  128. package/src/components/ui/media-resource-preloader.tsx +395 -0
  129. package/src/components/ui/play-button.tsx +107 -0
  130. package/src/components/ui/seek-bar.tsx +161 -0
  131. package/src/components/ui/time-display.tsx +40 -0
  132. package/src/components/ui/volume-control.tsx +143 -0
  133. package/src/components/unified/base-media-player.tsx +246 -0
  134. package/src/components/unified/media-player.tsx +75 -0
  135. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
  136. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
  137. package/src/components/variants/minimal/MinimalControls.tsx +142 -0
  138. package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
  139. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
  140. package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
  141. package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
  142. package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
  143. package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
  144. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
  145. package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
  146. package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
  147. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
  148. package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
  149. package/src/components/variants/minimal/components/RightControls.tsx +173 -0
  150. package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
  151. package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
  152. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
  153. package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
  154. package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
  155. package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
  156. package/src/components/variants/minimal/index.ts +23 -0
  157. package/src/components/video-player.tsx +100 -0
  158. package/src/context/error-handling.ts +394 -0
  159. package/src/context/media-context.tsx +208 -0
  160. package/src/context/media-provider.tsx +265 -0
  161. package/src/context/media-store.ts +379 -0
  162. package/src/context/persistence.ts +453 -0
  163. package/src/core/events/event-system.ts +442 -0
  164. package/src/core/events/hooks.ts +302 -0
  165. package/src/core/events/index.ts +22 -0
  166. package/src/core/events/middleware.ts +269 -0
  167. package/src/core/index.ts +22 -0
  168. package/src/core/optimization/bundle-optimizer.tsx +308 -0
  169. package/src/core/performance/cicd.ts +96 -0
  170. package/src/core/performance/index.ts +38 -0
  171. package/src/core/performance/media-loading-optimizer.ts +538 -0
  172. package/src/core/performance/performance-budgets.ts +432 -0
  173. package/src/core/performance/performance-monitor.tsx +476 -0
  174. package/src/core/performance/performance-testing.ts +459 -0
  175. package/src/core/plugins/base-plugin.ts +224 -0
  176. package/src/core/plugins/enhanced-plugin-system.ts +411 -0
  177. package/src/core/plugins/examples/analytics-plugin.ts +242 -0
  178. package/src/core/plugins/index.ts +39 -0
  179. package/src/core/plugins/registry.ts +327 -0
  180. package/src/core/plugins/types.ts +159 -0
  181. package/src/core/plugins/utils.ts +316 -0
  182. package/src/core/progressive-loading.tsx +322 -0
  183. package/src/core/providers/enhanced-hls-provider.ts +339 -0
  184. package/src/core/providers/service-provider.tsx +168 -0
  185. package/src/core/utils.tsx +38 -0
  186. package/src/features/media-session/media-session-manager.ts +429 -0
  187. package/src/features/picture-in-picture/pip-manager.ts +429 -0
  188. package/src/features/playlist/playlist-manager.ts +606 -0
  189. package/src/features/subtitles/subtitle-manager.ts +441 -0
  190. package/src/features/subtitles/subtitle-parser.ts +280 -0
  191. package/src/features/thumbnails/thumbnail-generator.ts +519 -0
  192. package/src/hooks/accessibility/index.ts +27 -0
  193. package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
  194. package/src/hooks/accessibility/use-focus-management.ts +176 -0
  195. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
  196. package/src/hooks/accessibility/use-screen-reader.ts +182 -0
  197. package/src/hooks/core/index.ts +47 -0
  198. package/src/hooks/legacy.ts +27 -0
  199. package/src/hooks/use-enhanced-media-player.ts +468 -0
  200. package/src/hooks/use-intelligent-preloading.ts +358 -0
  201. package/src/hooks/use-keyboard-controls.ts +115 -0
  202. package/src/hooks/use-media-actions.ts +175 -0
  203. package/src/hooks/use-media-metadata.ts +89 -0
  204. package/src/hooks/use-media-optimistic.ts +270 -0
  205. package/src/hooks/use-media-player.ts +312 -0
  206. package/src/hooks/use-media-state.ts +190 -0
  207. package/src/hooks/use-memory-optimization.ts +358 -0
  208. package/src/hooks/use-optimistic-controls.ts +92 -0
  209. package/src/hooks/use-optimized-media.ts +263 -0
  210. package/src/hooks/use-touch-gestures.ts +417 -0
  211. package/src/hooks/useEnhancedSubtitles.ts +258 -0
  212. package/src/hooks/useKeyboardShortcuts.ts +74 -0
  213. package/src/hooks/useMediaControls.ts +52 -0
  214. package/src/hooks/useScreenshot.ts +57 -0
  215. package/src/hooks/useSubtitles.ts +91 -0
  216. package/src/hooks/useVideoPlayer.ts +232 -0
  217. package/src/icons/components/FullscreenIcon.tsx +37 -0
  218. package/src/icons/components/SettingsIcon.tsx +38 -0
  219. package/src/icons/components/animated/LoadingIcon.tsx +43 -0
  220. package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
  221. package/src/icons/components/media/PauseIcon.tsx +39 -0
  222. package/src/icons/components/media/PlayIcon.tsx +38 -0
  223. package/src/icons/components/volume/VolumeIcon.tsx +39 -0
  224. package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
  225. package/src/icons/index.ts +56 -0
  226. package/src/icons/provider.tsx +64 -0
  227. package/src/icons/types.ts +40 -0
  228. package/src/index-enhanced.ts +35 -0
  229. package/src/index-legacy.ts +326 -0
  230. package/src/index.css +102 -0
  231. package/src/index.ts +216 -0
  232. package/src/lib/deprecation.ts +51 -0
  233. package/src/lib/format-time.ts +37 -0
  234. package/src/lib/index.ts +3 -0
  235. package/src/lib/utils.ts +6 -0
  236. package/src/styles/globals.css +462 -0
  237. package/src/styles/minimal-player.css +589 -0
  238. package/src/styles/pixel-art.css +46 -0
  239. package/src/styles/videojs.css +100 -0
  240. package/src/test/setup.ts +79 -0
  241. package/src/types/events.ts +47 -0
  242. package/src/types/formats.ts +95 -0
  243. package/src/types/index.ts +190 -0
  244. package/src/types/videojs-plugins.d.ts +14 -0
@@ -0,0 +1,316 @@
1
+ import type { Plugin, PluginLogger, PluginConfig } from './types'
2
+
3
+ // Simple console logger implementation
4
+ export class ConsolePluginLogger implements PluginLogger {
5
+ private prefix: string
6
+
7
+ constructor(prefix = '[Plugin]') {
8
+ this.prefix = prefix
9
+ }
10
+
11
+ info(message: string, data?: any): void {
12
+ if (data) {
13
+ console.info(`${this.prefix} ${message}`, data)
14
+ } else {
15
+ console.info(`${this.prefix} ${message}`)
16
+ }
17
+ }
18
+
19
+ warn(message: string, data?: any): void {
20
+ if (data) {
21
+ console.warn(`${this.prefix} ${message}`, data)
22
+ } else {
23
+ console.warn(`${this.prefix} ${message}`)
24
+ }
25
+ }
26
+
27
+ error(message: string, data?: any): void {
28
+ if (data) {
29
+ console.error(`${this.prefix} ${message}`, data)
30
+ } else {
31
+ console.error(`${this.prefix} ${message}`)
32
+ }
33
+ }
34
+
35
+ debug(message: string, data?: any): void {
36
+ if (process.env.NODE_ENV === 'development') {
37
+ if (data) {
38
+ console.debug(`${this.prefix} ${message}`, data)
39
+ } else {
40
+ console.debug(`${this.prefix} ${message}`)
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ // Plugin validation utilities
47
+ export class PluginValidator {
48
+ static validateMetadata(plugin: Plugin): boolean {
49
+ const { metadata } = plugin
50
+
51
+ if (!metadata.name || typeof metadata.name !== 'string') {
52
+ throw new Error('Plugin metadata must include a valid name')
53
+ }
54
+
55
+ if (!metadata.version || typeof metadata.version !== 'string') {
56
+ throw new Error('Plugin metadata must include a valid version')
57
+ }
58
+
59
+ if (!metadata.description || typeof metadata.description !== 'string') {
60
+ throw new Error('Plugin metadata must include a valid description')
61
+ }
62
+
63
+ if (!metadata.category) {
64
+ throw new Error('Plugin metadata must include a valid category')
65
+ }
66
+
67
+ if (!metadata.priority) {
68
+ throw new Error('Plugin metadata must include a valid priority')
69
+ }
70
+
71
+ return true
72
+ }
73
+
74
+ static validateConfig(config: PluginConfig, schema?: Record<string, any>): boolean {
75
+ if (!schema) return true
76
+
77
+ // Simple schema validation - could be enhanced with a proper schema validator
78
+ for (const [key, rules] of Object.entries(schema)) {
79
+ const value = config[key]
80
+
81
+ if (rules.required && (value === undefined || value === null)) {
82
+ throw new Error(`Configuration property '${key}' is required`)
83
+ }
84
+
85
+ if (value !== undefined && rules.type && typeof value !== rules.type) {
86
+ throw new Error(`Configuration property '${key}' must be of type '${rules.type}'`)
87
+ }
88
+
89
+ if (rules.enum && !rules.enum.includes(value)) {
90
+ throw new Error(`Configuration property '${key}' must be one of: ${rules.enum.join(', ')}`)
91
+ }
92
+
93
+ if (rules.min !== undefined && typeof value === 'number' && value < rules.min) {
94
+ throw new Error(`Configuration property '${key}' must be at least ${rules.min}`)
95
+ }
96
+
97
+ if (rules.max !== undefined && typeof value === 'number' && value > rules.max) {
98
+ throw new Error(`Configuration property '${key}' must be at most ${rules.max}`)
99
+ }
100
+ }
101
+
102
+ return true
103
+ }
104
+ }
105
+
106
+ // Plugin performance monitoring
107
+ export class PluginPerformanceMonitor {
108
+ private metrics = new Map<string, {
109
+ calls: number
110
+ totalTime: number
111
+ averageTime: number
112
+ lastCall: number
113
+ }>()
114
+
115
+ measure<T>(pluginName: string, operation: string, fn: () => T | Promise<T>): T | Promise<T> {
116
+ const key = `${pluginName}.${operation}`
117
+ const startTime = performance.now()
118
+
119
+ const updateMetrics = () => {
120
+ const endTime = performance.now()
121
+ const duration = endTime - startTime
122
+
123
+ const existing = this.metrics.get(key) || {
124
+ calls: 0,
125
+ totalTime: 0,
126
+ averageTime: 0,
127
+ lastCall: 0
128
+ }
129
+
130
+ existing.calls++
131
+ existing.totalTime += duration
132
+ existing.averageTime = existing.totalTime / existing.calls
133
+ existing.lastCall = endTime
134
+
135
+ this.metrics.set(key, existing)
136
+ }
137
+
138
+ const result = fn()
139
+
140
+ if (result instanceof Promise) {
141
+ return result.then(
142
+ (value) => {
143
+ updateMetrics()
144
+ return value
145
+ },
146
+ (error) => {
147
+ updateMetrics()
148
+ throw error
149
+ }
150
+ )
151
+ } else {
152
+ updateMetrics()
153
+ return result
154
+ }
155
+ }
156
+
157
+ getMetrics(pluginName?: string) {
158
+ if (pluginName) {
159
+ const pluginMetrics: Record<string, any> = {}
160
+ for (const [key, value] of this.metrics.entries()) {
161
+ if (key.startsWith(`${pluginName}.`)) {
162
+ const operation = key.substring(pluginName.length + 1)
163
+ pluginMetrics[operation] = value
164
+ }
165
+ }
166
+ return pluginMetrics
167
+ }
168
+
169
+ return Object.fromEntries(this.metrics.entries())
170
+ }
171
+
172
+ reset(pluginName?: string): void {
173
+ if (pluginName) {
174
+ for (const key of this.metrics.keys()) {
175
+ if (key.startsWith(`${pluginName}.`)) {
176
+ this.metrics.delete(key)
177
+ }
178
+ }
179
+ } else {
180
+ this.metrics.clear()
181
+ }
182
+ }
183
+ }
184
+
185
+ // Plugin development helpers
186
+ export const PluginDevelopmentHelpers = {
187
+ // Create a mock plugin context for testing
188
+ createMockContext(): any {
189
+ return {
190
+ state: {
191
+ isPlaying: false,
192
+ currentTime: 0,
193
+ duration: 0,
194
+ volume: 1,
195
+ isMuted: false,
196
+ isLoading: false,
197
+ error: null
198
+ },
199
+ controls: {
200
+ play: () => Promise.resolve(),
201
+ pause: () => Promise.resolve(),
202
+ seek: (time: number) => Promise.resolve(),
203
+ setVolume: (volume: number) => Promise.resolve(),
204
+ mute: () => Promise.resolve(),
205
+ unmute: () => Promise.resolve(),
206
+ toggleMute: () => Promise.resolve()
207
+ },
208
+ plugins: {
209
+ get: () => undefined,
210
+ getAll: () => [],
211
+ isEnabled: () => false
212
+ },
213
+ emit: () => {},
214
+ on: () => () => {},
215
+ element: null,
216
+ logger: new ConsolePluginLogger('[MockPlugin]')
217
+ }
218
+ },
219
+
220
+ // Create a test plugin for development
221
+ createTestPlugin(name: string, hooks: Partial<Plugin> = {}): Plugin {
222
+ return {
223
+ metadata: {
224
+ name,
225
+ version: '1.0.0',
226
+ description: `Test plugin: ${name}`,
227
+ category: 'ui',
228
+ priority: 'medium'
229
+ },
230
+ initialize: async () => {},
231
+ activate: async () => {},
232
+ deactivate: async () => {},
233
+ destroy: async () => {},
234
+ healthCheck: () => true,
235
+ ...hooks
236
+ }
237
+ },
238
+
239
+ // Plugin timing utilities
240
+ time: {
241
+ async: async <T>(label: string, fn: () => Promise<T>): Promise<T> => {
242
+ console.time(label)
243
+ try {
244
+ const result = await fn()
245
+ console.timeEnd(label)
246
+ return result
247
+ } catch (error) {
248
+ console.timeEnd(label)
249
+ throw error
250
+ }
251
+ },
252
+
253
+ sync: <T>(label: string, fn: () => T): T => {
254
+ console.time(label)
255
+ try {
256
+ const result = fn()
257
+ console.timeEnd(label)
258
+ return result
259
+ } catch (error) {
260
+ console.timeEnd(label)
261
+ throw error
262
+ }
263
+ }
264
+ }
265
+ }
266
+
267
+ // Plugin storage utilities for persistent data
268
+ export class PluginStorage {
269
+ private prefix: string
270
+
271
+ constructor(pluginName: string) {
272
+ this.prefix = `baroi-plugin-${pluginName}`
273
+ }
274
+
275
+ get<T>(key: string, defaultValue?: T): T | undefined {
276
+ try {
277
+ const item = localStorage.getItem(`${this.prefix}-${key}`)
278
+ return item ? JSON.parse(item) as T : defaultValue
279
+ } catch {
280
+ return defaultValue
281
+ }
282
+ }
283
+
284
+ set<T>(key: string, value: T): void {
285
+ try {
286
+ localStorage.setItem(`${this.prefix}-${key}`, JSON.stringify(value))
287
+ } catch (error) {
288
+ console.warn(`Failed to store plugin data for key: ${key}`, error)
289
+ }
290
+ }
291
+
292
+ remove(key: string): void {
293
+ try {
294
+ localStorage.removeItem(`${this.prefix}-${key}`)
295
+ } catch (error) {
296
+ console.warn(`Failed to remove plugin data for key: ${key}`, error)
297
+ }
298
+ }
299
+
300
+ clear(): void {
301
+ try {
302
+ const keys = Object.keys(localStorage).filter(key =>
303
+ key.startsWith(`${this.prefix}-`)
304
+ )
305
+ keys.forEach(key => localStorage.removeItem(key))
306
+ } catch (error) {
307
+ console.warn('Failed to clear plugin data', error)
308
+ }
309
+ }
310
+ }
311
+
312
+ // Export default logger instance
313
+ export const defaultPluginLogger = new ConsolePluginLogger()
314
+
315
+ // Export default performance monitor instance
316
+ export const defaultPerformanceMonitor = new PluginPerformanceMonitor()
@@ -0,0 +1,322 @@
1
+ import React, { lazy, Suspense } from 'react';
2
+
3
+ // Feature flags for progressive loading
4
+ export const FEATURES = {
5
+ SUBTITLES: 'subtitles',
6
+ PLAYLISTS: 'playlists',
7
+ ADVANCED_CONTROLS: 'advanced_controls',
8
+ ANALYTICS: 'analytics',
9
+ PICTURE_IN_PICTURE: 'picture_in_picture',
10
+ QUALITY_SELECTOR: 'quality_selector',
11
+ PLAYBACK_SPEED: 'playback_speed',
12
+ CHAPTERS: 'chapters',
13
+ THUMBNAILS: 'thumbnails',
14
+ KEYBOARD_SHORTCUTS: 'keyboard_shortcuts'
15
+ } as const;
16
+
17
+ export type FeatureType = typeof FEATURES[keyof typeof FEATURES];
18
+
19
+ // Progressive loading configuration
20
+ export interface ProgressiveLoadingConfig {
21
+ enabledFeatures: FeatureType[];
22
+ loadingStrategy: 'lazy' | 'preload' | 'immediate';
23
+ fallbackTimeout: number;
24
+ retryAttempts: number;
25
+ }
26
+
27
+ export const defaultProgressiveConfig: ProgressiveLoadingConfig = {
28
+ enabledFeatures: [
29
+ FEATURES.SUBTITLES,
30
+ FEATURES.ADVANCED_CONTROLS,
31
+ FEATURES.KEYBOARD_SHORTCUTS
32
+ ],
33
+ loadingStrategy: 'lazy',
34
+ fallbackTimeout: 5000,
35
+ retryAttempts: 3
36
+ };
37
+
38
+ // Dynamic imports with error handling and retry logic
39
+ export const lazyComponents = {
40
+ // Subtitle system
41
+ SubtitleSelector: lazy(() =>
42
+ import('../components/enhanced/advanced-features')
43
+ .then(module => ({ default: module.SubtitleSelector }))
44
+ ),
45
+
46
+ // Playlist functionality
47
+ PlaylistManager: lazy(() =>
48
+ import('../components/enhanced/advanced-features')
49
+ .then(module => ({ default: module.SubtitleSelector })) // Use existing component as placeholder
50
+ ),
51
+
52
+ // Advanced controls
53
+ QualitySelector: lazy(() =>
54
+ import('../components/enhanced/advanced-features')
55
+ .then(module => ({ default: module.QualitySelector }))
56
+ ),
57
+
58
+ PlaybackSpeedSelector: lazy(() =>
59
+ import('../components/enhanced/advanced-features')
60
+ .then(module => ({ default: module.PlaybackSpeedSelector }))
61
+ ),
62
+
63
+ ChaptersPanel: lazy(() =>
64
+ import('../components/enhanced/advanced-features')
65
+ .then(module => ({ default: module.ChaptersPanel }))
66
+ ),
67
+
68
+ PictureInPictureButton: lazy(() =>
69
+ import('../components/enhanced/advanced-features')
70
+ .then(module => ({ default: module.PictureInPictureButton }))
71
+ ),
72
+
73
+ // Analytics
74
+ AnalyticsTracker: lazy(() =>
75
+ import('../components/enhanced/advanced-features')
76
+ .then(module => ({ default: module.SubtitleSelector })) // Use existing component as placeholder
77
+ ),
78
+ };
79
+
80
+ // Feature detection utilities
81
+ export class FeatureDetector {
82
+ private static cache = new Map<FeatureType, boolean>();
83
+
84
+ static async isSupported(feature: FeatureType): Promise<boolean> {
85
+ if (this.cache.has(feature)) {
86
+ return this.cache.get(feature)!;
87
+ }
88
+
89
+ const supported = await this.checkFeatureSupport(feature);
90
+ this.cache.set(feature, supported);
91
+ return supported;
92
+ }
93
+
94
+ private static async checkFeatureSupport(feature: FeatureType): Promise<boolean> {
95
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
96
+ // Server-side rendering - assume basic support
97
+ return true;
98
+ }
99
+
100
+ switch (feature) {
101
+ case FEATURES.SUBTITLES:
102
+ return 'TextTrack' in window;
103
+
104
+ case FEATURES.PICTURE_IN_PICTURE:
105
+ return 'pictureInPictureEnabled' in document;
106
+
107
+ case FEATURES.ADVANCED_CONTROLS:
108
+ return true; // Always supported
109
+
110
+ case FEATURES.PLAYLISTS:
111
+ return 'MediaSession' in window;
112
+
113
+ case FEATURES.ANALYTICS:
114
+ return 'IntersectionObserver' in window;
115
+
116
+ case FEATURES.QUALITY_SELECTOR:
117
+ return 'MediaSource' in window;
118
+
119
+ case FEATURES.PLAYBACK_SPEED:
120
+ return true; // HTML5 video supports this
121
+
122
+ case FEATURES.CHAPTERS:
123
+ return 'TextTrack' in window;
124
+
125
+ case FEATURES.THUMBNAILS:
126
+ return 'OffscreenCanvas' in window || 'canvas' in document.createElement('canvas');
127
+
128
+ case FEATURES.KEYBOARD_SHORTCUTS:
129
+ return 'KeyboardEvent' in window;
130
+
131
+ default:
132
+ return false;
133
+ }
134
+ }
135
+ }
136
+
137
+ // Progressive loading manager
138
+ export class ProgressiveLoader {
139
+ private config: ProgressiveLoadingConfig;
140
+ private loadedFeatures = new Set<FeatureType>();
141
+ private loadingPromises = new Map<FeatureType, Promise<any>>();
142
+
143
+ constructor(config: Partial<ProgressiveLoadingConfig> = {}) {
144
+ this.config = { ...defaultProgressiveConfig, ...config };
145
+ }
146
+
147
+ async loadFeature<T = any>(feature: FeatureType): Promise<T | null> {
148
+ // Check if feature is enabled
149
+ if (!this.config.enabledFeatures.includes(feature)) {
150
+ return null;
151
+ }
152
+
153
+ // Check if already loaded
154
+ if (this.loadedFeatures.has(feature)) {
155
+ return this.getLoadedFeature(feature);
156
+ }
157
+
158
+ // Check if currently loading
159
+ if (this.loadingPromises.has(feature)) {
160
+ return this.loadingPromises.get(feature);
161
+ }
162
+
163
+ // Check browser support
164
+ const isSupported = await FeatureDetector.isSupported(feature);
165
+ if (!isSupported) {
166
+ console.warn(`Feature ${feature} is not supported in this browser`);
167
+ return null;
168
+ }
169
+
170
+ // Start loading with retry logic
171
+ const loadingPromise = this.loadWithRetry(feature);
172
+ this.loadingPromises.set(feature, loadingPromise);
173
+
174
+ try {
175
+ const result = await loadingPromise;
176
+ this.loadedFeatures.add(feature);
177
+ return result as T;
178
+ } catch (error) {
179
+ console.error(`Failed to load feature ${feature}:`, error);
180
+ this.loadingPromises.delete(feature);
181
+ return null;
182
+ }
183
+ }
184
+
185
+ private async loadWithRetry<T>(feature: FeatureType, attempt = 1): Promise<T> {
186
+ try {
187
+ const result = await this.loadFeatureModule(feature);
188
+ return result as T;
189
+ } catch (error) {
190
+ if (attempt < this.config.retryAttempts) {
191
+ console.warn(`Loading feature ${feature} failed, retrying (${attempt}/${this.config.retryAttempts})`);
192
+ await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
193
+ return this.loadWithRetry(feature, attempt + 1);
194
+ }
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ private async loadFeatureModule(feature: FeatureType) {
200
+ switch (feature) {
201
+ case FEATURES.SUBTITLES:
202
+ return import('../hooks/useEnhancedSubtitles');
203
+
204
+ case FEATURES.PLAYLISTS:
205
+ return import('../components/enhanced/advanced-features'); // Use existing features
206
+
207
+ case FEATURES.ADVANCED_CONTROLS:
208
+ return import('../components/enhanced/advanced-features');
209
+
210
+ case FEATURES.ANALYTICS:
211
+ return import('../components/enhanced/advanced-features'); // Use existing features
212
+
213
+ case FEATURES.PICTURE_IN_PICTURE:
214
+ return import('../components/enhanced/advanced-features'); // Use existing features
215
+
216
+ case FEATURES.QUALITY_SELECTOR:
217
+ return import('../components/enhanced/advanced-features'); // Use existing features
218
+
219
+ case FEATURES.PLAYBACK_SPEED:
220
+ return import('../components/enhanced/advanced-features'); // Use existing features
221
+
222
+ case FEATURES.CHAPTERS:
223
+ return import('../components/enhanced/advanced-features'); // Use existing features
224
+
225
+ case FEATURES.THUMBNAILS:
226
+ return import('../components/enhanced/advanced-features'); // Use existing features
227
+
228
+ case FEATURES.KEYBOARD_SHORTCUTS:
229
+ return import('../hooks/use-keyboard-controls');
230
+
231
+ default:
232
+ throw new Error(`Unknown feature: ${feature}`);
233
+ }
234
+ }
235
+
236
+ private getLoadedFeature(feature: FeatureType) {
237
+ // Return cached feature instance
238
+ return this.loadingPromises.get(feature);
239
+ }
240
+
241
+ // Preload features for faster access
242
+ async preloadFeatures(features: FeatureType[] = this.config.enabledFeatures) {
243
+ const preloadPromises = features.map(feature => this.loadFeature(feature));
244
+ await Promise.allSettled(preloadPromises);
245
+ }
246
+
247
+ // Get loading state
248
+ getLoadingState() {
249
+ return {
250
+ loaded: Array.from(this.loadedFeatures),
251
+ loading: Array.from(this.loadingPromises.keys()),
252
+ enabled: this.config.enabledFeatures
253
+ };
254
+ }
255
+ }
256
+
257
+ // Global progressive loader instance
258
+ export const progressiveLoader = new ProgressiveLoader();
259
+
260
+ // React hook for progressive loading
261
+ export function useProgressiveFeature<T = any>(feature: FeatureType): {
262
+ feature: T | null;
263
+ loading: boolean;
264
+ error: Error | null;
265
+ load: () => Promise<void>;
266
+ } {
267
+ const [featureModule, setFeatureModule] = React.useState<T | null>(null);
268
+ const [loading, setLoading] = React.useState(false);
269
+ const [error, setError] = React.useState<Error | null>(null);
270
+
271
+ const load = React.useCallback(async () => {
272
+ if (loading || featureModule) return;
273
+
274
+ setLoading(true);
275
+ setError(null);
276
+
277
+ try {
278
+ const module = await progressiveLoader.loadFeature<T>(feature);
279
+ setFeatureModule(module);
280
+ } catch (err) {
281
+ setError(err as Error);
282
+ } finally {
283
+ setLoading(false);
284
+ }
285
+ }, [feature, loading, featureModule]);
286
+
287
+ // Auto-load if strategy is immediate
288
+ React.useEffect(() => {
289
+ if (progressiveLoader['config'].loadingStrategy === 'immediate') {
290
+ load();
291
+ }
292
+ }, [load]);
293
+
294
+ return {
295
+ feature: featureModule,
296
+ loading,
297
+ error,
298
+ load
299
+ };
300
+ }
301
+
302
+ // HOC for progressive feature loading
303
+ export function withProgressiveFeature<P extends object>(
304
+ WrappedComponent: React.ComponentType<P>,
305
+ feature: FeatureType,
306
+ fallback?: React.ComponentType<P>
307
+ ) {
308
+ return function ProgressiveFeatureWrapper(props: P) {
309
+ const { feature: featureModule, loading, error } = useProgressiveFeature(feature);
310
+
311
+ if (loading) {
312
+ return <div className="h-8 animate-pulse rounded bg-gray-200" />;
313
+ }
314
+
315
+ if (error || !featureModule) {
316
+ const Fallback = fallback;
317
+ return Fallback ? <Fallback {...props} /> : null;
318
+ }
319
+
320
+ return <WrappedComponent {...props} />;
321
+ };
322
+ }