@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Motto Video Player
2
2
 
3
- A modern, feature-rich video player built on top of Shaka Player with React support.
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
- ## Basic Usage
24
+ ## Quick Start
28
25
 
29
- ```tsx
30
- import { Player } from '@motto/video-player';
26
+ ### Setup QueryClient (Required for Video wrapper)
31
27
 
32
- function MyVideoPlayer() {
28
+ ```jsx
29
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
30
+
31
+ const queryClient = new QueryClient();
32
+
33
+ function App() {
33
34
  return (
34
- <Player
35
- src="https://example.com/video.m3u8"
36
- autoPlay={false}
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
- ## Next.js Usage (SSR Support)
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
- ### Option 1: Using next/dynamic (Recommended)
44
+ #### VideoPlayer (Bare Component)
45
+ For direct stream URL playback:
50
46
 
51
- ```tsx
52
- import dynamic from 'next/dynamic';
47
+ ```jsx
48
+ import { VideoPlayer } from '@motto-ui-components/motto-video-player';
53
49
 
54
- const MottoPlayer = dynamic(
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
- <div>
65
- <h1>My Video</h1>
66
- <MottoPlayer
67
- src="https://example.com/video.m3u8"
68
- autoPlay={false}
69
- controls={true}
70
- width={800}
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
- ### Option 2: Using the built-in ClientOnlyPlayer
63
+ #### Video (Wrapper Component)
64
+ For data fetching with TanStack Query:
79
65
 
80
- ```tsx
81
- import { ClientOnlyPlayer } from '@motto/video-player';
66
+ ```jsx
67
+ import { Video } from '@motto-ui-components/motto-video-player';
82
68
 
83
- function MyVideoPage() {
69
+ function MyPlayer() {
84
70
  return (
85
- <div>
86
- <h1>My Video</h1>
87
- <ClientOnlyPlayer
88
- src="https://example.com/video.m3u8"
89
- autoPlay={false}
90
- controls={true}
91
- width={800}
92
- height={450}
93
- />
94
- </div>
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
- ### Option 3: Using useEffect for client-side only rendering
86
+ ## Component Comparison
100
87
 
101
- ```tsx
102
- import { Player } from '@motto/video-player';
103
- import { useEffect, useState } from 'react';
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
- function MyVideoPage() {
106
- const [isClient, setIsClient] = useState(false);
97
+ ## Advanced Configuration
107
98
 
108
- useEffect(() => {
109
- setIsClient(true);
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
- if (!isClient) {
113
- return <div>Loading player...</div>;
114
- }
114
+ ### Skip Controls
115
115
 
116
- return (
117
- <div>
118
- <h1>My Video</h1>
119
- <Player
120
- src="https://example.com/video.m3u8"
121
- autoPlay={false}
122
- controls={true}
123
- width={800}
124
- height={450}
125
- />
126
- </div>
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
- ## Player Props
130
+ ### Keyboard Controls
132
131
 
133
- The player accepts the following props:
132
+ Desktop users can control the player using keyboard shortcuts:
134
133
 
135
- - `src` (string, required): URL of the video manifest (HLS, DASH, etc.)
136
- - `autoPlay` (boolean, default: false): Whether to start playing automatically
137
- - `controls` (boolean, default: true): Whether to show player controls
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
- ## Advanced Configuration
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
- ### Quality Control
140
+ ### Responsive Sizing
148
141
 
149
- ```tsx
150
- <Player
151
- src="https://example.com/video.m3u8"
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
- ### DRM Configuration
146
+ // Custom aspect ratio
147
+ <VideoPlayer src="..." aspectRatio={4/3} />
161
148
 
162
- ```tsx
163
- <Player
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
- ### Mux Analytics
153
+ ### Analytics Integration
175
154
 
176
- ```tsx
177
- <Player
178
- src="https://example.com/video.m3u8"
155
+ ```jsx
156
+ <VideoPlayer
157
+ src="..."
179
158
  muxConfig={{
180
- envKey: 'your-mux-env-key',
181
- metadata: {
182
- video_title: 'My Video',
183
- viewer_user_id: 'user123'
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
- ## Event Handling
190
-
191
- ```tsx
192
- <Player
193
- src="https://example.com/video.m3u8"
194
- events={{
195
- onPlay: () => console.log('Video started playing'),
196
- onPause: () => console.log('Video paused'),
197
- onEnded: () => console.log('Video ended'),
198
- onError: (error) => console.error('Playback error:', error),
199
- onQualityChange: (quality) => console.log('Quality changed:', quality)
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
- ## Responsive Design
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
- For responsive video players, omit the `width` and `height` props and optionally set an `aspectRatio`:
211
+ ## TanStack Query Benefits
207
212
 
208
- ```tsx
209
- <Player
210
- src="https://example.com/video.m3u8"
211
- aspectRatio={16/9}
212
- containerClassName="w-full max-w-4xl"
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
- ## Live Streaming
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
- The player automatically detects live streams and shows appropriate UI:
225
+ ## Examples
219
226
 
220
- ```tsx
221
- <Player
222
- src="https://example.com/live-stream.m3u8"
223
- streamStartDate={new Date('2024-01-01T12:00:00Z')} // Optional: for absolute time display
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
- ## Browser Support
235
+ ## Contributing
228
236
 
229
- - Chrome 80+
230
- - Firefox 75+
231
- - Safari 13+
232
- - Edge 80+
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
- MIT
244
+ ISC