@therealtinhtute/baroiplayer 1.2.1 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -71
- 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 +1 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +750 -5640
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +3 -0
- package/package.json +110 -114
- 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 -1
- package/dist/context/media.mjs +0 -3
- package/dist/context/store.js +0 -1
- package/dist/context/store.mjs +0 -3
- package/dist/context-Bzd5QCKM.cjs +0 -7
- package/dist/context-Bzd5QCKM.cjs.map +0 -1
- package/dist/context-DD_SH4tT.js +0 -1053
- package/dist/context-DD_SH4tT.js.map +0 -1
- package/dist/core-events-BRnLMB7s.cjs +0 -2
- package/dist/core-events-BRnLMB7s.cjs.map +0 -1
- package/dist/core-events-v_mKdj5p.js +0 -417
- package/dist/core-events-v_mKdj5p.js.map +0 -1
- package/dist/core-plugins-CMBv-yVh.cjs +0 -2
- package/dist/core-plugins-CMBv-yVh.cjs.map +0 -1
- package/dist/core-plugins-CqCxLkbd.js +0 -754
- package/dist/core-plugins-CqCxLkbd.js.map +0 -1
- package/dist/core.js +0 -15
- package/dist/core.js.map +0 -1
- package/dist/core.mjs +0 -960
- package/dist/core.mjs.map +0 -1
- package/dist/enhanced-components-BwjBqSA1.js +0 -2858
- package/dist/enhanced-components-BwjBqSA1.js.map +0 -1
- package/dist/enhanced-components-C-ka-XLp.cjs +0 -2
- package/dist/enhanced-components-C-ka-XLp.cjs.map +0 -1
- package/dist/hooks-B-IIWPJr.js +0 -1842
- package/dist/hooks-B-IIWPJr.js.map +0 -1
- package/dist/hooks-DcHzmBwA.cjs +0 -4
- package/dist/hooks-DcHzmBwA.cjs.map +0 -1
- package/dist/minimal-components-BYsMQde5.js +0 -1610
- package/dist/minimal-components-BYsMQde5.js.map +0 -1
- package/dist/minimal-components-CsxQbDp7.cjs +0 -2
- package/dist/minimal-components-CsxQbDp7.cjs.map +0 -1
- package/dist/minimal-components.css +0 -1
- package/dist/mona-loading.gif +0 -0
- package/dist/performance-monitor-DCSijLJg.js +0 -312
- package/dist/performance-monitor-DCSijLJg.js.map +0 -1
- package/dist/performance-monitor-wNFKmqMr.cjs +0 -2
- package/dist/performance-monitor-wNFKmqMr.cjs.map +0 -1
- package/dist/rolldown-runtime-BmowowmI.js +0 -14
- package/dist/rolldown-runtime-mLOUI7ql.cjs +0 -1
- package/dist/utils-D2gQ7c2R.js +0 -64
- package/dist/utils-D2gQ7c2R.js.map +0 -1
- package/dist/utils-DJaAwiZ9.cjs +0 -2
- package/dist/utils-DJaAwiZ9.cjs.map +0 -1
- package/dist/utils.js +0 -1
- package/dist/utils.mjs +0 -3
- package/src/adapters/videojs-adapter.tsx +0 -470
- package/src/assets/mona-loading.gif +0 -0
- package/src/components/AnimateLoading.tsx +0 -111
- 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 -141
- package/src/components/examples/react-19-demo.tsx +0 -349
- package/src/components/examples/volume-orientation-demo.tsx +0 -105
- 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 -96
- 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 -35
- 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 -545
- 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 -77
- 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/assets.d.ts +0 -29
- 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,194 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { useActionState, useCallback, useOptimistic, useState } from "react"
|
|
4
|
-
import { useMediaSelector, useMediaStore } from "../context/media-context"
|
|
5
|
-
import type { EnhancedMediaStore } from "../context/media-store"
|
|
6
|
-
import type { MediaPlayerState } from "../types/index"
|
|
7
|
-
import { useMediaActions } from "./use-media-actions"
|
|
8
|
-
import { useMediaOptimistic } from "./use-media-optimistic"
|
|
9
|
-
|
|
10
|
-
// Legacy hook for backward compatibility
|
|
11
|
-
export function useMediaState() {
|
|
12
|
-
const [state, setState] = useState<MediaPlayerState>({
|
|
13
|
-
isPlaying: false,
|
|
14
|
-
currentTime: 0,
|
|
15
|
-
duration: 0,
|
|
16
|
-
volume: 1,
|
|
17
|
-
isMuted: false,
|
|
18
|
-
isLoading: false,
|
|
19
|
-
isFullscreen: false,
|
|
20
|
-
error: null,
|
|
21
|
-
buffered: null
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
const updateState = (updates: Partial<MediaPlayerState>) => {
|
|
25
|
-
setState((prev: MediaPlayerState) => ({ ...prev, ...updates }))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const setPlaying = (isPlaying: boolean) => {
|
|
29
|
-
updateState({ isPlaying })
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const setCurrentTime = (currentTime: number) => {
|
|
33
|
-
updateState({ currentTime })
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const setDuration = (duration: number) => {
|
|
37
|
-
updateState({ duration })
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const setVolume = (volume: number) => {
|
|
41
|
-
updateState({ volume: Math.max(0, Math.min(1, volume)) })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const setMuted = (isMuted: boolean) => {
|
|
45
|
-
updateState({ isMuted })
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const setLoading = (isLoading: boolean) => {
|
|
49
|
-
updateState({ isLoading })
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const setFullscreen = (isFullscreen: boolean) => {
|
|
53
|
-
updateState({ isFullscreen })
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const setError = (error: string | null) => {
|
|
57
|
-
updateState({ error })
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const setBuffered = (buffered: TimeRanges | null) => {
|
|
61
|
-
updateState({ buffered })
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
state,
|
|
66
|
-
updateState,
|
|
67
|
-
setPlaying,
|
|
68
|
-
setCurrentTime,
|
|
69
|
-
setDuration,
|
|
70
|
-
setVolume,
|
|
71
|
-
setMuted,
|
|
72
|
-
setLoading,
|
|
73
|
-
setFullscreen,
|
|
74
|
-
setError,
|
|
75
|
-
setBuffered
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// React 19 enhanced media state hook
|
|
80
|
-
export function useEnhancedMediaState() {
|
|
81
|
-
const store = useMediaStore()
|
|
82
|
-
|
|
83
|
-
// Check if this is an enhanced store
|
|
84
|
-
const isEnhanced = "getOptimisticState" in store
|
|
85
|
-
|
|
86
|
-
// Always call hooks unconditionally
|
|
87
|
-
const regularState = useMediaState()
|
|
88
|
-
const enhancedStore = store as unknown as EnhancedMediaStore
|
|
89
|
-
const optimisticState = useMediaOptimistic(enhancedStore)
|
|
90
|
-
const actions = useMediaActions(enhancedStore)
|
|
91
|
-
|
|
92
|
-
// Return appropriate state based on store type
|
|
93
|
-
if (!isEnhanced) {
|
|
94
|
-
// Fall back to regular media state if not enhanced
|
|
95
|
-
return regularState as any
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
// State (optimistic values for immediate UI feedback)
|
|
100
|
-
state: optimisticState.state,
|
|
101
|
-
actualState: optimisticState.actualState,
|
|
102
|
-
|
|
103
|
-
// Individual state selectors
|
|
104
|
-
isPlaying: optimisticState.isPlaying,
|
|
105
|
-
currentTime: optimisticState.currentTime,
|
|
106
|
-
duration: optimisticState.state.duration,
|
|
107
|
-
volume: optimisticState.volume,
|
|
108
|
-
isMuted: optimisticState.isMuted,
|
|
109
|
-
isLoading: optimisticState.isBuffering,
|
|
110
|
-
isFullscreen: optimisticState.isFullscreen,
|
|
111
|
-
error: optimisticState.state.error,
|
|
112
|
-
buffered: optimisticState.state.buffered,
|
|
113
|
-
|
|
114
|
-
// Computed values
|
|
115
|
-
progress: optimisticState.progress,
|
|
116
|
-
formattedTime: optimisticState.formattedTime,
|
|
117
|
-
formattedDuration: optimisticState.formattedDuration,
|
|
118
|
-
|
|
119
|
-
// Actions with optimistic updates
|
|
120
|
-
actions,
|
|
121
|
-
|
|
122
|
-
// Action state for loading/error handling
|
|
123
|
-
isActionLoading: actions.isLoading,
|
|
124
|
-
actionError: actions.errorMessage,
|
|
125
|
-
retryLastAction: actions.retryLastAction,
|
|
126
|
-
|
|
127
|
-
// Legacy compatibility methods
|
|
128
|
-
updateState: (updates: Partial<MediaPlayerState>) => {
|
|
129
|
-
// Map legacy updates to new actions
|
|
130
|
-
if ("isPlaying" in updates) {
|
|
131
|
-
updates.isPlaying ? actions.play() : actions.pause()
|
|
132
|
-
}
|
|
133
|
-
if ("currentTime" in updates) {
|
|
134
|
-
actions.setCurrentTime(updates.currentTime!)
|
|
135
|
-
}
|
|
136
|
-
if ("duration" in updates) {
|
|
137
|
-
actions.setDuration(updates.duration!)
|
|
138
|
-
}
|
|
139
|
-
if ("volume" in updates) {
|
|
140
|
-
actions.setVolume(updates.volume!)
|
|
141
|
-
}
|
|
142
|
-
if ("isMuted" in updates) {
|
|
143
|
-
updates.isMuted ? actions.mute() : actions.unmute()
|
|
144
|
-
}
|
|
145
|
-
if ("isLoading" in updates) {
|
|
146
|
-
actions.setLoading(updates.isLoading!)
|
|
147
|
-
}
|
|
148
|
-
if ("isFullscreen" in updates) {
|
|
149
|
-
updates.isFullscreen ? actions.enterFullscreen() : actions.exitFullscreen()
|
|
150
|
-
}
|
|
151
|
-
if ("error" in updates) {
|
|
152
|
-
actions.setError(updates.error ?? null)
|
|
153
|
-
}
|
|
154
|
-
if ("buffered" in updates) {
|
|
155
|
-
actions.setBuffered(updates.buffered ?? null)
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
// Individual action methods for legacy compatibility
|
|
160
|
-
setPlaying: (isPlaying: boolean) => {
|
|
161
|
-
isPlaying ? actions.play(true) : actions.pause(true) // Use optimistic updates
|
|
162
|
-
},
|
|
163
|
-
setCurrentTime: (time: number) => actions.setCurrentTime(time),
|
|
164
|
-
setDuration: (duration: number) => actions.setDuration(duration),
|
|
165
|
-
setVolume: (volume: number) => actions.setVolume(volume, true),
|
|
166
|
-
setMuted: (muted: boolean) => {
|
|
167
|
-
muted ? actions.mute(true) : actions.unmute(true)
|
|
168
|
-
},
|
|
169
|
-
setLoading: (loading: boolean) => actions.setLoading(loading),
|
|
170
|
-
setFullscreen: (fullscreen: boolean) => {
|
|
171
|
-
fullscreen ? actions.enterFullscreen(true) : actions.exitFullscreen(true)
|
|
172
|
-
},
|
|
173
|
-
setError: (error: string | null) => actions.setError(error),
|
|
174
|
-
setBuffered: (buffered: TimeRanges | null) => actions.setBuffered(buffered)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Hook that automatically chooses between legacy and enhanced based on context availability
|
|
179
|
-
export function useAdaptiveMediaState() {
|
|
180
|
-
// Always call hooks unconditionally
|
|
181
|
-
const enhancedState = useEnhancedMediaState()
|
|
182
|
-
const regularState = useMediaState()
|
|
183
|
-
|
|
184
|
-
// Check if we're in an enhanced context by testing a property that would only exist in enhanced mode
|
|
185
|
-
const isEnhancedContext = "getOptimisticState" in enhancedState
|
|
186
|
-
|
|
187
|
-
if (!isEnhancedContext) {
|
|
188
|
-
// Fall back to legacy version if not in MediaProvider context
|
|
189
|
-
console.warn("MediaStore context not available, using legacy state management")
|
|
190
|
-
return regularState
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return enhancedState
|
|
194
|
-
}
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React, { useEffect, useRef, useCallback, useMemo } from "react"
|
|
4
|
-
|
|
5
|
-
// Memory optimization hook for media players
|
|
6
|
-
export function useMemoryOptimization(
|
|
7
|
-
options: {
|
|
8
|
-
maxMemoryUsage?: number // in MB
|
|
9
|
-
cleanupInterval?: number // in ms
|
|
10
|
-
enableGC?: boolean
|
|
11
|
-
monitorMemory?: boolean
|
|
12
|
-
} = {}
|
|
13
|
-
) {
|
|
14
|
-
const {
|
|
15
|
-
maxMemoryUsage = 100, // 100MB default
|
|
16
|
-
cleanupInterval = 30000, // 30 seconds default
|
|
17
|
-
enableGC = true,
|
|
18
|
-
monitorMemory = true
|
|
19
|
-
} = options
|
|
20
|
-
|
|
21
|
-
const cleanupTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
|
|
22
|
-
const observersRef = useRef<Set<MutationObserver>>(new Set())
|
|
23
|
-
const eventListenersRef = useRef<Map<Element, Array<{ event: string; handler: EventListener }>>>(
|
|
24
|
-
new Map()
|
|
25
|
-
)
|
|
26
|
-
const intervalRefs = useRef<Set<ReturnType<typeof setInterval>>>(new Set())
|
|
27
|
-
const animationFrameRefs = useRef<Set<number>>(new Set())
|
|
28
|
-
|
|
29
|
-
// Get current memory usage
|
|
30
|
-
const getMemoryUsage = useCallback(() => {
|
|
31
|
-
if (typeof window === "undefined" || !("memory" in performance)) {
|
|
32
|
-
return { used: 0, total: 0, limit: 0 }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const memory = (performance as any).memory
|
|
36
|
-
return {
|
|
37
|
-
used: memory.usedJSHeapSize,
|
|
38
|
-
total: memory.totalJSHeapSize,
|
|
39
|
-
limit: memory.jsHeapSizeLimit
|
|
40
|
-
}
|
|
41
|
-
}, [])
|
|
42
|
-
|
|
43
|
-
// Memory monitoring state
|
|
44
|
-
const [memoryStats, setMemoryStats] = React.useState({
|
|
45
|
-
used: 0,
|
|
46
|
-
total: 0,
|
|
47
|
-
limit: 0,
|
|
48
|
-
usage: 0,
|
|
49
|
-
isHighUsage: false
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// Cleanup function (must be declared before use)
|
|
53
|
-
const performCleanup = useCallback(() => {
|
|
54
|
-
// Clear all timeouts
|
|
55
|
-
intervalRefs.current.forEach((timeout) => {
|
|
56
|
-
clearTimeout(timeout)
|
|
57
|
-
})
|
|
58
|
-
intervalRefs.current.clear()
|
|
59
|
-
|
|
60
|
-
// Cancel all animation frames
|
|
61
|
-
animationFrameRefs.current.forEach((frameId) => {
|
|
62
|
-
cancelAnimationFrame(frameId)
|
|
63
|
-
})
|
|
64
|
-
animationFrameRefs.current.clear()
|
|
65
|
-
|
|
66
|
-
// Disconnect all observers
|
|
67
|
-
observersRef.current.forEach((observer) => {
|
|
68
|
-
observer.disconnect()
|
|
69
|
-
})
|
|
70
|
-
observersRef.current.clear()
|
|
71
|
-
|
|
72
|
-
// Remove all event listeners
|
|
73
|
-
eventListenersRef.current.forEach((listeners, element) => {
|
|
74
|
-
listeners.forEach(({ event, handler }) => {
|
|
75
|
-
element.removeEventListener(event, handler)
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
eventListenersRef.current.clear()
|
|
79
|
-
|
|
80
|
-
// Force garbage collection if available
|
|
81
|
-
if (typeof window !== "undefined" && "gc" in window) {
|
|
82
|
-
;(window as any).gc()
|
|
83
|
-
}
|
|
84
|
-
}, [])
|
|
85
|
-
|
|
86
|
-
// Safe interval management (must be declared before use)
|
|
87
|
-
const useInterval = useCallback((callback: () => void, delay: number) => {
|
|
88
|
-
const timeoutId = globalThis.setInterval(callback, delay)
|
|
89
|
-
intervalRefs.current.add(timeoutId)
|
|
90
|
-
|
|
91
|
-
return () => {
|
|
92
|
-
globalThis.clearInterval(timeoutId)
|
|
93
|
-
intervalRefs.current.delete(timeoutId)
|
|
94
|
-
}
|
|
95
|
-
}, [])
|
|
96
|
-
|
|
97
|
-
// Memory monitoring
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
if (!monitorMemory) return
|
|
100
|
-
|
|
101
|
-
const checkMemory = () => {
|
|
102
|
-
const memory = getMemoryUsage()
|
|
103
|
-
const usage = memory.used / 1024 / 1024 // Convert to MB
|
|
104
|
-
const isHighUsage = usage > maxMemoryUsage
|
|
105
|
-
|
|
106
|
-
setMemoryStats({
|
|
107
|
-
...memory,
|
|
108
|
-
usage,
|
|
109
|
-
isHighUsage
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Trigger cleanup if memory usage is high
|
|
113
|
-
if (isHighUsage && enableGC) {
|
|
114
|
-
performCleanup()
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
checkMemory()
|
|
119
|
-
return useInterval(checkMemory, cleanupInterval)
|
|
120
|
-
}, [monitorMemory, getMemoryUsage, maxMemoryUsage, enableGC, cleanupInterval, performCleanup])
|
|
121
|
-
|
|
122
|
-
// Safe event listener management
|
|
123
|
-
const addEventListener = useCallback(
|
|
124
|
-
(
|
|
125
|
-
element: Element,
|
|
126
|
-
event: string,
|
|
127
|
-
handler: EventListener,
|
|
128
|
-
options?: AddEventListenerOptions
|
|
129
|
-
) => {
|
|
130
|
-
element.addEventListener(event, handler, options)
|
|
131
|
-
|
|
132
|
-
if (!eventListenersRef.current.has(element)) {
|
|
133
|
-
eventListenersRef.current.set(element, [])
|
|
134
|
-
}
|
|
135
|
-
eventListenersRef.current.get(element)!.push({ event, handler })
|
|
136
|
-
|
|
137
|
-
// Return cleanup function
|
|
138
|
-
return () => {
|
|
139
|
-
element.removeEventListener(event, handler)
|
|
140
|
-
const listeners = eventListenersRef.current.get(element)
|
|
141
|
-
if (listeners) {
|
|
142
|
-
const index = listeners.findIndex((l) => l.event === event && l.handler === handler)
|
|
143
|
-
if (index > -1) {
|
|
144
|
-
listeners.splice(index, 1)
|
|
145
|
-
}
|
|
146
|
-
if (listeners.length === 0) {
|
|
147
|
-
eventListenersRef.current.delete(element)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
[]
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
// Safe timeout management
|
|
156
|
-
const useSafeTimeout = useCallback((callback: () => void, delay: number) => {
|
|
157
|
-
const timeoutId = globalThis.setTimeout(callback, delay)
|
|
158
|
-
intervalRefs.current.add(timeoutId)
|
|
159
|
-
|
|
160
|
-
return () => {
|
|
161
|
-
globalThis.clearTimeout(timeoutId)
|
|
162
|
-
intervalRefs.current.delete(timeoutId)
|
|
163
|
-
}
|
|
164
|
-
}, [])
|
|
165
|
-
|
|
166
|
-
// Safe animation frame management
|
|
167
|
-
const useSafeAnimationFrame = useCallback((callback: FrameRequestCallback) => {
|
|
168
|
-
const frameId = globalThis.requestAnimationFrame(callback)
|
|
169
|
-
animationFrameRefs.current.add(frameId)
|
|
170
|
-
|
|
171
|
-
return () => {
|
|
172
|
-
globalThis.cancelAnimationFrame(frameId)
|
|
173
|
-
animationFrameRefs.current.delete(frameId)
|
|
174
|
-
}
|
|
175
|
-
}, [])
|
|
176
|
-
|
|
177
|
-
// Safe observer management
|
|
178
|
-
const addObserver = useCallback((observer: MutationObserver) => {
|
|
179
|
-
observersRef.current.add(observer)
|
|
180
|
-
|
|
181
|
-
return () => {
|
|
182
|
-
observer.disconnect()
|
|
183
|
-
observersRef.current.delete(observer)
|
|
184
|
-
}
|
|
185
|
-
}, [])
|
|
186
|
-
|
|
187
|
-
// Cleanup on unmount
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
return () => {
|
|
190
|
-
performCleanup()
|
|
191
|
-
}
|
|
192
|
-
}, [performCleanup])
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
// Memory stats
|
|
196
|
-
memoryStats,
|
|
197
|
-
getMemoryUsage,
|
|
198
|
-
|
|
199
|
-
// Cleanup functions
|
|
200
|
-
performCleanup,
|
|
201
|
-
|
|
202
|
-
// Safe API functions
|
|
203
|
-
addEventListener,
|
|
204
|
-
setInterval: useInterval,
|
|
205
|
-
setTimeout: useSafeTimeout,
|
|
206
|
-
requestAnimationFrame: useSafeAnimationFrame,
|
|
207
|
-
addObserver,
|
|
208
|
-
|
|
209
|
-
// Utilities
|
|
210
|
-
formatBytes: (bytes: number) => {
|
|
211
|
-
if (bytes === 0) return "0 Bytes"
|
|
212
|
-
const k = 1024
|
|
213
|
-
const sizes = ["Bytes", "KB", "MB", "GB"]
|
|
214
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
215
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Resource cleanup hook for media elements
|
|
221
|
-
export function useMediaResourceCleanup(
|
|
222
|
-
mediaRef: React.RefObject<HTMLVideoElement | HTMLAudioElement>
|
|
223
|
-
) {
|
|
224
|
-
const { addEventListener, performCleanup } = useMemoryOptimization()
|
|
225
|
-
|
|
226
|
-
// Track resource cleanup
|
|
227
|
-
const cleanupResources = useCallback(() => {
|
|
228
|
-
const media = mediaRef.current
|
|
229
|
-
if (!media) return
|
|
230
|
-
|
|
231
|
-
// Stop media playback
|
|
232
|
-
if (!media.paused) {
|
|
233
|
-
media.pause()
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Clear source
|
|
237
|
-
if (media.src) {
|
|
238
|
-
media.src = ""
|
|
239
|
-
media.load()
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Remove source elements
|
|
243
|
-
while (media.firstChild) {
|
|
244
|
-
media.removeChild(media.firstChild)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Clear any pending seeks
|
|
248
|
-
media.currentTime = 0
|
|
249
|
-
|
|
250
|
-
// Clear buffered data
|
|
251
|
-
if ("clearBuffered" in media) {
|
|
252
|
-
;(media as any).clearBuffered()
|
|
253
|
-
}
|
|
254
|
-
}, [mediaRef])
|
|
255
|
-
|
|
256
|
-
// Enhanced event listener registration
|
|
257
|
-
const registerMediaEventListener = useCallback(
|
|
258
|
-
(event: string, handler: EventListener, options?: AddEventListenerOptions) => {
|
|
259
|
-
const media = mediaRef.current
|
|
260
|
-
if (!media) return () => {}
|
|
261
|
-
|
|
262
|
-
return addEventListener(media, event, handler, options)
|
|
263
|
-
},
|
|
264
|
-
[mediaRef, addEventListener]
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
// Cleanup on unmount
|
|
268
|
-
useEffect(() => {
|
|
269
|
-
return cleanupResources
|
|
270
|
-
}, [cleanupResources])
|
|
271
|
-
|
|
272
|
-
return {
|
|
273
|
-
cleanupResources,
|
|
274
|
-
registerMediaEventListener
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Performance monitoring hook
|
|
279
|
-
export function usePerformanceMonitoring() {
|
|
280
|
-
const [metrics, setMetrics] = React.useState({
|
|
281
|
-
fps: 0,
|
|
282
|
-
frameDrops: 0,
|
|
283
|
-
longTasks: 0,
|
|
284
|
-
totalLongTaskDuration: 0
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
const frameCountRef = useRef(0)
|
|
288
|
-
const lastFrameTimeRef = useRef(performance.now())
|
|
289
|
-
const longTaskObserverRef = useRef<PerformanceObserver | undefined>(undefined)
|
|
290
|
-
|
|
291
|
-
// FPS monitoring
|
|
292
|
-
useEffect(() => {
|
|
293
|
-
let rafId: number
|
|
294
|
-
|
|
295
|
-
const measureFrame = () => {
|
|
296
|
-
frameCountRef.current++
|
|
297
|
-
const now = performance.now()
|
|
298
|
-
|
|
299
|
-
// Calculate FPS every second
|
|
300
|
-
if (now - lastFrameTimeRef.current >= 1000) {
|
|
301
|
-
const fps = Math.round((frameCountRef.current * 1000) / (now - lastFrameTimeRef.current))
|
|
302
|
-
const expectedFrames = Math.round((now - lastFrameTimeRef.current) / 16.67) // 60fps
|
|
303
|
-
const frameDrops = Math.max(0, expectedFrames - frameCountRef.current)
|
|
304
|
-
|
|
305
|
-
setMetrics((prev) => ({
|
|
306
|
-
...prev,
|
|
307
|
-
fps,
|
|
308
|
-
frameDrops: prev.frameDrops + frameDrops
|
|
309
|
-
}))
|
|
310
|
-
|
|
311
|
-
frameCountRef.current = 0
|
|
312
|
-
lastFrameTimeRef.current = now
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
rafId = requestAnimationFrame(measureFrame)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
rafId = requestAnimationFrame(measureFrame)
|
|
319
|
-
|
|
320
|
-
return () => {
|
|
321
|
-
cancelAnimationFrame(rafId)
|
|
322
|
-
}
|
|
323
|
-
}, [])
|
|
324
|
-
|
|
325
|
-
// Long task monitoring
|
|
326
|
-
useEffect(() => {
|
|
327
|
-
if (!("PerformanceObserver" in window)) return
|
|
328
|
-
|
|
329
|
-
try {
|
|
330
|
-
const observer = new PerformanceObserver((list) => {
|
|
331
|
-
for (const entry of list.getEntries()) {
|
|
332
|
-
if (entry.duration > 50) {
|
|
333
|
-
// Long task threshold
|
|
334
|
-
setMetrics((prev) => ({
|
|
335
|
-
...prev,
|
|
336
|
-
longTasks: prev.longTasks + 1,
|
|
337
|
-
totalLongTaskDuration: prev.totalLongTaskDuration + entry.duration
|
|
338
|
-
}))
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
observer.observe({ entryTypes: ["longtask"] })
|
|
344
|
-
longTaskObserverRef.current = observer
|
|
345
|
-
|
|
346
|
-
return () => {
|
|
347
|
-
observer.disconnect()
|
|
348
|
-
}
|
|
349
|
-
} catch (error) {
|
|
350
|
-
console.warn("Long task monitoring not supported:", error)
|
|
351
|
-
}
|
|
352
|
-
}, [])
|
|
353
|
-
|
|
354
|
-
return {
|
|
355
|
-
...metrics,
|
|
356
|
-
averageLongTaskDuration:
|
|
357
|
-
metrics.longTasks > 0 ? metrics.totalLongTaskDuration / metrics.longTasks : 0,
|
|
358
|
-
isPerformanceGood: metrics.fps >= 50 && metrics.frameDrops < 5
|
|
359
|
-
}
|
|
360
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from "react"
|
|
2
|
-
|
|
3
|
-
export interface NetworkStatus {
|
|
4
|
-
isOnline: boolean
|
|
5
|
-
connectionType: string | null
|
|
6
|
-
downlink: number | null
|
|
7
|
-
effectiveType: string | null
|
|
8
|
-
rtt: number | null
|
|
9
|
-
saveData: boolean | null
|
|
10
|
-
wasOffline: boolean
|
|
11
|
-
reconnectedAt: number | null
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function useNetworkStatus(): NetworkStatus {
|
|
15
|
-
const [status, setStatus] = useState<NetworkStatus>(() => ({
|
|
16
|
-
isOnline: typeof navigator !== "undefined" ? navigator.onLine : true,
|
|
17
|
-
connectionType: null,
|
|
18
|
-
downlink: null,
|
|
19
|
-
effectiveType: null,
|
|
20
|
-
rtt: null,
|
|
21
|
-
saveData: null,
|
|
22
|
-
wasOffline: false,
|
|
23
|
-
reconnectedAt: null
|
|
24
|
-
}))
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
const updateStatus = () => {
|
|
28
|
-
const connection =
|
|
29
|
-
(navigator as any).connection ||
|
|
30
|
-
(navigator as any).mozConnection ||
|
|
31
|
-
(navigator as any).webkitConnection
|
|
32
|
-
setStatus((prev) => ({
|
|
33
|
-
...prev,
|
|
34
|
-
isOnline: navigator.onLine,
|
|
35
|
-
connectionType: connection?.type || null,
|
|
36
|
-
downlink: connection?.downlink || null,
|
|
37
|
-
effectiveType: connection?.effectiveType || null,
|
|
38
|
-
rtt: connection?.rtt || null,
|
|
39
|
-
saveData: connection?.saveData || null
|
|
40
|
-
}))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const handleOnline = () => {
|
|
44
|
-
setStatus((prev) => ({
|
|
45
|
-
...prev,
|
|
46
|
-
isOnline: true,
|
|
47
|
-
wasOffline: true,
|
|
48
|
-
reconnectedAt: Date.now()
|
|
49
|
-
}))
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const handleOffline = () => {
|
|
53
|
-
setStatus((prev) => ({
|
|
54
|
-
...prev,
|
|
55
|
-
isOnline: false
|
|
56
|
-
}))
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
window.addEventListener("online", handleOnline)
|
|
60
|
-
window.addEventListener("offline", handleOffline)
|
|
61
|
-
|
|
62
|
-
const connection =
|
|
63
|
-
(navigator as any).connection ||
|
|
64
|
-
(navigator as any).mozConnection ||
|
|
65
|
-
(navigator as any).webkitConnection
|
|
66
|
-
if (connection) {
|
|
67
|
-
connection.addEventListener?.("change", updateStatus)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
updateStatus()
|
|
71
|
-
|
|
72
|
-
return () => {
|
|
73
|
-
window.removeEventListener("online", handleOnline)
|
|
74
|
-
window.removeEventListener("offline", handleOffline)
|
|
75
|
-
if (connection) {
|
|
76
|
-
connection.removeEventListener?.("change", updateStatus)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}, [])
|
|
80
|
-
|
|
81
|
-
return status
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function useAdaptiveQuality() {
|
|
85
|
-
const { effectiveType, downlink, isOnline } = useNetworkStatus()
|
|
86
|
-
|
|
87
|
-
const getQualityLevel = useCallback(() => {
|
|
88
|
-
if (!isOnline) return 0
|
|
89
|
-
|
|
90
|
-
switch (effectiveType) {
|
|
91
|
-
case "4g":
|
|
92
|
-
if (downlink && downlink >= 10) return 3
|
|
93
|
-
if (downlink && downlink >= 5) return 2
|
|
94
|
-
return 1
|
|
95
|
-
case "3g":
|
|
96
|
-
if (downlink && downlink >= 1.5) return 1
|
|
97
|
-
return 0
|
|
98
|
-
case "2g":
|
|
99
|
-
case "slow-2g":
|
|
100
|
-
return 0
|
|
101
|
-
default:
|
|
102
|
-
return 1
|
|
103
|
-
}
|
|
104
|
-
}, [effectiveType, downlink, isOnline])
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
qualityLevel: getQualityLevel(),
|
|
108
|
-
shouldReduceQuality: effectiveType === "3g" || effectiveType === "2g" || !isOnline,
|
|
109
|
-
supportsHD: effectiveType === "4g" && downlink !== null && downlink >= 5
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function useAutoQualitySwitch(enabled = true) {
|
|
114
|
-
const { isOnline, effectiveType } = useNetworkStatus()
|
|
115
|
-
|
|
116
|
-
const shouldAutoSwitch = useCallback(() => {
|
|
117
|
-
if (!enabled) return false
|
|
118
|
-
if (!isOnline) return false
|
|
119
|
-
if (effectiveType === "4g" || effectiveType === "3g") return true
|
|
120
|
-
return false
|
|
121
|
-
}, [enabled, isOnline, effectiveType])
|
|
122
|
-
|
|
123
|
-
return { shouldAutoSwitch: shouldAutoSwitch() }
|
|
124
|
-
}
|