@djangocfg/ui-nextjs 2.1.64 → 2.1.66
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/package.json +9 -6
- package/src/blocks/SplitHero/SplitHeroMedia.tsx +2 -1
- package/src/tools/AudioPlayer/AudioEqualizer.tsx +235 -0
- package/src/tools/AudioPlayer/AudioPlayer.tsx +223 -0
- package/src/tools/AudioPlayer/AudioReactiveCover.tsx +389 -0
- package/src/tools/AudioPlayer/AudioShortcutsPopover.tsx +95 -0
- package/src/tools/AudioPlayer/README.md +301 -0
- package/src/tools/AudioPlayer/SimpleAudioPlayer.tsx +275 -0
- package/src/tools/AudioPlayer/VisualizationToggle.tsx +68 -0
- package/src/tools/AudioPlayer/context.tsx +426 -0
- package/src/tools/AudioPlayer/effects/index.ts +412 -0
- package/src/tools/AudioPlayer/index.ts +84 -0
- package/src/tools/AudioPlayer/types.ts +162 -0
- package/src/tools/AudioPlayer/useAudioHotkeys.ts +142 -0
- package/src/tools/AudioPlayer/useAudioVisualization.tsx +195 -0
- package/src/tools/ImageViewer/ImageViewer.tsx +416 -0
- package/src/tools/ImageViewer/README.md +161 -0
- package/src/tools/ImageViewer/index.ts +16 -0
- package/src/tools/VideoPlayer/README.md +196 -187
- package/src/tools/VideoPlayer/VideoErrorFallback.tsx +174 -0
- package/src/tools/VideoPlayer/VideoPlayer.tsx +189 -218
- package/src/tools/VideoPlayer/VideoPlayerContext.tsx +125 -0
- package/src/tools/VideoPlayer/index.ts +59 -7
- package/src/tools/VideoPlayer/providers/NativeProvider.tsx +206 -0
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +311 -0
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +254 -0
- package/src/tools/VideoPlayer/providers/index.ts +8 -0
- package/src/tools/VideoPlayer/types.ts +320 -71
- package/src/tools/index.ts +82 -4
- package/src/tools/VideoPlayer/NativePlayer.tsx +0 -141
|
@@ -1,231 +1,202 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* VideoPlayer - Unified Video Player Component
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple modes:
|
|
5
|
+
* - vidstack: Full-featured player (YouTube, Vimeo, HLS, DASH)
|
|
6
|
+
* - native: Lightweight HTML5 player
|
|
7
|
+
* - streaming: HTTP Range streaming with auth / Blob sources
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // YouTube video
|
|
11
|
+
* <VideoPlayer source={{ type: 'youtube', id: 'dQw4w9WgXcQ' }} />
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // HLS stream
|
|
15
|
+
* <VideoPlayer source={{ type: 'hls', url: 'https://example.com/video.m3u8' }} />
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // HTTP Range streaming with auth (full source)
|
|
19
|
+
* <VideoPlayer
|
|
20
|
+
* source={{
|
|
21
|
+
* type: 'stream',
|
|
22
|
+
* sessionId: 'abc123',
|
|
23
|
+
* path: '/videos/movie.mp4',
|
|
24
|
+
* getStreamUrl: (id, path) => `/api/stream/${id}?path=${path}&token=${token}`
|
|
25
|
+
* }}
|
|
26
|
+
* />
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // HTTP Range streaming (simplified, using VideoPlayerProvider context)
|
|
30
|
+
* <VideoPlayerProvider sessionId={sessionId} getStreamUrl={getStreamUrl}>
|
|
31
|
+
* <VideoPlayer source={{ type: 'stream', path: '/videos/movie.mp4' }} />
|
|
32
|
+
* </VideoPlayerProvider>
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Blob/ArrayBuffer
|
|
36
|
+
* <VideoPlayer source={{ type: 'blob', data: arrayBuffer, mimeType: 'video/mp4' }} />
|
|
5
37
|
*/
|
|
6
38
|
|
|
7
39
|
'use client';
|
|
8
40
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import '
|
|
13
|
-
import '
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
42
|
+
|
|
43
|
+
import { VidstackProvider, NativeProvider, StreamProvider } from './providers';
|
|
44
|
+
import { useVideoPlayerContext, isSimpleStreamSource, resolveStreamSource } from './VideoPlayerContext';
|
|
45
|
+
import { resolvePlayerMode } from './types';
|
|
46
|
+
|
|
47
|
+
import type { VideoPlayerProps, VideoPlayerRef, VideoSourceUnion, VidstackProviderProps, NativeProviderProps, StreamProviderProps } from './types';
|
|
48
|
+
import type { SimpleStreamSource } from './VideoPlayerContext';
|
|
49
|
+
|
|
50
|
+
export const VideoPlayer = forwardRef<VideoPlayerRef, VideoPlayerProps & { source: VideoSourceUnion | SimpleStreamSource }>(
|
|
51
|
+
(
|
|
52
|
+
{
|
|
53
|
+
source: rawSource,
|
|
54
|
+
mode = 'auto',
|
|
55
|
+
aspectRatio = 16 / 9,
|
|
56
|
+
autoPlay = false,
|
|
57
|
+
muted = false,
|
|
58
|
+
loop = false,
|
|
59
|
+
playsInline = true,
|
|
60
|
+
controls = true,
|
|
61
|
+
preload = 'metadata',
|
|
62
|
+
theme = 'default',
|
|
63
|
+
showInfo = false,
|
|
64
|
+
className,
|
|
65
|
+
videoClassName,
|
|
66
|
+
disableContextMenu = false,
|
|
67
|
+
showPreloader = true,
|
|
68
|
+
preloaderTimeout = 5000,
|
|
69
|
+
errorFallback,
|
|
70
|
+
onPlay,
|
|
71
|
+
onPause,
|
|
72
|
+
onEnded,
|
|
73
|
+
onError,
|
|
74
|
+
onLoadStart,
|
|
75
|
+
onCanPlay,
|
|
76
|
+
onTimeUpdate,
|
|
77
|
+
},
|
|
78
|
+
ref
|
|
79
|
+
) => {
|
|
80
|
+
// Get context for simplified stream sources
|
|
81
|
+
const context = useVideoPlayerContext();
|
|
82
|
+
|
|
83
|
+
// Resolve simplified stream source to full source using context
|
|
84
|
+
const source = useMemo(() => {
|
|
85
|
+
if (isSimpleStreamSource(rawSource)) {
|
|
86
|
+
const resolved = resolveStreamSource(rawSource, context);
|
|
87
|
+
if (!resolved) {
|
|
88
|
+
// Return a special error source that will trigger error fallback
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return resolved;
|
|
92
|
+
}
|
|
93
|
+
return rawSource;
|
|
94
|
+
}, [rawSource, context]);
|
|
95
|
+
|
|
96
|
+
// Handle unresolved source
|
|
97
|
+
if (!source) {
|
|
98
|
+
// Render error state
|
|
99
|
+
const errorMessage = 'Stream source requires VideoPlayerProvider with getStreamUrl and sessionId';
|
|
100
|
+
|
|
101
|
+
if (typeof errorFallback === 'function') {
|
|
102
|
+
return (
|
|
103
|
+
<div className={className} style={{ aspectRatio: aspectRatio === 'fill' ? undefined : aspectRatio }}>
|
|
104
|
+
{errorFallback({ error: errorMessage })}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
48
108
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
109
|
+
if (errorFallback) {
|
|
110
|
+
return (
|
|
111
|
+
<div className={className} style={{ aspectRatio: aspectRatio === 'fill' ? undefined : aspectRatio }}>
|
|
112
|
+
{errorFallback}
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
53
116
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
117
|
+
// Default error UI
|
|
118
|
+
return (
|
|
119
|
+
<div
|
|
120
|
+
className={className}
|
|
121
|
+
style={{
|
|
122
|
+
aspectRatio: aspectRatio === 'fill' ? undefined : aspectRatio,
|
|
123
|
+
display: 'flex',
|
|
124
|
+
alignItems: 'center',
|
|
125
|
+
justifyContent: 'center',
|
|
126
|
+
backgroundColor: 'black',
|
|
127
|
+
color: 'white',
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
<p>{errorMessage}</p>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
66
133
|
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Vimeo URL patterns - auto-convert to vimeo/ID format
|
|
70
|
-
const vimeoPattern = /vimeo\.com\/(\d+)/;
|
|
71
|
-
const vimeoMatch = trimmedUrl.match(vimeoPattern);
|
|
72
|
-
if (vimeoMatch) {
|
|
73
|
-
const videoId = vimeoMatch[1];
|
|
74
|
-
return `vimeo/${videoId}`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Direct video URLs (mp4, webm, etc.) - allow as-is
|
|
78
|
-
if (/\.(mp4|webm|ogg|m3u8|mpd)(\?.*)?$/i.test(trimmedUrl)) {
|
|
79
|
-
return trimmedUrl;
|
|
80
|
-
}
|
|
81
134
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
135
|
+
// Determine which provider to use
|
|
136
|
+
const resolvedMode = resolvePlayerMode(source, mode);
|
|
137
|
+
|
|
138
|
+
// Common props for all providers
|
|
139
|
+
const commonProps = {
|
|
140
|
+
aspectRatio,
|
|
141
|
+
autoPlay,
|
|
142
|
+
muted,
|
|
143
|
+
loop,
|
|
144
|
+
playsInline,
|
|
145
|
+
controls,
|
|
146
|
+
preload,
|
|
147
|
+
className,
|
|
148
|
+
onPlay,
|
|
149
|
+
onPause,
|
|
150
|
+
onEnded,
|
|
151
|
+
onError,
|
|
152
|
+
onLoadStart,
|
|
153
|
+
onCanPlay,
|
|
154
|
+
onTimeUpdate,
|
|
155
|
+
};
|
|
86
156
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
157
|
+
// Render appropriate provider
|
|
158
|
+
switch (resolvedMode) {
|
|
159
|
+
case 'vidstack':
|
|
160
|
+
return (
|
|
161
|
+
<VidstackProvider
|
|
162
|
+
ref={ref}
|
|
163
|
+
source={source as VidstackProviderProps['source']}
|
|
164
|
+
theme={theme}
|
|
165
|
+
showInfo={showInfo}
|
|
166
|
+
errorFallback={errorFallback}
|
|
167
|
+
{...commonProps}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
case 'streaming':
|
|
172
|
+
return (
|
|
173
|
+
<StreamProvider
|
|
174
|
+
ref={ref}
|
|
175
|
+
source={source as StreamProviderProps['source']}
|
|
176
|
+
videoClassName={videoClassName}
|
|
177
|
+
disableContextMenu={disableContextMenu}
|
|
178
|
+
showPreloader={showPreloader}
|
|
179
|
+
preloaderTimeout={preloaderTimeout}
|
|
180
|
+
errorFallback={errorFallback}
|
|
181
|
+
{...commonProps}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
case 'native':
|
|
186
|
+
default:
|
|
187
|
+
return (
|
|
188
|
+
<NativeProvider
|
|
189
|
+
ref={ref}
|
|
190
|
+
source={source as NativeProviderProps['source']}
|
|
191
|
+
videoClassName={videoClassName}
|
|
192
|
+
disableContextMenu={disableContextMenu}
|
|
193
|
+
showPreloader={showPreloader}
|
|
194
|
+
preloaderTimeout={preloaderTimeout}
|
|
195
|
+
{...commonProps}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
126
198
|
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Expose player methods via ref
|
|
130
|
-
useImperativeHandle(ref, () => {
|
|
131
|
-
const player = playerRef.current;
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
play: () => player?.play(),
|
|
135
|
-
pause: () => player?.pause(),
|
|
136
|
-
togglePlay: () => {
|
|
137
|
-
if (player) {
|
|
138
|
-
player.paused ? player.play() : player.pause();
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
seekTo: (time: number) => {
|
|
142
|
-
if (player) player.currentTime = time;
|
|
143
|
-
},
|
|
144
|
-
setVolume: (volume: number) => {
|
|
145
|
-
if (player) player.volume = Math.max(0, Math.min(1, volume));
|
|
146
|
-
},
|
|
147
|
-
toggleMute: () => {
|
|
148
|
-
if (player) player.muted = !player.muted;
|
|
149
|
-
},
|
|
150
|
-
enterFullscreen: () => player?.enterFullscreen(),
|
|
151
|
-
exitFullscreen: () => player?.exitFullscreen(),
|
|
152
|
-
};
|
|
153
|
-
}, []);
|
|
154
|
-
|
|
155
|
-
const handlePlay = () => {
|
|
156
|
-
onPlay?.();
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const handlePause = () => {
|
|
160
|
-
onPause?.();
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const handleEnded = () => {
|
|
164
|
-
onEnded?.();
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const handleError = (detail: any) => {
|
|
168
|
-
onError?.(detail?.message || 'Video playback error');
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
return (
|
|
172
|
-
<div className={cn("w-full", className)}>
|
|
173
|
-
{/* Video Player */}
|
|
174
|
-
<div
|
|
175
|
-
className={cn(
|
|
176
|
-
"relative w-full rounded-sm bg-black overflow-hidden",
|
|
177
|
-
theme === 'minimal' && "rounded-none",
|
|
178
|
-
theme === 'modern' && "rounded-xl shadow-2xl"
|
|
179
|
-
)}
|
|
180
|
-
style={{ aspectRatio: aspectRatio }}
|
|
181
|
-
>
|
|
182
|
-
<MediaPlayer
|
|
183
|
-
ref={playerRef}
|
|
184
|
-
title={source.title || 'Video'}
|
|
185
|
-
src={normalizedUrl}
|
|
186
|
-
autoPlay={autoplay}
|
|
187
|
-
muted={muted}
|
|
188
|
-
playsInline={playsInline}
|
|
189
|
-
onPlay={handlePlay}
|
|
190
|
-
onPause={handlePause}
|
|
191
|
-
onEnded={handleEnded}
|
|
192
|
-
onError={handleError}
|
|
193
|
-
className="w-full h-full"
|
|
194
|
-
>
|
|
195
|
-
<MediaProvider />
|
|
196
|
-
|
|
197
|
-
{/* Poster with proper aspect ratio handling */}
|
|
198
|
-
{posterUrl && (
|
|
199
|
-
<Poster
|
|
200
|
-
className="vds-poster"
|
|
201
|
-
src={posterUrl}
|
|
202
|
-
alt={source.title || 'Video poster'}
|
|
203
|
-
style={{ objectFit: 'cover' }}
|
|
204
|
-
/>
|
|
205
|
-
)}
|
|
206
|
-
|
|
207
|
-
{/* Use Vidstack's built-in default layout */}
|
|
208
|
-
{controls && (
|
|
209
|
-
<DefaultVideoLayout
|
|
210
|
-
icons={defaultLayoutIcons}
|
|
211
|
-
thumbnails={posterUrl}
|
|
212
|
-
/>
|
|
213
|
-
)}
|
|
214
|
-
</MediaPlayer>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
{/* Video Info */}
|
|
218
|
-
{showInfo && source.title && (
|
|
219
|
-
<div className="mt-4 space-y-2">
|
|
220
|
-
<h3 className="text-xl font-semibold text-foreground">{source.title}</h3>
|
|
221
|
-
{source.description && (
|
|
222
|
-
<p className="text-muted-foreground">{source.description}</p>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
225
|
-
)}
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
228
|
-
});
|
|
199
|
+
}
|
|
200
|
+
);
|
|
229
201
|
|
|
230
202
|
VideoPlayer.displayName = 'VideoPlayer';
|
|
231
|
-
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VideoPlayerContext - Context for streaming configuration
|
|
3
|
+
* Simplifies streaming API by providing getStreamUrl globally
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use client';
|
|
7
|
+
|
|
8
|
+
import React, { createContext, useContext, useMemo } from 'react';
|
|
9
|
+
|
|
10
|
+
import type { VideoSourceUnion, StreamSource } from './types';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Context Types
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export interface VideoPlayerContextValue {
|
|
17
|
+
/** Function to generate stream URL (for HTTP Range streaming) */
|
|
18
|
+
getStreamUrl?: (sessionId: string, path: string) => string;
|
|
19
|
+
/** Current session ID */
|
|
20
|
+
sessionId?: string | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface VideoPlayerProviderProps extends VideoPlayerContextValue {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Context
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
const VideoPlayerContext = createContext<VideoPlayerContextValue | null>(null);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Provider for VideoPlayer streaming configuration
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // In your app layout or FileWorkspace
|
|
38
|
+
* <VideoPlayerProvider
|
|
39
|
+
* sessionId={sessionId}
|
|
40
|
+
* getStreamUrl={terminalClient.terminal_media.streamStreamRetrieveUrl}
|
|
41
|
+
* >
|
|
42
|
+
* <VideoPlayer source={{ type: 'stream', path: '/video.mp4' }} />
|
|
43
|
+
* </VideoPlayerProvider>
|
|
44
|
+
*/
|
|
45
|
+
export function VideoPlayerProvider({
|
|
46
|
+
children,
|
|
47
|
+
getStreamUrl,
|
|
48
|
+
sessionId,
|
|
49
|
+
}: VideoPlayerProviderProps) {
|
|
50
|
+
const value = useMemo(
|
|
51
|
+
() => ({ getStreamUrl, sessionId }),
|
|
52
|
+
[getStreamUrl, sessionId]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<VideoPlayerContext.Provider value={value}>
|
|
57
|
+
{children}
|
|
58
|
+
</VideoPlayerContext.Provider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hook to access VideoPlayer context
|
|
64
|
+
*/
|
|
65
|
+
export function useVideoPlayerContext(): VideoPlayerContextValue | null {
|
|
66
|
+
return useContext(VideoPlayerContext);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// Simplified Stream Source
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
/** Simplified stream source (uses context for getStreamUrl) */
|
|
74
|
+
export interface SimpleStreamSource {
|
|
75
|
+
type: 'stream';
|
|
76
|
+
/** File path on server */
|
|
77
|
+
path: string;
|
|
78
|
+
/** Session ID (optional, uses context if not provided) */
|
|
79
|
+
sessionId?: string;
|
|
80
|
+
/** MIME type for the video */
|
|
81
|
+
mimeType?: string;
|
|
82
|
+
title?: string;
|
|
83
|
+
poster?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if source is a simplified stream source (without getStreamUrl)
|
|
88
|
+
*/
|
|
89
|
+
export function isSimpleStreamSource(
|
|
90
|
+
source: VideoSourceUnion | SimpleStreamSource
|
|
91
|
+
): source is SimpleStreamSource {
|
|
92
|
+
return source.type === 'stream' && !('getStreamUrl' in source);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Resolve simplified stream source to full stream source using context
|
|
97
|
+
*/
|
|
98
|
+
export function resolveStreamSource(
|
|
99
|
+
source: SimpleStreamSource,
|
|
100
|
+
context: VideoPlayerContextValue | null
|
|
101
|
+
): StreamSource | null {
|
|
102
|
+
if (!context?.getStreamUrl) {
|
|
103
|
+
console.warn(
|
|
104
|
+
'VideoPlayer: Stream source requires getStreamUrl. ' +
|
|
105
|
+
'Either provide it in source or wrap with VideoPlayerProvider.'
|
|
106
|
+
);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const sessionId = source.sessionId || context.sessionId;
|
|
111
|
+
if (!sessionId) {
|
|
112
|
+
console.warn('VideoPlayer: Stream source requires sessionId.');
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
type: 'stream',
|
|
118
|
+
sessionId,
|
|
119
|
+
path: source.path,
|
|
120
|
+
getStreamUrl: context.getStreamUrl,
|
|
121
|
+
mimeType: source.mimeType,
|
|
122
|
+
title: source.title,
|
|
123
|
+
poster: source.poster,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -1,16 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* VideoPlayer - Unified Video Player
|
|
3
|
+
* Supports Vidstack (YouTube, Vimeo, HLS, DASH), Native HTML5, and HTTP Streaming
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
export {
|
|
6
|
+
// Main component
|
|
7
|
+
export { VideoPlayer } from './VideoPlayer';
|
|
8
|
+
|
|
9
|
+
// Controls (can be used standalone with Vidstack)
|
|
8
10
|
export { VideoControls } from './VideoControls';
|
|
11
|
+
|
|
12
|
+
// Providers (for advanced usage)
|
|
13
|
+
export { VidstackProvider, NativeProvider, StreamProvider } from './providers';
|
|
14
|
+
|
|
15
|
+
// Context (for streaming configuration)
|
|
16
|
+
export {
|
|
17
|
+
VideoPlayerProvider,
|
|
18
|
+
useVideoPlayerContext,
|
|
19
|
+
isSimpleStreamSource,
|
|
20
|
+
resolveStreamSource,
|
|
21
|
+
} from './VideoPlayerContext';
|
|
22
|
+
export type {
|
|
23
|
+
VideoPlayerContextValue,
|
|
24
|
+
VideoPlayerProviderProps,
|
|
25
|
+
SimpleStreamSource,
|
|
26
|
+
} from './VideoPlayerContext';
|
|
27
|
+
|
|
28
|
+
// Error Fallback
|
|
29
|
+
export {
|
|
30
|
+
VideoErrorFallback,
|
|
31
|
+
createVideoErrorFallback,
|
|
32
|
+
} from './VideoErrorFallback';
|
|
33
|
+
export type {
|
|
34
|
+
VideoErrorFallbackProps,
|
|
35
|
+
CreateVideoErrorFallbackOptions,
|
|
36
|
+
} from './VideoErrorFallback';
|
|
37
|
+
|
|
38
|
+
// Types
|
|
9
39
|
export type {
|
|
10
|
-
|
|
40
|
+
// Source types
|
|
41
|
+
VideoSourceUnion,
|
|
42
|
+
UrlSource,
|
|
43
|
+
YouTubeSource,
|
|
44
|
+
VimeoSource,
|
|
45
|
+
HLSSource,
|
|
46
|
+
DASHSource,
|
|
47
|
+
StreamSource,
|
|
48
|
+
BlobSource,
|
|
49
|
+
DataUrlSource,
|
|
50
|
+
// Player types
|
|
51
|
+
PlayerMode,
|
|
52
|
+
AspectRatioValue,
|
|
11
53
|
VideoPlayerProps,
|
|
12
54
|
VideoPlayerRef,
|
|
13
|
-
|
|
14
|
-
|
|
55
|
+
ErrorFallbackProps,
|
|
56
|
+
// Provider props (internal)
|
|
57
|
+
VidstackProviderProps,
|
|
58
|
+
NativeProviderProps,
|
|
59
|
+
StreamProviderProps,
|
|
60
|
+
// Common types
|
|
61
|
+
CommonPlayerSettings,
|
|
62
|
+
CommonPlayerEvents,
|
|
63
|
+
// File source helper types
|
|
64
|
+
ResolveFileSourceOptions,
|
|
15
65
|
} from './types';
|
|
16
66
|
|
|
67
|
+
// Helpers
|
|
68
|
+
export { resolvePlayerMode, resolveFileSource } from './types';
|