@obipascal/player 1.0.15 → 1.0.16

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.
@@ -0,0 +1,36 @@
1
+ import { AnalyticsConfig, AnalyticsEvent } from './types';
2
+
3
+ /**
4
+ * Analytics - Tracks player events and quality metrics
5
+ */
6
+ export declare class Analytics {
7
+ private config;
8
+ private sessionId;
9
+ private events;
10
+ private sessionStartTime;
11
+ private playbackStartTime;
12
+ private totalPlayTime;
13
+ private totalBufferTime;
14
+ private bufferStartTime;
15
+ private rebufferCount;
16
+ private seekCount;
17
+ private webSocket;
18
+ private socketIO;
19
+ private wsReconnectTimeout;
20
+ private isDestroyed;
21
+ constructor(config?: AnalyticsConfig);
22
+ trackEvent(eventType: string, data?: Record<string, any>): void;
23
+ private updateMetrics;
24
+ private getQoEMetrics;
25
+ private getSessionData;
26
+ private getConnectionInfo;
27
+ private sendEvent;
28
+ private generateSessionId;
29
+ private initializeSocketIO;
30
+ private sendToSocketIO;
31
+ private initializeWebSocket;
32
+ private sendToWebSocket;
33
+ getEvents(): AnalyticsEvent[];
34
+ getMetrics(): Record<string, any>;
35
+ destroy(): void;
36
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Video file information extractor
3
+ * Extracts metadata from video files (width, height, duration, size, etc.)
4
+ */
5
+ declare global {
6
+ interface HTMLVideoElement {
7
+ mozHasAudio?: boolean;
8
+ webkitAudioDecodedByteCount?: number;
9
+ audioTracks?: {
10
+ length: number;
11
+ };
12
+ }
13
+ }
14
+ export interface VideoFileInfo {
15
+ width: number;
16
+ height: number;
17
+ aspectRatio: string;
18
+ size: number;
19
+ sizeInBytes: number;
20
+ sizeFormatted: string;
21
+ duration: number;
22
+ durationInSeconds: number;
23
+ durationFormatted: string;
24
+ mimeType: string;
25
+ fileName: string;
26
+ fileExtension: string;
27
+ bitrate?: number;
28
+ frameRate?: number;
29
+ audioChannels?: number;
30
+ videoCodec?: string;
31
+ audioCodec?: string;
32
+ hasAudio?: boolean;
33
+ }
34
+ export declare class WontumFileInfo {
35
+ private file;
36
+ private videoElement;
37
+ private audioContext;
38
+ private info;
39
+ constructor(file: File);
40
+ /**
41
+ * Check if the file is a valid video file
42
+ */
43
+ private isVideoFile;
44
+ /**
45
+ * Extract video metadata
46
+ */
47
+ extract(): Promise<VideoFileInfo>;
48
+ /**
49
+ * Calculate aspect ratio (e.g., "16:9", "4:3")
50
+ */
51
+ private calculateAspectRatio;
52
+ /**
53
+ * Detect frame rate by analyzing video playback
54
+ */
55
+ private detectFrameRate;
56
+ /**
57
+ * Detect audio channel information using Web Audio API
58
+ */
59
+ private detectAudioInfo;
60
+ /**
61
+ * Get Greatest Common Divisor
62
+ */
63
+ private getGCD;
64
+ /**
65
+ * Format bytes to human-readable size
66
+ */
67
+ private formatBytes;
68
+ /**
69
+ * Format duration to HH:MM:SS
70
+ */
71
+ private formatDuration;
72
+ /**
73
+ * Get file extension
74
+ */
75
+ private getFileExtension;
76
+ get width(): number;
77
+ get height(): number;
78
+ get aspectRatio(): string;
79
+ get size(): number;
80
+ get sizeInBytes(): number;
81
+ get sizeFormatted(): string;
82
+ get duration(): number;
83
+ get durationInSeconds(): number;
84
+ get durationFormatted(): string;
85
+ get mimeType(): string;
86
+ get fileName(): string;
87
+ get fileExtension(): string;
88
+ get bitrate(): number | undefined;
89
+ get frameRate(): number | undefined;
90
+ get audioChannels(): number | undefined;
91
+ get hasAudio(): boolean;
92
+ get quality(): string;
93
+ /**
94
+ * Get all information as object
95
+ */
96
+ getInfo(): VideoFileInfo | null;
97
+ /**
98
+ * Clean up resources
99
+ */
100
+ destroy(): void;
101
+ }
@@ -0,0 +1,74 @@
1
+ import { WontumPlayerConfig, PlayerState, PlayerEvent, PlayerEventType, QualityLevel } from './types';
2
+ import { Analytics } from './analytics';
3
+
4
+ /**
5
+ * WontumPlayer - A modern HLS video player for educational platforms
6
+ */
7
+ export declare class WontumPlayer {
8
+ private container;
9
+ private videoElement;
10
+ private hls;
11
+ private config;
12
+ private eventListeners;
13
+ analytics: Analytics;
14
+ private s3Handler;
15
+ private uiController;
16
+ private qualities;
17
+ private state;
18
+ constructor(config: WontumPlayerConfig);
19
+ private addSubtitleTracks;
20
+ private createVideoElement;
21
+ private setupVideoListeners;
22
+ private loadSource;
23
+ private extractQualities;
24
+ private handleHlsError;
25
+ private getAnalyticsData;
26
+ play(): Promise<void>;
27
+ pause(): void;
28
+ seek(time: number): void;
29
+ skipForward(seconds?: number): void;
30
+ skipBackward(seconds?: number): void;
31
+ setVolume(volume: number): void;
32
+ mute(): void;
33
+ unmute(): void;
34
+ setPlaybackRate(rate: number): void;
35
+ setQuality(qualityIndex: number): void;
36
+ getQualities(): QualityLevel[];
37
+ enterFullscreen(): void;
38
+ exitFullscreen(): void;
39
+ enterPictureInPicture(): Promise<void>;
40
+ exitPictureInPicture(): Promise<void>;
41
+ togglePictureInPicture(): Promise<void>;
42
+ getState(): PlayerState;
43
+ getVideoElement(): HTMLVideoElement;
44
+ /**
45
+ * Enable subtitles for a specific track
46
+ */
47
+ enableSubtitles(trackIndex: number): void;
48
+ /**
49
+ * Disable all subtitles
50
+ */
51
+ disableSubtitles(): void;
52
+ /**
53
+ * Toggle subtitles on/off
54
+ */
55
+ toggleSubtitles(): boolean;
56
+ /**
57
+ * Get available subtitle tracks
58
+ */
59
+ getSubtitleTracks(): TextTrack[];
60
+ /**
61
+ * Check if subtitles are currently enabled
62
+ */
63
+ areSubtitlesEnabled(): boolean;
64
+ on(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
65
+ off(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
66
+ private emit;
67
+ /**
68
+ * Update video source without recreating the entire player
69
+ * This is more efficient than destroying and recreating the player
70
+ * @param src - New video source URL
71
+ */
72
+ updateSource(src: string): Promise<void>;
73
+ destroy(): void;
74
+ }
@@ -0,0 +1,104 @@
1
+ import { WontumPlayer } from './player';
2
+ import { WontumPlayerConfig, PlayerState, AnalyticsConfig, AnalyticsEvent } from './types';
3
+ import { VideoFileInfo } from './file-info';
4
+ import * as React from "react";
5
+ export interface WontumPlayerReactProps extends Omit<WontumPlayerConfig, "container"> {
6
+ /** Callback when player is ready */
7
+ onReady?: (player: WontumPlayer) => void;
8
+ /** Callback for player events */
9
+ onPlay?: () => void;
10
+ onPause?: () => void;
11
+ onEnded?: () => void;
12
+ onTimeUpdate?: (currentTime: number) => void;
13
+ onVolumeChange?: (volume: number, muted: boolean) => void;
14
+ onError?: (error: any) => void;
15
+ onLoadedMetadata?: () => void;
16
+ onQualityChange?: (level: number) => void;
17
+ /** Container style */
18
+ style?: React.CSSProperties;
19
+ /** Container className */
20
+ className?: string;
21
+ /** Width of player */
22
+ width?: string | number;
23
+ /** Height of player */
24
+ height?: string | number;
25
+ }
26
+ /**
27
+ * WontumPlayerReact - React component wrapper for WontumPlayer
28
+ */
29
+ export declare const WontumPlayerReact: React.FC<WontumPlayerReactProps>;
30
+ /**
31
+ * useWontumPlayer - React hook for imperative player control
32
+ */
33
+ export declare const useWontumPlayer: (config: Omit<WontumPlayerConfig, "container">) => {
34
+ containerRef: React.RefObject<HTMLDivElement | null>;
35
+ player: WontumPlayer | null;
36
+ state: PlayerState | null;
37
+ };
38
+ /**
39
+ * WontumPlayerProvider - Context provider for player instance
40
+ */
41
+ interface WontumPlayerContextValue {
42
+ player: WontumPlayer | null;
43
+ state: PlayerState | null;
44
+ }
45
+ export declare const WontumPlayerProvider: React.FC<{
46
+ player: WontumPlayer;
47
+ children: React.ReactNode;
48
+ }>;
49
+ export declare const useWontumPlayerContext: () => WontumPlayerContextValue;
50
+ /**
51
+ * Hook for extracting video file information
52
+ * @param file - The video file to analyze (File object or null)
53
+ * @returns Object containing loading state, error, and video info
54
+ */
55
+ export interface UseVideoFileInfoResult {
56
+ /** Video file information (null if not loaded or error occurred) */
57
+ info: VideoFileInfo | null;
58
+ /** Whether extraction is in progress */
59
+ loading: boolean;
60
+ /** Error message if extraction failed */
61
+ error: string | null;
62
+ /** Re-extract file info (useful for retry after error) */
63
+ refetch: () => Promise<void>;
64
+ }
65
+ export declare const useVideoFileInfo: (file: File | null | undefined) => UseVideoFileInfoResult;
66
+ /**
67
+ * Result type for useAnalytics hook
68
+ */
69
+ export interface UseAnalyticsResult {
70
+ /** Track a custom event */
71
+ trackEvent: (eventType: string, data?: Record<string, any>) => void;
72
+ /** Get all tracked events */
73
+ getEvents: () => AnalyticsEvent[];
74
+ /** Get analytics metrics (session duration, buffer time, etc.) */
75
+ getMetrics: () => Record<string, any>;
76
+ /** WebSocket connection status (for websocket/socket.io analytics) */
77
+ connected: boolean;
78
+ /** Session ID for this analytics instance */
79
+ sessionId: string;
80
+ }
81
+ /**
82
+ * React hook for analytics tracking
83
+ * Automatically handles lifecycle management and cleanup
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * const { trackEvent, getMetrics, connected } = useAnalytics({
88
+ * enabled: true,
89
+ * endpoint: "https://api.example.com/analytics",
90
+ * videoId: "video-123",
91
+ * userId: "user-456",
92
+ * webSocket: {
93
+ * type: "socket.io",
94
+ * url: "https://analytics.example.com",
95
+ * auth: { token: "your-token" }
96
+ * }
97
+ * })
98
+ *
99
+ * // Track custom events
100
+ * trackEvent("button_clicked", { buttonName: "share" })
101
+ * ```
102
+ */
103
+ export declare const useAnalytics: (config?: AnalyticsConfig) => UseAnalyticsResult;
104
+ export {};
@@ -0,0 +1,95 @@
1
+ import { S3Config } from './types';
2
+
3
+ /**
4
+ * S3Handler - Manages S3/CloudFront URLs and signed cookie authentication
5
+ */
6
+ export declare class S3Handler {
7
+ private config;
8
+ private urlCache;
9
+ private signedUrls;
10
+ constructor(config?: S3Config);
11
+ /**
12
+ * Process a URL - sign with CloudFront cookies or generate presigned URL for S3
13
+ */
14
+ processUrl(url: string): Promise<string>;
15
+ /**
16
+ * Check if URL is a CloudFront URL that needs signing
17
+ */
18
+ private isCloudFrontUrl;
19
+ /**
20
+ * Check if URL is an S3 URL
21
+ */
22
+ private isS3Url;
23
+ /**
24
+ * Sign CloudFront URL by calling the signing endpoint
25
+ * The endpoint should set signed cookies and return the URL
26
+ */
27
+ private signCloudFrontUrl;
28
+ /**
29
+ * Extract S3 key from URL
30
+ */
31
+ private extractS3Key;
32
+ /**
33
+ * Get presigned URL from cache or generate new one
34
+ */
35
+ private getPresignedUrl;
36
+ /**
37
+ * Helper to construct S3 URL from bucket and key
38
+ */
39
+ static constructS3Url(bucket: string, key: string, region?: string): string;
40
+ /**
41
+ * Helper to parse S3 URI (s3://bucket/key)
42
+ */
43
+ static parseS3Uri(uri: string): {
44
+ bucket: string;
45
+ key: string;
46
+ } | null;
47
+ /**
48
+ * Clear URL cache and signed URLs
49
+ */
50
+ clearCache(): void;
51
+ }
52
+ /**
53
+ * Example CloudFront signed cookie implementation:
54
+ *
55
+ * async function signUrl(url: string): Promise<string> {
56
+ * const response = await fetch('/api/cloudfront/sign', {
57
+ * method: 'POST',
58
+ * headers: { 'Content-Type': 'application/json' },
59
+ * body: JSON.stringify({ url }),
60
+ * credentials: 'include' // Important: include cookies in request
61
+ * });
62
+ *
63
+ * const data = await response.json();
64
+ * // Backend sets CloudFront signed cookies in response
65
+ * // and returns the original URL
66
+ * return data.url;
67
+ * }
68
+ *
69
+ * const player = new WontumPlayer({
70
+ * src: 'https://media.domain.com/path/to/video/index.m3u8',
71
+ * container: '#player',
72
+ * s3Config: {
73
+ * signUrl,
74
+ * cloudFrontDomains: ['media.domain.com']
75
+ * }
76
+ * });
77
+ *
78
+ * ---
79
+ *
80
+ * Legacy S3 presigned URL example:
81
+ *
82
+ * import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
83
+ * import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
84
+ *
85
+ * const s3Client = new S3Client({ region: 'us-east-1' });
86
+ *
87
+ * async function getPresignedUrl(key: string): Promise<string> {
88
+ * const command = new GetObjectCommand({
89
+ * Bucket: 'your-bucket-name',
90
+ * Key: key,
91
+ * });
92
+ *
93
+ * return getSignedUrl(s3Client, command, { expiresIn: 3600 });
94
+ * }
95
+ */
@@ -0,0 +1,161 @@
1
+ import { Socket } from 'socket.io-client';
2
+
3
+ /**
4
+ * Player configuration options
5
+ */
6
+ export interface WontumPlayerConfig {
7
+ /** The S3 URL or HLS manifest URL */
8
+ src: string;
9
+ /** Container element or selector */
10
+ container: HTMLElement | string;
11
+ /** Autoplay video (subject to browser policies) */
12
+ autoplay?: boolean;
13
+ /** Start muted */
14
+ muted?: boolean;
15
+ /** Show player controls */
16
+ controls?: boolean;
17
+ /** Video poster image URL */
18
+ poster?: string;
19
+ /** Preload strategy: 'none' | 'metadata' | 'auto' */
20
+ preload?: "none" | "metadata" | "auto";
21
+ /** Custom player theme */
22
+ theme?: PlayerTheme;
23
+ /** S3 configuration for presigned URLs */
24
+ s3Config?: S3Config;
25
+ /** Analytics configuration */
26
+ analytics?: AnalyticsConfig;
27
+ /** HLS.js configuration override */
28
+ hlsConfig?: Partial<any>;
29
+ /** Subtitle tracks */
30
+ subtitles?: SubtitleTrack[];
31
+ /** Keep controls always visible (sticky) */
32
+ stickyControls?: boolean;
33
+ }
34
+ export interface PlayerTheme {
35
+ primaryColor?: string;
36
+ accentColor?: string;
37
+ fontFamily?: string;
38
+ controlsBackground?: string;
39
+ buttonHoverBg?: string;
40
+ progressHeight?: string;
41
+ borderRadius?: string;
42
+ }
43
+ export interface S3Config {
44
+ /** Function to sign URL and set CloudFront cookies (returns the original URL after setting cookies) */
45
+ signUrl?: (url: string) => Promise<string>;
46
+ /** Legacy: Function to generate presigned URL (for S3 direct access) */
47
+ getPresignedUrl?: (key: string) => Promise<string>;
48
+ /** CloudFront domain patterns to match (e.g., ['media.domain.com']) */
49
+ cloudFrontDomains?: string[];
50
+ /** Enable credentials (cookies) for HLS requests - required for CloudFront signed cookies */
51
+ withCredentials?: boolean;
52
+ /** S3 bucket region */
53
+ region?: string;
54
+ /** Custom S3 endpoint */
55
+ endpoint?: string;
56
+ }
57
+ export interface AnalyticsConfig {
58
+ /** Enable analytics */
59
+ enabled?: boolean;
60
+ /** Custom analytics endpoint (HTTP/HTTPS) */
61
+ endpoint?: string;
62
+ /** WebSocket handler for real-time analytics streaming (supports both native WebSocket and Socket.IO) */
63
+ webSocket?: WebSocketAnalyticsHandler | SocketIOAnalyticsHandler;
64
+ /** Session identifier */
65
+ sessionId?: string;
66
+ /** User identifier */
67
+ userId?: string;
68
+ /** Video identifier */
69
+ videoId?: string;
70
+ }
71
+ /**
72
+ * Native WebSocket handler for real-time analytics
73
+ */
74
+ export interface WebSocketAnalyticsHandler {
75
+ /** Type identifier for native WebSocket */
76
+ type: "websocket";
77
+ /** WebSocket connection instance or URL to connect to */
78
+ connection: WebSocket | string;
79
+ /** Optional: Transform event before sending (allows filtering, formatting, etc.) */
80
+ transform?: (event: AnalyticsEvent) => any;
81
+ /** Optional: Error handler for WebSocket errors */
82
+ onError?: (error: Event) => void;
83
+ /** Optional: Handler for when WebSocket connection opens */
84
+ onOpen?: (event: Event) => void;
85
+ /** Optional: Handler for when WebSocket connection closes */
86
+ onClose?: (event: CloseEvent) => void;
87
+ /** Optional: Reconnect automatically on disconnect (default: true) */
88
+ autoReconnect?: boolean;
89
+ /** Optional: Reconnect delay in milliseconds (default: 3000) */
90
+ reconnectDelay?: number;
91
+ }
92
+ /**
93
+ * Socket.IO handler for real-time analytics
94
+ */
95
+ export interface SocketIOAnalyticsHandler {
96
+ /** Type identifier for Socket.IO */
97
+ type: "socket.io";
98
+ /** Socket.IO client instance or URL to connect to */
99
+ connection: typeof Socket | string;
100
+ /** Optional: Socket.IO connection options (used when connection is a URL) */
101
+ options?: Record<string, any>;
102
+ /** Optional: Event name to emit (default: "analytics") */
103
+ eventName?: string;
104
+ /** Optional: Transform event before sending (allows filtering, formatting, etc.) */
105
+ transform?: (event: AnalyticsEvent) => any;
106
+ /** Optional: Error handler */
107
+ onError?: (error: Error) => void;
108
+ /** Optional: Handler for when connection is established */
109
+ onConnect?: () => void;
110
+ /** Optional: Handler for when connection is lost */
111
+ onDisconnect?: (reason: string) => void;
112
+ }
113
+ /**
114
+ * Player state
115
+ */
116
+ export interface PlayerState {
117
+ playing: boolean;
118
+ paused: boolean;
119
+ ended: boolean;
120
+ buffering: boolean;
121
+ currentTime: number;
122
+ duration: number;
123
+ volume: number;
124
+ muted: boolean;
125
+ playbackRate: number;
126
+ quality: string;
127
+ availableQualities: string[];
128
+ fullscreen: boolean;
129
+ }
130
+ /**
131
+ * Player events (compatible with Mux Player and HTML5 MediaElement events)
132
+ */
133
+ export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "pictureinpictureenter" | "pictureinpictureexit" | "resize" | "sourcechange";
134
+ export interface PlayerEvent {
135
+ type: PlayerEventType;
136
+ data?: any;
137
+ timestamp: number;
138
+ }
139
+ /**
140
+ * Analytics event types
141
+ */
142
+ export interface AnalyticsEvent {
143
+ eventType: string;
144
+ timestamp: number;
145
+ sessionId: string;
146
+ videoId?: string;
147
+ userId?: string;
148
+ data: Record<string, any>;
149
+ }
150
+ export interface QualityLevel {
151
+ height: number;
152
+ width: number;
153
+ bitrate: number;
154
+ name: string;
155
+ }
156
+ export interface SubtitleTrack {
157
+ label: string;
158
+ src: string;
159
+ srclang: string;
160
+ default?: boolean;
161
+ }
@@ -0,0 +1,49 @@
1
+ import { WontumPlayer } from './player';
2
+
3
+ /**
4
+ * UI Controller - Manages player controls and interface
5
+ */
6
+ export declare class UIController {
7
+ private container;
8
+ private player;
9
+ private controlsContainer;
10
+ private progressContainer;
11
+ private progressBar;
12
+ private playButton;
13
+ private skipBackwardButton;
14
+ private skipForwardButton;
15
+ private volumeButton;
16
+ private volumeContainer;
17
+ private fullscreenButton;
18
+ private pipButton;
19
+ private settingsButton;
20
+ private volumeSlider;
21
+ private progressInput;
22
+ private hideControlsTimeout;
23
+ private stickyControls;
24
+ private isVolumeSliderActive;
25
+ constructor(container: HTMLElement, player: WontumPlayer);
26
+ private injectStyles;
27
+ private createProgressBar;
28
+ private createControls;
29
+ private setupEventListeners;
30
+ private setupPlayerEventListeners;
31
+ private updateSubtitleMenu;
32
+ private updateSpeedMenu;
33
+ private updateSettingsMenu;
34
+ private updateQualityMenu;
35
+ private showControls;
36
+ private hideControls;
37
+ private resetHideControlsTimeout;
38
+ private formatTime;
39
+ private getPlayIcon;
40
+ private getPauseIcon;
41
+ private getVolumeIcon;
42
+ private getMutedIcon;
43
+ private getFullscreenIcon;
44
+ private getPipIcon;
45
+ private getSkipBackwardIcon;
46
+ private getSkipForwardIcon;
47
+ private getSettingsIcon;
48
+ destroy(): void;
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obipascal/player",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "A modern HLS video player SDK for educational platforms with S3 integration",
5
5
  "main": "dist/wontum-player.cjs.js",
6
6
  "module": "dist/wontum-player.esm.js",
@@ -8,10 +8,7 @@
8
8
  "files": [
9
9
  "dist/wontum-player.esm.js",
10
10
  "dist/wontum-player.cjs.js",
11
- "dist/index.d.ts",
12
- "dist/src/**/*.d.ts",
13
- "!dist/src/test-app.d.ts",
14
- "!dist/examples"
11
+ "dist/*.d.ts"
15
12
  ],
16
13
  "scripts": {
17
14
  "dev": "vite",