@mottosports/motto-video-player 1.0.1-rc.7 → 1.0.1-rc.70
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 +167 -159
- package/dist/index.d.mts +178 -98
- package/dist/index.d.ts +178 -98
- package/dist/index.js +4154 -1327
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4118 -1287
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Motto Video Player
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React video player component for the Motto platform, powered by Shaka Player with TanStack Query integration.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ A modern, feature-rich video player built on top of Shaka Player with React supp
|
|
|
8
8
|
- 🔄 **TanStack Query Integration**: Advanced caching, background refetching, and error handling
|
|
9
9
|
- 📱 **Responsive Design**: Automatic aspect ratio handling and mobile-friendly controls
|
|
10
10
|
- 🎮 **Skip Controls**: Built-in skip back/forward buttons with customizable durations
|
|
11
|
+
- ⌨️ **Keyboard Controls**: Desktop keyboard shortcuts (arrows for skip, spacebar for play/pause)
|
|
11
12
|
- 🎯 **Quality Control**: Automatic quality selection and manual quality switching
|
|
12
13
|
- 📊 **Analytics**: Built-in Mux analytics support
|
|
13
14
|
- 🖥️ **Chromecast Support**: Cast videos to compatible devices
|
|
@@ -17,220 +18,227 @@ A modern, feature-rich video player built on top of Shaka Player with React supp
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
19
20
|
```bash
|
|
20
|
-
npm install @motto/video-player
|
|
21
|
-
# or
|
|
22
|
-
yarn add @motto/video-player
|
|
23
|
-
# or
|
|
24
|
-
pnpm add @motto/video-player
|
|
21
|
+
npm install @motto-ui-components/motto-video-player @tanstack/react-query
|
|
25
22
|
```
|
|
26
23
|
|
|
27
|
-
##
|
|
24
|
+
## Quick Start
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
import { Player } from '@motto/video-player';
|
|
26
|
+
### Setup QueryClient (Required for Video wrapper)
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
```jsx
|
|
29
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
30
|
+
|
|
31
|
+
const queryClient = new QueryClient();
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
33
34
|
return (
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
controls={true}
|
|
38
|
-
width={800}
|
|
39
|
-
height={450}
|
|
40
|
-
/>
|
|
35
|
+
<QueryClientProvider client={queryClient}>
|
|
36
|
+
<YourComponents />
|
|
37
|
+
</QueryClientProvider>
|
|
41
38
|
);
|
|
42
39
|
}
|
|
43
40
|
```
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
If you're using Next.js, you need to handle server-side rendering (SSR) since Shaka Player requires browser APIs. Here are three approaches:
|
|
42
|
+
### Basic Usage
|
|
48
43
|
|
|
49
|
-
|
|
44
|
+
#### VideoPlayer (Bare Component)
|
|
45
|
+
For direct stream URL playback:
|
|
50
46
|
|
|
51
|
-
```
|
|
52
|
-
import
|
|
47
|
+
```jsx
|
|
48
|
+
import { VideoPlayer } from '@motto-ui-components/motto-video-player';
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
() => import('@motto/video-player').then((mod) => ({ default: mod.Player })),
|
|
56
|
-
{
|
|
57
|
-
ssr: false,
|
|
58
|
-
loading: () => <div>Loading player...</div>
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
function MyVideoPage() {
|
|
50
|
+
function MyPlayer() {
|
|
63
51
|
return (
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
height={450}
|
|
72
|
-
/>
|
|
73
|
-
</div>
|
|
52
|
+
<VideoPlayer
|
|
53
|
+
src="https://example.com/video.m3u8"
|
|
54
|
+
controls
|
|
55
|
+
aspectRatio={16/9}
|
|
56
|
+
onPlay={() => console.log('Playing')}
|
|
57
|
+
onError={(error) => console.error(error)}
|
|
58
|
+
/>
|
|
74
59
|
);
|
|
75
60
|
}
|
|
76
61
|
```
|
|
77
62
|
|
|
78
|
-
|
|
63
|
+
#### Video (Wrapper Component)
|
|
64
|
+
For data fetching with TanStack Query:
|
|
79
65
|
|
|
80
|
-
```
|
|
81
|
-
import {
|
|
66
|
+
```jsx
|
|
67
|
+
import { Video } from '@motto-ui-components/motto-video-player';
|
|
82
68
|
|
|
83
|
-
function
|
|
69
|
+
function MyPlayer() {
|
|
84
70
|
return (
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
71
|
+
<Video
|
|
72
|
+
videoId="your-video-id"
|
|
73
|
+
publicKey="your-public-key"
|
|
74
|
+
controls
|
|
75
|
+
refetchInterval={30000}
|
|
76
|
+
events={{
|
|
77
|
+
onVideoData: (video) => console.log('Video loaded:', video),
|
|
78
|
+
onError: (error) => console.error('Error:', error),
|
|
79
|
+
onPlay: () => console.log('Playing')
|
|
80
|
+
}}
|
|
81
|
+
/>
|
|
95
82
|
);
|
|
96
83
|
}
|
|
97
84
|
```
|
|
98
85
|
|
|
99
|
-
|
|
86
|
+
## Component Comparison
|
|
100
87
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
88
|
+
| Feature | VideoPlayer | Video |
|
|
89
|
+
|---------|-------------|-------|
|
|
90
|
+
| **Use Case** | Direct stream URL | Data fetching with videoId |
|
|
91
|
+
| **Data Fetching** | ❌ Manual | ✅ Automatic with TanStack Query |
|
|
92
|
+
| **Caching** | ❌ None | ✅ Smart caching & background updates |
|
|
93
|
+
| **Loading States** | ❌ Manual | ✅ Built-in loading indicators |
|
|
94
|
+
| **Error Handling** | ❌ Manual | ✅ Automatic retry with exponential backoff |
|
|
95
|
+
| **Performance** | ✅ Minimal overhead | ✅ Optimized with query deduplication |
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
const [isClient, setIsClient] = useState(false);
|
|
97
|
+
## Advanced Configuration
|
|
107
98
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
### TanStack Query Options
|
|
100
|
+
|
|
101
|
+
```jsx
|
|
102
|
+
<Video
|
|
103
|
+
videoId="123"
|
|
104
|
+
publicKey="key"
|
|
105
|
+
refetchInterval={30000}
|
|
106
|
+
queryOptions={{
|
|
107
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
108
|
+
retry: 3,
|
|
109
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000)
|
|
110
|
+
}}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
return <div>Loading player...</div>;
|
|
114
|
-
}
|
|
114
|
+
### Skip Controls
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
116
|
+
```jsx
|
|
117
|
+
<VideoPlayer
|
|
118
|
+
src="..."
|
|
119
|
+
skipConfig={{
|
|
120
|
+
showSkipBack: true,
|
|
121
|
+
showSkipForward: true,
|
|
122
|
+
skipDuration: 15,
|
|
123
|
+
position: 'controls' // or 'overlay'
|
|
124
|
+
}}
|
|
125
|
+
onSkipBack={(newTime) => console.log('Skipped to:', newTime)}
|
|
126
|
+
onSkipForward={(newTime) => console.log('Skipped to:', newTime)}
|
|
127
|
+
/>
|
|
129
128
|
```
|
|
130
129
|
|
|
131
|
-
|
|
130
|
+
### Keyboard Controls
|
|
132
131
|
|
|
133
|
-
|
|
132
|
+
Desktop users can control the player using keyboard shortcuts:
|
|
134
133
|
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
- `width` (number): Fixed width in pixels
|
|
139
|
-
- `height` (number): Fixed height in pixels
|
|
140
|
-
- `aspectRatio` (number, default: 16/9): Aspect ratio for responsive sizing
|
|
141
|
-
- `poster` (string): URL of poster image to show before video loads
|
|
142
|
-
- `muted` (boolean, default: false): Whether to start muted
|
|
143
|
-
- `loop` (boolean, default: false): Whether to loop the video
|
|
134
|
+
- **←** Left Arrow: Skip back 15 seconds
|
|
135
|
+
- **→** Right Arrow: Skip forward 15 seconds
|
|
136
|
+
- **Space**: Play/Pause toggle
|
|
144
137
|
|
|
145
|
-
|
|
138
|
+
Keyboard controls are automatically enabled on desktop devices (disabled on mobile) and work when the player is focused or when no input fields are active.
|
|
146
139
|
|
|
147
|
-
###
|
|
140
|
+
### Responsive Sizing
|
|
148
141
|
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
qualityConfig={{
|
|
153
|
-
enableAutoQuality: true,
|
|
154
|
-
preferredVideoHeight: 720,
|
|
155
|
-
preferredAudioLanguage: 'en'
|
|
156
|
-
}}
|
|
157
|
-
/>
|
|
158
|
-
```
|
|
142
|
+
```jsx
|
|
143
|
+
// Default responsive 16:9
|
|
144
|
+
<VideoPlayer src="..." />
|
|
159
145
|
|
|
160
|
-
|
|
146
|
+
// Custom aspect ratio
|
|
147
|
+
<VideoPlayer src="..." aspectRatio={4/3} />
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
<
|
|
164
|
-
src="https://example.com/protected-video.mpd"
|
|
165
|
-
drmConfig={{
|
|
166
|
-
servers: {
|
|
167
|
-
'com.widevine.alpha': 'https://license-server.com/widevine',
|
|
168
|
-
'com.microsoft.playready': 'https://license-server.com/playready'
|
|
169
|
-
}
|
|
170
|
-
}}
|
|
171
|
-
/>
|
|
149
|
+
// Fixed dimensions
|
|
150
|
+
<VideoPlayer src="..." width={800} height={450} />
|
|
172
151
|
```
|
|
173
152
|
|
|
174
|
-
###
|
|
153
|
+
### Analytics Integration
|
|
175
154
|
|
|
176
|
-
```
|
|
177
|
-
<
|
|
178
|
-
src="
|
|
155
|
+
```jsx
|
|
156
|
+
<VideoPlayer
|
|
157
|
+
src="..."
|
|
179
158
|
muxConfig={{
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
159
|
+
debug: false,
|
|
160
|
+
data: {
|
|
161
|
+
env_key: 'your-mux-env-key',
|
|
162
|
+
video_title: 'Video Title',
|
|
163
|
+
video_id: 'video-123',
|
|
164
|
+
player_name: 'Web Player',
|
|
165
|
+
viewer_user_id: 'user-456'
|
|
184
166
|
}
|
|
185
167
|
}}
|
|
168
|
+
onMuxReady={(monitor) => console.log('Mux ready')}
|
|
186
169
|
/>
|
|
187
170
|
```
|
|
188
171
|
|
|
189
|
-
##
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
172
|
+
## API Reference
|
|
173
|
+
|
|
174
|
+
### VideoPlayer Props
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
interface VideoPlayerProps {
|
|
178
|
+
src: string; // Video source URL
|
|
179
|
+
autoPlay?: boolean; // Auto-play video
|
|
180
|
+
controls?: boolean; // Show player controls
|
|
181
|
+
aspectRatio?: number; // Video aspect ratio (default: 16/9)
|
|
182
|
+
width?: number; // Fixed width
|
|
183
|
+
height?: number; // Fixed height
|
|
184
|
+
skipConfig?: SkipConfig; // Skip controls configuration
|
|
185
|
+
muxConfig?: MuxConfig; // Mux analytics configuration
|
|
186
|
+
onPlay?: () => void; // Play event callback
|
|
187
|
+
onPause?: () => void; // Pause event callback
|
|
188
|
+
onError?: (error: any) => void; // Error event callback
|
|
189
|
+
// ... more props
|
|
190
|
+
}
|
|
202
191
|
```
|
|
203
192
|
|
|
204
|
-
|
|
193
|
+
### Video Props
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface VideoProps extends Omit<VideoPlayerProps, 'src'> {
|
|
197
|
+
videoId?: string; // Video ID for data fetching
|
|
198
|
+
publicKey?: string; // Public key for API authentication
|
|
199
|
+
videoData?: VideoData; // Pre-loaded video data
|
|
200
|
+
refetchInterval?: number; // Background refetch interval (ms)
|
|
201
|
+
queryOptions?: QueryOptions; // TanStack Query configuration
|
|
202
|
+
events?: {
|
|
203
|
+
onVideoData?: (video: VideoData) => void;
|
|
204
|
+
onEmptyPlaylists?: () => void;
|
|
205
|
+
onError?: (error: Error) => void;
|
|
206
|
+
// ... player events
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
```
|
|
205
210
|
|
|
206
|
-
|
|
211
|
+
## TanStack Query Benefits
|
|
207
212
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
/>
|
|
214
|
-
```
|
|
213
|
+
### Caching & Performance
|
|
214
|
+
- **Automatic Caching**: Videos are cached with configurable stale time
|
|
215
|
+
- **Background Refetching**: Data stays fresh with background updates
|
|
216
|
+
- **Request Deduplication**: Identical requests are automatically deduplicated
|
|
217
|
+
- **Garbage Collection**: Memory-efficient cleanup of unused cache entries
|
|
215
218
|
|
|
216
|
-
|
|
219
|
+
### Resilience & UX
|
|
220
|
+
- **Smart Retries**: Exponential backoff retry logic for failed requests
|
|
221
|
+
- **Loading States**: Built-in loading indicators for better UX
|
|
222
|
+
- **Error Recovery**: Automatic error handling and recovery mechanisms
|
|
223
|
+
- **Optimistic Updates**: Support for optimistic UI updates
|
|
217
224
|
|
|
218
|
-
|
|
225
|
+
## Examples
|
|
219
226
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
227
|
+
Check out the [example app](../../apps/example) for comprehensive usage examples including:
|
|
228
|
+
|
|
229
|
+
- Basic VideoPlayer usage
|
|
230
|
+
- Video wrapper with TanStack Query
|
|
231
|
+
- Pre-loaded data scenarios
|
|
232
|
+
- Skip controls integration
|
|
233
|
+
- Responsive design patterns
|
|
226
234
|
|
|
227
|
-
##
|
|
235
|
+
## Contributing
|
|
228
236
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
237
|
+
1. Clone the repository
|
|
238
|
+
2. Install dependencies: `pnpm install`
|
|
239
|
+
3. Start development: `pnpm dev`
|
|
240
|
+
4. Build: `pnpm build`
|
|
233
241
|
|
|
234
242
|
## License
|
|
235
243
|
|
|
236
|
-
|
|
244
|
+
ISC
|