docs: rewrite README and DOCUMENTATION for modular player API
This commit is contained in:
+530
-2500
File diff suppressed because it is too large
Load Diff
@@ -1,112 +1,31 @@
|
||||
# 🎬 Modern Video Player
|
||||
# @source/player
|
||||
|
||||
[](https://www.npmjs.com/package/@source/player)
|
||||
[](https://bundlephobia.com/package/@source/player)
|
||||
[](https://www.typescriptlang.org/)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
`@source/player` is a modular, highly customizable React video player library for VOD and live streaming workflows.
|
||||
|
||||
**A compact, feature-rich React video player** with zero runtime dependencies.
|
||||
Current package version: `3.1.0`.
|
||||
|
||||
A feature-rich, modern video player library built with React, TypeScript, and Vite. Designed for reusability across multiple projects.
|
||||
## Why this player
|
||||
|
||||
## 🏆 Why Choose This Player?
|
||||
- React-first component architecture (`VideoPlayer`, `PlayerProvider`, `usePlayerContext`)
|
||||
- Protocol-aware playback with automatic detection (`native`, `hls`, `rtmp/flv`, `mpegts`)
|
||||
- Runtime loading for streaming engines (`hls.js`, `flv.js`, `mpegts.js`) with CDN fallback
|
||||
- Built-in settings UI for speed, quality, audio track, subtitles, and subtitle style editor
|
||||
- Slot-style customization (`children`, `controlsLeftExtra`, `controlsRightExtra`)
|
||||
- Configurable keyboard and touch interaction
|
||||
- TypeScript-first API with strong exported types and an imperative ref handle
|
||||
|
||||
| Feature | @source/player | video.js | react-player | plyr |
|
||||
| ------------------------- | ---------------------------- | ---------- | ------------ | ---------- |
|
||||
| **Bundle Size (gzipped)** | **~18KB JS + ~3.5KB CSS** ✅ | ~500KB ❌ | ~50KB ⚠️ | ~30KB ⚠️ |
|
||||
| **Runtime Dependencies** | **0** ✅ | Many ❌ | Few ⚠️ | Few ⚠️ |
|
||||
| **React (Web)** | **Yes** ✅ | Wrapper ⚠️ | **Yes** ✅ | Wrapper ⚠️ |
|
||||
| **TypeScript Native** | **Yes** ✅ | Types ⚠️ | Partial ⚠️ | Types ⚠️ |
|
||||
| **HLS Support** | **Yes** ✅ | Yes ✅ | Yes ✅ | No ❌ |
|
||||
| **Quality Switching** | **Yes** ✅ | Yes ✅ | Limited ⚠️ | No ❌ |
|
||||
| **Touch Gestures** | **15+** ✅ | Limited ⚠️ | No ❌ | Limited ⚠️ |
|
||||
| **Keyboard Shortcuts** | **15+** ✅ | ~8 ⚠️ | Basic ⚠️ | ~10 ⚠️ |
|
||||
| **i18n Support** | **Yes** ✅ | Yes ✅ | No ❌ | Yes ✅ |
|
||||
## Installation
|
||||
|
||||
### Key Advantages
|
||||
This package is published to a private registry.
|
||||
|
||||
- 📦 **Compact bundle** - Core player ships around ~18KB gzipped JS (+ ~3.5KB CSS)
|
||||
- ⚡ **Blazing fast** - Zero runtime dependencies means faster load times
|
||||
- 🎯 **React-first** - Built specifically for React, not a wrapper
|
||||
- 🔧 **Full TypeScript** - Complete type safety out of the box
|
||||
- 🎨 **Easy customization** - CSS variables for theming
|
||||
- 📱 **Mobile-ready** - Comprehensive touch gesture support
|
||||
- 🌍 **Internationalized** - Built-in i18n with English and Turkish
|
||||
- ♿ **Accessible** - ARIA labels and keyboard navigation
|
||||
|
||||
## ✨ Features
|
||||
|
||||
### 🎮 Core Playback
|
||||
|
||||
- ▶️ Play/Pause controls
|
||||
- ⏭️ Seek/scrub with progress bar
|
||||
- 🔊 Volume control with slider
|
||||
- 🎚️ Playback speed control
|
||||
- 🔄 Loop support
|
||||
- 🖼️ Custom poster/thumbnail
|
||||
|
||||
### 🎨 Modern UI
|
||||
|
||||
- Clean, minimalist design with red theme
|
||||
- Smooth animations and transitions
|
||||
- Auto-hiding controls
|
||||
- Responsive layout (desktop & mobile)
|
||||
- Custom SVG icons
|
||||
- Loading spinner
|
||||
- Center play button
|
||||
|
||||
### ⌨️ Keyboard Shortcuts
|
||||
|
||||
- `Space` or `K` - Play/Pause
|
||||
- `←` / `→` - Seek 5 seconds
|
||||
- `J` / `L` - Seek 10 seconds
|
||||
- `↑` / `↓` - Volume up/down
|
||||
- `M` - Mute/Unmute
|
||||
- `F` - Fullscreen toggle
|
||||
- `P` - Picture-in-Picture
|
||||
- `0-9` - Jump to percentage (10%-90%)
|
||||
- `Home` / `End` - Jump to start/end
|
||||
- Shortcuts only work for the currently active/focused player instance
|
||||
|
||||
### 📱 Touch Gestures
|
||||
|
||||
- **Tap** - Play/Pause
|
||||
- **Double tap left** - Rewind 10 seconds
|
||||
- **Double tap right** - Forward 10 seconds
|
||||
- **Swipe left/right** - Seek
|
||||
- **Swipe up/down** - Volume control
|
||||
|
||||
### 🚀 Advanced Features
|
||||
|
||||
- **HLS Streaming** - Automatic HLS.js integration for .m3u8 files
|
||||
- **IPTV Support** - MPEG-TS (.ts) streams for IPTV services
|
||||
- **HTTP Range Request** - Progressive download for large MP4 files
|
||||
- **Subtitles** - WebVTT and SRT support
|
||||
- **Subtitle Style Editor** - Optional in-player style controls with live preview and local persistence
|
||||
- **Multiple Audio Tracks** - Switch between different audio streams
|
||||
- **Picture-in-Picture** - Native browser PIP support
|
||||
- **Fullscreen** - Native fullscreen API
|
||||
- **Buffer Indicator** - Visual buffering progress
|
||||
- **Error Handling** - Graceful error states
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
This package is distributed through a private registry.
|
||||
|
||||
### 1. Configure `.npmrc`
|
||||
|
||||
Create `.npmrc` in your app root:
|
||||
1. Configure `.npmrc`:
|
||||
|
||||
```ini
|
||||
@source:registry=https://gits.hibna.com.tr/api/packages/hibna/npm/
|
||||
//gits.hibna.com.tr/api/packages/hibna/npm/:_authToken=${GITS_NPM_TOKEN}
|
||||
```
|
||||
|
||||
### 2. Set token
|
||||
|
||||
Set your token in environment variables (`GITS_NPM_TOKEN`) and do not commit `.npmrc` with a hardcoded token.
|
||||
|
||||
### 3. Install package
|
||||
2. Install:
|
||||
|
||||
```bash
|
||||
npm install @source/player
|
||||
@@ -116,436 +35,167 @@ pnpm add @source/player
|
||||
yarn add @source/player
|
||||
```
|
||||
|
||||
> **Note:** This package requires `react` (>=18) and `react-dom` (>=18) at runtime but does **not** list them as `peerDependencies` to avoid install conflicts with private registries. Make sure your project already has React installed.
|
||||
3. Ensure your app already has React and ReactDOM installed (`>=18`).
|
||||
|
||||
> **Streaming libraries (optional):** HLS, FLV and MPEG-TS streaming libraries are loaded automatically from CDN when needed. If you prefer to bundle them locally, install them separately:
|
||||
>
|
||||
> ```bash
|
||||
> npm install hls.js # HLS (.m3u8) streams
|
||||
> npm install flv.js # FLV/RTMP streams
|
||||
> npm install mpegts.js # MPEG-TS (.ts) streams
|
||||
> ```
|
||||
|
||||
### Local development (optional)
|
||||
Optional local dependencies (if you prefer bundling instead of CDN fallback):
|
||||
|
||||
```bash
|
||||
# In this repository
|
||||
npm run build:lib
|
||||
npm link
|
||||
|
||||
# In your consuming app
|
||||
npm link @source/player
|
||||
npm install hls.js flv.js mpegts.js
|
||||
```
|
||||
|
||||
## 🚀 Usage
|
||||
|
||||
### Basic Example
|
||||
## Quick start
|
||||
|
||||
```tsx
|
||||
import { VideoPlayer } from '@source/player'
|
||||
import '@source/player/styles.css'
|
||||
|
||||
function App() {
|
||||
return <VideoPlayer src="https://example.com/video.mp4" poster="https://example.com/poster.jpg" />
|
||||
export function App() {
|
||||
return <VideoPlayer src="https://example.com/video.mp4" />
|
||||
}
|
||||
```
|
||||
|
||||
### Error Boundary (Optional)
|
||||
## Common usage scenarios
|
||||
|
||||
### 1. Standard VOD playback
|
||||
|
||||
```tsx
|
||||
import { VideoPlayer, PlayerErrorBoundary } from '@source/player'
|
||||
import '@source/player/styles.css'
|
||||
<VideoPlayer
|
||||
src="https://cdn.example.com/movie.mp4"
|
||||
poster="https://cdn.example.com/poster.jpg"
|
||||
controlsAutoHideDelay={2500}
|
||||
/>
|
||||
```
|
||||
|
||||
### 2. HLS playback with quality/audio menus
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://stream.example.com/master.m3u8"
|
||||
onQualityChange={(quality) => console.log('quality', quality.label)}
|
||||
/>
|
||||
```
|
||||
|
||||
### 3. IPTV MPEG-TS stream
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="http://provider.example/live/user/pass/channel.ts"
|
||||
protocol="mpegts"
|
||||
/>
|
||||
```
|
||||
|
||||
### 4. Subtitle style editor with local persistence
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
subtitles={[{ src: '/subs/en.vtt', lang: 'en', label: 'English', default: true }]}
|
||||
subtitleStyleEditor={{
|
||||
enabled: true,
|
||||
storageKey: 'my-player-subtitle-style',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### 5. Modular control customization
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
controlsLeftExtra={<button type="button">Bookmark</button>}
|
||||
controlsRightExtra={<button type="button">Share</button>}
|
||||
theme={{
|
||||
primaryColor: '#22c55e',
|
||||
accentColor: '#16a34a',
|
||||
borderRadius: 18,
|
||||
fontFamily: 'Manrope, sans-serif',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## API at a glance
|
||||
|
||||
Key `VideoPlayer` props:
|
||||
|
||||
- Playback: `src`, `protocol`, `autoplay`, `loop`, `muted`, `volume`, `playbackRate`, `currentTime`
|
||||
- Media element config: `crossOrigin`, `preload`, `playsInline`, `controlsList`
|
||||
- UI toggles: `controls`, `keyboardShortcuts`, `pictureInPicture`
|
||||
- Customization: `theme`, `className`, `style`, `aspectRatio`, `playbackRates`
|
||||
- Subtitles: `subtitles`, `subtitleStyle`, `subtitleStyleEditor`, `subtitlePosition`, `subtitleOffset`
|
||||
- Extensibility: `children`, `controlsLeftExtra`, `controlsRightExtra`
|
||||
- Input config: `keyboardShortcutConfig`, `touchConfig`
|
||||
- Localization: `language`, `translations`
|
||||
- Events: `onPlay`, `onPause`, `onEnded`, `onTimeUpdate`, `onError`, `onQualityChange`, `onBufferStart`, `onBufferEnd`, `onFirstPlay`, and more
|
||||
|
||||
## Imperative control via ref
|
||||
|
||||
```tsx
|
||||
import { useRef } from 'react'
|
||||
import { VideoPlayer, type VideoPlayerHandle } from '@source/player'
|
||||
|
||||
export function PlayerWithRef() {
|
||||
const playerRef = useRef<VideoPlayerHandle>(null)
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<PlayerErrorBoundary>
|
||||
<VideoPlayer src="https://example.com/video.mp4" />
|
||||
</PlayerErrorBoundary>
|
||||
<>
|
||||
<VideoPlayer ref={playerRef} src="https://example.com/video.mp4" />
|
||||
<button type="button" onClick={() => playerRef.current?.seek(120)}>
|
||||
Jump to 02:00
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### With Subtitles
|
||||
## Other exports
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
subtitles={[
|
||||
{ src: '/subtitles/en.vtt', lang: 'en', label: 'English', default: true },
|
||||
{ src: '/subtitles/tr.srt', lang: 'tr', label: 'Türkçe' },
|
||||
]}
|
||||
/>
|
||||
```ts
|
||||
import {
|
||||
PlayerErrorBoundary,
|
||||
PlayerProvider,
|
||||
usePlayerContext,
|
||||
useKeyboardShortcuts,
|
||||
useTouchGestures,
|
||||
formatTime,
|
||||
parseTime,
|
||||
parseSRT,
|
||||
createSubtitleBlobURL,
|
||||
fetchSubtitle,
|
||||
validateVideoURL,
|
||||
checkVideoCORS,
|
||||
initializePolyfills,
|
||||
features,
|
||||
getTranslations,
|
||||
detectBrowserLanguage,
|
||||
} from '@source/player'
|
||||
```
|
||||
|
||||
### Subtitle Styling (Custom Renderer)
|
||||
## Documentation map
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
subtitles={[{ src: '/subtitles/en.vtt', lang: 'en', label: 'English', default: true }]}
|
||||
subtitlePosition="bottom"
|
||||
subtitleOffset={72}
|
||||
subtitleStyle={{
|
||||
fontSize: 24,
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
color: '#f8fafc',
|
||||
backgroundColor: '#111827',
|
||||
backgroundOpacity: 0.72,
|
||||
}}
|
||||
/>
|
||||
```
|
||||
For complete details, see `DOCUMENTATION.md`:
|
||||
|
||||
### Subtitle Style Editor (Optional)
|
||||
- Full `VideoPlayerProps` and event reference
|
||||
- Streaming architecture (HLS/RTMP-FLV/MPEG-TS)
|
||||
- Subtitle rendering and style editor internals
|
||||
- Theme tokens and CSS variable mapping
|
||||
- Keyboard and touch behavior
|
||||
- Error handling and browser caveats
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
subtitles={[{ src: '/subtitles/en.vtt', lang: 'en', label: 'English', default: true }]}
|
||||
subtitleStyleEditor={{
|
||||
enabled: true,
|
||||
storageKey: 'my-app-player-subtitle-style',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
`enabled: true` adds a subtitle style editor in `Settings > Subtitles`.
|
||||
Changes are previewed in real-time and saved to `localStorage` only when the user presses `Save`.
|
||||
|
||||
### HLS Streaming
|
||||
|
||||
```tsx
|
||||
<VideoPlayer src="https://example.com/stream/playlist.m3u8" autoplay={false} />
|
||||
```
|
||||
|
||||
### Force Protocol (Override Auto Detection)
|
||||
|
||||
```tsx
|
||||
<VideoPlayer src="https://cdn.example.com/video" protocol="hls" />
|
||||
```
|
||||
|
||||
### IPTV Streaming
|
||||
|
||||
```tsx
|
||||
// Note: Browser support for direct .ts streams is limited
|
||||
// For best compatibility, request .m3u8 (HLS) links from your IPTV provider
|
||||
<VideoPlayer
|
||||
src="http://server.com:8080/live/username/password/12345.ts"
|
||||
poster="http://example.com/channel-logo.png"
|
||||
onError={(error) => {
|
||||
console.error('Stream error - try requesting .m3u8 format:', error)
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom Theme
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
theme={{
|
||||
primaryColor: '#ef4444',
|
||||
accentColor: '#dc2626',
|
||||
backgroundColor: '#000000',
|
||||
textColor: '#ffffff',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### With Volume and Playback Control
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
volume={0.5} // 50% volume
|
||||
playbackRate={1.5} // 1.5x speed
|
||||
currentTime={30} // Start at 30 seconds
|
||||
/>
|
||||
```
|
||||
|
||||
### With Event Handlers
|
||||
|
||||
```tsx
|
||||
<VideoPlayer
|
||||
src="https://example.com/video.mp4"
|
||||
onPlay={() => console.log('Video started playing')}
|
||||
onPause={() => console.log('Video paused')}
|
||||
onEnded={() => console.log('Video ended')}
|
||||
onTimeUpdate={(time) => console.log('Current time:', time)}
|
||||
onVolumeChange={(volume) => console.log('Volume:', volume)}
|
||||
onRateChange={(rate) => console.log('Playback rate:', rate)}
|
||||
onFullscreenChange={(isFs) => console.log('Fullscreen:', isFs)}
|
||||
onError={(error) => console.error('Video error:', error)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Feature Detection & Polyfills
|
||||
|
||||
```tsx
|
||||
import { features, initializePolyfills } from '@source/player'
|
||||
|
||||
// Initialize polyfills manually (optional - auto-initialized on VideoPlayer mount)
|
||||
initializePolyfills()
|
||||
|
||||
// Check browser capabilities
|
||||
console.log('Has PIP support:', features.hasPIP())
|
||||
console.log('Has native HLS:', features.hasNativeHLS())
|
||||
console.log('Has MSE for HLS.js:', features.hasMSE())
|
||||
console.log('Is iOS Safari:', features.isIOSSafari())
|
||||
console.log('Has volume control:', features.hasVolumeControl())
|
||||
|
||||
// Hide PIP button on unsupported devices
|
||||
<VideoPlayer
|
||||
src="video.mp4"
|
||||
pictureInPicture={features.hasPIP()}
|
||||
/>
|
||||
```
|
||||
|
||||
### CORS Error Handling
|
||||
|
||||
```tsx
|
||||
import { validateVideoURL, checkVideoCORS } from '@source/player'
|
||||
|
||||
// Validate URL before loading
|
||||
const validation = validateVideoURL(videoUrl)
|
||||
if (!validation.valid) {
|
||||
console.error(validation.error)
|
||||
}
|
||||
|
||||
// Check CORS support (async)
|
||||
const corsCheck = await checkVideoCORS(videoUrl)
|
||||
if (!corsCheck.supported) {
|
||||
console.error('CORS issue:', corsCheck.error)
|
||||
console.log('Needs proxy:', corsCheck.needsProxy)
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Setup
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development server
|
||||
npm run dev
|
||||
|
||||
# Build library
|
||||
npm run test:run
|
||||
npm run build:lib
|
||||
|
||||
# Type check
|
||||
npx tsc --noEmit
|
||||
|
||||
# Format check
|
||||
npm run format:check
|
||||
|
||||
# Full publish validation
|
||||
npm run validate:publish
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
Useful scripts:
|
||||
|
||||
```
|
||||
video-player/
|
||||
├── src/
|
||||
│ ├── components/ # React components
|
||||
│ │ ├── controls/ # Control UI components
|
||||
│ │ ├── overlays/ # Overlay components (loading, etc.)
|
||||
│ │ └── menus/ # Settings menus
|
||||
│ ├── contexts/ # React Context (PlayerContext)
|
||||
│ ├── hooks/ # Custom React hooks
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── types/ # TypeScript type definitions
|
||||
│ ├── icons/ # Custom SVG icons
|
||||
│ ├── styles/ # Global styles and CSS variables
|
||||
│ └── index.ts # Main export file
|
||||
├── examples/ # Demo application
|
||||
├── public/ # Static assets
|
||||
└── dist/ # Built library (generated)
|
||||
```
|
||||
- `npm run lint`
|
||||
- `npm run typecheck`
|
||||
- `npm run validate:publish`
|
||||
|
||||
## 📖 API Reference
|
||||
|
||||
### VideoPlayer Props
|
||||
|
||||
#### Basic Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| --------------------- | ------------------------------------------------------------- | ------------ | -------------------------------------------------------------- |
|
||||
| `src` | `string` | **required** | Video source URL (MP4, WebM, HLS, IPTV .ts) |
|
||||
| `poster` | `string` | - | Poster image URL |
|
||||
| `protocol` | `'auto' \| 'native' \| 'hls' \| 'rtmp' \| 'dash' \| 'mpegts'` | `'auto'` | Force playback engine instead of URL auto-detection |
|
||||
| `autoplay` | `boolean` | `false` | Auto-play video on load |
|
||||
| `loop` | `boolean` | `false` | Loop video playback |
|
||||
| `muted` | `boolean` | `false` | Start muted |
|
||||
| `volume` | `number` | - | Initial volume (0-1) |
|
||||
| `playbackRate` | `number` | - | Playback speed (0.25, 0.5, 1, 1.5, 2, etc.) |
|
||||
| `currentTime` | `number` | - | Initial playback position in seconds |
|
||||
| `crossOrigin` | `'' \| 'anonymous' \| 'use-credentials'` | - | Sets the video `crossOrigin` attribute |
|
||||
| `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | Sets the video preload strategy |
|
||||
| `playsInline` | `boolean` | `true` | Enables inline playback on mobile browsers |
|
||||
| `controlsList` | `string` | - | Passes `controlsList` attribute to the video element |
|
||||
| `controls` | `boolean` | `true` | Show player controls |
|
||||
| `subtitles` | `SubtitleTrack[]` | `[]` | Subtitle tracks |
|
||||
| `subtitleStyle` | `SubtitleStyle` | - | Custom subtitle text/background style |
|
||||
| `subtitleStyleEditor` | `boolean \| SubtitleStyleEditorConfig` | `false` | Optional subtitle style editor UI and localStorage persistence |
|
||||
| `subtitlePosition` | `'top' \| 'center' \| 'bottom'` | `'bottom'` | Subtitle vertical placement |
|
||||
| `subtitleOffset` | `number \| string` | - | Subtitle offset (`px` if number) |
|
||||
| `theme` | `PlayerTheme` | - | Custom theme colors |
|
||||
| `language` | `string` | `'en'` | UI language ('en' or 'tr') |
|
||||
| `keyboardShortcuts` | `boolean` | `true` | Enable keyboard shortcuts |
|
||||
| `pictureInPicture` | `boolean` | `true` | Enable PIP button |
|
||||
| `className` | `string` | - | Custom CSS class |
|
||||
| `style` | `CSSProperties` | - | Inline styles |
|
||||
|
||||
#### Event Handlers
|
||||
|
||||
| Prop | Type | Description |
|
||||
| -------------------------- | --------------------------------- | ------------------------------------------- |
|
||||
| `onPlay` | `() => void` | Fired when playback starts |
|
||||
| `onPause` | `() => void` | Fired when playback pauses |
|
||||
| `onEnded` | `() => void` | Fired when playback ends |
|
||||
| `onTimeUpdate` | `(currentTime: number) => void` | Fired during playback with current time |
|
||||
| `onVolumeChange` | `(volume: number) => void` | Fired when volume changes |
|
||||
| `onError` | `(error: Error) => void` | Fired on playback error |
|
||||
| `onLoadedMetadata` | `() => void` | Fired when video metadata is loaded |
|
||||
| `onSeeking` | `() => void` | Fired when seeking starts |
|
||||
| `onSeeked` | `() => void` | Fired when seeking completes |
|
||||
| `onProgress` | `(buffered: number) => void` | Fired during download progress |
|
||||
| `onDurationChange` | `(duration: number) => void` | Fired when duration changes |
|
||||
| `onRateChange` | `(playbackRate: number) => void` | Fired when playback rate changes |
|
||||
| `onFullscreenChange` | `(isFullscreen: boolean) => void` | Fired when fullscreen state changes |
|
||||
| `onPictureInPictureChange` | `(isPip: boolean) => void` | Fired when PIP state changes |
|
||||
| `onWaiting` | `() => void` | Fired when buffering starts |
|
||||
| `onCanPlay` | `() => void` | Fired when enough data is available to play |
|
||||
|
||||
### PlayerErrorBoundary Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
| ----------- | ------------------------------------------------------------- | -------------------------------------- |
|
||||
| `children` | `ReactNode` | Wrapped player/content tree |
|
||||
| `fallback` | `ReactNode \| (error: Error, retry: () => void) => ReactNode` | Optional custom fallback UI |
|
||||
| `onError` | `(error: Error, errorInfo: React.ErrorInfo) => void` | Called when render errors are captured |
|
||||
| `onReset` | `() => void` | Called when retry/reset is triggered |
|
||||
| `resetKeys` | `readonly unknown[]` | Resets boundary when any key changes |
|
||||
|
||||
### SubtitleTrack
|
||||
|
||||
```typescript
|
||||
interface SubtitleTrack {
|
||||
src: string // Subtitle file URL (.vtt or .srt)
|
||||
lang: string // Language code (e.g., 'en', 'tr')
|
||||
label: string // Display label
|
||||
default?: boolean // Set as default subtitle
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
interface SubtitleStyleEditorConfig {
|
||||
enabled?: boolean // Enables subtitle style editor in settings
|
||||
storageKey?: string // localStorage key (default: 'source-player-subtitle-style')
|
||||
}
|
||||
```
|
||||
|
||||
### PlayerTheme
|
||||
|
||||
```typescript
|
||||
interface PlayerTheme {
|
||||
primaryColor?: string // Primary color (default: #ef4444)
|
||||
accentColor?: string // Accent/hover color (default: #dc2626)
|
||||
backgroundColor?: string // Background color (default: #000000)
|
||||
textColor?: string // Text color (default: #ffffff)
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 Browser Support
|
||||
|
||||
- Chrome/Edge 90+
|
||||
- Firefox 88+
|
||||
- Safari 14+
|
||||
- Mobile Safari 14+
|
||||
- Chrome Mobile 90+
|
||||
|
||||
## 📊 Bundle Size
|
||||
|
||||
- Core player JS bundle: **~18KB** (gzipped)
|
||||
- Core player CSS bundle: **~3.5KB** (gzipped)
|
||||
- HLS.js (optional, lazy-loaded): **~200KB** (only when using HLS streams)
|
||||
- MPEGTS.js (optional, lazy-loaded): **~72KB** (gzipped, only for `.ts` streams)
|
||||
- Zero runtime dependencies (React is a prerequisite, see installation notes)
|
||||
|
||||
## 🔧 Technical Details
|
||||
|
||||
### Native Browser APIs Used
|
||||
|
||||
- HTML5 Video API
|
||||
- Fullscreen API
|
||||
- Picture-in-Picture API
|
||||
- Fetch API (Range Requests)
|
||||
- TextTrack API (subtitles)
|
||||
- Touch Events API
|
||||
- Keyboard Events API
|
||||
|
||||
### Streaming Support
|
||||
|
||||
**MP4/WebM (Progressive Download)**
|
||||
|
||||
- Uses HTTP Range Requests
|
||||
- Browser automatically chunks the download
|
||||
- No additional library needed
|
||||
- Works with any standard web server that supports Range headers
|
||||
|
||||
**HLS (.m3u8)**
|
||||
|
||||
- Automatically detects HLS sources
|
||||
- Lazy loads hls.js library when needed
|
||||
- Safari has native HLS support (no library needed)
|
||||
- Adaptive bitrate streaming
|
||||
|
||||
### Performance Optimizations
|
||||
|
||||
- Lazy loading of HLS.js with CDN fallback
|
||||
- CSS-only animations
|
||||
- Debounced control hiding
|
||||
- Optimized re-renders with React.memo
|
||||
- Tree-shakeable exports
|
||||
- Memory leak prevention with proper cleanup
|
||||
- Polyfills for older browser support
|
||||
|
||||
### Error Handling & Reliability
|
||||
|
||||
- **CORS Detection**: Automatically detects and reports CORS issues with helpful error messages
|
||||
- **HLS.js Fallback**: If npm package fails to load, automatically falls back to CDN
|
||||
- **Memory Management**: Proper cleanup of HLS instances to prevent memory leaks
|
||||
- **Browser Polyfills**: Vendor prefix support for Fullscreen and PIP APIs
|
||||
- **URL Validation**: Validates video URLs before attempting to load
|
||||
- **Feature Detection**: Checks browser capabilities before using advanced features
|
||||
|
||||
## 🚧 TODO / Future Enhancements
|
||||
|
||||
- [x] Multiple audio track UI and switching
|
||||
- [x] Quality selector for HLS streams
|
||||
- [x] Playback speed menu
|
||||
- [x] Settings panel
|
||||
- [ ] Chapters/markers support
|
||||
- [ ] Thumbnail preview on hover
|
||||
- [ ] Playlist support
|
||||
- [ ] Chromecast support
|
||||
- [ ] AirPlay support
|
||||
- [ ] DASH streaming support
|
||||
- [ ] Accessibility improvements (ARIA labels)
|
||||
- [x] Unit tests
|
||||
- [ ] E2E tests
|
||||
- [ ] Storybook documentation
|
||||
|
||||
## 📝 License
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## 👤 Author
|
||||
|
||||
Alper
|
||||
|
||||
---
|
||||
|
||||
Built with ❤️ using React, TypeScript, and Vite
|
||||
|
||||
Reference in New Issue
Block a user