boss-web-player-sdk 1.1.0

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/dist/core.d.ts ADDED
@@ -0,0 +1,482 @@
1
+ export declare type AnalyticsCallback = (event: AnalyticsEvent) => void;
2
+
3
+ export declare interface AnalyticsEvent {
4
+ eventType: 'play' | 'pause' | 'seek' | 'ended' | 'complete' | 'buffering_start' | 'buffering_end' | 'stall' | 'quality_change' | 'audio_track_change' | 'volume_change' | 'speed_change' | 'subtitle_change' | 'pip_toggle' | 'fullscreen_enter' | 'fullscreen_exit' | 'cast_start' | 'cast_stop' | 'error' | 'network_error' | 'session_start' | 'video_loaded' | 'first_quartile' | 'midpoint' | 'third_quartile' | 'heartbeat' | 'watch_progress' | 'streaming_time';
5
+ timestamp: number;
6
+ currentTime: number;
7
+ duration: number;
8
+ bitrate?: number;
9
+ rendition?: string;
10
+ fromRendition?: string;
11
+ volume?: number;
12
+ speed?: number;
13
+ errorMessage?: string;
14
+ errorCode?: number;
15
+ sessionId?: string;
16
+ videoId?: string;
17
+ deviceType?: string;
18
+ networkType?: string;
19
+ watchPercentage?: number;
20
+ totalWatchTime?: number;
21
+ streamingTime?: number;
22
+ adWatchTime?: number;
23
+ bufferingCount?: number;
24
+ totalBufferingTime?: number;
25
+ seekFrom?: number;
26
+ pipState?: 'entered' | 'exited';
27
+ }
28
+
29
+ export declare class AnalyticsModule {
30
+ private callback?;
31
+ private heartbeatInterval?;
32
+ private watchProgressTimer?;
33
+ private isBuffering;
34
+ private sessionId;
35
+ private videoId;
36
+ private deviceType;
37
+ private networkType;
38
+ private adBreaks;
39
+ private isFirstPlay;
40
+ private watchStartTime;
41
+ private totalWatchTime;
42
+ private streamingWindowStart;
43
+ private streamingTime;
44
+ private isInAdBreak;
45
+ private adWatchWindowStart;
46
+ private adWatchTime;
47
+ private bufferingCount;
48
+ private totalBufferingTime;
49
+ private bufferingStartTime;
50
+ private milestonesHit;
51
+ private lastHeartbeatPosition;
52
+ private lastHeartbeatAt;
53
+ constructor(callback?: AnalyticsCallback, src?: string);
54
+ registerCallback(callback: AnalyticsCallback): void;
55
+ setAdBreaks(adBreaks: Array<{
56
+ startTime: number;
57
+ endTime: number;
58
+ }>): void;
59
+ private getTotalAdDuration;
60
+ private getElapsedAdTime;
61
+ track(eventType: AnalyticsEvent['eventType'], videoEl: HTMLVideoElement, extra?: Partial<AnalyticsEvent>): void;
62
+ startHeartbeat(videoEl: HTMLVideoElement, getExtra: () => Partial<AnalyticsEvent>, watchProgressInterval?: number): void;
63
+ stopHeartbeat(): void;
64
+ setBuffering(isBuffering: boolean, videoEl: HTMLVideoElement, getExtra: () => Partial<AnalyticsEvent>): void;
65
+ setAdBreak(inAdBreak: boolean, videoEl: HTMLVideoElement): void;
66
+ private checkMilestones;
67
+ private checkStall;
68
+ private getTotalWatchTime;
69
+ private getStreamingTime;
70
+ private getAdWatchTime;
71
+ private dispatchRaw;
72
+ private generateSessionId;
73
+ private extractVideoId;
74
+ private getDeviceType;
75
+ private getNetworkType;
76
+ }
77
+
78
+ export declare abstract class BasePlayerPlugin implements PlayerPlugin {
79
+ abstract id: string;
80
+ abstract name: string;
81
+ protected player: any;
82
+ install(player: any): void;
83
+ protected abstract onInstall(): void;
84
+ destroy(): void;
85
+ protected onDestroy(): void;
86
+ }
87
+
88
+ export declare class CastingModule {
89
+ private isCasting;
90
+ private castDeviceName;
91
+ private onCastStateChangeCallback?;
92
+ private onRemoteStateChangeCallback?;
93
+ private castContext;
94
+ private remotePlayer;
95
+ private remotePlayerController;
96
+ constructor();
97
+ private initCastApi;
98
+ getCastingState(): {
99
+ isCasting: boolean;
100
+ deviceName: string;
101
+ };
102
+ getRemoteState(): RemoteCastState | null;
103
+ /**
104
+ * Prompts the native Google Cast device picker overlay, then loads media on the remote device.
105
+ * The caller is responsible for pausing local playback before/after this resolves.
106
+ */
107
+ requestSession(currentSrc: string, currentTime: number): Promise<void>;
108
+ /**
109
+ * Disconnects the current cast session.
110
+ */
111
+ stopCasting(): void;
112
+ remotePlayPause(): void;
113
+ remoteSeek(time: number): void;
114
+ remoteSetVolume(volume: number): void;
115
+ remoteSetMute(muted: boolean): void;
116
+ onCastStateChange(callback: (isCasting: boolean, deviceName: string) => void): void;
117
+ onRemoteStateChange(callback: (state: RemoteCastState) => void): void;
118
+ requestAirPlaySession(videoElement: HTMLVideoElement): void;
119
+ stopAirPlay(videoElement: HTMLVideoElement): void;
120
+ isAirPlayAvailable(): boolean;
121
+ }
122
+
123
+ export declare interface Chapter {
124
+ title: string;
125
+ startTime: number;
126
+ endTime: number;
127
+ thumbnail?: string;
128
+ description?: string;
129
+ }
130
+
131
+ export declare class ChaptersModule extends KeyMomentsModule {
132
+ }
133
+
134
+ export declare interface DRMConfig {
135
+ widevineLicenseUrl?: string;
136
+ playreadyLicenseUrl?: string;
137
+ fairplayLicenseUrl?: string;
138
+ authToken?: string;
139
+ authHeader?: string;
140
+ allowedDomains?: string[];
141
+ watermarkText?: string;
142
+ }
143
+
144
+ export declare class DRMModule {
145
+ private config?;
146
+ private watermarkElement?;
147
+ private floatInterval?;
148
+ constructor(config?: DRMConfig);
149
+ /**
150
+ * Validates if the active origin domain is permitted to load this stream asset.
151
+ */
152
+ validateDomain(currentDomain: string): boolean;
153
+ getAuthToken(): string | undefined;
154
+ getAuthHeader(): string | undefined;
155
+ getRequestHeaders(): Record<string, string>;
156
+ /**
157
+ * Injects an animated floating watermark on top of the media container to obstruct piracy or recording.
158
+ */
159
+ setupWatermark(container: HTMLElement): void;
160
+ /**
161
+ * Cleans up active watermarks.
162
+ */
163
+ removeWatermark(): void;
164
+ isDRMProtected(): boolean;
165
+ getDRMDetails(): {
166
+ widevine: string | null;
167
+ playready: string | null;
168
+ fairplay: string | null;
169
+ authTokenPresent: boolean;
170
+ allowedDomains: string[];
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Sends all player analytics events to Firebase Analytics (GA4).
176
+ *
177
+ * Events appear in:
178
+ * Firebase Console → Analytics → Events (24-48 hr aggregated view)
179
+ * Firebase Console → Analytics → DebugView (real-time while testing)
180
+ * Google Analytics 4 → Reports → Realtime (within a few minutes)
181
+ *
182
+ * No Firestore / database setup required — Firebase Analytics handles all storage.
183
+ */
184
+ export declare class FirebaseAnalyticsProvider {
185
+ private analytics;
186
+ private logEventFn;
187
+ private pendingEvents;
188
+ constructor(config: FirebaseConfig);
189
+ private init;
190
+ private flushPending;
191
+ createCallback(): AnalyticsCallback;
192
+ private handleEvent;
193
+ private logToFirebase;
194
+ private buildParams;
195
+ destroy(): Promise<void>;
196
+ }
197
+
198
+ export declare interface FirebaseConfig {
199
+ apiKey: string;
200
+ authDomain: string;
201
+ projectId: string;
202
+ storageBucket: string;
203
+ messagingSenderId: string;
204
+ appId: string;
205
+ measurementId?: string;
206
+ }
207
+
208
+ export declare type KeyMoment = Chapter;
209
+
210
+ export declare class KeyMomentsModule {
211
+ private keyMoments;
212
+ private currentMomentIndex;
213
+ private onMomentChangeCallback?;
214
+ constructor(keyMoments?: KeyMoment[]);
215
+ /**
216
+ * Sorts and stores the key moments.
217
+ */
218
+ setKeyMoments(keyMoments: KeyMoment[]): void;
219
+ getKeyMoments(): KeyMoment[];
220
+ /**
221
+ * Locates the key moment corresponding to the active playback timestamp.
222
+ */
223
+ getCurrentMoment(currentTime: number): {
224
+ keyMoment: KeyMoment | null;
225
+ index: number;
226
+ };
227
+ /**
228
+ * Evaluates if playback has crossed a key moment boundary.
229
+ */
230
+ updateTime(currentTime: number): void;
231
+ /**
232
+ * Subscribes a callback to change events.
233
+ */
234
+ onMomentChange(callback: (keyMoment: KeyMoment | null, index: number) => void): void;
235
+ setChapters(chapters: KeyMoment[]): void;
236
+ getChapters(): KeyMoment[];
237
+ getCurrentChapter(currentTime: number): {
238
+ chapter: KeyMoment | null;
239
+ index: number;
240
+ };
241
+ onChapterChange(callback: (chapter: KeyMoment | null, index: number) => void): void;
242
+ }
243
+
244
+ export declare interface PlayerPlugin {
245
+ id: string;
246
+ name: string;
247
+ install(player: any): void;
248
+ destroy?(): void;
249
+ }
250
+
251
+ export declare interface PlayerSDKOptions {
252
+ container: HTMLElement;
253
+ src: string;
254
+ autoplay?: boolean;
255
+ muted?: boolean;
256
+ controls?: boolean;
257
+ chapters?: Chapter[];
258
+ keyMoments?: KeyMoment[];
259
+ subtitles?: SubtitleTrack[];
260
+ thumbnails?: ThumbnailConfig;
261
+ drm?: DRMConfig;
262
+ analyticsCallback?: AnalyticsCallback;
263
+ watchProgressInterval?: number;
264
+ themeColor?: string;
265
+ watermark?: string;
266
+ /**
267
+ * Optional URL transformer applied to every HLS segment/manifest request.
268
+ * Use this to route requests through a CORS proxy without hardcoding domains.
269
+ * Example: (url) => url.replace('https://cdn.example.com', '/my-proxy')
270
+ */
271
+ urlTransformer?: (url: string) => string;
272
+ }
273
+
274
+ declare interface RemoteCastState {
275
+ currentTime: number;
276
+ duration: number;
277
+ isPaused: boolean;
278
+ volumeLevel: number;
279
+ isMuted: boolean;
280
+ }
281
+
282
+ export declare class SubtitlesModule {
283
+ private tracks;
284
+ private activeTrackId;
285
+ private currentCues;
286
+ private activeText;
287
+ private onSubtitleChangeCallback?;
288
+ private onTrackSwitchCallback?;
289
+ constructor(tracks?: SubtitleTrack[]);
290
+ getTracks(): SubtitleTrack[];
291
+ getActiveTrackId(): string;
292
+ setHlsTracks(hlsTracks: SubtitleTrack[]): void;
293
+ addTrack(track: SubtitleTrack): void;
294
+ onTrackSwitch(callback: (track: SubtitleTrack | null) => void): void;
295
+ setCustomSubtitleText(text: string): void;
296
+ /**
297
+ * Switches the active track. Fetches external tracks if they need loading.
298
+ */
299
+ setActiveTrack(trackId: string): Promise<void>;
300
+ /**
301
+ * Scans the subtitle cues for the current playback position.
302
+ */
303
+ updateTime(currentTime: number): void;
304
+ /**
305
+ * Triggers the text update callback if a change in caption is detected.
306
+ */
307
+ private updateActiveText;
308
+ onSubtitleChange(callback: (text: string) => void): void;
309
+ /**
310
+ * Robust parser supporting WebVTT and SRT formats.
311
+ */
312
+ private parseVttOrSrt;
313
+ }
314
+
315
+ export declare interface SubtitleTrack {
316
+ id: string;
317
+ label: string;
318
+ lang: string;
319
+ src?: string;
320
+ isDefault?: boolean;
321
+ cues?: Array<{
322
+ startTime: number;
323
+ endTime: number;
324
+ text: string;
325
+ }>;
326
+ isHls?: boolean;
327
+ hlsTrackId?: number;
328
+ isNative?: boolean;
329
+ nativeTrackIndex?: number;
330
+ }
331
+
332
+ export declare interface ThumbnailConfig {
333
+ spriteUrl: string;
334
+ tileWidth: number;
335
+ tileHeight: number;
336
+ columns: number;
337
+ rows: number;
338
+ interval: number;
339
+ totalCount: number;
340
+ }
341
+
342
+ export declare class ThumbnailsModule {
343
+ private config?;
344
+ constructor(config?: ThumbnailConfig);
345
+ /**
346
+ * Calculates the position offset inside the sprite sheet for a given seek hover time.
347
+ */
348
+ getThumbnail(time: number): {
349
+ url: string;
350
+ x: number;
351
+ y: number;
352
+ width: number;
353
+ height: number;
354
+ } | null;
355
+ hasThumbnails(): boolean;
356
+ }
357
+
358
+ export declare class VideoPlayerSDK {
359
+ private options;
360
+ private videoElement;
361
+ private hlsInstance;
362
+ private dashInstance;
363
+ private activeQuality;
364
+ private qualityLevels;
365
+ analytics: AnalyticsModule;
366
+ keyMoments: KeyMomentsModule;
367
+ chapters: ChaptersModule;
368
+ subtitles: SubtitlesModule;
369
+ drm: DRMModule;
370
+ casting: CastingModule;
371
+ thumbnails: ThumbnailsModule;
372
+ private hlsSubtitleCues;
373
+ private hlsActiveSubtitleKey;
374
+ private audioTrackList;
375
+ private adBreaks;
376
+ private isAdBreak;
377
+ private contentPlaybackRate;
378
+ private networkErrorRetries;
379
+ private mediaErrorRecovered;
380
+ private static readonly MAX_NETWORK_RETRIES;
381
+ private eventListeners;
382
+ constructor(options: PlayerSDKOptions);
383
+ /**
384
+ * Builds the video DOM hierarchy, binds events, validates domain restrictions, and mounts DRM watermarks.
385
+ */
386
+ private initializePlayer;
387
+ /**
388
+ * Binds direct event listeners to the native HTML5 Video tag, routing them to our sub-packages.
389
+ */
390
+ private bindMediaEvents;
391
+ private rewriteToProxy;
392
+ /**
393
+ * Initializes HLS adaptive streaming through Hls.js or falls back to native browser playback.
394
+ */
395
+ private loadSource;
396
+ /**
397
+ * Sets up global lock-screen metadata and media control keys (Media Session API).
398
+ */
399
+ private setupBackgroundControls;
400
+ play(): void;
401
+ pause(): void;
402
+ seek(seconds: number): void;
403
+ setVolume(volume: number): void;
404
+ setMute(muted: boolean): void;
405
+ setPlaybackRate(rate: number): void;
406
+ /**
407
+ * Sets manual video quality rendition or switches back to auto bitrate scaling.
408
+ */
409
+ setQuality(qualityId: number): void;
410
+ /**
411
+ * Activates native Picture-in-Picture floating viewport.
412
+ */
413
+ togglePictureInPicture(): Promise<boolean>;
414
+ /**
415
+ * Requests element-level fullscreen.
416
+ */
417
+ toggleFullscreen(): void;
418
+ getVideoElement(): HTMLVideoElement;
419
+ getCurrentTime(): number;
420
+ getDuration(): number;
421
+ getVolume(): number;
422
+ isMuted(): boolean;
423
+ getPlaybackRate(): number;
424
+ getActiveQuality(): VideoQuality;
425
+ getQualityLevels(): VideoQuality[];
426
+ getBufferLength(): number;
427
+ getBufferedRanges(): Array<{
428
+ start: number;
429
+ end: number;
430
+ }>;
431
+ /**
432
+ * Returns true if the browser can decode at least one of the manifest's renditions.
433
+ *
434
+ * Deliberately conservative to avoid ever blocking a valid stream:
435
+ * - A codec that isn't declared is treated as playable (we never assume unsupported).
436
+ * - Any failure to verify (no MediaSource, isTypeSupported throws) returns true.
437
+ * - The stream is "playable" if even one rendition's declared codecs are all supported,
438
+ * matching how HLS.js itself selects a level.
439
+ * Returns false only when the browser explicitly reports every declared codec as
440
+ * undecodable (e.g. Dolby EC-3/AC-3 in Chrome).
441
+ */
442
+ private hasPlayableLevel;
443
+ private getAnalyticsPayload;
444
+ on(event: string, callback: (...args: any[]) => void): void;
445
+ off(event: string, callback: (...args: any[]) => void): void;
446
+ private emit;
447
+ private extractSubtitlesFromManifest;
448
+ private extractKeyMomentsFromManifest;
449
+ private extractAdBreaksFromManifest;
450
+ private buildManifestUrl;
451
+ private findFirstVariantUri;
452
+ private resolveUrl;
453
+ private parseAdBreaksFromFragments;
454
+ private parseAdBreaksFromPlaylist;
455
+ private isTimeInAdBreak;
456
+ getAdBreaks(): Array<{
457
+ startTime: number;
458
+ endTime: number;
459
+ }>;
460
+ setAdBreaks(breaks: Array<{
461
+ startTime: number;
462
+ endTime: number;
463
+ }>): void;
464
+ isInAdBreak(): boolean;
465
+ getAudioTracks(): Array<{
466
+ id: number;
467
+ label: string;
468
+ lang: string;
469
+ }>;
470
+ setAudioTrack(id: number): void;
471
+ destroy(): void;
472
+ }
473
+
474
+ export declare interface VideoQuality {
475
+ id: number;
476
+ height: number;
477
+ width: number;
478
+ bitrate: number;
479
+ label: string;
480
+ }
481
+
482
+ export { }
package/dist/core.js ADDED
@@ -0,0 +1,16 @@
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "./src-4MqtK4Qy.js";
2
+ //#region ../plugins/src/plugins.ts
3
+ var l = class {
4
+ player;
5
+ install(e) {
6
+ this.player = e, this.onInstall();
7
+ }
8
+ destroy() {
9
+ this.onDestroy();
10
+ }
11
+ onDestroy() {}
12
+ };
13
+ //#endregion
14
+ export { r as AnalyticsModule, l as BasePlayerPlugin, o as CastingModule, a as ChaptersModule, n as DRMModule, t as FirebaseAnalyticsProvider, s as KeyMomentsModule, e as SubtitlesModule, i as ThumbnailsModule, c as VideoPlayerSDK };
15
+
16
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","names":[],"sources":["../../plugins/src/plugins.ts"],"sourcesContent":["export interface PlayerPlugin {\r\n id: string;\r\n name: string;\r\n install(player: any): void;\r\n destroy?(): void;\r\n}\r\n\r\nexport abstract class BasePlayerPlugin implements PlayerPlugin {\r\n public abstract id: string;\r\n public abstract name: string;\r\n protected player: any;\r\n\r\n public install(player: any): void {\r\n this.player = player;\r\n this.onInstall();\r\n }\r\n\r\n protected abstract onInstall(): void;\r\n\r\n public destroy(): void {\r\n this.onDestroy();\r\n }\r\n\r\n protected onDestroy(): void {}\r\n}\r\n"],"mappings":";;AAOA,IAAsB,IAAtB,MAA+D;CAG7D;CAEA,QAAe,GAAmB;EAEhC,AADA,KAAK,SAAS,GACd,KAAK,UAAU;CACjB;CAIA,UAAuB;EACrB,KAAK,UAAU;CACjB;CAEA,YAA4B,CAAC;AAC/B"}