@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,264 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React from "react"
|
|
4
|
-
import { MediaErrorHandler, type RetryConfig } from "./error-handling"
|
|
5
|
-
import {
|
|
6
|
-
type MediaAction,
|
|
7
|
-
MediaActionTypes,
|
|
8
|
-
MediaContext,
|
|
9
|
-
type MediaContextValue,
|
|
10
|
-
type MediaState,
|
|
11
|
-
type MediaStore,
|
|
12
|
-
MediaStoreContext,
|
|
13
|
-
initialMediaState
|
|
14
|
-
} from "./media-context"
|
|
15
|
-
import { type EnhancedMediaStore, createEnhancedMediaStore } from "./media-store"
|
|
16
|
-
import { type PersistenceConfig, useAutoMediaPersistence } from "./persistence"
|
|
17
|
-
|
|
18
|
-
// Legacy store for backward compatibility
|
|
19
|
-
function createLegacyMediaStore(initialState: MediaState = initialMediaState): MediaStore {
|
|
20
|
-
let state = { ...initialState }
|
|
21
|
-
const listeners = new Set<() => void>()
|
|
22
|
-
|
|
23
|
-
const subscribe = (callback: () => void) => {
|
|
24
|
-
listeners.add(callback)
|
|
25
|
-
return () => listeners.delete(callback)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const getState = () => state
|
|
29
|
-
|
|
30
|
-
const setState = (updates: Partial<MediaState>) => {
|
|
31
|
-
const newState = { ...state, ...updates }
|
|
32
|
-
if (JSON.stringify(newState) !== JSON.stringify(state)) {
|
|
33
|
-
state = newState
|
|
34
|
-
listeners.forEach((callback) => callback())
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const dispatch = (action: MediaAction) => {
|
|
39
|
-
switch (action.type) {
|
|
40
|
-
case MediaActionTypes.PLAY:
|
|
41
|
-
setState({ isPlaying: true, error: null })
|
|
42
|
-
break
|
|
43
|
-
|
|
44
|
-
case MediaActionTypes.PAUSE:
|
|
45
|
-
setState({ isPlaying: false })
|
|
46
|
-
break
|
|
47
|
-
|
|
48
|
-
case MediaActionTypes.SEEK:
|
|
49
|
-
setState({ currentTime: action.detail })
|
|
50
|
-
break
|
|
51
|
-
|
|
52
|
-
case MediaActionTypes.SET_VOLUME:
|
|
53
|
-
setState({ volume: Math.max(0, Math.min(1, action.detail)) })
|
|
54
|
-
break
|
|
55
|
-
|
|
56
|
-
case MediaActionTypes.MUTE:
|
|
57
|
-
setState({ isMuted: true })
|
|
58
|
-
break
|
|
59
|
-
|
|
60
|
-
case MediaActionTypes.UNMUTE:
|
|
61
|
-
setState({ isMuted: false })
|
|
62
|
-
break
|
|
63
|
-
|
|
64
|
-
case MediaActionTypes.TOGGLE_MUTE:
|
|
65
|
-
setState({ isMuted: !state.isMuted })
|
|
66
|
-
break
|
|
67
|
-
|
|
68
|
-
case MediaActionTypes.SET_DURATION:
|
|
69
|
-
setState({ duration: action.detail })
|
|
70
|
-
break
|
|
71
|
-
|
|
72
|
-
case MediaActionTypes.SET_CURRENT_TIME:
|
|
73
|
-
setState({ currentTime: action.detail })
|
|
74
|
-
break
|
|
75
|
-
|
|
76
|
-
case MediaActionTypes.SET_BUFFERED:
|
|
77
|
-
setState({ buffered: action.detail })
|
|
78
|
-
break
|
|
79
|
-
|
|
80
|
-
case MediaActionTypes.SET_LOADING:
|
|
81
|
-
setState({ isLoading: action.detail })
|
|
82
|
-
break
|
|
83
|
-
|
|
84
|
-
case MediaActionTypes.SET_ERROR:
|
|
85
|
-
setState({ error: action.detail, isLoading: false })
|
|
86
|
-
break
|
|
87
|
-
|
|
88
|
-
case MediaActionTypes.ENTER_FULLSCREEN:
|
|
89
|
-
setState({ isFullscreen: true })
|
|
90
|
-
break
|
|
91
|
-
|
|
92
|
-
case MediaActionTypes.EXIT_FULLSCREEN:
|
|
93
|
-
setState({ isFullscreen: false })
|
|
94
|
-
break
|
|
95
|
-
|
|
96
|
-
case MediaActionTypes.ENTER_PIP:
|
|
97
|
-
setState({ isPictureInPicture: true })
|
|
98
|
-
break
|
|
99
|
-
|
|
100
|
-
case MediaActionTypes.EXIT_PIP:
|
|
101
|
-
setState({ isPictureInPicture: false })
|
|
102
|
-
break
|
|
103
|
-
|
|
104
|
-
case MediaActionTypes.SET_PLAYBACK_RATE:
|
|
105
|
-
setState({ playbackRate: action.detail })
|
|
106
|
-
break
|
|
107
|
-
|
|
108
|
-
case MediaActionTypes.SET_SUBTITLE_TRACK:
|
|
109
|
-
setState({ selectedSubtitleTrack: action.detail })
|
|
110
|
-
break
|
|
111
|
-
|
|
112
|
-
case MediaActionTypes.SET_RENDITION:
|
|
113
|
-
setState({ selectedRendition: action.detail })
|
|
114
|
-
break
|
|
115
|
-
|
|
116
|
-
case MediaActionTypes.TOGGLE_SUBTITLES:
|
|
117
|
-
setState({ subtitlesShowing: !state.subtitlesShowing })
|
|
118
|
-
break
|
|
119
|
-
|
|
120
|
-
case MediaActionTypes.PREVIEW_TIME:
|
|
121
|
-
setState({ previewTime: action.detail })
|
|
122
|
-
break
|
|
123
|
-
|
|
124
|
-
case MediaActionTypes.CLEAR_PREVIEW:
|
|
125
|
-
setState({ previewTime: null, previewImage: null, previewCoords: null })
|
|
126
|
-
break
|
|
127
|
-
|
|
128
|
-
default:
|
|
129
|
-
console.warn(`Unknown media action type: ${action.type}`)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return { subscribe, getState, setState, dispatch }
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Enhanced media provider props with React 19 features
|
|
137
|
-
export interface MediaProviderProps {
|
|
138
|
-
children: React.ReactNode
|
|
139
|
-
mediaId?: string
|
|
140
|
-
labelId?: string
|
|
141
|
-
descriptionId?: string
|
|
142
|
-
dir?: "ltr" | "rtl"
|
|
143
|
-
portalContainer?: HTMLElement
|
|
144
|
-
tooltipDelayDuration?: number
|
|
145
|
-
tooltipSideOffset?: number
|
|
146
|
-
disabled?: boolean
|
|
147
|
-
isVideo?: boolean
|
|
148
|
-
withoutTooltip?: boolean
|
|
149
|
-
initialState?: Partial<MediaState>
|
|
150
|
-
|
|
151
|
-
// React 19 enhancements
|
|
152
|
-
useEnhancedStore?: boolean
|
|
153
|
-
persistenceConfig?: Partial<PersistenceConfig>
|
|
154
|
-
retryConfig?: Partial<RetryConfig>
|
|
155
|
-
enableOptimisticUpdates?: boolean
|
|
156
|
-
enableErrorRecovery?: boolean
|
|
157
|
-
onStateRehydrated?: (state: Partial<MediaState>) => void
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Enhanced media provider component with React 19 features
|
|
161
|
-
export function MediaProvider({
|
|
162
|
-
children,
|
|
163
|
-
mediaId = "media-player",
|
|
164
|
-
labelId = "media-player-label",
|
|
165
|
-
descriptionId = "media-player-description",
|
|
166
|
-
dir = "ltr",
|
|
167
|
-
portalContainer,
|
|
168
|
-
tooltipDelayDuration = 700,
|
|
169
|
-
tooltipSideOffset = 4,
|
|
170
|
-
disabled = false,
|
|
171
|
-
isVideo = true,
|
|
172
|
-
withoutTooltip = false,
|
|
173
|
-
initialState = {},
|
|
174
|
-
// React 19 enhancements
|
|
175
|
-
useEnhancedStore = true,
|
|
176
|
-
persistenceConfig,
|
|
177
|
-
retryConfig,
|
|
178
|
-
enableOptimisticUpdates = true,
|
|
179
|
-
enableErrorRecovery = true,
|
|
180
|
-
onStateRehydrated
|
|
181
|
-
}: MediaProviderProps) {
|
|
182
|
-
const rootRef = React.useRef<HTMLDivElement>(null)
|
|
183
|
-
const mediaRef = React.useRef<HTMLVideoElement | HTMLAudioElement>(null)
|
|
184
|
-
|
|
185
|
-
// Create enhanced or legacy store based on configuration
|
|
186
|
-
const store = React.useMemo(() => {
|
|
187
|
-
const combinedInitialState = { ...initialMediaState, ...initialState }
|
|
188
|
-
|
|
189
|
-
if (useEnhancedStore) {
|
|
190
|
-
return createEnhancedMediaStore(combinedInitialState, persistenceConfig) as MediaStore &
|
|
191
|
-
EnhancedMediaStore
|
|
192
|
-
} else {
|
|
193
|
-
return createLegacyMediaStore(combinedInitialState)
|
|
194
|
-
}
|
|
195
|
-
}, [useEnhancedStore, persistenceConfig])
|
|
196
|
-
|
|
197
|
-
// Error handler for React 19 features
|
|
198
|
-
const errorHandler = React.useMemo(() => {
|
|
199
|
-
if (enableErrorRecovery && useEnhancedStore) {
|
|
200
|
-
return new MediaErrorHandler(retryConfig)
|
|
201
|
-
}
|
|
202
|
-
return null
|
|
203
|
-
}, [enableErrorRecovery, useEnhancedStore, retryConfig])
|
|
204
|
-
|
|
205
|
-
// Auto-persistence for React 19 enhanced store - always call hooks unconditionally
|
|
206
|
-
const persistenceResult = useAutoMediaPersistence(store.getState(), mediaId, persistenceConfig)
|
|
207
|
-
|
|
208
|
-
// Handle state rehydration callback
|
|
209
|
-
React.useEffect(() => {
|
|
210
|
-
if (persistenceResult?.isRehydrated && onStateRehydrated) {
|
|
211
|
-
const currentState = store.getState()
|
|
212
|
-
onStateRehydrated(currentState)
|
|
213
|
-
}
|
|
214
|
-
}, [persistenceResult?.isRehydrated, onStateRehydrated, store])
|
|
215
|
-
|
|
216
|
-
// Enhanced context value with React 19 features
|
|
217
|
-
const contextValue = React.useMemo<
|
|
218
|
-
MediaContextValue & {
|
|
219
|
-
errorHandler?: MediaErrorHandler | null
|
|
220
|
-
isEnhanced?: boolean
|
|
221
|
-
isRehydrated?: boolean
|
|
222
|
-
}
|
|
223
|
-
>(
|
|
224
|
-
() => ({
|
|
225
|
-
mediaId,
|
|
226
|
-
labelId,
|
|
227
|
-
descriptionId,
|
|
228
|
-
dir,
|
|
229
|
-
rootRef,
|
|
230
|
-
mediaRef,
|
|
231
|
-
portalContainer,
|
|
232
|
-
tooltipDelayDuration,
|
|
233
|
-
tooltipSideOffset,
|
|
234
|
-
disabled,
|
|
235
|
-
isVideo,
|
|
236
|
-
withoutTooltip,
|
|
237
|
-
// React 19 enhancements
|
|
238
|
-
errorHandler,
|
|
239
|
-
isEnhanced: useEnhancedStore,
|
|
240
|
-
isRehydrated: persistenceResult?.isRehydrated
|
|
241
|
-
}),
|
|
242
|
-
[
|
|
243
|
-
mediaId,
|
|
244
|
-
labelId,
|
|
245
|
-
descriptionId,
|
|
246
|
-
dir,
|
|
247
|
-
portalContainer,
|
|
248
|
-
tooltipDelayDuration,
|
|
249
|
-
tooltipSideOffset,
|
|
250
|
-
disabled,
|
|
251
|
-
isVideo,
|
|
252
|
-
withoutTooltip,
|
|
253
|
-
errorHandler,
|
|
254
|
-
useEnhancedStore,
|
|
255
|
-
persistenceResult?.isRehydrated
|
|
256
|
-
]
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
return (
|
|
260
|
-
<MediaContext.Provider value={contextValue}>
|
|
261
|
-
<MediaStoreContext.Provider value={store}>{children}</MediaStoreContext.Provider>
|
|
262
|
-
</MediaContext.Provider>
|
|
263
|
-
)
|
|
264
|
-
}
|
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React from "react"
|
|
4
|
-
import type { MediaAction, MediaActionType, MediaState } from "./media-context"
|
|
5
|
-
import { MediaActionTypes, initialMediaState } from "./media-context"
|
|
6
|
-
|
|
7
|
-
// Enhanced action types for React 19 features
|
|
8
|
-
export interface OptimisticMediaAction extends MediaAction {
|
|
9
|
-
optimistic?: boolean
|
|
10
|
-
retryCount?: number
|
|
11
|
-
timestamp?: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Action state for useActionState
|
|
15
|
-
export interface MediaActionState {
|
|
16
|
-
pending: boolean
|
|
17
|
-
error: string | null
|
|
18
|
-
lastAction: OptimisticMediaAction | null
|
|
19
|
-
retryCount: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// State persistence configuration
|
|
23
|
-
export interface PersistenceConfig {
|
|
24
|
-
enabled: boolean
|
|
25
|
-
key: string
|
|
26
|
-
persist: Array<keyof MediaState>
|
|
27
|
-
debounceMs: number
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Enhanced media store interface
|
|
31
|
-
export interface EnhancedMediaStore {
|
|
32
|
-
// Original store interface
|
|
33
|
-
subscribe: (callback: () => void) => () => void
|
|
34
|
-
getState: () => MediaState
|
|
35
|
-
setState: (updates: Partial<MediaState>) => void
|
|
36
|
-
dispatch: (action: MediaAction) => void
|
|
37
|
-
|
|
38
|
-
// React 19 enhancements
|
|
39
|
-
getOptimisticState: () => MediaState
|
|
40
|
-
dispatchOptimistic: (action: OptimisticMediaAction) => Promise<void>
|
|
41
|
-
rollbackOptimistic: (actionId: string) => void
|
|
42
|
-
getActionState: () => MediaActionState
|
|
43
|
-
setPersistenceConfig: (config: Partial<PersistenceConfig>) => void
|
|
44
|
-
rehydrateFromStorage: () => Promise<void>
|
|
45
|
-
clearPersistedState: () => void
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Default persistence configuration
|
|
49
|
-
const DEFAULT_PERSISTENCE_CONFIG: PersistenceConfig = {
|
|
50
|
-
enabled: true,
|
|
51
|
-
key: "baroi-player-state",
|
|
52
|
-
persist: ["volume", "isMuted", "playbackRate", "subtitlesShowing"],
|
|
53
|
-
debounceMs: 500
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Create enhanced media store with React 19 features
|
|
57
|
-
export function createEnhancedMediaStore(
|
|
58
|
-
initialState: MediaState = initialMediaState,
|
|
59
|
-
persistenceConfig: Partial<PersistenceConfig> = {}
|
|
60
|
-
): EnhancedMediaStore {
|
|
61
|
-
let state = { ...initialState }
|
|
62
|
-
let optimisticState = { ...initialState }
|
|
63
|
-
let actionState: MediaActionState = {
|
|
64
|
-
pending: false,
|
|
65
|
-
error: null,
|
|
66
|
-
lastAction: null,
|
|
67
|
-
retryCount: 0
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const config = { ...DEFAULT_PERSISTENCE_CONFIG, ...persistenceConfig }
|
|
71
|
-
const listeners = new Set<() => void>()
|
|
72
|
-
const optimisticQueue = new Map<string, OptimisticMediaAction>()
|
|
73
|
-
let persistenceTimeout: NodeJS.Timeout | null = null
|
|
74
|
-
|
|
75
|
-
const subscribe = (callback: () => void) => {
|
|
76
|
-
listeners.add(callback)
|
|
77
|
-
return () => listeners.delete(callback)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const notifyListeners = () => {
|
|
81
|
-
listeners.forEach((callback) => callback())
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const getState = () => state
|
|
85
|
-
|
|
86
|
-
const getOptimisticState = () => optimisticState
|
|
87
|
-
|
|
88
|
-
const getActionState = () => actionState
|
|
89
|
-
|
|
90
|
-
// Persistence helpers
|
|
91
|
-
const persistState = async () => {
|
|
92
|
-
if (!config.enabled || typeof window === "undefined") return
|
|
93
|
-
|
|
94
|
-
const persistedData = config.persist.reduce(
|
|
95
|
-
(acc, key) => {
|
|
96
|
-
;(acc as any)[key] = state[key]
|
|
97
|
-
return acc
|
|
98
|
-
},
|
|
99
|
-
{} as Partial<MediaState>
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
localStorage.setItem(
|
|
104
|
-
config.key,
|
|
105
|
-
JSON.stringify({
|
|
106
|
-
...persistedData,
|
|
107
|
-
timestamp: Date.now()
|
|
108
|
-
})
|
|
109
|
-
)
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.warn("Failed to persist media state:", error)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const debouncedPersist = () => {
|
|
116
|
-
if (persistenceTimeout) {
|
|
117
|
-
clearTimeout(persistenceTimeout)
|
|
118
|
-
}
|
|
119
|
-
persistenceTimeout = setTimeout(persistState, config.debounceMs)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const rehydrateFromStorage = async () => {
|
|
123
|
-
if (!config.enabled || typeof window === "undefined") return
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const stored = localStorage.getItem(config.key)
|
|
127
|
-
if (!stored) return
|
|
128
|
-
|
|
129
|
-
const parsedData = JSON.parse(stored) as any
|
|
130
|
-
const { timestamp, ...persistedState } = parsedData
|
|
131
|
-
|
|
132
|
-
// Only rehydrate if data is less than 7 days old
|
|
133
|
-
const maxAge = 7 * 24 * 60 * 60 * 1000 // 7 days
|
|
134
|
-
if (timestamp && Date.now() - timestamp > maxAge) {
|
|
135
|
-
clearPersistedState()
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Merge persisted state with current state
|
|
140
|
-
const newState = { ...state, ...persistedState }
|
|
141
|
-
if (JSON.stringify(newState) !== JSON.stringify(state)) {
|
|
142
|
-
state = newState
|
|
143
|
-
optimisticState = { ...newState }
|
|
144
|
-
notifyListeners()
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.warn("Failed to rehydrate media state:", error)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const clearPersistedState = () => {
|
|
152
|
-
if (typeof window === "undefined") return
|
|
153
|
-
try {
|
|
154
|
-
localStorage.removeItem(config.key)
|
|
155
|
-
} catch (error) {
|
|
156
|
-
console.warn("Failed to clear persisted state:", error)
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const setPersistenceConfig = (newConfig: Partial<PersistenceConfig>) => {
|
|
161
|
-
Object.assign(config, newConfig)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const setState = (updates: Partial<MediaState>) => {
|
|
165
|
-
const newState = { ...state, ...updates }
|
|
166
|
-
if (JSON.stringify(newState) !== JSON.stringify(state)) {
|
|
167
|
-
state = newState
|
|
168
|
-
optimisticState = { ...newState }
|
|
169
|
-
|
|
170
|
-
// Persist relevant changes
|
|
171
|
-
debouncedPersist()
|
|
172
|
-
notifyListeners()
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const applyOptimisticUpdate = (action: OptimisticMediaAction) => {
|
|
177
|
-
const actionId = `${action.type}-${Date.now()}-${Math.random()}`
|
|
178
|
-
|
|
179
|
-
// Store original action for rollback
|
|
180
|
-
optimisticQueue.set(actionId, { ...action, timestamp: Date.now() })
|
|
181
|
-
|
|
182
|
-
// Apply optimistic update to optimistic state
|
|
183
|
-
const optimisticUpdate = processMediaAction(optimisticState, action)
|
|
184
|
-
optimisticState = { ...optimisticState, ...optimisticUpdate }
|
|
185
|
-
|
|
186
|
-
notifyListeners()
|
|
187
|
-
return actionId
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const rollbackOptimistic = (actionId: string) => {
|
|
191
|
-
if (!optimisticQueue.has(actionId)) return
|
|
192
|
-
|
|
193
|
-
// Remove from queue and recalculate optimistic state
|
|
194
|
-
optimisticQueue.delete(actionId)
|
|
195
|
-
|
|
196
|
-
// Rebuild optimistic state from actual state + remaining optimistic actions
|
|
197
|
-
optimisticState = { ...state }
|
|
198
|
-
for (const [, action] of optimisticQueue) {
|
|
199
|
-
const update = processMediaAction(optimisticState, action)
|
|
200
|
-
optimisticState = { ...optimisticState, ...update }
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
notifyListeners()
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Process media action and return state updates
|
|
207
|
-
const processMediaAction = (
|
|
208
|
-
currentState: MediaState,
|
|
209
|
-
action: MediaAction
|
|
210
|
-
): Partial<MediaState> => {
|
|
211
|
-
switch (action.type) {
|
|
212
|
-
case MediaActionTypes.PLAY:
|
|
213
|
-
return { isPlaying: true, error: null }
|
|
214
|
-
|
|
215
|
-
case MediaActionTypes.PAUSE:
|
|
216
|
-
return { isPlaying: false }
|
|
217
|
-
|
|
218
|
-
case MediaActionTypes.SEEK:
|
|
219
|
-
return { currentTime: action.detail }
|
|
220
|
-
|
|
221
|
-
case MediaActionTypes.SET_VOLUME:
|
|
222
|
-
return { volume: Math.max(0, Math.min(1, action.detail)) }
|
|
223
|
-
|
|
224
|
-
case MediaActionTypes.MUTE:
|
|
225
|
-
return { isMuted: true }
|
|
226
|
-
|
|
227
|
-
case MediaActionTypes.UNMUTE:
|
|
228
|
-
return { isMuted: false }
|
|
229
|
-
|
|
230
|
-
case MediaActionTypes.TOGGLE_MUTE:
|
|
231
|
-
return { isMuted: !currentState.isMuted }
|
|
232
|
-
|
|
233
|
-
case MediaActionTypes.SET_DURATION:
|
|
234
|
-
return { duration: action.detail }
|
|
235
|
-
|
|
236
|
-
case MediaActionTypes.SET_CURRENT_TIME:
|
|
237
|
-
return { currentTime: action.detail }
|
|
238
|
-
|
|
239
|
-
case MediaActionTypes.SET_BUFFERED:
|
|
240
|
-
return { buffered: action.detail }
|
|
241
|
-
|
|
242
|
-
case MediaActionTypes.SET_LOADING:
|
|
243
|
-
return { isLoading: action.detail }
|
|
244
|
-
|
|
245
|
-
case MediaActionTypes.SET_ERROR:
|
|
246
|
-
return { error: action.detail, isLoading: false }
|
|
247
|
-
|
|
248
|
-
case MediaActionTypes.ENTER_FULLSCREEN:
|
|
249
|
-
return { isFullscreen: true }
|
|
250
|
-
|
|
251
|
-
case MediaActionTypes.EXIT_FULLSCREEN:
|
|
252
|
-
return { isFullscreen: false }
|
|
253
|
-
|
|
254
|
-
case MediaActionTypes.ENTER_PIP:
|
|
255
|
-
return { isPictureInPicture: true }
|
|
256
|
-
|
|
257
|
-
case MediaActionTypes.EXIT_PIP:
|
|
258
|
-
return { isPictureInPicture: false }
|
|
259
|
-
|
|
260
|
-
case MediaActionTypes.SET_PLAYBACK_RATE:
|
|
261
|
-
return { playbackRate: action.detail }
|
|
262
|
-
|
|
263
|
-
case MediaActionTypes.SET_SUBTITLE_TRACK:
|
|
264
|
-
return { selectedSubtitleTrack: action.detail }
|
|
265
|
-
|
|
266
|
-
case MediaActionTypes.SET_RENDITION:
|
|
267
|
-
return { selectedRendition: action.detail }
|
|
268
|
-
|
|
269
|
-
case MediaActionTypes.TOGGLE_SUBTITLES:
|
|
270
|
-
return { subtitlesShowing: !currentState.subtitlesShowing }
|
|
271
|
-
|
|
272
|
-
case MediaActionTypes.PREVIEW_TIME:
|
|
273
|
-
return { previewTime: action.detail }
|
|
274
|
-
|
|
275
|
-
case MediaActionTypes.CLEAR_PREVIEW:
|
|
276
|
-
return { previewTime: null, previewImage: null, previewCoords: null }
|
|
277
|
-
|
|
278
|
-
default:
|
|
279
|
-
console.warn(`Unknown media action type: ${action.type}`)
|
|
280
|
-
return {}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const dispatch = (action: MediaAction) => {
|
|
285
|
-
const updates = processMediaAction(state, action)
|
|
286
|
-
setState(updates)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const dispatchOptimistic = async (action: OptimisticMediaAction): Promise<void> => {
|
|
290
|
-
// Set action state to pending
|
|
291
|
-
actionState = {
|
|
292
|
-
pending: true,
|
|
293
|
-
error: null,
|
|
294
|
-
lastAction: action,
|
|
295
|
-
retryCount: action.retryCount || 0
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Apply optimistic update immediately
|
|
299
|
-
const actionId = applyOptimisticUpdate(action)
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
// Simulate async operation (e.g., network request, DOM manipulation)
|
|
303
|
-
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
304
|
-
|
|
305
|
-
// Apply the actual update to the real state
|
|
306
|
-
const updates = processMediaAction(state, action)
|
|
307
|
-
const newState = { ...state, ...updates }
|
|
308
|
-
|
|
309
|
-
if (JSON.stringify(newState) !== JSON.stringify(state)) {
|
|
310
|
-
state = newState
|
|
311
|
-
debouncedPersist()
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Clean up optimistic action
|
|
315
|
-
optimisticQueue.delete(actionId)
|
|
316
|
-
|
|
317
|
-
// Update action state
|
|
318
|
-
actionState = {
|
|
319
|
-
pending: false,
|
|
320
|
-
error: null,
|
|
321
|
-
lastAction: action,
|
|
322
|
-
retryCount: 0
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Sync optimistic state with actual state
|
|
326
|
-
optimisticState = { ...state }
|
|
327
|
-
for (const [, queuedAction] of optimisticQueue) {
|
|
328
|
-
const update = processMediaAction(optimisticState, queuedAction)
|
|
329
|
-
optimisticState = { ...optimisticState, ...update }
|
|
330
|
-
}
|
|
331
|
-
} catch (error) {
|
|
332
|
-
// Rollback optimistic update on error
|
|
333
|
-
rollbackOptimistic(actionId)
|
|
334
|
-
|
|
335
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"
|
|
336
|
-
actionState = {
|
|
337
|
-
pending: false,
|
|
338
|
-
error: errorMessage,
|
|
339
|
-
lastAction: action,
|
|
340
|
-
retryCount: (action.retryCount || 0) + 1
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Auto-retry logic for certain actions
|
|
344
|
-
if (actionState.retryCount < 3 && shouldRetry(action.type)) {
|
|
345
|
-
setTimeout(() => {
|
|
346
|
-
dispatchOptimistic({
|
|
347
|
-
...action,
|
|
348
|
-
retryCount: actionState.retryCount
|
|
349
|
-
})
|
|
350
|
-
}, Math.pow(2, actionState.retryCount) * 1000) // Exponential backoff
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
notifyListeners()
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Determine if an action should be retried
|
|
358
|
-
const shouldRetry = (actionType: MediaActionType): boolean => {
|
|
359
|
-
const retryableActions: MediaActionType[] = [
|
|
360
|
-
MediaActionTypes.PLAY,
|
|
361
|
-
MediaActionTypes.PAUSE,
|
|
362
|
-
MediaActionTypes.SEEK,
|
|
363
|
-
MediaActionTypes.SET_VOLUME,
|
|
364
|
-
MediaActionTypes.MUTE,
|
|
365
|
-
MediaActionTypes.UNMUTE,
|
|
366
|
-
MediaActionTypes.TOGGLE_MUTE
|
|
367
|
-
]
|
|
368
|
-
return retryableActions.includes(actionType)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Initialize with rehydrated state
|
|
372
|
-
rehydrateFromStorage()
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
subscribe,
|
|
376
|
-
getState,
|
|
377
|
-
setState,
|
|
378
|
-
dispatch,
|
|
379
|
-
getOptimisticState,
|
|
380
|
-
dispatchOptimistic,
|
|
381
|
-
rollbackOptimistic,
|
|
382
|
-
getActionState,
|
|
383
|
-
setPersistenceConfig,
|
|
384
|
-
rehydrateFromStorage,
|
|
385
|
-
clearPersistedState
|
|
386
|
-
}
|
|
387
|
-
}
|