@therealtinhtute/baroiplayer 1.2.0 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -73
- package/dist/components/icons/index.d.ts +36 -0
- package/dist/components/icons/index.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
- package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
- package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
- package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
- package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -112
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +786 -6271
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +3 -0
- package/package.json +110 -108
- package/src/components/variants/gradient/gradient-audio.tsx +47 -0
- package/src/components/variants/gradient/gradient-controls.tsx +254 -0
- package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
- package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
- package/src/components/variants/gradient/gradient-skin.css +211 -0
- package/src/components/variants/gradient/gradient-video.tsx +70 -0
- package/src/index.ts +5 -198
- package/src/test/accessibility-utils.ts +0 -59
- package/dist/context/media.js +0 -2
- package/dist/context/media.js.map +0 -1
- package/dist/context/media.mjs +0 -15
- package/dist/context/media.mjs.map +0 -1
- package/dist/context/store.js +0 -2
- package/dist/context/store.js.map +0 -1
- package/dist/context/store.mjs +0 -5
- package/dist/context/store.mjs.map +0 -1
- package/dist/context-BYwDoSRX.js +0 -1172
- package/dist/context-BYwDoSRX.js.map +0 -1
- package/dist/context-eNS62_ac.cjs +0 -23
- package/dist/context-eNS62_ac.cjs.map +0 -1
- package/dist/core-events-B1iM2F46.cjs +0 -2
- package/dist/core-events-B1iM2F46.cjs.map +0 -1
- package/dist/core-events-DunPHKRE.js +0 -484
- package/dist/core-events-DunPHKRE.js.map +0 -1
- package/dist/core-plugins-By-4-kGs.cjs +0 -2
- package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
- package/dist/core-plugins-DSBWcTuX.js +0 -821
- package/dist/core-plugins-DSBWcTuX.js.map +0 -1
- package/dist/core.js +0 -37
- package/dist/core.js.map +0 -1
- package/dist/core.mjs +0 -1233
- package/dist/core.mjs.map +0 -1
- package/dist/enhanced-components-B_l3cist.js +0 -1142
- package/dist/enhanced-components-B_l3cist.js.map +0 -1
- package/dist/enhanced-components-BspFs9OO.cjs +0 -2
- package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
- package/dist/hooks-BXwI8QG6.cjs +0 -4
- package/dist/hooks-BXwI8QG6.cjs.map +0 -1
- package/dist/hooks-Bpi-jDiO.js +0 -1816
- package/dist/hooks-Bpi-jDiO.js.map +0 -1
- package/dist/minimal-components-C4z900Ro.js +0 -1926
- package/dist/minimal-components-C4z900Ro.js.map +0 -1
- package/dist/minimal-components-v4qBp6jv.cjs +0 -2
- package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
- package/dist/minimal-components.css +0 -1
- package/dist/mona-loading.gif +0 -0
- package/dist/performance-monitor-C5k6FDXw.js +0 -301
- package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
- package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
- package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
- package/dist/utils-CFOue_9K.cjs +0 -9
- package/dist/utils-CFOue_9K.cjs.map +0 -1
- package/dist/utils-Dzpl2ArK.js +0 -2844
- package/dist/utils-Dzpl2ArK.js.map +0 -1
- package/dist/utils.js +0 -2
- package/dist/utils.js.map +0 -1
- package/dist/utils.mjs +0 -11
- package/dist/utils.mjs.map +0 -1
- package/src/adapters/videojs-adapter.tsx +0 -470
- package/src/assets/mona-loading.gif +0 -0
- package/src/components/AnimateLoading.tsx +0 -107
- package/src/components/LoadingState.tsx +0 -239
- package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
- package/src/components/__tests__/media-player-react19.test.tsx +0 -457
- package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
- package/src/components/audio-player.tsx +0 -85
- package/src/components/basic/index.ts +0 -37
- package/src/components/enhanced/advanced-features.tsx +0 -311
- package/src/components/enhanced/debug-panel.tsx +0 -448
- package/src/components/enhanced/enhanced-controls.tsx +0 -597
- package/src/components/enhanced/enhanced-media-player.tsx +0 -566
- package/src/components/enhanced/error-handling.tsx +0 -338
- package/src/components/enhanced/index.ts +0 -39
- package/src/components/enhanced/media-player-enhanced.tsx +0 -383
- package/src/components/examples/basic-video-player.tsx +0 -50
- package/src/components/examples/custom-controls-example.tsx +0 -63
- package/src/components/examples/enhanced-controls-example.tsx +0 -100
- package/src/components/examples/enhanced-media-player-example.tsx +0 -302
- package/src/components/examples/loading-states-demo.tsx +0 -142
- package/src/components/examples/react-19-demo.tsx +0 -353
- package/src/components/examples/volume-orientation-demo.tsx +0 -106
- package/src/components/icon-demo.tsx +0 -196
- package/src/components/legacy.tsx +0 -87
- package/src/components/media-metadata-display.tsx +0 -99
- package/src/components/media-player-audio.tsx +0 -39
- package/src/components/media-player-controls.tsx +0 -223
- package/src/components/media-player-error.tsx +0 -163
- package/src/components/media-player-fullscreen.tsx +0 -109
- package/src/components/media-player-hls.tsx +0 -111
- package/src/components/media-player-loading.tsx +0 -76
- package/src/components/media-player-play.tsx +0 -75
- package/src/components/media-player-root.tsx +0 -338
- package/src/components/media-player-seek.tsx +0 -168
- package/src/components/media-player-time.tsx +0 -99
- package/src/components/media-player-tooltip.tsx +0 -58
- package/src/components/media-player-video.tsx +0 -54
- package/src/components/media-player-volume.tsx +0 -155
- package/src/components/media-player.tsx +0 -292
- package/src/components/media-suspense.tsx +0 -344
- package/src/components/player-settings-form.tsx +0 -158
- package/src/components/react-player-wrapper.tsx +0 -651
- package/src/components/simple-video-player.tsx +0 -62
- package/src/components/ui/blur-poster.tsx +0 -93
- package/src/components/ui/empty-state.tsx +0 -91
- package/src/components/ui/enhanced-seek-bar.tsx +0 -254
- package/src/components/ui/error-state.tsx +0 -124
- package/src/components/ui/fullscreen-button.tsx +0 -81
- package/src/components/ui/loading-skeleton.tsx +0 -107
- package/src/components/ui/media-resource-preloader.tsx +0 -458
- package/src/components/ui/offline-message.tsx +0 -98
- package/src/components/ui/play-button.tsx +0 -99
- package/src/components/ui/seek-bar.tsx +0 -191
- package/src/components/ui/time-display.tsx +0 -61
- package/src/components/ui/volume-control.tsx +0 -190
- package/src/components/unified/base-media-player.tsx +0 -252
- package/src/components/unified/media-player.tsx +0 -75
- package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
- package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
- package/src/components/variants/minimal/MinimalControls.tsx +0 -124
- package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
- package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
- package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
- package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
- package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
- package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
- package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
- package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
- package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
- package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
- package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
- package/src/components/variants/minimal/components/RightControls.tsx +0 -164
- package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
- package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
- package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
- package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
- package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
- package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
- package/src/components/variants/minimal/index.ts +0 -23
- package/src/components/video-player.tsx +0 -100
- package/src/context/__tests__/media-store.test.ts +0 -509
- package/src/context/error-handling.ts +0 -398
- package/src/context/media-context.tsx +0 -254
- package/src/context/media-provider.tsx +0 -264
- package/src/context/media-store.ts +0 -387
- package/src/context/persistence.ts +0 -462
- package/src/core/events/event-system.ts +0 -448
- package/src/core/events/hooks.ts +0 -325
- package/src/core/events/index.ts +0 -22
- package/src/core/events/middleware.ts +0 -286
- package/src/core/index.ts +0 -22
- package/src/core/optimization/bundle-optimizer.tsx +0 -312
- package/src/core/performance/cicd.ts +0 -98
- package/src/core/performance/index.ts +0 -38
- package/src/core/performance/media-loading-optimizer.ts +0 -544
- package/src/core/performance/performance-budgets.ts +0 -437
- package/src/core/performance/performance-monitor.tsx +0 -488
- package/src/core/performance/performance-testing.ts +0 -461
- package/src/core/plugins/__tests__/registry.test.ts +0 -595
- package/src/core/plugins/base-plugin.ts +0 -225
- package/src/core/plugins/enhanced-plugin-system.ts +0 -435
- package/src/core/plugins/examples/analytics-plugin.ts +0 -241
- package/src/core/plugins/index.ts +0 -39
- package/src/core/plugins/registry.ts +0 -546
- package/src/core/plugins/types.ts +0 -169
- package/src/core/plugins/utils.ts +0 -317
- package/src/core/progressive-loading.tsx +0 -331
- package/src/core/providers/enhanced-hls-provider.ts +0 -307
- package/src/core/providers/lazy-provider.tsx +0 -14
- package/src/core/providers/service-provider.tsx +0 -164
- package/src/core/utils.tsx +0 -34
- package/src/features/media-session/media-session-manager.ts +0 -411
- package/src/features/picture-in-picture/pip-manager.ts +0 -428
- package/src/features/playlist/playlist-manager.ts +0 -626
- package/src/features/subtitles/subtitle-manager.ts +0 -435
- package/src/features/subtitles/subtitle-parser.ts +0 -284
- package/src/features/thumbnails/thumbnail-generator.ts +0 -528
- package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
- package/src/hooks/__tests__/use-media-player.test.ts +0 -712
- package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
- package/src/hooks/accessibility/index.ts +0 -27
- package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
- package/src/hooks/accessibility/use-focus-management.ts +0 -183
- package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
- package/src/hooks/accessibility/use-screen-reader.ts +0 -212
- package/src/hooks/core/index.ts +0 -47
- package/src/hooks/legacy.ts +0 -21
- package/src/hooks/use-buffer-health.ts +0 -218
- package/src/hooks/use-enhanced-media-player.ts +0 -575
- package/src/hooks/use-focus-trap.tsx +0 -162
- package/src/hooks/use-intelligent-preloading.ts +0 -387
- package/src/hooks/use-keyboard-controls.ts +0 -115
- package/src/hooks/use-keyboard-shortcuts.ts +0 -255
- package/src/hooks/use-media-actions.ts +0 -184
- package/src/hooks/use-media-metadata.ts +0 -91
- package/src/hooks/use-media-optimistic.ts +0 -264
- package/src/hooks/use-media-player.ts +0 -343
- package/src/hooks/use-media-state.ts +0 -194
- package/src/hooks/use-memory-optimization.ts +0 -360
- package/src/hooks/use-network-status.ts +0 -124
- package/src/hooks/use-optimistic-controls.ts +0 -95
- package/src/hooks/use-optimized-media.ts +0 -283
- package/src/hooks/use-smart-preload.ts +0 -229
- package/src/hooks/use-touch-gestures.ts +0 -461
- package/src/hooks/useEnhancedSubtitles.ts +0 -258
- package/src/hooks/useKeyboardShortcuts.ts +0 -106
- package/src/hooks/useMediaControls.ts +0 -52
- package/src/hooks/useScreenshot.ts +0 -61
- package/src/hooks/useSubtitles.ts +0 -91
- package/src/hooks/useVideoPlayer.ts +0 -278
- package/src/icons/components/FullscreenIcon.tsx +0 -36
- package/src/icons/components/SettingsIcon.tsx +0 -37
- package/src/icons/components/animated/LoadingIcon.tsx +0 -27
- package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
- package/src/icons/components/media/PauseIcon.tsx +0 -38
- package/src/icons/components/media/PlayIcon.tsx +0 -37
- package/src/icons/components/volume/VolumeIcon.tsx +0 -38
- package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
- package/src/icons/index.ts +0 -56
- package/src/icons/provider.tsx +0 -58
- package/src/icons/types.ts +0 -60
- package/src/index-enhanced.ts +0 -35
- package/src/index-legacy.ts +0 -324
- package/src/index.css +0 -102
- package/src/lib/__tests__/async-utils.test.ts +0 -291
- package/src/lib/async-utils.ts +0 -194
- package/src/lib/deprecation.ts +0 -51
- package/src/lib/format-time.ts +0 -37
- package/src/lib/index.ts +0 -4
- package/src/lib/utils.ts +0 -6
- package/src/styles/globals.css +0 -462
- package/src/styles/minimal-player.css +0 -621
- package/src/styles/pixel-art.css +0 -41
- package/src/styles/videojs.css +0 -100
- package/src/types/events.ts +0 -47
- package/src/types/formats.ts +0 -79
- package/src/types/index.ts +0 -203
- package/src/types/videojs-plugins.d.ts +0 -14
|
@@ -1,544 +0,0 @@
|
|
|
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 =
|
|
76
|
-
(navigator as any).connection ||
|
|
77
|
-
(navigator as any).mozConnection ||
|
|
78
|
-
(navigator as any).webkitConnection
|
|
79
|
-
|
|
80
|
-
this.currentInfo = this.getNetworkInfo()
|
|
81
|
-
this.initializeListeners()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private getNetworkInfo(): NetworkInfo {
|
|
85
|
-
if (typeof navigator === "undefined") {
|
|
86
|
-
// Server-side rendering fallback
|
|
87
|
-
return {
|
|
88
|
-
effectiveType: "unknown",
|
|
89
|
-
downlink: 0,
|
|
90
|
-
rtt: 0,
|
|
91
|
-
saveData: false,
|
|
92
|
-
isOnline: true
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const isOnline = navigator.onLine
|
|
97
|
-
|
|
98
|
-
if (this.connection) {
|
|
99
|
-
return {
|
|
100
|
-
effectiveType: this.connection.effectiveType || "unknown",
|
|
101
|
-
downlink: this.connection.downlink || 0,
|
|
102
|
-
rtt: this.connection.rtt || 0,
|
|
103
|
-
saveData: this.connection.saveData || false,
|
|
104
|
-
isOnline
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Fallback for browsers without Network Information API
|
|
109
|
-
return {
|
|
110
|
-
effectiveType: "unknown",
|
|
111
|
-
downlink: 0,
|
|
112
|
-
rtt: 0,
|
|
113
|
-
saveData: false,
|
|
114
|
-
isOnline
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private initializeListeners() {
|
|
119
|
-
if (typeof window === "undefined") {
|
|
120
|
-
// Server-side rendering - skip event listeners
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (this.connection) {
|
|
125
|
-
this.connection.addEventListener("change", this.handleNetworkChange.bind(this))
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
window.addEventListener("online", this.handleNetworkChange.bind(this))
|
|
129
|
-
window.addEventListener("offline", this.handleNetworkChange.bind(this))
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private handleNetworkChange() {
|
|
133
|
-
const newInfo = this.getNetworkInfo()
|
|
134
|
-
this.currentInfo = newInfo
|
|
135
|
-
this.listeners.forEach((listener) => listener(newInfo))
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
getCurrentNetworkInfo(): NetworkInfo {
|
|
139
|
-
return { ...this.currentInfo }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
subscribe(listener: (info: NetworkInfo) => void): () => void {
|
|
143
|
-
this.listeners.add(listener)
|
|
144
|
-
return () => this.listeners.delete(listener)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Estimate available bandwidth with fallback detection
|
|
148
|
-
async estimateBandwidth(): Promise<number> {
|
|
149
|
-
if (this.connection && this.connection.downlink) {
|
|
150
|
-
return this.connection.downlink * 1000 // Convert to kbps
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Fallback: simple bandwidth test
|
|
154
|
-
try {
|
|
155
|
-
const startTime = performance.now()
|
|
156
|
-
const testUrl = "/api/bandwidth-test?size=100kb" // Would need to be implemented
|
|
157
|
-
const response = await fetch(testUrl)
|
|
158
|
-
const blob = await response.blob()
|
|
159
|
-
const endTime = performance.now()
|
|
160
|
-
|
|
161
|
-
const timeInSeconds = (endTime - startTime) / 1000
|
|
162
|
-
const bytesLoaded = blob.size
|
|
163
|
-
const bitsPerSecond = (bytesLoaded * 8) / timeInSeconds
|
|
164
|
-
|
|
165
|
-
return bitsPerSecond / 1000 // Return in kbps
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.warn("Bandwidth estimation failed:", error)
|
|
168
|
-
return 1000 // Default to 1Mbps
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Media loading optimizer
|
|
174
|
-
export class MediaLoadingOptimizer {
|
|
175
|
-
private config: MediaLoadingConfig
|
|
176
|
-
private networkMonitor: NetworkMonitor
|
|
177
|
-
private loadingMetrics: Map<string, MediaLoadingMetrics> = new Map()
|
|
178
|
-
private preloadCache: Map<string, Promise<Blob>> = new Map()
|
|
179
|
-
|
|
180
|
-
constructor(config: Partial<MediaLoadingConfig> = {}) {
|
|
181
|
-
this.config = { ...defaultMediaLoadingConfig, ...config }
|
|
182
|
-
this.networkMonitor = new NetworkMonitor()
|
|
183
|
-
this.initializeNetworkMonitoring()
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private initializeNetworkMonitoring() {
|
|
187
|
-
this.networkMonitor.subscribe((networkInfo) => {
|
|
188
|
-
this.handleNetworkChange(networkInfo)
|
|
189
|
-
})
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private handleNetworkChange(networkInfo: NetworkInfo) {
|
|
193
|
-
console.log("Network changed:", networkInfo)
|
|
194
|
-
|
|
195
|
-
// Adjust quality based on network conditions
|
|
196
|
-
if (this.config.adaptiveBitrate) {
|
|
197
|
-
this.adjustQualityForNetwork(networkInfo)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Clear preload cache if on slow network
|
|
201
|
-
if (networkInfo.effectiveType === "2g" || networkInfo.saveData) {
|
|
202
|
-
this.clearPreloadCache()
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Optimize media loading based on network conditions
|
|
207
|
-
async optimizeMediaLoading(
|
|
208
|
-
mediaUrl: string,
|
|
209
|
-
element: HTMLMediaElement,
|
|
210
|
-
options: {
|
|
211
|
-
quality?: string
|
|
212
|
-
preload?: boolean
|
|
213
|
-
priority?: "high" | "normal" | "low"
|
|
214
|
-
} = {}
|
|
215
|
-
): Promise<MediaLoadingMetrics> {
|
|
216
|
-
const startTime = performance.now()
|
|
217
|
-
const networkInfo = this.networkMonitor.getCurrentNetworkInfo()
|
|
218
|
-
|
|
219
|
-
const metrics: MediaLoadingMetrics = {
|
|
220
|
-
loadStartTime: startTime,
|
|
221
|
-
bytesLoaded: 0,
|
|
222
|
-
loadSpeed: 0,
|
|
223
|
-
networkType: networkInfo.effectiveType,
|
|
224
|
-
quality: options.quality || "auto",
|
|
225
|
-
bufferHealth: 0,
|
|
226
|
-
stallsCount: 0,
|
|
227
|
-
stallsDuration: 0
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
this.loadingMetrics.set(mediaUrl, metrics)
|
|
231
|
-
|
|
232
|
-
try {
|
|
233
|
-
// Choose optimal loading strategy
|
|
234
|
-
const loadingStrategy = this.chooseLoadingStrategy(networkInfo, options)
|
|
235
|
-
|
|
236
|
-
// Apply preload strategy
|
|
237
|
-
if (loadingStrategy.shouldPreload) {
|
|
238
|
-
await this.preloadMedia(mediaUrl, loadingStrategy.preloadAmount)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Set appropriate preload attribute
|
|
242
|
-
element.preload = loadingStrategy.preloadAttribute
|
|
243
|
-
|
|
244
|
-
// Monitor loading progress
|
|
245
|
-
this.monitorLoadingProgress(element, metrics)
|
|
246
|
-
|
|
247
|
-
// Apply quality adjustments
|
|
248
|
-
if (this.config.adaptiveBitrate && loadingStrategy.suggestedQuality) {
|
|
249
|
-
this.applyQualitySettings(element, loadingStrategy.suggestedQuality)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return metrics
|
|
253
|
-
} catch (error) {
|
|
254
|
-
console.error("Media loading optimization failed:", error)
|
|
255
|
-
return metrics
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
private chooseLoadingStrategy(
|
|
260
|
-
networkInfo: NetworkInfo,
|
|
261
|
-
options: { preload?: boolean; priority?: string; quality?: string }
|
|
262
|
-
) {
|
|
263
|
-
const effectiveType = networkInfo.effectiveType === "unknown" ? "4g" : networkInfo.effectiveType
|
|
264
|
-
const threshold =
|
|
265
|
-
this.config.networkThresholds[effectiveType] || this.config.networkThresholds["4g"]
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
shouldPreload: options.preload !== false && threshold.preload && !networkInfo.saveData,
|
|
269
|
-
preloadAmount: networkInfo.saveData ? 0 : this.config.maxPreloadSize,
|
|
270
|
-
preloadAttribute: this.getPreloadAttribute(networkInfo),
|
|
271
|
-
suggestedQuality: this.getSuggestedQuality(networkInfo, threshold.maxBitrate),
|
|
272
|
-
bufferTarget: this.getBufferTarget(networkInfo)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
private getPreloadAttribute(networkInfo: NetworkInfo): "none" | "metadata" | "auto" {
|
|
277
|
-
if (networkInfo.saveData || networkInfo.effectiveType === "2g") {
|
|
278
|
-
return "none"
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (networkInfo.effectiveType === "3g") {
|
|
282
|
-
return "metadata"
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return this.config.preloadStrategy
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
private getSuggestedQuality(networkInfo: NetworkInfo, maxBitrate: number): string {
|
|
289
|
-
const availableBandwidth = networkInfo.downlink * 1000 // Convert to kbps
|
|
290
|
-
|
|
291
|
-
if (availableBandwidth >= maxBitrate * 2) return "high"
|
|
292
|
-
if (availableBandwidth >= maxBitrate) return "medium"
|
|
293
|
-
return "low"
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
private getBufferTarget(networkInfo: NetworkInfo): number {
|
|
297
|
-
switch (networkInfo.effectiveType) {
|
|
298
|
-
case "2g":
|
|
299
|
-
return 2 // 2 seconds
|
|
300
|
-
case "3g":
|
|
301
|
-
return 5 // 5 seconds
|
|
302
|
-
case "4g":
|
|
303
|
-
return this.config.bufferSize
|
|
304
|
-
case "5g":
|
|
305
|
-
return this.config.bufferSize * 1.5
|
|
306
|
-
default:
|
|
307
|
-
return this.config.bufferSize
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Preload media content
|
|
312
|
-
async preloadMedia(url: string, maxSize: number): Promise<void> {
|
|
313
|
-
if (this.preloadCache.has(url)) {
|
|
314
|
-
return // Already preloading or preloaded
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const preloadPromise = this.fetchWithProgress(url, maxSize)
|
|
318
|
-
this.preloadCache.set(url, preloadPromise)
|
|
319
|
-
|
|
320
|
-
try {
|
|
321
|
-
await preloadPromise
|
|
322
|
-
} catch (error) {
|
|
323
|
-
console.warn(`Preload failed for ${url}:`, error)
|
|
324
|
-
this.preloadCache.delete(url)
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
private async fetchWithProgress(url: string, maxSize: number): Promise<Blob> {
|
|
329
|
-
const response = await fetch(url, {
|
|
330
|
-
headers: {
|
|
331
|
-
Range: `bytes=0-${maxSize - 1}` // Limit preload size
|
|
332
|
-
}
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
if (!response.ok) {
|
|
336
|
-
throw new Error(`Failed to preload: ${response.status}`)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const reader = response.body?.getReader()
|
|
340
|
-
if (!reader) {
|
|
341
|
-
throw new Error("Response body not readable")
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const chunks: Uint8Array[] = []
|
|
345
|
-
let bytesRead = 0
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
while (bytesRead < maxSize) {
|
|
349
|
-
const { done, value } = await reader.read()
|
|
350
|
-
if (done) break
|
|
351
|
-
|
|
352
|
-
chunks.push(value)
|
|
353
|
-
bytesRead += value.length
|
|
354
|
-
}
|
|
355
|
-
} finally {
|
|
356
|
-
reader.releaseLock()
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return new Blob(chunks)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Monitor loading progress and update metrics
|
|
363
|
-
private monitorLoadingProgress(element: HTMLMediaElement, metrics: MediaLoadingMetrics) {
|
|
364
|
-
let stallStartTime: number | null = null
|
|
365
|
-
|
|
366
|
-
const updateMetrics = () => {
|
|
367
|
-
if (element.buffered.length > 0) {
|
|
368
|
-
const bufferedEnd = element.buffered.end(element.buffered.length - 1)
|
|
369
|
-
const currentTime = element.currentTime
|
|
370
|
-
metrics.bufferHealth = Math.min((bufferedEnd - currentTime) / this.config.bufferSize, 1)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Track first byte
|
|
375
|
-
const onLoadStart = () => {
|
|
376
|
-
metrics.firstByteTime = performance.now()
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Track load completion
|
|
380
|
-
const onCanPlay = () => {
|
|
381
|
-
metrics.loadCompleteTime = performance.now()
|
|
382
|
-
metrics.totalLoadTime = metrics.loadCompleteTime - metrics.loadStartTime
|
|
383
|
-
|
|
384
|
-
// Calculate load speed
|
|
385
|
-
if (metrics.totalLoadTime && metrics.bytesLoaded > 0) {
|
|
386
|
-
metrics.loadSpeed = metrics.bytesLoaded / (metrics.totalLoadTime / 1000)
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Track stalls
|
|
391
|
-
const onWaiting = () => {
|
|
392
|
-
if (stallStartTime === null) {
|
|
393
|
-
stallStartTime = performance.now()
|
|
394
|
-
metrics.stallsCount++
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const onPlaying = () => {
|
|
399
|
-
if (stallStartTime !== null) {
|
|
400
|
-
metrics.stallsDuration += performance.now() - stallStartTime
|
|
401
|
-
stallStartTime = null
|
|
402
|
-
}
|
|
403
|
-
updateMetrics()
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// Track progress
|
|
407
|
-
const onProgress = () => {
|
|
408
|
-
if (element.buffered.length > 0) {
|
|
409
|
-
const bufferedBytes = element.buffered.end(0) * 1000 // Rough estimate
|
|
410
|
-
metrics.bytesLoaded = bufferedBytes
|
|
411
|
-
}
|
|
412
|
-
updateMetrics()
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Add event listeners
|
|
416
|
-
element.addEventListener("loadstart", onLoadStart)
|
|
417
|
-
element.addEventListener("canplay", onCanPlay)
|
|
418
|
-
element.addEventListener("waiting", onWaiting)
|
|
419
|
-
element.addEventListener("playing", onPlaying)
|
|
420
|
-
element.addEventListener("progress", onProgress)
|
|
421
|
-
|
|
422
|
-
// Cleanup function
|
|
423
|
-
const cleanup = () => {
|
|
424
|
-
element.removeEventListener("loadstart", onLoadStart)
|
|
425
|
-
element.removeEventListener("canplay", onCanPlay)
|
|
426
|
-
element.removeEventListener("waiting", onWaiting)
|
|
427
|
-
element.removeEventListener("playing", onPlaying)
|
|
428
|
-
element.removeEventListener("progress", onProgress)
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Auto-cleanup after 5 minutes
|
|
432
|
-
setTimeout(cleanup, 5 * 60 * 1000)
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// Apply quality settings (would integrate with HLS.js or similar)
|
|
436
|
-
private applyQualitySettings(element: HTMLMediaElement, quality: string) {
|
|
437
|
-
// This would integrate with your video streaming library
|
|
438
|
-
console.log(`Applying quality setting: ${quality} to`, element)
|
|
439
|
-
|
|
440
|
-
// Example integration with HLS.js:
|
|
441
|
-
// if (element.hls) {
|
|
442
|
-
// element.hls.currentLevel = this.getQualityLevel(quality);
|
|
443
|
-
// }
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
private adjustQualityForNetwork(networkInfo: NetworkInfo) {
|
|
447
|
-
// Auto-adjust quality for all active media elements
|
|
448
|
-
console.log("Adjusting quality for network conditions:", networkInfo.effectiveType)
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// Clear preload cache to save memory
|
|
452
|
-
clearPreloadCache() {
|
|
453
|
-
this.preloadCache.clear()
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Get loading metrics for a specific media URL
|
|
457
|
-
getLoadingMetrics(url: string): MediaLoadingMetrics | undefined {
|
|
458
|
-
return this.loadingMetrics.get(url)
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Get all loading metrics
|
|
462
|
-
getAllMetrics(): MediaLoadingMetrics[] {
|
|
463
|
-
return Array.from(this.loadingMetrics.values())
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Calculate average loading performance
|
|
467
|
-
getAverageLoadingTime(): number {
|
|
468
|
-
const metrics = this.getAllMetrics()
|
|
469
|
-
const completedLoads = metrics.filter((m) => m.totalLoadTime !== undefined)
|
|
470
|
-
|
|
471
|
-
if (completedLoads.length === 0) return 0
|
|
472
|
-
|
|
473
|
-
const total = completedLoads.reduce((sum, m) => sum + (m.totalLoadTime || 0), 0)
|
|
474
|
-
return total / completedLoads.length
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Get network-specific performance stats
|
|
478
|
-
getNetworkPerformanceStats(): {
|
|
479
|
-
networkType: string
|
|
480
|
-
avgLoadTime: number
|
|
481
|
-
avgStalls: number
|
|
482
|
-
avgBufferHealth: number
|
|
483
|
-
}[] {
|
|
484
|
-
const statsByNetwork = new Map<string, MediaLoadingMetrics[]>()
|
|
485
|
-
|
|
486
|
-
this.getAllMetrics().forEach((metrics) => {
|
|
487
|
-
const network = metrics.networkType
|
|
488
|
-
if (!statsByNetwork.has(network)) {
|
|
489
|
-
statsByNetwork.set(network, [])
|
|
490
|
-
}
|
|
491
|
-
statsByNetwork.get(network)!.push(metrics)
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
return Array.from(statsByNetwork.entries()).map(([networkType, metrics]) => ({
|
|
495
|
-
networkType,
|
|
496
|
-
avgLoadTime: metrics.reduce((sum, m) => sum + (m.totalLoadTime || 0), 0) / metrics.length,
|
|
497
|
-
avgStalls: metrics.reduce((sum, m) => sum + m.stallsCount, 0) / metrics.length,
|
|
498
|
-
avgBufferHealth: metrics.reduce((sum, m) => sum + m.bufferHealth, 0) / metrics.length
|
|
499
|
-
}))
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Global media loading optimizer instance
|
|
504
|
-
export const mediaLoadingOptimizer = new MediaLoadingOptimizer()
|
|
505
|
-
|
|
506
|
-
// React hook for media loading optimization
|
|
507
|
-
export function useMediaLoadingOptimizer(config?: Partial<MediaLoadingConfig>) {
|
|
508
|
-
const [optimizer] = React.useState(() =>
|
|
509
|
-
config ? new MediaLoadingOptimizer(config) : mediaLoadingOptimizer
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
const [networkInfo, setNetworkInfo] = React.useState<NetworkInfo | null>(null)
|
|
513
|
-
const [loadingMetrics, setLoadingMetrics] = React.useState<MediaLoadingMetrics[]>([])
|
|
514
|
-
|
|
515
|
-
React.useEffect(() => {
|
|
516
|
-
const unsubscribe = optimizer["networkMonitor"].subscribe(setNetworkInfo)
|
|
517
|
-
setNetworkInfo(optimizer["networkMonitor"].getCurrentNetworkInfo())
|
|
518
|
-
|
|
519
|
-
// Update metrics periodically
|
|
520
|
-
const interval = setInterval(() => {
|
|
521
|
-
setLoadingMetrics(optimizer.getAllMetrics())
|
|
522
|
-
}, 1000)
|
|
523
|
-
|
|
524
|
-
return () => {
|
|
525
|
-
unsubscribe()
|
|
526
|
-
clearInterval(interval)
|
|
527
|
-
}
|
|
528
|
-
}, [optimizer])
|
|
529
|
-
|
|
530
|
-
const optimizeLoading = React.useCallback(
|
|
531
|
-
(mediaUrl: string, element: HTMLMediaElement, options?: any) => {
|
|
532
|
-
return optimizer.optimizeMediaLoading(mediaUrl, element, options)
|
|
533
|
-
},
|
|
534
|
-
[optimizer]
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
return {
|
|
538
|
-
networkInfo,
|
|
539
|
-
loadingMetrics,
|
|
540
|
-
optimizeLoading,
|
|
541
|
-
averageLoadTime: optimizer.getAverageLoadingTime(),
|
|
542
|
-
networkStats: optimizer.getNetworkPerformanceStats()
|
|
543
|
-
}
|
|
544
|
-
}
|