@therealtinhtute/baroiplayer 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-plugins-By-4-kGs.cjs +2 -0
- package/dist/core-plugins-By-4-kGs.cjs.map +1 -0
- package/dist/{core-plugins-CROGvQUy.js → core-plugins-DSBWcTuX.js} +444 -309
- package/dist/core-plugins-DSBWcTuX.js.map +1 -0
- package/dist/core.js +2 -2
- package/dist/core.mjs +19 -19
- package/dist/{enhanced-components-DUw2KrmQ.js → enhanced-components-B_l3cist.js} +2 -2
- package/dist/{enhanced-components-DUw2KrmQ.js.map → enhanced-components-B_l3cist.js.map} +1 -1
- package/dist/{enhanced-components-DXBCHU0v.cjs → enhanced-components-BspFs9OO.cjs} +2 -2
- package/dist/{enhanced-components-DXBCHU0v.cjs.map → enhanced-components-BspFs9OO.cjs.map} +1 -1
- package/dist/hooks-BXwI8QG6.cjs +4 -0
- package/dist/hooks-BXwI8QG6.cjs.map +1 -0
- package/dist/hooks-Bpi-jDiO.js +1816 -0
- package/dist/hooks-Bpi-jDiO.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -20
- package/dist/index.mjs.map +1 -1
- package/dist/{minimal-components-DlRK7Qu_.js → minimal-components-C4z900Ro.js} +297 -298
- package/dist/minimal-components-C4z900Ro.js.map +1 -0
- package/dist/minimal-components-v4qBp6jv.cjs +2 -0
- package/dist/minimal-components-v4qBp6jv.cjs.map +1 -0
- package/package.json +1 -1
- package/src/components/accessibility/keyboard-help-overlay.tsx +2 -0
- package/src/components/enhanced/debug-panel.tsx +1 -1
- package/src/components/enhanced/enhanced-media-player.tsx +68 -25
- package/src/components/legacy.tsx +6 -6
- package/src/components/media-player-video.tsx +5 -12
- package/src/components/media-player.tsx +2 -2
- package/src/components/ui/enhanced-seek-bar.tsx +2 -2
- package/src/components/ui/media-resource-preloader.tsx +21 -23
- package/src/components/unified/base-media-player.tsx +22 -10
- package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +58 -38
- package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +6 -6
- package/src/core/optimization/bundle-optimizer.tsx +26 -27
- package/src/core/plugins/__tests__/registry.test.ts +1 -1
- package/src/core/plugins/enhanced-plugin-system.ts +26 -8
- package/src/core/plugins/registry.ts +319 -92
- package/src/core/plugins/types.ts +21 -3
- package/src/core/providers/enhanced-hls-provider.ts +11 -40
- package/src/core/providers/lazy-provider.tsx +5 -42
- package/src/features/media-session/media-session-manager.ts +4 -26
- package/src/features/picture-in-picture/pip-manager.ts +2 -2
- package/src/features/playlist/playlist-manager.ts +26 -18
- package/src/features/subtitles/subtitle-manager.ts +1 -1
- package/src/features/subtitles/subtitle-parser.ts +19 -16
- package/src/features/thumbnails/thumbnail-generator.ts +12 -5
- package/src/hooks/__tests__/currentTime-fix.test.ts +149 -0
- package/src/hooks/accessibility/use-accessibility-preferences.ts +1 -1
- package/src/hooks/accessibility/use-focus-management.ts +2 -2
- package/src/hooks/accessibility/use-keyboard-shortcuts.ts +2 -2
- package/src/hooks/accessibility/use-screen-reader.ts +1 -1
- package/src/hooks/core/index.ts +1 -1
- package/src/hooks/use-buffer-health.ts +1 -1
- package/src/hooks/use-enhanced-media-player.ts +107 -9
- package/src/hooks/use-focus-trap.tsx +2 -2
- package/src/hooks/use-intelligent-preloading.ts +23 -3
- package/src/hooks/use-keyboard-shortcuts.ts +2 -2
- package/src/hooks/use-media-player.ts +74 -43
- package/src/hooks/use-memory-optimization.ts +15 -15
- package/src/hooks/use-smart-preload.ts +1 -2
- package/src/hooks/useKeyboardShortcuts.ts +34 -2
- package/src/hooks/useVideoPlayer.ts +50 -4
- package/src/index-legacy.ts +3 -5
- package/src/test/accessibility-utils.ts +7 -7
- package/src/test/media-mocks.ts +41 -28
- package/src/test/setup.ts +22 -4
- package/src/types/index.ts +13 -0
- package/dist/core-plugins-CROGvQUy.js.map +0 -1
- package/dist/core-plugins-DtsHBOtF.cjs +0 -2
- package/dist/core-plugins-DtsHBOtF.cjs.map +0 -1
- package/dist/hooks-BW-JjVgP.cjs +0 -4
- package/dist/hooks-BW-JjVgP.cjs.map +0 -1
- package/dist/hooks-CyX6De5M.js +0 -1693
- package/dist/hooks-CyX6De5M.js.map +0 -1
- package/dist/minimal-components-Bdcpxav5.cjs +0 -2
- package/dist/minimal-components-Bdcpxav5.cjs.map +0 -1
- package/dist/minimal-components-DlRK7Qu_.js.map +0 -1
|
@@ -21,10 +21,25 @@ import {
|
|
|
21
21
|
} from "../../core/providers/enhanced-hls-provider"
|
|
22
22
|
import { useIntelligentPreloading } from "../../hooks/use-intelligent-preloading"
|
|
23
23
|
import { cn } from "../../lib/utils"
|
|
24
|
-
import { MediaPlayerProps,
|
|
24
|
+
import { MediaPlayerProps, type MediaMimeType } from "../../types"
|
|
25
25
|
import { MediaResourcePreloader } from "../ui/media-resource-preloader"
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// Extend MediaMimeType to include HLS and define extended MediaSource
|
|
28
|
+
type ExtendedMediaMimeType = MediaMimeType | "hls"
|
|
29
|
+
|
|
30
|
+
interface ExtendedMediaSource {
|
|
31
|
+
src: string
|
|
32
|
+
type?: ExtendedMediaMimeType
|
|
33
|
+
media?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface EnhancedMediaPlayerProps extends Omit<MediaPlayerProps, 'src' | 'onTimeUpdate' | 'onError'> {
|
|
37
|
+
src?: string
|
|
38
|
+
sources?: ExtendedMediaSource[]
|
|
39
|
+
controls?: boolean
|
|
40
|
+
onCanPlay?: () => void
|
|
41
|
+
onTimeUpdate?: () => void
|
|
42
|
+
onError?: (error: MediaError) => void
|
|
28
43
|
/** Enable enhanced HLS optimization */
|
|
29
44
|
enableEnhancedHLS?: boolean
|
|
30
45
|
/** Enable intelligent preloading */
|
|
@@ -84,7 +99,18 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
84
99
|
onTimeUpdate,
|
|
85
100
|
onLoadStart,
|
|
86
101
|
onCanPlay,
|
|
87
|
-
|
|
102
|
+
onDurationChange,
|
|
103
|
+
onVolumeChange,
|
|
104
|
+
onLoadedData,
|
|
105
|
+
volume,
|
|
106
|
+
preload,
|
|
107
|
+
crossOrigin,
|
|
108
|
+
playbackRates,
|
|
109
|
+
keyboardControls,
|
|
110
|
+
showControls,
|
|
111
|
+
customControls,
|
|
112
|
+
children,
|
|
113
|
+
...restProps
|
|
88
114
|
}) => {
|
|
89
115
|
const videoRef = useRef<HTMLVideoElement>(null)
|
|
90
116
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
@@ -125,20 +151,20 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
125
151
|
const deferredVolume = useDeferredValue(mediaState.volume)
|
|
126
152
|
|
|
127
153
|
// Prepare media sources
|
|
128
|
-
const mediaSources = useMemo(():
|
|
154
|
+
const mediaSources = useMemo((): ExtendedMediaSource[] => {
|
|
129
155
|
if (sources) {
|
|
130
156
|
return sources
|
|
131
157
|
}
|
|
132
158
|
if (src) {
|
|
133
159
|
const extension = src.split(".").pop()?.toLowerCase()
|
|
134
160
|
const type = getMediaTypeFromExtension(extension)
|
|
135
|
-
return [{ src, type }]
|
|
161
|
+
return [{ src, type: type as ExtendedMediaMimeType }]
|
|
136
162
|
}
|
|
137
163
|
return []
|
|
138
164
|
}, [src, sources])
|
|
139
165
|
|
|
140
166
|
// Intelligent preloading
|
|
141
|
-
const preloadingControls = useIntelligentPreloading(mediaSources, {
|
|
167
|
+
const preloadingControls = useIntelligentPreloading(mediaSources as any, {
|
|
142
168
|
trackUserBehavior: enableIntelligentPreloading,
|
|
143
169
|
adaptToNetwork: true,
|
|
144
170
|
strategy: preloadingStrategy,
|
|
@@ -147,18 +173,23 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
147
173
|
|
|
148
174
|
// Initialize HLS provider
|
|
149
175
|
const initializeHLS = useCallback(async () => {
|
|
150
|
-
if (!videoRef.current || !enableEnhancedHLS) return
|
|
176
|
+
if (!videoRef.current || !enableEnhancedHLS || !mediaSources[0]?.src) return
|
|
151
177
|
|
|
152
|
-
const
|
|
153
|
-
const provider = new EnhancedHLSProvider(
|
|
178
|
+
const mergedHlsConfig = { ...ENHANCED_HLS_DEFAULTS, ...hlsConfig }
|
|
179
|
+
const provider = new EnhancedHLSProvider(mergedHlsConfig)
|
|
154
180
|
hlsProviderRef.current = provider
|
|
155
181
|
|
|
156
182
|
try {
|
|
157
183
|
const hls = provider.initialize(videoRef.current, mediaSources[0].src, {
|
|
158
|
-
|
|
159
|
-
|
|
184
|
+
autoPlay,
|
|
185
|
+
muted,
|
|
186
|
+
loop,
|
|
187
|
+
preload,
|
|
188
|
+
crossOrigin
|
|
160
189
|
})
|
|
161
190
|
|
|
191
|
+
// Import Hls dynamically to access Events
|
|
192
|
+
const Hls = (await import('hls.js')).default
|
|
162
193
|
// Setup HLS event listeners
|
|
163
194
|
hls.on(Hls.Events.LEVEL_SWITCHED, handleQualityChange)
|
|
164
195
|
hls.on(Hls.Events.FRAG_BUFFERED, handleFragmentBuffered)
|
|
@@ -167,7 +198,7 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
167
198
|
console.error("HLS initialization failed:", error)
|
|
168
199
|
fallbackToNativePlayback()
|
|
169
200
|
}
|
|
170
|
-
}, [enableEnhancedHLS, hlsConfig, mediaSources])
|
|
201
|
+
}, [enableEnhancedHLS, hlsConfig, mediaSources, autoPlay, muted, loop, preload, crossOrigin])
|
|
171
202
|
|
|
172
203
|
// Fallback to native playback
|
|
173
204
|
const fallbackToNativePlayback = useCallback(() => {
|
|
@@ -175,7 +206,7 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
175
206
|
|
|
176
207
|
const source = document.createElement("source")
|
|
177
208
|
source.src = mediaSources[0].src
|
|
178
|
-
source.type = getMediaTypeFromUrl(mediaSources[0].src)
|
|
209
|
+
source.type = getMediaTypeFromUrl(mediaSources[0].src) || "video/mp4"
|
|
179
210
|
|
|
180
211
|
videoRef.current.appendChild(source)
|
|
181
212
|
videoRef.current.load()
|
|
@@ -265,11 +296,13 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
265
296
|
}, [])
|
|
266
297
|
|
|
267
298
|
const handleMediaError = useCallback(
|
|
268
|
-
(error: MediaError) => {
|
|
299
|
+
(error: MediaError | Error) => {
|
|
269
300
|
startTransition(() => {
|
|
270
|
-
setMediaState((prev) => ({ ...prev, error }))
|
|
301
|
+
setMediaState((prev) => ({ ...prev, error: error as MediaError }))
|
|
271
302
|
})
|
|
272
|
-
|
|
303
|
+
// Convert to string for the callback
|
|
304
|
+
const errorMessage = error instanceof Error ? error.message : `Media error code: ${error.code}`
|
|
305
|
+
onError?.(error as MediaError)
|
|
273
306
|
},
|
|
274
307
|
[onError]
|
|
275
308
|
)
|
|
@@ -278,7 +311,9 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
278
311
|
(event: any, data: any) => {
|
|
279
312
|
if (data.fatal) {
|
|
280
313
|
console.error("Fatal HLS error:", data)
|
|
281
|
-
|
|
314
|
+
const mediaError = new Error(`HLS Error: ${data.details}`) as any
|
|
315
|
+
mediaError.code = 4 // MEDIA_ERR_SRC_NOT_SUPPORTED
|
|
316
|
+
handleMediaError(mediaError)
|
|
282
317
|
}
|
|
283
318
|
},
|
|
284
319
|
[handleMediaError]
|
|
@@ -348,11 +383,15 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
348
383
|
video.addEventListener("timeupdate", handleTimeUpdate)
|
|
349
384
|
video.addEventListener("loadedmetadata", handleLoadedMetadata)
|
|
350
385
|
video.addEventListener("volumechange", handleVolumeChange)
|
|
351
|
-
|
|
352
|
-
|
|
386
|
+
if (onLoadStart) {
|
|
387
|
+
video.addEventListener("loadstart", onLoadStart)
|
|
388
|
+
}
|
|
389
|
+
if (onCanPlay) {
|
|
390
|
+
video.addEventListener("canplay", onCanPlay)
|
|
391
|
+
}
|
|
353
392
|
|
|
354
393
|
// Initialize HLS if needed
|
|
355
|
-
if (mediaSources[0]
|
|
394
|
+
if (mediaSources[0]?.type === "hls" && enableEnhancedHLS) {
|
|
356
395
|
initializeHLS()
|
|
357
396
|
} else {
|
|
358
397
|
fallbackToNativePlayback()
|
|
@@ -371,8 +410,12 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
371
410
|
video.removeEventListener("timeupdate", handleTimeUpdate)
|
|
372
411
|
video.removeEventListener("loadedmetadata", handleLoadedMetadata)
|
|
373
412
|
video.removeEventListener("volumechange", handleVolumeChange)
|
|
374
|
-
|
|
375
|
-
|
|
413
|
+
if (onLoadStart) {
|
|
414
|
+
video.removeEventListener("loadstart", onLoadStart)
|
|
415
|
+
}
|
|
416
|
+
if (onCanPlay) {
|
|
417
|
+
video.removeEventListener("canplay", onCanPlay)
|
|
418
|
+
}
|
|
376
419
|
|
|
377
420
|
hlsProviderRef.current?.destroy()
|
|
378
421
|
pluginManagerRef.current?.dispose()
|
|
@@ -439,15 +482,15 @@ export const EnhancedMediaPlayer: React.FC<EnhancedMediaPlayerProps> = ({
|
|
|
439
482
|
<div
|
|
440
483
|
ref={containerRef}
|
|
441
484
|
className={cn("relative aspect-video overflow-hidden rounded-lg bg-black", className)}
|
|
442
|
-
{...
|
|
485
|
+
{...restProps}>
|
|
443
486
|
{/* Media Resource Preloader */}
|
|
444
487
|
{enableIntelligentPreloading && (
|
|
445
488
|
<MediaResourcePreloader
|
|
446
|
-
sources={mediaSources}
|
|
489
|
+
sources={mediaSources as any}
|
|
447
490
|
enableIntelligentPreloading={true}
|
|
448
491
|
adaptToNetworkConditions={true}
|
|
449
492
|
priority="auto"
|
|
450
|
-
strategy={preloadingStrategy}
|
|
493
|
+
strategy={preloadingStrategy === "balanced" ? "adaptive" : preloadingStrategy}
|
|
451
494
|
/>
|
|
452
495
|
)}
|
|
453
496
|
|
|
@@ -30,7 +30,7 @@ ModernMediaPlayer.displayName = "DeprecatedModernMediaPlayer"
|
|
|
30
30
|
|
|
31
31
|
export const SimpleVideoPlayer = React.forwardRef<any, any>((props, ref) => {
|
|
32
32
|
showDeprecationWarning("SimpleVideoPlayer", "VideoPlayer (the primary video player component)")
|
|
33
|
-
return <SimpleVideoPlayerBase {...props
|
|
33
|
+
return <SimpleVideoPlayerBase {...(props as any)} />
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
SimpleVideoPlayer.displayName = "DeprecatedSimpleVideoPlayer"
|
|
@@ -41,7 +41,7 @@ export const LegacyPlayButton = React.forwardRef<any, any>((props, ref) => {
|
|
|
41
41
|
"PlayButton",
|
|
42
42
|
"Use MediaPlayer compound components or MediaPlayer (all-in-one)"
|
|
43
43
|
)
|
|
44
|
-
return <PlayButton {...props
|
|
44
|
+
return <PlayButton {...(props as any)} />
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
LegacyPlayButton.displayName = "DeprecatedPlayButton"
|
|
@@ -51,7 +51,7 @@ export const LegacySeekBar = React.forwardRef<any, any>((props, ref) => {
|
|
|
51
51
|
"SeekBar",
|
|
52
52
|
"Use MediaPlayer compound components or MediaPlayer (all-in-one)"
|
|
53
53
|
)
|
|
54
|
-
return <SeekBar {...props
|
|
54
|
+
return <SeekBar {...(props as any)} />
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
LegacySeekBar.displayName = "DeprecatedSeekBar"
|
|
@@ -61,7 +61,7 @@ export const LegacyTimeDisplay = React.forwardRef<any, any>((props, ref) => {
|
|
|
61
61
|
"TimeDisplay",
|
|
62
62
|
"Use MediaPlayer compound components or MediaPlayer (all-in-one)"
|
|
63
63
|
)
|
|
64
|
-
return <TimeDisplay {...props
|
|
64
|
+
return <TimeDisplay {...(props as any)} />
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
LegacyTimeDisplay.displayName = "DeprecatedTimeDisplay"
|
|
@@ -71,7 +71,7 @@ export const LegacyVolumeControl = React.forwardRef<any, any>((props, ref) => {
|
|
|
71
71
|
"VolumeControl",
|
|
72
72
|
"Use MediaPlayer compound components or MediaPlayer (all-in-one)"
|
|
73
73
|
)
|
|
74
|
-
return <VolumeControl {...props
|
|
74
|
+
return <VolumeControl {...(props as any)} />
|
|
75
75
|
})
|
|
76
76
|
|
|
77
77
|
LegacyVolumeControl.displayName = "DeprecatedVolumeControl"
|
|
@@ -81,7 +81,7 @@ export const LegacyFullscreenButton = React.forwardRef<any, any>((props, ref) =>
|
|
|
81
81
|
"FullscreenButton",
|
|
82
82
|
"Use MediaPlayer compound components or MediaPlayer (all-in-one)"
|
|
83
83
|
)
|
|
84
|
-
return <FullscreenButton {...props
|
|
84
|
+
return <FullscreenButton {...(props as any)} />
|
|
85
85
|
})
|
|
86
86
|
|
|
87
87
|
LegacyFullscreenButton.displayName = "DeprecatedFullscreenButton"
|
|
@@ -5,12 +5,12 @@ import { useMediaContext } from "../context/media-context"
|
|
|
5
5
|
|
|
6
6
|
// Utility function to compose refs
|
|
7
7
|
function composeRefs<T>(...refs: Array<React.Ref<T> | undefined>) {
|
|
8
|
-
return (node: T) => {
|
|
8
|
+
return (node: T | null) => {
|
|
9
9
|
refs.forEach((ref) => {
|
|
10
10
|
if (typeof ref === "function") {
|
|
11
11
|
ref(node)
|
|
12
12
|
} else if (ref) {
|
|
13
|
-
;(ref as React.MutableRefObject<T>).current = node
|
|
13
|
+
;(ref as React.MutableRefObject<T | null>).current = node
|
|
14
14
|
}
|
|
15
15
|
})
|
|
16
16
|
}
|
|
@@ -29,18 +29,11 @@ export function MediaPlayerVideo({
|
|
|
29
29
|
const context = useMediaContext()
|
|
30
30
|
|
|
31
31
|
// Create a ref that will be composed with the context mediaRef when mounted
|
|
32
|
-
const
|
|
33
|
-
() =>
|
|
34
|
-
|
|
35
|
-
return composeRefs(context.mediaRef)
|
|
36
|
-
}
|
|
32
|
+
const combinedRef = React.useMemo(
|
|
33
|
+
() => composeRefs(context.mediaRef),
|
|
34
|
+
[context.mediaRef]
|
|
37
35
|
)
|
|
38
36
|
|
|
39
|
-
// Update combined ref when context changes (but this won't trigger render)
|
|
40
|
-
React.useEffect(() => {
|
|
41
|
-
setCombinedRef(() => composeRefs(context.mediaRef))
|
|
42
|
-
}, [context.mediaRef])
|
|
43
|
-
|
|
44
37
|
if (asChild) {
|
|
45
38
|
// When asChild is true, clone the child element and add our props
|
|
46
39
|
const child = React.Children.only(children) as React.ReactElement
|
|
@@ -191,7 +191,7 @@ export const MediaPlayer = forwardRef<HTMLDivElement, MediaPlayerProps>(
|
|
|
191
191
|
playsInline
|
|
192
192
|
x-webkit-airplay="allow"
|
|
193
193
|
style={{ willChange: "transform" }}>
|
|
194
|
-
{renderSources
|
|
194
|
+
{renderSources}
|
|
195
195
|
Your browser does not support the video element.
|
|
196
196
|
</video>
|
|
197
197
|
) : (
|
|
@@ -201,7 +201,7 @@ export const MediaPlayer = forwardRef<HTMLDivElement, MediaPlayerProps>(
|
|
|
201
201
|
// Performance optimizations
|
|
202
202
|
preload={preloadStrategy === "eager" ? "auto" : "metadata"}
|
|
203
203
|
>
|
|
204
|
-
{renderSources
|
|
204
|
+
{renderSources}
|
|
205
205
|
Your browser does not support the audio element.
|
|
206
206
|
</audio>
|
|
207
207
|
)}
|
|
@@ -28,9 +28,9 @@ export const EnhancedSeekBar = forwardRef<HTMLDivElement, SeekBarProps>(
|
|
|
28
28
|
const deferredPreviewTime = useDeferredValue(previewTime)
|
|
29
29
|
|
|
30
30
|
// Throttling refs
|
|
31
|
-
const seekTimeoutRef = useRef<NodeJS.Timeout>()
|
|
31
|
+
const seekTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
|
|
32
32
|
const lastSeekTime = useRef<number>(0)
|
|
33
|
-
const rafId = useRef<number>()
|
|
33
|
+
const rafId = useRef<number | undefined>(undefined)
|
|
34
34
|
|
|
35
35
|
// Memoize expensive calculations
|
|
36
36
|
const progress = useMemo(
|
|
@@ -34,7 +34,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
34
34
|
priority = "auto",
|
|
35
35
|
strategy = "adaptive"
|
|
36
36
|
}) => {
|
|
37
|
-
const networkInfoRef = useRef<
|
|
37
|
+
const networkInfoRef = useRef<any>(null)
|
|
38
38
|
const userBehaviorRef = useRef<UserBehaviorTracker | null>(null)
|
|
39
39
|
const preloadingHistoryRef = useRef<Map<string, number>>(new Map())
|
|
40
40
|
|
|
@@ -56,10 +56,9 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
56
56
|
|
|
57
57
|
// Preload the content
|
|
58
58
|
preload(url, {
|
|
59
|
-
as: "fetch",
|
|
60
|
-
crossOrigin: "anonymous"
|
|
61
|
-
|
|
62
|
-
})
|
|
59
|
+
as: "fetch" as any,
|
|
60
|
+
crossOrigin: "anonymous"
|
|
61
|
+
} as any)
|
|
63
62
|
})
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -92,7 +91,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
// Preconnect to media domains
|
|
95
|
-
if (shouldPreconnect(source.type, strategy)) {
|
|
94
|
+
if (shouldPreconnect(source.type || "", strategy)) {
|
|
96
95
|
config.preconnect.push(domain)
|
|
97
96
|
}
|
|
98
97
|
|
|
@@ -100,7 +99,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
100
99
|
if (shouldPreloadBasic(source, priority, strategy)) {
|
|
101
100
|
config.preload.push({
|
|
102
101
|
url: source.src,
|
|
103
|
-
type: getPreloadType(source.type)
|
|
102
|
+
type: getPreloadType(source.type || "")
|
|
104
103
|
})
|
|
105
104
|
}
|
|
106
105
|
|
|
@@ -133,7 +132,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
133
132
|
|
|
134
133
|
// Strategy-based decision
|
|
135
134
|
if (strategy === "conservative") {
|
|
136
|
-
return priority === "high" && source.type === "hls"
|
|
135
|
+
return priority === "high" && (source.type as string) === "hls"
|
|
137
136
|
}
|
|
138
137
|
|
|
139
138
|
if (strategy === "aggressive") {
|
|
@@ -146,10 +145,10 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
146
145
|
|
|
147
146
|
if (saveData) return false
|
|
148
147
|
if (effectiveType === "slow-2g" || effectiveType === "2g") {
|
|
149
|
-
return priority === "high" && source.type === "hls"
|
|
148
|
+
return priority === "high" && (source.type as string) === "hls"
|
|
150
149
|
}
|
|
151
150
|
if (effectiveType === "3g") {
|
|
152
|
-
return ["hls", "m3u8"].includes(source.type)
|
|
151
|
+
return ["hls", "m3u8"].includes(source.type || "")
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
154
|
|
|
@@ -208,11 +207,10 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
208
207
|
const crossOrigin = shouldUseCrossOrigin(url) ? "anonymous" : undefined
|
|
209
208
|
|
|
210
209
|
preload(url, {
|
|
211
|
-
as: type,
|
|
210
|
+
as: type as any,
|
|
212
211
|
crossOrigin,
|
|
213
|
-
integrity: getAssetIntegrity(url)
|
|
214
|
-
|
|
215
|
-
})
|
|
212
|
+
integrity: getAssetIntegrity(url)
|
|
213
|
+
} as any)
|
|
216
214
|
})
|
|
217
215
|
}, [filteredPreloadingConfig.preload, priority])
|
|
218
216
|
|
|
@@ -222,9 +220,9 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
222
220
|
const crossOrigin = shouldUseCrossOrigin(url) ? "anonymous" : undefined
|
|
223
221
|
|
|
224
222
|
preinit(url, {
|
|
225
|
-
as: type,
|
|
223
|
+
as: type as any,
|
|
226
224
|
crossOrigin
|
|
227
|
-
})
|
|
225
|
+
} as any)
|
|
228
226
|
})
|
|
229
227
|
}, [filteredPreloadingConfig.preinit])
|
|
230
228
|
|
|
@@ -264,7 +262,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
264
262
|
function shouldPreloadBasic(source: MediaSource, priority: string, strategy: string): boolean {
|
|
265
263
|
// Basic strategy-based decision without ref access
|
|
266
264
|
if (strategy === "conservative") {
|
|
267
|
-
return priority === "high" && source.type === "hls"
|
|
265
|
+
return priority === "high" && (source.type as string) === "hls"
|
|
268
266
|
}
|
|
269
267
|
|
|
270
268
|
if (strategy === "aggressive") {
|
|
@@ -280,7 +278,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
280
278
|
priority: string,
|
|
281
279
|
strategy: string,
|
|
282
280
|
preloadingHistory: Map<string, number>,
|
|
283
|
-
networkInfo:
|
|
281
|
+
networkInfo: any
|
|
284
282
|
): boolean {
|
|
285
283
|
// Check if already preloaded recently
|
|
286
284
|
const lastPreload = preloadingHistory.get(source.src)
|
|
@@ -288,7 +286,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
288
286
|
|
|
289
287
|
// Strategy-based decision
|
|
290
288
|
if (strategy === "conservative") {
|
|
291
|
-
return priority === "high" && source.type === "hls"
|
|
289
|
+
return priority === "high" && (source.type as string) === "hls"
|
|
292
290
|
}
|
|
293
291
|
|
|
294
292
|
if (strategy === "aggressive") {
|
|
@@ -302,7 +300,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
302
300
|
function shouldAdaptivePreload(
|
|
303
301
|
source: MediaSource,
|
|
304
302
|
priority: string,
|
|
305
|
-
networkInfo:
|
|
303
|
+
networkInfo: any
|
|
306
304
|
): boolean {
|
|
307
305
|
// Consider network conditions
|
|
308
306
|
if (networkInfo) {
|
|
@@ -310,10 +308,10 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
310
308
|
|
|
311
309
|
if (saveData) return false
|
|
312
310
|
if (effectiveType === "slow-2g" || effectiveType === "2g") {
|
|
313
|
-
return priority === "high" && source.type === "hls"
|
|
311
|
+
return priority === "high" && (source.type as string) === "hls"
|
|
314
312
|
}
|
|
315
313
|
if (effectiveType === "3g") {
|
|
316
|
-
return ["hls", "m3u8"].includes(source.type)
|
|
314
|
+
return ["hls", "m3u8"].includes(source.type || "")
|
|
317
315
|
}
|
|
318
316
|
}
|
|
319
317
|
|
|
@@ -329,7 +327,7 @@ export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
|
|
|
329
327
|
}
|
|
330
328
|
|
|
331
329
|
function shouldPreinit(source: MediaSource, strategy: string): boolean {
|
|
332
|
-
return strategy === "aggressive" && source.type === "hls"
|
|
330
|
+
return strategy === "aggressive" && (source.type as string) === "hls"
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
function getPreloadType(mediaType: string): string {
|
|
@@ -111,9 +111,16 @@ export const BaseMediaPlayer = forwardRef<HTMLDivElement, BaseMediaPlayerProps>(
|
|
|
111
111
|
|
|
112
112
|
// Determine the media element based on type
|
|
113
113
|
const MediaElement = useMemo(() => {
|
|
114
|
+
type MediaSource = { src: string; type?: string }
|
|
115
|
+
|
|
116
|
+
const srcString = typeof src === "string"
|
|
117
|
+
? src
|
|
118
|
+
: Array.isArray(src)
|
|
119
|
+
? (typeof src[0] === "string" ? src[0] : ((src[0] as unknown) as MediaSource)?.src || "")
|
|
120
|
+
: ""
|
|
121
|
+
|
|
114
122
|
const commonProps = {
|
|
115
|
-
|
|
116
|
-
src,
|
|
123
|
+
src: srcString,
|
|
117
124
|
className: cn(
|
|
118
125
|
"w-full h-full",
|
|
119
126
|
state.isLoading && "opacity-0",
|
|
@@ -129,8 +136,8 @@ export const BaseMediaPlayer = forwardRef<HTMLDivElement, BaseMediaPlayerProps>(
|
|
|
129
136
|
|
|
130
137
|
if (detectedMediaType === "audio") {
|
|
131
138
|
return (
|
|
132
|
-
<audio {...commonProps} controls={!customControls && showControls}>
|
|
133
|
-
{
|
|
139
|
+
<audio {...commonProps} ref={mediaRef as React.RefObject<HTMLAudioElement>} controls={!customControls && showControls}>
|
|
140
|
+
{typeof src === "string" && <source src={src} />}
|
|
134
141
|
Your browser does not support the audio element.
|
|
135
142
|
</audio>
|
|
136
143
|
)
|
|
@@ -140,14 +147,21 @@ export const BaseMediaPlayer = forwardRef<HTMLDivElement, BaseMediaPlayerProps>(
|
|
|
140
147
|
return (
|
|
141
148
|
<video
|
|
142
149
|
{...commonProps}
|
|
150
|
+
ref={mediaRef as React.RefObject<HTMLVideoElement>}
|
|
143
151
|
poster={poster}
|
|
144
152
|
muted={state.isMuted}
|
|
145
153
|
playsInline
|
|
146
154
|
controls={!customControls && showControls}>
|
|
147
155
|
{Array.isArray(src) ? (
|
|
148
|
-
src.map((source, index) =>
|
|
156
|
+
src.map((source, index) => (
|
|
157
|
+
<source
|
|
158
|
+
key={index}
|
|
159
|
+
src={typeof source === "string" ? source : ((source as unknown) as MediaSource).src}
|
|
160
|
+
type={typeof source === "string" ? undefined : ((source as unknown) as MediaSource).type}
|
|
161
|
+
/>
|
|
162
|
+
))
|
|
149
163
|
) : src ? (
|
|
150
|
-
<source src={
|
|
164
|
+
<source src={srcString} />
|
|
151
165
|
) : null}
|
|
152
166
|
Your browser does not support the video element.
|
|
153
167
|
</video>
|
|
@@ -208,7 +222,7 @@ export const BaseMediaPlayer = forwardRef<HTMLDivElement, BaseMediaPlayerProps>(
|
|
|
208
222
|
<div className="p-4 text-center text-white">
|
|
209
223
|
<div className="mb-2 text-lg text-red-400">⚠️</div>
|
|
210
224
|
<p className="text-sm">Failed to load media</p>
|
|
211
|
-
<p className="mt-1 text-xs opacity-75">{state.error
|
|
225
|
+
<p className="mt-1 text-xs opacity-75">{state.error}</p>
|
|
212
226
|
</div>
|
|
213
227
|
</div>
|
|
214
228
|
)}
|
|
@@ -216,9 +230,7 @@ export const BaseMediaPlayer = forwardRef<HTMLDivElement, BaseMediaPlayerProps>(
|
|
|
216
230
|
{/* Custom controls or children */}
|
|
217
231
|
{children && (
|
|
218
232
|
<div className="pointer-events-none absolute inset-0">
|
|
219
|
-
{typeof children === "function"
|
|
220
|
-
? children({ state, controls, mediaType: detectedMediaType })
|
|
221
|
-
: children}
|
|
233
|
+
{typeof children === "function" ? children({ state, controls }) : children}
|
|
222
234
|
</div>
|
|
223
235
|
)}
|
|
224
236
|
|