@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,538 @@
1
+ import React from 'react';
2
+
3
+ // Network monitoring and adaptive loading
4
+ export interface NetworkInfo {
5
+ effectiveType: '2g' | '3g' | '4g' | '5g' | 'unknown';
6
+ downlink: number; // Mbps
7
+ rtt: number; // Round trip time in ms
8
+ saveData: boolean;
9
+ isOnline: boolean;
10
+ }
11
+
12
+ export interface MediaLoadingConfig {
13
+ preloadStrategy: 'none' | 'metadata' | 'auto';
14
+ adaptiveBitrate: boolean;
15
+ maxPreloadSize: number; // bytes
16
+ networkThresholds: {
17
+ '2g': { maxBitrate: number; preload: boolean };
18
+ '3g': { maxBitrate: number; preload: boolean };
19
+ '4g': { maxBitrate: number; preload: boolean };
20
+ '5g': { maxBitrate: number; preload: boolean };
21
+ };
22
+ bufferSize: number; // seconds
23
+ enableServiceWorker: boolean;
24
+ }
25
+
26
+ export const defaultMediaLoadingConfig: MediaLoadingConfig = {
27
+ preloadStrategy: 'metadata',
28
+ adaptiveBitrate: true,
29
+ maxPreloadSize: 2 * 1024 * 1024, // 2MB
30
+ networkThresholds: {
31
+ '2g': { maxBitrate: 128, preload: false }, // 128 kbps
32
+ '3g': { maxBitrate: 500, preload: false }, // 500 kbps
33
+ '4g': { maxBitrate: 2000, preload: true }, // 2 Mbps
34
+ '5g': { maxBitrate: 10000, preload: true } // 10 Mbps
35
+ },
36
+ bufferSize: 10, // 10 seconds
37
+ enableServiceWorker: true
38
+ };
39
+
40
+ // Media loading performance tracker
41
+ export interface MediaLoadingMetrics {
42
+ loadStartTime: number;
43
+ firstByteTime?: number;
44
+ loadCompleteTime?: number;
45
+ totalLoadTime?: number;
46
+ bytesLoaded: number;
47
+ loadSpeed: number; // bytes per second
48
+ networkType: string;
49
+ quality: string;
50
+ bufferHealth: number; // 0-1 scale
51
+ stallsCount: number;
52
+ stallsDuration: number;
53
+ }
54
+
55
+ // Network monitoring utility
56
+ export class NetworkMonitor {
57
+ private connection: any;
58
+ private listeners: Set<(info: NetworkInfo) => void> = new Set();
59
+ private currentInfo: NetworkInfo;
60
+
61
+ constructor() {
62
+ if (typeof window === 'undefined' || typeof navigator === 'undefined') {
63
+ // Server-side rendering fallback
64
+ this.connection = null;
65
+ this.currentInfo = {
66
+ effectiveType: 'unknown',
67
+ downlink: 0,
68
+ rtt: 0,
69
+ saveData: false,
70
+ isOnline: true
71
+ };
72
+ return;
73
+ }
74
+
75
+ this.connection = (navigator as any).connection ||
76
+ (navigator as any).mozConnection ||
77
+ (navigator as any).webkitConnection;
78
+
79
+ this.currentInfo = this.getNetworkInfo();
80
+ this.initializeListeners();
81
+ }
82
+
83
+ private getNetworkInfo(): NetworkInfo {
84
+ if (typeof navigator === 'undefined') {
85
+ // Server-side rendering fallback
86
+ return {
87
+ effectiveType: 'unknown',
88
+ downlink: 0,
89
+ rtt: 0,
90
+ saveData: false,
91
+ isOnline: true
92
+ };
93
+ }
94
+
95
+ const isOnline = navigator.onLine;
96
+
97
+ if (this.connection) {
98
+ return {
99
+ effectiveType: this.connection.effectiveType || 'unknown',
100
+ downlink: this.connection.downlink || 0,
101
+ rtt: this.connection.rtt || 0,
102
+ saveData: this.connection.saveData || false,
103
+ isOnline
104
+ };
105
+ }
106
+
107
+ // Fallback for browsers without Network Information API
108
+ return {
109
+ effectiveType: 'unknown',
110
+ downlink: 0,
111
+ rtt: 0,
112
+ saveData: false,
113
+ isOnline
114
+ };
115
+ }
116
+
117
+ private initializeListeners() {
118
+ if (typeof window === 'undefined') {
119
+ // Server-side rendering - skip event listeners
120
+ return;
121
+ }
122
+
123
+ if (this.connection) {
124
+ this.connection.addEventListener('change', this.handleNetworkChange.bind(this));
125
+ }
126
+
127
+ window.addEventListener('online', this.handleNetworkChange.bind(this));
128
+ window.addEventListener('offline', this.handleNetworkChange.bind(this));
129
+ }
130
+
131
+ private handleNetworkChange() {
132
+ const newInfo = this.getNetworkInfo();
133
+ this.currentInfo = newInfo;
134
+ this.listeners.forEach(listener => listener(newInfo));
135
+ }
136
+
137
+ getCurrentNetworkInfo(): NetworkInfo {
138
+ return { ...this.currentInfo };
139
+ }
140
+
141
+ subscribe(listener: (info: NetworkInfo) => void): () => void {
142
+ this.listeners.add(listener);
143
+ return () => this.listeners.delete(listener);
144
+ }
145
+
146
+ // Estimate available bandwidth with fallback detection
147
+ async estimateBandwidth(): Promise<number> {
148
+ if (this.connection && this.connection.downlink) {
149
+ return this.connection.downlink * 1000; // Convert to kbps
150
+ }
151
+
152
+ // Fallback: simple bandwidth test
153
+ try {
154
+ const startTime = performance.now();
155
+ const testUrl = '/api/bandwidth-test?size=100kb'; // Would need to be implemented
156
+ const response = await fetch(testUrl);
157
+ const blob = await response.blob();
158
+ const endTime = performance.now();
159
+
160
+ const timeInSeconds = (endTime - startTime) / 1000;
161
+ const bytesLoaded = blob.size;
162
+ const bitsPerSecond = (bytesLoaded * 8) / timeInSeconds;
163
+
164
+ return bitsPerSecond / 1000; // Return in kbps
165
+ } catch (error) {
166
+ console.warn('Bandwidth estimation failed:', error);
167
+ return 1000; // Default to 1Mbps
168
+ }
169
+ }
170
+ }
171
+
172
+ // Media loading optimizer
173
+ export class MediaLoadingOptimizer {
174
+ private config: MediaLoadingConfig;
175
+ private networkMonitor: NetworkMonitor;
176
+ private loadingMetrics: Map<string, MediaLoadingMetrics> = new Map();
177
+ private preloadCache: Map<string, Promise<Blob>> = new Map();
178
+
179
+ constructor(config: Partial<MediaLoadingConfig> = {}) {
180
+ this.config = { ...defaultMediaLoadingConfig, ...config };
181
+ this.networkMonitor = new NetworkMonitor();
182
+ this.initializeNetworkMonitoring();
183
+ }
184
+
185
+ private initializeNetworkMonitoring() {
186
+ this.networkMonitor.subscribe((networkInfo) => {
187
+ this.handleNetworkChange(networkInfo);
188
+ });
189
+ }
190
+
191
+ private handleNetworkChange(networkInfo: NetworkInfo) {
192
+ console.log('Network changed:', networkInfo);
193
+
194
+ // Adjust quality based on network conditions
195
+ if (this.config.adaptiveBitrate) {
196
+ this.adjustQualityForNetwork(networkInfo);
197
+ }
198
+
199
+ // Clear preload cache if on slow network
200
+ if (networkInfo.effectiveType === '2g' || networkInfo.saveData) {
201
+ this.clearPreloadCache();
202
+ }
203
+ }
204
+
205
+ // Optimize media loading based on network conditions
206
+ async optimizeMediaLoading(
207
+ mediaUrl: string,
208
+ element: HTMLMediaElement,
209
+ options: {
210
+ quality?: string;
211
+ preload?: boolean;
212
+ priority?: 'high' | 'normal' | 'low';
213
+ } = {}
214
+ ): Promise<MediaLoadingMetrics> {
215
+ const startTime = performance.now();
216
+ const networkInfo = this.networkMonitor.getCurrentNetworkInfo();
217
+
218
+ const metrics: MediaLoadingMetrics = {
219
+ loadStartTime: startTime,
220
+ bytesLoaded: 0,
221
+ loadSpeed: 0,
222
+ networkType: networkInfo.effectiveType,
223
+ quality: options.quality || 'auto',
224
+ bufferHealth: 0,
225
+ stallsCount: 0,
226
+ stallsDuration: 0
227
+ };
228
+
229
+ this.loadingMetrics.set(mediaUrl, metrics);
230
+
231
+ try {
232
+ // Choose optimal loading strategy
233
+ const loadingStrategy = this.chooseLoadingStrategy(networkInfo, options);
234
+
235
+ // Apply preload strategy
236
+ if (loadingStrategy.shouldPreload) {
237
+ await this.preloadMedia(mediaUrl, loadingStrategy.preloadAmount);
238
+ }
239
+
240
+ // Set appropriate preload attribute
241
+ element.preload = loadingStrategy.preloadAttribute;
242
+
243
+ // Monitor loading progress
244
+ this.monitorLoadingProgress(element, metrics);
245
+
246
+ // Apply quality adjustments
247
+ if (this.config.adaptiveBitrate && loadingStrategy.suggestedQuality) {
248
+ this.applyQualitySettings(element, loadingStrategy.suggestedQuality);
249
+ }
250
+
251
+ return metrics;
252
+ } catch (error) {
253
+ console.error('Media loading optimization failed:', error);
254
+ return metrics;
255
+ }
256
+ }
257
+
258
+ private chooseLoadingStrategy(
259
+ networkInfo: NetworkInfo,
260
+ options: { preload?: boolean; priority?: string; quality?: string }
261
+ ) {
262
+ const effectiveType = networkInfo.effectiveType === 'unknown' ? '4g' : networkInfo.effectiveType;
263
+ const threshold = this.config.networkThresholds[effectiveType] ||
264
+ this.config.networkThresholds['4g'];
265
+
266
+ return {
267
+ shouldPreload: options.preload !== false && threshold.preload && !networkInfo.saveData,
268
+ preloadAmount: networkInfo.saveData ? 0 : this.config.maxPreloadSize,
269
+ preloadAttribute: this.getPreloadAttribute(networkInfo),
270
+ suggestedQuality: this.getSuggestedQuality(networkInfo, threshold.maxBitrate),
271
+ bufferTarget: this.getBufferTarget(networkInfo)
272
+ };
273
+ }
274
+
275
+ private getPreloadAttribute(networkInfo: NetworkInfo): 'none' | 'metadata' | 'auto' {
276
+ if (networkInfo.saveData || networkInfo.effectiveType === '2g') {
277
+ return 'none';
278
+ }
279
+
280
+ if (networkInfo.effectiveType === '3g') {
281
+ return 'metadata';
282
+ }
283
+
284
+ return this.config.preloadStrategy;
285
+ }
286
+
287
+ private getSuggestedQuality(networkInfo: NetworkInfo, maxBitrate: number): string {
288
+ const availableBandwidth = networkInfo.downlink * 1000; // Convert to kbps
289
+
290
+ if (availableBandwidth >= maxBitrate * 2) return 'high';
291
+ if (availableBandwidth >= maxBitrate) return 'medium';
292
+ return 'low';
293
+ }
294
+
295
+ private getBufferTarget(networkInfo: NetworkInfo): number {
296
+ switch (networkInfo.effectiveType) {
297
+ case '2g': return 2; // 2 seconds
298
+ case '3g': return 5; // 5 seconds
299
+ case '4g': return this.config.bufferSize;
300
+ case '5g': return this.config.bufferSize * 1.5;
301
+ default: return this.config.bufferSize;
302
+ }
303
+ }
304
+
305
+ // Preload media content
306
+ async preloadMedia(url: string, maxSize: number): Promise<void> {
307
+ if (this.preloadCache.has(url)) {
308
+ return; // Already preloading or preloaded
309
+ }
310
+
311
+ const preloadPromise = this.fetchWithProgress(url, maxSize);
312
+ this.preloadCache.set(url, preloadPromise);
313
+
314
+ try {
315
+ await preloadPromise;
316
+ } catch (error) {
317
+ console.warn(`Preload failed for ${url}:`, error);
318
+ this.preloadCache.delete(url);
319
+ }
320
+ }
321
+
322
+ private async fetchWithProgress(url: string, maxSize: number): Promise<Blob> {
323
+ const response = await fetch(url, {
324
+ headers: {
325
+ 'Range': `bytes=0-${maxSize - 1}` // Limit preload size
326
+ }
327
+ });
328
+
329
+ if (!response.ok) {
330
+ throw new Error(`Failed to preload: ${response.status}`);
331
+ }
332
+
333
+ const reader = response.body?.getReader();
334
+ if (!reader) {
335
+ throw new Error('Response body not readable');
336
+ }
337
+
338
+ const chunks: Uint8Array[] = [];
339
+ let bytesRead = 0;
340
+
341
+ try {
342
+ while (bytesRead < maxSize) {
343
+ const { done, value } = await reader.read();
344
+ if (done) break;
345
+
346
+ chunks.push(value);
347
+ bytesRead += value.length;
348
+ }
349
+ } finally {
350
+ reader.releaseLock();
351
+ }
352
+
353
+ return new Blob(chunks);
354
+ }
355
+
356
+ // Monitor loading progress and update metrics
357
+ private monitorLoadingProgress(element: HTMLMediaElement, metrics: MediaLoadingMetrics) {
358
+ let stallStartTime: number | null = null;
359
+
360
+ const updateMetrics = () => {
361
+ if (element.buffered.length > 0) {
362
+ const bufferedEnd = element.buffered.end(element.buffered.length - 1);
363
+ const currentTime = element.currentTime;
364
+ metrics.bufferHealth = Math.min((bufferedEnd - currentTime) / this.config.bufferSize, 1);
365
+ }
366
+ };
367
+
368
+ // Track first byte
369
+ const onLoadStart = () => {
370
+ metrics.firstByteTime = performance.now();
371
+ };
372
+
373
+ // Track load completion
374
+ const onCanPlay = () => {
375
+ metrics.loadCompleteTime = performance.now();
376
+ metrics.totalLoadTime = metrics.loadCompleteTime - metrics.loadStartTime;
377
+
378
+ // Calculate load speed
379
+ if (metrics.totalLoadTime && metrics.bytesLoaded > 0) {
380
+ metrics.loadSpeed = metrics.bytesLoaded / (metrics.totalLoadTime / 1000);
381
+ }
382
+ };
383
+
384
+ // Track stalls
385
+ const onWaiting = () => {
386
+ if (stallStartTime === null) {
387
+ stallStartTime = performance.now();
388
+ metrics.stallsCount++;
389
+ }
390
+ };
391
+
392
+ const onPlaying = () => {
393
+ if (stallStartTime !== null) {
394
+ metrics.stallsDuration += performance.now() - stallStartTime;
395
+ stallStartTime = null;
396
+ }
397
+ updateMetrics();
398
+ };
399
+
400
+ // Track progress
401
+ const onProgress = () => {
402
+ if (element.buffered.length > 0) {
403
+ const bufferedBytes = element.buffered.end(0) * 1000; // Rough estimate
404
+ metrics.bytesLoaded = bufferedBytes;
405
+ }
406
+ updateMetrics();
407
+ };
408
+
409
+ // Add event listeners
410
+ element.addEventListener('loadstart', onLoadStart);
411
+ element.addEventListener('canplay', onCanPlay);
412
+ element.addEventListener('waiting', onWaiting);
413
+ element.addEventListener('playing', onPlaying);
414
+ element.addEventListener('progress', onProgress);
415
+
416
+ // Cleanup function
417
+ const cleanup = () => {
418
+ element.removeEventListener('loadstart', onLoadStart);
419
+ element.removeEventListener('canplay', onCanPlay);
420
+ element.removeEventListener('waiting', onWaiting);
421
+ element.removeEventListener('playing', onPlaying);
422
+ element.removeEventListener('progress', onProgress);
423
+ };
424
+
425
+ // Auto-cleanup after 5 minutes
426
+ setTimeout(cleanup, 5 * 60 * 1000);
427
+ }
428
+
429
+ // Apply quality settings (would integrate with HLS.js or similar)
430
+ private applyQualitySettings(element: HTMLMediaElement, quality: string) {
431
+ // This would integrate with your video streaming library
432
+ console.log(`Applying quality setting: ${quality} to`, element);
433
+
434
+ // Example integration with HLS.js:
435
+ // if (element.hls) {
436
+ // element.hls.currentLevel = this.getQualityLevel(quality);
437
+ // }
438
+ }
439
+
440
+ private adjustQualityForNetwork(networkInfo: NetworkInfo) {
441
+ // Auto-adjust quality for all active media elements
442
+ console.log('Adjusting quality for network conditions:', networkInfo.effectiveType);
443
+ }
444
+
445
+ // Clear preload cache to save memory
446
+ clearPreloadCache() {
447
+ this.preloadCache.clear();
448
+ }
449
+
450
+ // Get loading metrics for a specific media URL
451
+ getLoadingMetrics(url: string): MediaLoadingMetrics | undefined {
452
+ return this.loadingMetrics.get(url);
453
+ }
454
+
455
+ // Get all loading metrics
456
+ getAllMetrics(): MediaLoadingMetrics[] {
457
+ return Array.from(this.loadingMetrics.values());
458
+ }
459
+
460
+ // Calculate average loading performance
461
+ getAverageLoadingTime(): number {
462
+ const metrics = this.getAllMetrics();
463
+ const completedLoads = metrics.filter(m => m.totalLoadTime !== undefined);
464
+
465
+ if (completedLoads.length === 0) return 0;
466
+
467
+ const total = completedLoads.reduce((sum, m) => sum + (m.totalLoadTime || 0), 0);
468
+ return total / completedLoads.length;
469
+ }
470
+
471
+ // Get network-specific performance stats
472
+ getNetworkPerformanceStats(): {
473
+ networkType: string;
474
+ avgLoadTime: number;
475
+ avgStalls: number;
476
+ avgBufferHealth: number;
477
+ }[] {
478
+ const statsByNetwork = new Map<string, MediaLoadingMetrics[]>();
479
+
480
+ this.getAllMetrics().forEach(metrics => {
481
+ const network = metrics.networkType;
482
+ if (!statsByNetwork.has(network)) {
483
+ statsByNetwork.set(network, []);
484
+ }
485
+ statsByNetwork.get(network)!.push(metrics);
486
+ });
487
+
488
+ return Array.from(statsByNetwork.entries()).map(([networkType, metrics]) => ({
489
+ networkType,
490
+ avgLoadTime: metrics.reduce((sum, m) => sum + (m.totalLoadTime || 0), 0) / metrics.length,
491
+ avgStalls: metrics.reduce((sum, m) => sum + m.stallsCount, 0) / metrics.length,
492
+ avgBufferHealth: metrics.reduce((sum, m) => sum + m.bufferHealth, 0) / metrics.length
493
+ }));
494
+ }
495
+ }
496
+
497
+ // Global media loading optimizer instance
498
+ export const mediaLoadingOptimizer = new MediaLoadingOptimizer();
499
+
500
+ // React hook for media loading optimization
501
+ export function useMediaLoadingOptimizer(config?: Partial<MediaLoadingConfig>) {
502
+ const [optimizer] = React.useState(() =>
503
+ config ? new MediaLoadingOptimizer(config) : mediaLoadingOptimizer
504
+ );
505
+
506
+ const [networkInfo, setNetworkInfo] = React.useState<NetworkInfo | null>(null);
507
+ const [loadingMetrics, setLoadingMetrics] = React.useState<MediaLoadingMetrics[]>([]);
508
+
509
+ React.useEffect(() => {
510
+ const unsubscribe = optimizer['networkMonitor'].subscribe(setNetworkInfo);
511
+ setNetworkInfo(optimizer['networkMonitor'].getCurrentNetworkInfo());
512
+
513
+ // Update metrics periodically
514
+ const interval = setInterval(() => {
515
+ setLoadingMetrics(optimizer.getAllMetrics());
516
+ }, 1000);
517
+
518
+ return () => {
519
+ unsubscribe();
520
+ clearInterval(interval);
521
+ };
522
+ }, [optimizer]);
523
+
524
+ const optimizeLoading = React.useCallback(
525
+ (mediaUrl: string, element: HTMLMediaElement, options?: any) => {
526
+ return optimizer.optimizeMediaLoading(mediaUrl, element, options);
527
+ },
528
+ [optimizer]
529
+ );
530
+
531
+ return {
532
+ networkInfo,
533
+ loadingMetrics,
534
+ optimizeLoading,
535
+ averageLoadTime: optimizer.getAverageLoadingTime(),
536
+ networkStats: optimizer.getNetworkPerformanceStats()
537
+ };
538
+ }