boss-web-player-sdk 2.0.1 → 2.0.2
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/LICENSE +21 -21
- package/README.md +366 -366
- package/dist/boss-web-player-sdk.css +1 -1
- package/dist/chunks/{src-B9W4IMGS.cjs → src-CWZEcSuf.cjs} +1 -1
- package/dist/chunks/{src-QXXVFxiP.js → src-iIPWY3xk.js} +3 -3
- package/dist/core.cjs +1 -1
- package/dist/core.d.ts +11 -1
- package/dist/core.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +65 -9
- package/dist/index.js +47 -46
- package/package.json +68 -68
package/README.md
CHANGED
|
@@ -1,366 +1,366 @@
|
|
|
1
|
-
# boss-web-player-sdk
|
|
2
|
-
|
|
3
|
-
A unified, high-performance OTT web video player SDK for adaptive streaming — HLS/DASH, token-based DRM, dynamic watermarking, captions, chapters, casting, and premium UI controls.
|
|
4
|
-
|
|
5
|
-
> **Heads up:** the high-level `<BossVideoPlayer>` component is **tenant-gated**. It validates your GoBOSS player key before playback starts, and resolves its feature set (subtitles, DRM, chromecast, etc.) from your plan. Obtain a player key from the GoBOSS dashboard and supply it from your app config (never commit real keys). For a generic, ungated player use the [headless core entry](#headless-core-no-react).
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- **Adaptive streaming** — HLS (bundled `hls.js`) and DASH (bundled `dashjs`) with automatic quality switching
|
|
10
|
-
- **DRM** — token-based authorization, FairPlay / Widevine, dynamic watermarking
|
|
11
|
-
- **Rich controls** — quality, playback speed, subtitles, PiP, fullscreen, chapters/key-moments
|
|
12
|
-
- **Casting** — Chromecast and AirPlay
|
|
13
|
-
- **Server-side ads (SSAI)** — AWS MediaTailor ad-break tracking and skip-ad flow
|
|
14
|
-
- **Episodic playback** — Skip Intro and an auto-advancing Next Episode chip, for series content
|
|
15
|
-
- **Analytics** — first-party session/event telemetry, plus an `onAnalyticsEvent` callback
|
|
16
|
-
- **Framework-agnostic** — React component, a vanilla `createPlayer()` mount, and a zero-React headless core
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install boss-web-player-sdk
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Peer dependencies
|
|
25
|
-
|
|
26
|
-
| Package | Required? | Notes |
|
|
27
|
-
|---|---|---|
|
|
28
|
-
| `react`, `react-dom` (`^18` or `^19`) | **Required** for the React component & `createPlayer` | Not needed if you only use the headless `/core` entry |
|
|
29
|
-
|
|
30
|
-
> **DASH works out of the box.** `dashjs` is bundled into the SDK (lazily, like `hls.js`) — you do **not** need to install it separately. The DASH engine is only fetched by the browser when a `.mpd` stream actually plays, so HLS-only apps never download it.
|
|
31
|
-
|
|
32
|
-
### CSS — required, import once
|
|
33
|
-
|
|
34
|
-
> **The player stylesheet must be imported separately.** The SDK ships CSS as a standalone
|
|
35
|
-
> file so your bundler can handle it correctly (critical for SSR frameworks like Next.js).
|
|
36
|
-
> Forgetting this import will result in a broken, unstyled player.
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
import 'boss-web-player-sdk/css';
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Import it once at your app entry point (e.g. `main.tsx`, `_app.tsx`, `layout.tsx`) and it
|
|
43
|
-
applies globally — you do not need to import it in every file that uses `<BossVideoPlayer>`.
|
|
44
|
-
|
|
45
|
-
## Quick start (React)
|
|
46
|
-
|
|
47
|
-
```tsx
|
|
48
|
-
import { BossVideoPlayer } from 'boss-web-player-sdk';
|
|
49
|
-
import 'boss-web-player-sdk/css';
|
|
50
|
-
|
|
51
|
-
export default function App() {
|
|
52
|
-
return (
|
|
53
|
-
<BossVideoPlayer
|
|
54
|
-
playerKey={process.env.NEXT_PUBLIC_PLAYER_KEY!} // from your app config / env (required)
|
|
55
|
-
src="https://cdn.example.com/video.m3u8" // HLS (.m3u8) or DASH (.mpd)
|
|
56
|
-
title="My Video"
|
|
57
|
-
themeColor="#6366f1"
|
|
58
|
-
autoplay
|
|
59
|
-
muted
|
|
60
|
-
/>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
The component shows a loading spinner while it validates the player key, then renders the
|
|
66
|
-
player. If the key is invalid or the API is unreachable, it renders an error state instead.
|
|
67
|
-
|
|
68
|
-
## Next.js
|
|
69
|
-
|
|
70
|
-
The SDK works in Next.js (both Pages Router and App Router). The player is entirely
|
|
71
|
-
client-side — it uses browser APIs (`HTMLVideoElement`, `window`, `navigator`) that do not
|
|
72
|
-
exist on the server.
|
|
73
|
-
|
|
74
|
-
**App Router** — mark any file that imports the player as a Client Component:
|
|
75
|
-
|
|
76
|
-
```tsx
|
|
77
|
-
// app/watch/page.tsx
|
|
78
|
-
'use client';
|
|
79
|
-
|
|
80
|
-
import { BossVideoPlayer } from 'boss-web-player-sdk';
|
|
81
|
-
|
|
82
|
-
export default function WatchPage() {
|
|
83
|
-
return (
|
|
84
|
-
<BossVideoPlayer
|
|
85
|
-
playerKey={process.env.NEXT_PUBLIC_PLAYER_KEY!}
|
|
86
|
-
src="https://cdn.example.com/video.m3u8"
|
|
87
|
-
autoplay
|
|
88
|
-
muted
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Import the CSS in your root layout so it loads once for the whole app:
|
|
95
|
-
|
|
96
|
-
```tsx
|
|
97
|
-
// app/layout.tsx
|
|
98
|
-
import 'boss-web-player-sdk/css';
|
|
99
|
-
|
|
100
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
101
|
-
return <html><body>{children}</body></html>;
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**Pages Router** — import the CSS in `_app.tsx` (or `_app.js`):
|
|
106
|
-
|
|
107
|
-
```tsx
|
|
108
|
-
// pages/_app.tsx
|
|
109
|
-
import 'boss-web-player-sdk/css';
|
|
110
|
-
import type { AppProps } from 'next/app';
|
|
111
|
-
|
|
112
|
-
export default function App({ Component, pageProps }: AppProps) {
|
|
113
|
-
return <Component {...pageProps} />;
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
No `'use client'` directive is needed in the Pages Router — all pages are client-rendered
|
|
118
|
-
by default.
|
|
119
|
-
|
|
120
|
-
## `<BossVideoPlayer>` props
|
|
121
|
-
|
|
122
|
-
```ts
|
|
123
|
-
interface BossVideoPlayerProps {
|
|
124
|
-
// ── Required ──────────────────────────────────────────────
|
|
125
|
-
playerKey: string; // from your GoBOSS dashboard — supply via app config/env
|
|
126
|
-
src: string; // HLS (.m3u8) or DASH (.mpd) URL
|
|
127
|
-
|
|
128
|
-
// ── Identity / theming ────────────────────────────────────
|
|
129
|
-
title?: string; // Title shown in the player UI
|
|
130
|
-
watermark?: string; // Watermark text stamped on the video
|
|
131
|
-
themeColor?: string; // Accent color (hex). Default '#6366f1'
|
|
132
|
-
licenseKey?: string; // Required by DRM-enabled plans (presence-checked)
|
|
133
|
-
|
|
134
|
-
// ── Networking ────────────────────────────────────────────
|
|
135
|
-
apiBaseUrl?: string; // API base override: reverse proxy path, or the staging host
|
|
136
|
-
proxyDomains?: string; // CORS proxy map, "host=/path,host2=/path2" (see CORS)
|
|
137
|
-
|
|
138
|
-
// ── Ads (AWS MediaTailor SSAI) ────────────────────────────
|
|
139
|
-
adTrackingUrl?: string; // Ad-break tracking URL
|
|
140
|
-
overlayAdUrl?: string; // Overlay ad tracking URL
|
|
141
|
-
enableSkipAd?: boolean;
|
|
142
|
-
skipAdAfterSeconds?: number;
|
|
143
|
-
|
|
144
|
-
// ── Series / episodic ─────────────────────────────────────
|
|
145
|
-
introStartTime?: number; // Content-relative intro start, in seconds
|
|
146
|
-
introEndTime?: number; // Content-relative intro end, in seconds — Skip Intro seeks here
|
|
147
|
-
hasNextEpisode?: boolean; // Whether another episode is available to auto-advance into
|
|
148
|
-
outroStartTime?: number; // Content-relative outro/credits start, in seconds — reveals the Next Episode chip
|
|
149
|
-
nextEpisodeLabel?: string; // Label on the Next Episode chip. Default 'Next Episode'
|
|
150
|
-
nextEpisodeAutoAdvanceSeconds?: number; // Seconds before auto-advancing once the chip is shown. Default 5
|
|
151
|
-
onNextEpisode?: () => void; // Called on chip click, or when the auto-advance timer fires
|
|
152
|
-
|
|
153
|
-
// ── Behavior / UI ─────────────────────────────────────────
|
|
154
|
-
autoplay?: boolean; // Default false
|
|
155
|
-
muted?: boolean; // Default false (use with autoplay — browsers block unmuted autoplay)
|
|
156
|
-
autoFullscreen?: boolean;
|
|
157
|
-
enableControls?: boolean; // Default true
|
|
158
|
-
chaptersDisplayMode?: 'strip' | 'panel'; // Default 'strip'
|
|
159
|
-
volumeControlType?: 'slider' | 'button'; // Default 'slider'
|
|
160
|
-
subtitleStyle?: { size?: 'small'|'medium'|'large'; background?: 'none'|'dim'|'solid'; color?: string };
|
|
161
|
-
|
|
162
|
-
// ── Integrations ──────────────────────────────────────────
|
|
163
|
-
drmConfig?: DRMConfig; // DRM license / token configuration
|
|
164
|
-
|
|
165
|
-
// ── Callbacks ─────────────────────────────────────────────
|
|
166
|
-
onAnalyticsEvent?: (event: AnalyticsEvent) => void; // Every analytics event
|
|
167
|
-
onKeyMomentsLoaded?: (keyMoments: Chapter[]) => void; // When chapters parse from the stream
|
|
168
|
-
onTimeUpdate?: (currentTime: number) => void; // Every timeupdate — use to persist watch progress
|
|
169
|
-
|
|
170
|
-
// ── Resume playback ───────────────────────────────────────
|
|
171
|
-
initialTime?: number; // Seek to this position (seconds) once the video is ready
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Skip Intro / Next Episode (series)
|
|
176
|
-
|
|
177
|
-
Both are driven entirely by props — the SDK owns the timing, the chip UI, and the seek/auto-advance
|
|
178
|
-
behavior. All times are **content-relative** (the original episode timeline), so they stay correct
|
|
179
|
-
even if the stream has spliced ad breaks.
|
|
180
|
-
|
|
181
|
-
```tsx
|
|
182
|
-
<BossVideoPlayer
|
|
183
|
-
playerKey={playerKey}
|
|
184
|
-
src="https://cdn.example.com/episode-04.m3u8"
|
|
185
|
-
introStartTime={0}
|
|
186
|
-
introEndTime={78} // Skip Intro shows between 0s–78s, seeks to 78s on click
|
|
187
|
-
hasNextEpisode={true}
|
|
188
|
-
outroStartTime={1230} // Next Episode chip appears once playback reaches 1230s
|
|
189
|
-
nextEpisodeLabel="S2 · E5" // optional — defaults to "Next Episode"
|
|
190
|
-
nextEpisodeAutoAdvanceSeconds={5} // optional — auto-advances 5s after the chip appears
|
|
191
|
-
onNextEpisode={() => loadNextEpisode()}
|
|
192
|
-
/>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
> Feature availability (subtitles, chromecast, DRM, multiple resolutions, etc.) is **resolved from your
|
|
196
|
-
> plan** by the GoBOSS API at init — it is not toggled by individual props on this component.
|
|
197
|
-
|
|
198
|
-
## Use without JSX — `createPlayer()`
|
|
199
|
-
|
|
200
|
-
For Vue, Angular, Svelte, or vanilla JS. Renders the same gated `<BossVideoPlayer>` into any element.
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
import { createPlayer } from 'boss-web-player-sdk';
|
|
204
|
-
import 'boss-web-player-sdk/css';
|
|
205
|
-
|
|
206
|
-
const player = createPlayer(document.getElementById('player')!, {
|
|
207
|
-
playerKey, // from your app config / env
|
|
208
|
-
src: 'https://cdn.example.com/video.m3u8',
|
|
209
|
-
autoplay: true,
|
|
210
|
-
muted: true,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
player.update({ src: 'https://cdn.example.com/other.m3u8' }); // re-render with new props
|
|
214
|
-
player.destroy(); // unmount & release resources
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Headless core (no React)
|
|
218
|
-
|
|
219
|
-
Import from the `/core` subpath for a zero-React, zero-UI player and modules. This entry is **not**
|
|
220
|
-
player-key gated — you drive everything yourself.
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
import { VideoPlayerSDK } from 'boss-web-player-sdk/core';
|
|
224
|
-
|
|
225
|
-
const player = new VideoPlayerSDK({
|
|
226
|
-
container: document.getElementById('player')!,
|
|
227
|
-
src: 'https://cdn.example.com/video.m3u8',
|
|
228
|
-
autoplay: false,
|
|
229
|
-
muted: false,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// Playback
|
|
233
|
-
player.play();
|
|
234
|
-
player.pause();
|
|
235
|
-
player.seek(30);
|
|
236
|
-
player.setVolume(0.8);
|
|
237
|
-
player.setMute(false);
|
|
238
|
-
player.setPlaybackRate(1.5);
|
|
239
|
-
player.setQuality(qualityId); // id from a `qualitylevels` event entry
|
|
240
|
-
|
|
241
|
-
// Events (EventEmitter-style)
|
|
242
|
-
player.on('play', () => {});
|
|
243
|
-
player.on('qualitychange', (q) => {});
|
|
244
|
-
player.on('subtitlesloaded', (tracks) => {});
|
|
245
|
-
|
|
246
|
-
player.destroy(); // clean up
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
**Emitted events:** `play`, `pause`, `ended`, `timeupdate`, `seeking`, `buffering`, `volumechange`,
|
|
250
|
-
`ratechange`, `pipchange`, `error`, `qualitylevels`, `qualitychange`, `subtitlesloaded`,
|
|
251
|
-
`audiotracksloaded`, `audiotrackchange`, `keymomentsloaded`, `chaptersloaded`, `adbreaksloaded`,
|
|
252
|
-
`adbreakchange`.
|
|
253
|
-
|
|
254
|
-
The `/core` entry also exposes the individual modules: `AnalyticsModule`,
|
|
255
|
-
`SubtitlesModule`, `ThumbnailsModule`, `KeyMomentsModule`, `ChaptersModule`, `CastingModule`,
|
|
256
|
-
`DRMModule`, and `BasePlayerPlugin`.
|
|
257
|
-
|
|
258
|
-
## CORS & proxying
|
|
259
|
-
|
|
260
|
-
The player fetches the manifest and media segments **from the browser**, so those origins must send CORS
|
|
261
|
-
headers. Two tools help:
|
|
262
|
-
|
|
263
|
-
- **`apiBaseUrl`** — optional override for GoBOSS API calls. Use it for a same-origin reverse proxy
|
|
264
|
-
during local development, or to point a non-production build at the staging API
|
|
265
|
-
(`apiBaseUrl="https://dev-api.go-boss.com"`). Omit it in production, where the default is the
|
|
266
|
-
production API host.
|
|
267
|
-
- **`proxyDomains`** — a comma-separated `"<host>=/<proxyPath>"` map. Any stream URL whose host matches is
|
|
268
|
-
rewritten to `<proxyPath><pathname><search>`, and applied to the manifest **and** every segment/key
|
|
269
|
-
request. Back each `<proxyPath>` with a same-origin dev proxy.
|
|
270
|
-
|
|
271
|
-
```tsx
|
|
272
|
-
<BossVideoPlayer
|
|
273
|
-
playerKey={playerKey}
|
|
274
|
-
src="https://master.example.com/index.m3u8"
|
|
275
|
-
apiBaseUrl="/api-proxy"
|
|
276
|
-
proxyDomains="segments.example.com=/seg-proxy,master.example.com=/mt-proxy"
|
|
277
|
-
/>
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
> Proxying is a **development** convenience. For production, configure CORS on the content origin
|
|
281
|
-
> (S3 / CloudFront / MediaTailor) — you cannot proxy every viewer's traffic.
|
|
282
|
-
|
|
283
|
-
## DRM
|
|
284
|
-
|
|
285
|
-
```ts
|
|
286
|
-
const drmConfig = {
|
|
287
|
-
authToken: 'bearer-token', // sent with license/segment requests
|
|
288
|
-
watermarkText: 'Your Brand',
|
|
289
|
-
fairplayLicenseUrl: 'https://...', // Safari / Apple
|
|
290
|
-
widevineServiceUrl: 'https://...', // Chrome / Android
|
|
291
|
-
};
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
`licenseKey` is a separate, plan-level gate: when your resolved plan has DRM enabled, a non-empty
|
|
295
|
-
`licenseKey` must be provided or the player shows a "Playback restricted" overlay.
|
|
296
|
-
|
|
297
|
-
## Analytics
|
|
298
|
-
|
|
299
|
-
Every player event flows through `onAnalyticsEvent`:
|
|
300
|
-
|
|
301
|
-
```tsx
|
|
302
|
-
<BossVideoPlayer
|
|
303
|
-
playerKey={playerKey}
|
|
304
|
-
src="https://cdn.example.com/video.m3u8"
|
|
305
|
-
onAnalyticsEvent={(e) => console.log(e.eventType, e)}
|
|
306
|
-
/>
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
To forward events anywhere else — your own warehouse, a third-party analytics product — use
|
|
310
|
-
`onAnalyticsEvent` and send them on from there. The SDK reports session and event telemetry to the
|
|
311
|
-
GoBOSS backend on its own; `onAnalyticsEvent` is purely additive and does not replace it.
|
|
312
|
-
|
|
313
|
-
## Keyboard shortcuts
|
|
314
|
-
|
|
315
|
-
| Key | Action |
|
|
316
|
-
|---|---|
|
|
317
|
-
| `Space` / `K` | Play / Pause |
|
|
318
|
-
| `J` / `←` | Seek back 10s |
|
|
319
|
-
| `L` / `→` | Seek forward 10s |
|
|
320
|
-
| `↑` / `↓` | Volume ±10% |
|
|
321
|
-
| `M` | Mute toggle |
|
|
322
|
-
| `F` | Fullscreen toggle |
|
|
323
|
-
| `P` | Picture-in-Picture toggle |
|
|
324
|
-
| `C` | Subtitles toggle |
|
|
325
|
-
|
|
326
|
-
## Exports
|
|
327
|
-
|
|
328
|
-
```ts
|
|
329
|
-
// React component (gated, drop-in)
|
|
330
|
-
import { BossVideoPlayer, type BossVideoPlayerProps } from 'boss-web-player-sdk';
|
|
331
|
-
|
|
332
|
-
// Framework-agnostic mount
|
|
333
|
-
import { createPlayer, type PlayerProps, type PlayerInstance } from 'boss-web-player-sdk';
|
|
334
|
-
|
|
335
|
-
// Lower-level React UI / headless core
|
|
336
|
-
import { WebVideoPlayer, VideoPlayerSDK } from 'boss-web-player-sdk';
|
|
337
|
-
|
|
338
|
-
// Advanced: raw SDK API calls
|
|
339
|
-
import { initSdk, startSession, sendHeartbeat, endSession, sendEvent } from 'boss-web-player-sdk';
|
|
340
|
-
|
|
341
|
-
// Types
|
|
342
|
-
import type {
|
|
343
|
-
AnalyticsEvent, AnalyticsCallback, Chapter, KeyMoment, SubtitleTrack,
|
|
344
|
-
VideoQuality, ThumbnailConfig, DRMConfig, PlayerSDKOptions,
|
|
345
|
-
FeatureFlags, SubtitleStyle,
|
|
346
|
-
} from 'boss-web-player-sdk';
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
## Browser support
|
|
350
|
-
|
|
351
|
-
| Browser | Version |
|
|
352
|
-
|---|---|
|
|
353
|
-
| Chrome / Edge | 90+ |
|
|
354
|
-
| Firefox | 88+ |
|
|
355
|
-
| Safari (incl. iOS) | 14+ |
|
|
356
|
-
| Android Chrome | 90+ |
|
|
357
|
-
|
|
358
|
-
## Module formats
|
|
359
|
-
|
|
360
|
-
Ships **ES Module** (`dist/index.js`) and **CommonJS** (`dist/index.cjs`) builds with bundled TypeScript
|
|
361
|
-
definitions and an extracted stylesheet (`boss-web-player-sdk/css`). `react` and `react-dom` are
|
|
362
|
-
externalized (see peer dependencies); `hls.js` and `dashjs` are bundled (lazily).
|
|
363
|
-
|
|
364
|
-
## License
|
|
365
|
-
|
|
366
|
-
MIT — see [LICENSE](./LICENSE).
|
|
1
|
+
# boss-web-player-sdk
|
|
2
|
+
|
|
3
|
+
A unified, high-performance OTT web video player SDK for adaptive streaming — HLS/DASH, token-based DRM, dynamic watermarking, captions, chapters, casting, and premium UI controls.
|
|
4
|
+
|
|
5
|
+
> **Heads up:** the high-level `<BossVideoPlayer>` component is **tenant-gated**. It validates your GoBOSS player key before playback starts, and resolves its feature set (subtitles, DRM, chromecast, etc.) from your plan. Obtain a player key from the GoBOSS dashboard and supply it from your app config (never commit real keys). For a generic, ungated player use the [headless core entry](#headless-core-no-react).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Adaptive streaming** — HLS (bundled `hls.js`) and DASH (bundled `dashjs`) with automatic quality switching
|
|
10
|
+
- **DRM** — token-based authorization, FairPlay / Widevine, dynamic watermarking
|
|
11
|
+
- **Rich controls** — quality, playback speed, subtitles, PiP, fullscreen, chapters/key-moments
|
|
12
|
+
- **Casting** — Chromecast and AirPlay
|
|
13
|
+
- **Server-side ads (SSAI)** — AWS MediaTailor ad-break tracking and skip-ad flow
|
|
14
|
+
- **Episodic playback** — Skip Intro and an auto-advancing Next Episode chip, for series content
|
|
15
|
+
- **Analytics** — first-party session/event telemetry, plus an `onAnalyticsEvent` callback
|
|
16
|
+
- **Framework-agnostic** — React component, a vanilla `createPlayer()` mount, and a zero-React headless core
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install boss-web-player-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Peer dependencies
|
|
25
|
+
|
|
26
|
+
| Package | Required? | Notes |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `react`, `react-dom` (`^18` or `^19`) | **Required** for the React component & `createPlayer` | Not needed if you only use the headless `/core` entry |
|
|
29
|
+
|
|
30
|
+
> **DASH works out of the box.** `dashjs` is bundled into the SDK (lazily, like `hls.js`) — you do **not** need to install it separately. The DASH engine is only fetched by the browser when a `.mpd` stream actually plays, so HLS-only apps never download it.
|
|
31
|
+
|
|
32
|
+
### CSS — required, import once
|
|
33
|
+
|
|
34
|
+
> **The player stylesheet must be imported separately.** The SDK ships CSS as a standalone
|
|
35
|
+
> file so your bundler can handle it correctly (critical for SSR frameworks like Next.js).
|
|
36
|
+
> Forgetting this import will result in a broken, unstyled player.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import 'boss-web-player-sdk/css';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Import it once at your app entry point (e.g. `main.tsx`, `_app.tsx`, `layout.tsx`) and it
|
|
43
|
+
applies globally — you do not need to import it in every file that uses `<BossVideoPlayer>`.
|
|
44
|
+
|
|
45
|
+
## Quick start (React)
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { BossVideoPlayer } from 'boss-web-player-sdk';
|
|
49
|
+
import 'boss-web-player-sdk/css';
|
|
50
|
+
|
|
51
|
+
export default function App() {
|
|
52
|
+
return (
|
|
53
|
+
<BossVideoPlayer
|
|
54
|
+
playerKey={process.env.NEXT_PUBLIC_PLAYER_KEY!} // from your app config / env (required)
|
|
55
|
+
src="https://cdn.example.com/video.m3u8" // HLS (.m3u8) or DASH (.mpd)
|
|
56
|
+
title="My Video"
|
|
57
|
+
themeColor="#6366f1"
|
|
58
|
+
autoplay
|
|
59
|
+
muted
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The component shows a loading spinner while it validates the player key, then renders the
|
|
66
|
+
player. If the key is invalid or the API is unreachable, it renders an error state instead.
|
|
67
|
+
|
|
68
|
+
## Next.js
|
|
69
|
+
|
|
70
|
+
The SDK works in Next.js (both Pages Router and App Router). The player is entirely
|
|
71
|
+
client-side — it uses browser APIs (`HTMLVideoElement`, `window`, `navigator`) that do not
|
|
72
|
+
exist on the server.
|
|
73
|
+
|
|
74
|
+
**App Router** — mark any file that imports the player as a Client Component:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
// app/watch/page.tsx
|
|
78
|
+
'use client';
|
|
79
|
+
|
|
80
|
+
import { BossVideoPlayer } from 'boss-web-player-sdk';
|
|
81
|
+
|
|
82
|
+
export default function WatchPage() {
|
|
83
|
+
return (
|
|
84
|
+
<BossVideoPlayer
|
|
85
|
+
playerKey={process.env.NEXT_PUBLIC_PLAYER_KEY!}
|
|
86
|
+
src="https://cdn.example.com/video.m3u8"
|
|
87
|
+
autoplay
|
|
88
|
+
muted
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Import the CSS in your root layout so it loads once for the whole app:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// app/layout.tsx
|
|
98
|
+
import 'boss-web-player-sdk/css';
|
|
99
|
+
|
|
100
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
101
|
+
return <html><body>{children}</body></html>;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Pages Router** — import the CSS in `_app.tsx` (or `_app.js`):
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// pages/_app.tsx
|
|
109
|
+
import 'boss-web-player-sdk/css';
|
|
110
|
+
import type { AppProps } from 'next/app';
|
|
111
|
+
|
|
112
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
113
|
+
return <Component {...pageProps} />;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
No `'use client'` directive is needed in the Pages Router — all pages are client-rendered
|
|
118
|
+
by default.
|
|
119
|
+
|
|
120
|
+
## `<BossVideoPlayer>` props
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
interface BossVideoPlayerProps {
|
|
124
|
+
// ── Required ──────────────────────────────────────────────
|
|
125
|
+
playerKey: string; // from your GoBOSS dashboard — supply via app config/env
|
|
126
|
+
src: string; // HLS (.m3u8) or DASH (.mpd) URL
|
|
127
|
+
|
|
128
|
+
// ── Identity / theming ────────────────────────────────────
|
|
129
|
+
title?: string; // Title shown in the player UI
|
|
130
|
+
watermark?: string; // Watermark text stamped on the video
|
|
131
|
+
themeColor?: string; // Accent color (hex). Default '#6366f1'
|
|
132
|
+
licenseKey?: string; // Required by DRM-enabled plans (presence-checked)
|
|
133
|
+
|
|
134
|
+
// ── Networking ────────────────────────────────────────────
|
|
135
|
+
apiBaseUrl?: string; // API base override: reverse proxy path, or the staging host
|
|
136
|
+
proxyDomains?: string; // CORS proxy map, "host=/path,host2=/path2" (see CORS)
|
|
137
|
+
|
|
138
|
+
// ── Ads (AWS MediaTailor SSAI) ────────────────────────────
|
|
139
|
+
adTrackingUrl?: string; // Ad-break tracking URL
|
|
140
|
+
overlayAdUrl?: string; // Overlay ad tracking URL
|
|
141
|
+
enableSkipAd?: boolean;
|
|
142
|
+
skipAdAfterSeconds?: number;
|
|
143
|
+
|
|
144
|
+
// ── Series / episodic ─────────────────────────────────────
|
|
145
|
+
introStartTime?: number; // Content-relative intro start, in seconds
|
|
146
|
+
introEndTime?: number; // Content-relative intro end, in seconds — Skip Intro seeks here
|
|
147
|
+
hasNextEpisode?: boolean; // Whether another episode is available to auto-advance into
|
|
148
|
+
outroStartTime?: number; // Content-relative outro/credits start, in seconds — reveals the Next Episode chip
|
|
149
|
+
nextEpisodeLabel?: string; // Label on the Next Episode chip. Default 'Next Episode'
|
|
150
|
+
nextEpisodeAutoAdvanceSeconds?: number; // Seconds before auto-advancing once the chip is shown. Default 5
|
|
151
|
+
onNextEpisode?: () => void; // Called on chip click, or when the auto-advance timer fires
|
|
152
|
+
|
|
153
|
+
// ── Behavior / UI ─────────────────────────────────────────
|
|
154
|
+
autoplay?: boolean; // Default false
|
|
155
|
+
muted?: boolean; // Default false (use with autoplay — browsers block unmuted autoplay)
|
|
156
|
+
autoFullscreen?: boolean;
|
|
157
|
+
enableControls?: boolean; // Default true
|
|
158
|
+
chaptersDisplayMode?: 'strip' | 'panel'; // Default 'strip'
|
|
159
|
+
volumeControlType?: 'slider' | 'button'; // Default 'slider'
|
|
160
|
+
subtitleStyle?: { size?: 'small'|'medium'|'large'; background?: 'none'|'dim'|'solid'; color?: string };
|
|
161
|
+
|
|
162
|
+
// ── Integrations ──────────────────────────────────────────
|
|
163
|
+
drmConfig?: DRMConfig; // DRM license / token configuration
|
|
164
|
+
|
|
165
|
+
// ── Callbacks ─────────────────────────────────────────────
|
|
166
|
+
onAnalyticsEvent?: (event: AnalyticsEvent) => void; // Every analytics event
|
|
167
|
+
onKeyMomentsLoaded?: (keyMoments: Chapter[]) => void; // When chapters parse from the stream
|
|
168
|
+
onTimeUpdate?: (currentTime: number) => void; // Every timeupdate — use to persist watch progress
|
|
169
|
+
|
|
170
|
+
// ── Resume playback ───────────────────────────────────────
|
|
171
|
+
initialTime?: number; // Seek to this position (seconds) once the video is ready
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Skip Intro / Next Episode (series)
|
|
176
|
+
|
|
177
|
+
Both are driven entirely by props — the SDK owns the timing, the chip UI, and the seek/auto-advance
|
|
178
|
+
behavior. All times are **content-relative** (the original episode timeline), so they stay correct
|
|
179
|
+
even if the stream has spliced ad breaks.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
<BossVideoPlayer
|
|
183
|
+
playerKey={playerKey}
|
|
184
|
+
src="https://cdn.example.com/episode-04.m3u8"
|
|
185
|
+
introStartTime={0}
|
|
186
|
+
introEndTime={78} // Skip Intro shows between 0s–78s, seeks to 78s on click
|
|
187
|
+
hasNextEpisode={true}
|
|
188
|
+
outroStartTime={1230} // Next Episode chip appears once playback reaches 1230s
|
|
189
|
+
nextEpisodeLabel="S2 · E5" // optional — defaults to "Next Episode"
|
|
190
|
+
nextEpisodeAutoAdvanceSeconds={5} // optional — auto-advances 5s after the chip appears
|
|
191
|
+
onNextEpisode={() => loadNextEpisode()}
|
|
192
|
+
/>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> Feature availability (subtitles, chromecast, DRM, multiple resolutions, etc.) is **resolved from your
|
|
196
|
+
> plan** by the GoBOSS API at init — it is not toggled by individual props on this component.
|
|
197
|
+
|
|
198
|
+
## Use without JSX — `createPlayer()`
|
|
199
|
+
|
|
200
|
+
For Vue, Angular, Svelte, or vanilla JS. Renders the same gated `<BossVideoPlayer>` into any element.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { createPlayer } from 'boss-web-player-sdk';
|
|
204
|
+
import 'boss-web-player-sdk/css';
|
|
205
|
+
|
|
206
|
+
const player = createPlayer(document.getElementById('player')!, {
|
|
207
|
+
playerKey, // from your app config / env
|
|
208
|
+
src: 'https://cdn.example.com/video.m3u8',
|
|
209
|
+
autoplay: true,
|
|
210
|
+
muted: true,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
player.update({ src: 'https://cdn.example.com/other.m3u8' }); // re-render with new props
|
|
214
|
+
player.destroy(); // unmount & release resources
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Headless core (no React)
|
|
218
|
+
|
|
219
|
+
Import from the `/core` subpath for a zero-React, zero-UI player and modules. This entry is **not**
|
|
220
|
+
player-key gated — you drive everything yourself.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { VideoPlayerSDK } from 'boss-web-player-sdk/core';
|
|
224
|
+
|
|
225
|
+
const player = new VideoPlayerSDK({
|
|
226
|
+
container: document.getElementById('player')!,
|
|
227
|
+
src: 'https://cdn.example.com/video.m3u8',
|
|
228
|
+
autoplay: false,
|
|
229
|
+
muted: false,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Playback
|
|
233
|
+
player.play();
|
|
234
|
+
player.pause();
|
|
235
|
+
player.seek(30);
|
|
236
|
+
player.setVolume(0.8);
|
|
237
|
+
player.setMute(false);
|
|
238
|
+
player.setPlaybackRate(1.5);
|
|
239
|
+
player.setQuality(qualityId); // id from a `qualitylevels` event entry
|
|
240
|
+
|
|
241
|
+
// Events (EventEmitter-style)
|
|
242
|
+
player.on('play', () => {});
|
|
243
|
+
player.on('qualitychange', (q) => {});
|
|
244
|
+
player.on('subtitlesloaded', (tracks) => {});
|
|
245
|
+
|
|
246
|
+
player.destroy(); // clean up
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Emitted events:** `play`, `pause`, `ended`, `timeupdate`, `seeking`, `buffering`, `volumechange`,
|
|
250
|
+
`ratechange`, `pipchange`, `error`, `qualitylevels`, `qualitychange`, `subtitlesloaded`,
|
|
251
|
+
`audiotracksloaded`, `audiotrackchange`, `keymomentsloaded`, `chaptersloaded`, `adbreaksloaded`,
|
|
252
|
+
`adbreakchange`.
|
|
253
|
+
|
|
254
|
+
The `/core` entry also exposes the individual modules: `AnalyticsModule`,
|
|
255
|
+
`SubtitlesModule`, `ThumbnailsModule`, `KeyMomentsModule`, `ChaptersModule`, `CastingModule`,
|
|
256
|
+
`DRMModule`, and `BasePlayerPlugin`.
|
|
257
|
+
|
|
258
|
+
## CORS & proxying
|
|
259
|
+
|
|
260
|
+
The player fetches the manifest and media segments **from the browser**, so those origins must send CORS
|
|
261
|
+
headers. Two tools help:
|
|
262
|
+
|
|
263
|
+
- **`apiBaseUrl`** — optional override for GoBOSS API calls. Use it for a same-origin reverse proxy
|
|
264
|
+
during local development, or to point a non-production build at the staging API
|
|
265
|
+
(`apiBaseUrl="https://dev-api.go-boss.com"`). Omit it in production, where the default is the
|
|
266
|
+
production API host.
|
|
267
|
+
- **`proxyDomains`** — a comma-separated `"<host>=/<proxyPath>"` map. Any stream URL whose host matches is
|
|
268
|
+
rewritten to `<proxyPath><pathname><search>`, and applied to the manifest **and** every segment/key
|
|
269
|
+
request. Back each `<proxyPath>` with a same-origin dev proxy.
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
<BossVideoPlayer
|
|
273
|
+
playerKey={playerKey}
|
|
274
|
+
src="https://master.example.com/index.m3u8"
|
|
275
|
+
apiBaseUrl="/api-proxy"
|
|
276
|
+
proxyDomains="segments.example.com=/seg-proxy,master.example.com=/mt-proxy"
|
|
277
|
+
/>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
> Proxying is a **development** convenience. For production, configure CORS on the content origin
|
|
281
|
+
> (S3 / CloudFront / MediaTailor) — you cannot proxy every viewer's traffic.
|
|
282
|
+
|
|
283
|
+
## DRM
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
const drmConfig = {
|
|
287
|
+
authToken: 'bearer-token', // sent with license/segment requests
|
|
288
|
+
watermarkText: 'Your Brand',
|
|
289
|
+
fairplayLicenseUrl: 'https://...', // Safari / Apple
|
|
290
|
+
widevineServiceUrl: 'https://...', // Chrome / Android
|
|
291
|
+
};
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`licenseKey` is a separate, plan-level gate: when your resolved plan has DRM enabled, a non-empty
|
|
295
|
+
`licenseKey` must be provided or the player shows a "Playback restricted" overlay.
|
|
296
|
+
|
|
297
|
+
## Analytics
|
|
298
|
+
|
|
299
|
+
Every player event flows through `onAnalyticsEvent`:
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
<BossVideoPlayer
|
|
303
|
+
playerKey={playerKey}
|
|
304
|
+
src="https://cdn.example.com/video.m3u8"
|
|
305
|
+
onAnalyticsEvent={(e) => console.log(e.eventType, e)}
|
|
306
|
+
/>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
To forward events anywhere else — your own warehouse, a third-party analytics product — use
|
|
310
|
+
`onAnalyticsEvent` and send them on from there. The SDK reports session and event telemetry to the
|
|
311
|
+
GoBOSS backend on its own; `onAnalyticsEvent` is purely additive and does not replace it.
|
|
312
|
+
|
|
313
|
+
## Keyboard shortcuts
|
|
314
|
+
|
|
315
|
+
| Key | Action |
|
|
316
|
+
|---|---|
|
|
317
|
+
| `Space` / `K` | Play / Pause |
|
|
318
|
+
| `J` / `←` | Seek back 10s |
|
|
319
|
+
| `L` / `→` | Seek forward 10s |
|
|
320
|
+
| `↑` / `↓` | Volume ±10% |
|
|
321
|
+
| `M` | Mute toggle |
|
|
322
|
+
| `F` | Fullscreen toggle |
|
|
323
|
+
| `P` | Picture-in-Picture toggle |
|
|
324
|
+
| `C` | Subtitles toggle |
|
|
325
|
+
|
|
326
|
+
## Exports
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
// React component (gated, drop-in)
|
|
330
|
+
import { BossVideoPlayer, type BossVideoPlayerProps } from 'boss-web-player-sdk';
|
|
331
|
+
|
|
332
|
+
// Framework-agnostic mount
|
|
333
|
+
import { createPlayer, type PlayerProps, type PlayerInstance } from 'boss-web-player-sdk';
|
|
334
|
+
|
|
335
|
+
// Lower-level React UI / headless core
|
|
336
|
+
import { WebVideoPlayer, VideoPlayerSDK } from 'boss-web-player-sdk';
|
|
337
|
+
|
|
338
|
+
// Advanced: raw SDK API calls
|
|
339
|
+
import { initSdk, startSession, sendHeartbeat, endSession, sendEvent } from 'boss-web-player-sdk';
|
|
340
|
+
|
|
341
|
+
// Types
|
|
342
|
+
import type {
|
|
343
|
+
AnalyticsEvent, AnalyticsCallback, Chapter, KeyMoment, SubtitleTrack,
|
|
344
|
+
VideoQuality, ThumbnailConfig, DRMConfig, PlayerSDKOptions,
|
|
345
|
+
FeatureFlags, SubtitleStyle,
|
|
346
|
+
} from 'boss-web-player-sdk';
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Browser support
|
|
350
|
+
|
|
351
|
+
| Browser | Version |
|
|
352
|
+
|---|---|
|
|
353
|
+
| Chrome / Edge | 90+ |
|
|
354
|
+
| Firefox | 88+ |
|
|
355
|
+
| Safari (incl. iOS) | 14+ |
|
|
356
|
+
| Android Chrome | 90+ |
|
|
357
|
+
|
|
358
|
+
## Module formats
|
|
359
|
+
|
|
360
|
+
Ships **ES Module** (`dist/index.js`) and **CommonJS** (`dist/index.cjs`) builds with bundled TypeScript
|
|
361
|
+
definitions and an extracted stylesheet (`boss-web-player-sdk/css`). `react` and `react-dom` are
|
|
362
|
+
externalized (see peer dependencies); `hls.js` and `dashjs` are bundled (lazily).
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
MIT — see [LICENSE](./LICENSE).
|