@obipascal/player 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,6 +34,7 @@ A modern, feature-rich HLS video player SDK for educational platforms with Cloud
34
34
  - ⚛️ **React Support**: Component, Hook, and Context Provider patterns
35
35
  - 🔧 **TypeScript**: Full TypeScript support with comprehensive type definitions
36
36
  - 📊 **Analytics & QoE**: Built-in analytics tracking and Quality of Experience metrics
37
+ - 🔌 **Real-time Analytics**: Native WebSocket and Socket.IO support for live analytics streaming
37
38
  - 🎯 **25 Events**: Complete event system compatible with Mux Player
38
39
  - 📱 **Responsive**: Mobile-friendly with touch support
39
40
  - 🎬 **Quality Selector**: Automatic quality switching with manual override
@@ -50,6 +51,12 @@ Or with yarn:
50
51
  yarn add @obipascal/player hls.js
51
52
  ```
52
53
 
54
+ **Optional:** For Socket.IO real-time analytics support:
55
+
56
+ ```bash
57
+ npm install socket.io-client
58
+ ```
59
+
53
60
  ## 🚀 Quick Start
54
61
 
55
62
  ### Vanilla JavaScript
@@ -691,7 +698,19 @@ Modern vertical volume slider with popup interface - hover over volume button to
691
698
 
692
699
  ## 📊 Analytics
693
700
 
694
- Track video engagement and quality metrics:
701
+ Track video engagement and quality metrics with HTTP endpoints or real-time WebSocket/Socket.IO streaming:
702
+
703
+ **Features:**
704
+
705
+ - ✅ HTTP endpoint support for traditional analytics
706
+ - ✅ Native WebSocket support for real-time streaming
707
+ - ✅ Socket.IO support with full TypeScript types
708
+ - ✅ Dual streaming (HTTP + Socket simultaneously)
709
+ - ✅ Event transformation and filtering
710
+ - ✅ Auto-reconnection with configurable delays
711
+ - ✅ Quality of Experience (QoE) metrics included in every event
712
+
713
+ ### HTTP Analytics
695
714
 
696
715
  ```typescript
697
716
  const player = new WontumPlayer({
@@ -720,6 +739,206 @@ console.log(metrics)
720
739
  // }
721
740
  ```
722
741
 
742
+ ### WebSocket Real-Time Analytics
743
+
744
+ Stream analytics events in real-time using native WebSocket for live dashboards and monitoring:
745
+
746
+ ```typescript
747
+ const player = new WontumPlayer({
748
+ src: "https://example.com/video.m3u8",
749
+ container: "#player",
750
+ analytics: {
751
+ enabled: true,
752
+ userId: "user_456",
753
+ videoId: "video_789",
754
+ // Native WebSocket configuration
755
+ webSocket: {
756
+ type: "websocket", // Specify native WebSocket
757
+ connection: "wss://analytics.example.com/stream",
758
+ // Optional: Transform events before sending
759
+ transform: (event) => ({
760
+ type: event.eventType,
761
+ video_id: event.videoId,
762
+ user_id: event.userId,
763
+ timestamp: event.timestamp,
764
+ metrics: event.data,
765
+ }),
766
+ // Optional: Handle errors
767
+ onError: (error) => {
768
+ console.error("Analytics WebSocket error:", error)
769
+ },
770
+ // Optional: Connection opened
771
+ onOpen: (event) => {
772
+ console.log("Analytics WebSocket connected")
773
+ },
774
+ // Optional: Connection closed
775
+ onClose: (event) => {
776
+ console.log("Analytics WebSocket disconnected")
777
+ },
778
+ // Auto-reconnect on disconnect (default: true)
779
+ autoReconnect: true,
780
+ // Reconnect delay in milliseconds (default: 3000)
781
+ reconnectDelay: 3000,
782
+ },
783
+ },
784
+ })
785
+ ```
786
+
787
+ ### Socket.IO Real-Time Analytics
788
+
789
+ For Socket.IO-based real-time analytics (requires `socket.io-client` to be loaded):
790
+
791
+ ```typescript
792
+ // Option 1: Let the SDK create the Socket.IO connection
793
+ const player = new WontumPlayer({
794
+ src: "https://example.com/video.m3u8",
795
+ container: "#player",
796
+ analytics: {
797
+ enabled: true,
798
+ userId: "user_456",
799
+ videoId: "video_789",
800
+ webSocket: {
801
+ type: "socket.io",
802
+ connection: "https://analytics.example.com", // Socket.IO server URL
803
+ options: {
804
+ path: "/socket.io/",
805
+ transports: ["websocket", "polling"],
806
+ auth: {
807
+ token: "your-auth-token",
808
+ },
809
+ reconnection: true,
810
+ reconnectionDelay: 1000,
811
+ },
812
+ eventName: "video_analytics", // Event name to emit (default: "analytics")
813
+ transform: (event) => ({
814
+ event: event.eventType,
815
+ video: event.videoId,
816
+ user: event.userId,
817
+ data: event.data,
818
+ }),
819
+ onConnect: () => {
820
+ console.log("Socket.IO connected")
821
+ },
822
+ onDisconnect: (reason) => {
823
+ console.log("Socket.IO disconnected:", reason)
824
+ },
825
+ onError: (error) => {
826
+ console.error("Socket.IO error:", error)
827
+ },
828
+ },
829
+ },
830
+ })
831
+ ```
832
+
833
+ ```typescript
834
+ // Option 2: Use existing Socket.IO connection
835
+ import { io } from "socket.io-client"
836
+
837
+ const socket = io("https://analytics.example.com", {
838
+ auth: {
839
+ token: "your-auth-token",
840
+ },
841
+ })
842
+
843
+ const player = new WontumPlayer({
844
+ src: "https://example.com/video.m3u8",
845
+ container: "#player",
846
+ analytics: {
847
+ enabled: true,
848
+ userId: "user_456",
849
+ videoId: "video_789",
850
+ webSocket: {
851
+ type: "socket.io",
852
+ connection: socket, // Use existing Socket.IO instance
853
+ eventName: "analytics",
854
+ },
855
+ },
856
+ })
857
+ ```
858
+
859
+ ### Using Existing WebSocket Connection
860
+
861
+ ```typescript
862
+ // Create your own WebSocket connection
863
+ const ws = new WebSocket("wss://analytics.example.com/stream")
864
+
865
+ // Configure authentication or custom headers before connecting
866
+ ws.addEventListener("open", () => {
867
+ // Send authentication message
868
+ ws.send(
869
+ JSON.stringify({
870
+ type: "auth",
871
+ token: "your-auth-token",
872
+ }),
873
+ )
874
+ })
875
+
876
+ const player = new WontumPlayer({
877
+ src: "https://example.com/video.m3u8",
878
+ container: "#player",
879
+ analytics: {
880
+ enabled: true,
881
+ userId: "user_456",
882
+ videoId: "video_789",
883
+ webSocket: {
884
+ type: "websocket",
885
+ connection: ws, // Use existing connection
886
+ transform: (event) => ({
887
+ // Custom format for your backend
888
+ action: "video_event",
889
+ payload: {
890
+ event: event.eventType,
891
+ data: event.data,
892
+ },
893
+ }),
894
+ },
895
+ },
896
+ })
897
+ ```
898
+
899
+ ### Dual Analytics (HTTP + WebSocket/Socket.IO)
900
+
901
+ Send analytics to both HTTP endpoint and real-time socket simultaneously:
902
+
903
+ ```typescript
904
+ const player = new WontumPlayer({
905
+ src: "https://example.com/video.m3u8",
906
+ container: "#player",
907
+ analytics: {
908
+ enabled: true,
909
+ endpoint: "https://api.example.com/analytics", // HTTP fallback/storage
910
+ webSocket: {
911
+ type: "socket.io",
912
+ connection: "https://realtime.example.com", // Real-time monitoring
913
+ eventName: "video_analytics",
914
+ },
915
+ userId: "user_456",
916
+ videoId: "video_789",
917
+ },
918
+ })
919
+ ```
920
+
921
+ ### Analytics Events Tracked
922
+
923
+ The SDK automatically tracks these events:
924
+
925
+ - **Session**: `session_start`, `session_end`
926
+ - **Playback**: `play`, `pause`, `ended`, `playing`
927
+ - **Buffering**: `buffering_start`, `buffering_end`, `waiting`, `stalled`
928
+ - **Seeking**: `seeking`, `seeked`
929
+ - **Quality**: `qualitychange`, `renditionchange`
930
+ - **Errors**: `error`
931
+ - **User Actions**: Volume changes, fullscreen, playback rate changes
932
+
933
+ Each event includes Quality of Experience (QoE) metrics:
934
+
935
+ - `sessionDuration` - Total session time
936
+ - `totalPlayTime` - Actual video play time
937
+ - `totalBufferTime` - Time spent buffering
938
+ - `bufferingRatio` - Buffer time / play time ratio
939
+ - `rebufferCount` - Number of rebuffer events
940
+ - `seekCount` - Number of seek operations
941
+
723
942
  ## API Reference
724
943
 
725
944
  ### WontumPlayer
@@ -750,6 +969,39 @@ interface S3Config {
750
969
  region?: string // S3 region
751
970
  endpoint?: string // Custom S3 endpoint
752
971
  }
972
+
973
+ interface AnalyticsConfig {
974
+ enabled?: boolean // Enable analytics tracking
975
+ endpoint?: string // HTTP endpoint for analytics events
976
+ webSocket?: WebSocketAnalyticsHandler | SocketIOAnalyticsHandler // Real-time streaming
977
+ sessionId?: string // Session identifier
978
+ userId?: string // User identifier
979
+ videoId?: string // Video identifier
980
+ }
981
+
982
+ // Native WebSocket Configuration
983
+ interface WebSocketAnalyticsHandler {
984
+ type: "websocket"
985
+ connection: WebSocket | string // WebSocket instance or URL
986
+ transform?: (event: AnalyticsEvent) => any // Transform before sending
987
+ onError?: (error: Event) => void
988
+ onOpen?: (event: Event) => void
989
+ onClose?: (event: CloseEvent) => void
990
+ autoReconnect?: boolean // Default: true
991
+ reconnectDelay?: number // Default: 3000ms
992
+ }
993
+
994
+ // Socket.IO Configuration
995
+ interface SocketIOAnalyticsHandler {
996
+ type: "socket.io"
997
+ connection: Socket | string // Socket.IO instance or URL
998
+ options?: Partial<ManagerOptions & SocketOptions> // Socket.IO options
999
+ eventName?: string // Event name to emit (default: "analytics")
1000
+ transform?: (event: AnalyticsEvent) => any
1001
+ onError?: (error: Error) => void
1002
+ onConnect?: () => void
1003
+ onDisconnect?: (reason: string) => void
1004
+ }
753
1005
  ```
754
1006
 
755
1007
  #### Methods
@@ -1134,6 +1386,92 @@ pipButton.addEventListener("click", async () => {
1134
1386
 
1135
1387
  **Note:** Picture-in-Picture is supported in most modern browsers. The player includes a built-in PiP button in the controls.
1136
1388
 
1389
+ ### File Information Utility
1390
+
1391
+ The SDK includes a `WontumFileInfo` utility class to extract metadata from video files before uploading or processing them.
1392
+
1393
+ ```typescript
1394
+ import { WontumFileInfo } from "@obipascal/player"
1395
+
1396
+ // Example: File input handling
1397
+ const fileInput = document.querySelector<HTMLInputElement>("#video-upload")
1398
+
1399
+ fileInput.addEventListener("change", async (event) => {
1400
+ const file = event.target.files?.[0]
1401
+ if (!file) return
1402
+
1403
+ try {
1404
+ // Create instance (validates it's a video file)
1405
+ const videoInfo = new WontumFileInfo(file)
1406
+
1407
+ // Extract metadata
1408
+ await videoInfo.extract()
1409
+
1410
+ // Access properties
1411
+ console.log("Video Information:")
1412
+ console.log("- Width:", videoInfo.width) // e.g., 1920
1413
+ console.log("- Height:", videoInfo.height) // e.g., 1080
1414
+ console.log("- Aspect Ratio:", videoInfo.aspectRatio) // e.g., "16:9"
1415
+ console.log("- Quality:", videoInfo.quality) // e.g., "Full HD (1080p)"
1416
+ console.log("- Duration (raw):", videoInfo.durationInSeconds, "seconds") // e.g., 125.5
1417
+ console.log("- Formatted Duration:", videoInfo.durationFormatted) // e.g., "02:05"
1418
+ console.log("- File Size (raw):", videoInfo.sizeInBytes, "bytes") // e.g., 52428800
1419
+ console.log("- Formatted Size:", videoInfo.sizeFormatted) // e.g., "50 MB"
1420
+ console.log("- MIME Type:", videoInfo.mimeType) // e.g., "video/mp4"
1421
+ console.log("- File Name:", videoInfo.fileName) // e.g., "my-video.mp4"
1422
+ console.log("- Extension:", videoInfo.fileExtension) // e.g., ".mp4"
1423
+ console.log("- Bitrate:", videoInfo.bitrate, "kbps") // e.g., 3500
1424
+
1425
+ // Get all info as object
1426
+ const allInfo = videoInfo.getInfo()
1427
+ console.log(allInfo)
1428
+
1429
+ // Clean up when done
1430
+ videoInfo.destroy()
1431
+ } catch (error) {
1432
+ console.error("Error extracting video info:", error.message)
1433
+ // Throws error if file is not a video
1434
+ }
1435
+ })
1436
+ ```
1437
+
1438
+ #### WontumFileInfo API
1439
+
1440
+ **Constructor:**
1441
+
1442
+ ```typescript
1443
+ new WontumFileInfo(file: File)
1444
+ ```
1445
+
1446
+ Throws an error if the file is not a valid video file.
1447
+
1448
+ **Methods:**
1449
+
1450
+ - `extract(): Promise<VideoFileInfo>` - Extracts metadata from the video file
1451
+ - `getInfo(): VideoFileInfo | null` - Returns the extracted information object
1452
+ - `destroy(): void` - Cleans up resources
1453
+
1454
+ **Properties (available after calling `extract()`):**
1455
+
1456
+ - `width: number` - Video width in pixels
1457
+ - `height: number` - Video height in pixels
1458
+ - `aspectRatio: string` - Aspect ratio (e.g., "16:9", "4:3", "21:9")
1459
+ - `quality: string` - Quality description (e.g., "4K (2160p)", "Full HD (1080p)")
1460
+ - `size: number` - File size in bytes (raw value for computation)
1461
+ - `sizeInBytes: number` - Alias for size (raw value for computation)
1462
+ - `sizeFormatted: string` - Human-readable size (e.g., "50 MB")
1463
+ - `duration: number` - Duration in seconds (raw value for computation)
1464
+ - `durationInSeconds: number` - Alias for duration (raw value for computation)
1465
+ - `durationFormatted: string` - Formatted duration (e.g., "01:23:45")
1466
+ - `mimeType: string` - MIME type (e.g., "video/mp4")
1467
+ - `fileName: string` - Original file name
1468
+ - `fileExtension: string` - File extension (e.g., ".mp4")
1469
+ - `bitrate: number | undefined` - Estimated bitrate in kbps
1470
+
1471
+ **Supported Video Formats:**
1472
+
1473
+ `.mp4`, `.webm`, `.ogg`, `.mov`, `.avi`, `.mkv`, `.flv`, `.wmv`, `.m4v`, `.3gp`, `.ts`, `.m3u8`
1474
+
1137
1475
  ## 📋 Complete API Reference
1138
1476
 
1139
1477
  For detailed API documentation including all methods, events, types, and configuration options, see **[API-REFERENCE.md](./API-REFERENCE.md)**.
@@ -14,6 +14,10 @@ export declare class Analytics {
14
14
  private bufferStartTime;
15
15
  private rebufferCount;
16
16
  private seekCount;
17
+ private webSocket;
18
+ private socketIO;
19
+ private wsReconnectTimeout;
20
+ private isDestroyed;
17
21
  constructor(config?: AnalyticsConfig);
18
22
  trackEvent(eventType: string, data?: Record<string, any>): void;
19
23
  private updateMetrics;
@@ -22,6 +26,10 @@ export declare class Analytics {
22
26
  private getConnectionInfo;
23
27
  private sendEvent;
24
28
  private generateSessionId;
29
+ private initializeSocketIO;
30
+ private sendToSocketIO;
31
+ private initializeWebSocket;
32
+ private sendToWebSocket;
25
33
  getEvents(): AnalyticsEvent[];
26
34
  getMetrics(): Record<string, any>;
27
35
  destroy(): void;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Video file information extractor
3
+ * Extracts metadata from video files (width, height, duration, size, etc.)
4
+ */
5
+ export interface VideoFileInfo {
6
+ width: number;
7
+ height: number;
8
+ aspectRatio: string;
9
+ size: number;
10
+ sizeInBytes: number;
11
+ sizeFormatted: string;
12
+ duration: number;
13
+ durationInSeconds: number;
14
+ durationFormatted: string;
15
+ mimeType: string;
16
+ fileName: string;
17
+ fileExtension: string;
18
+ bitrate?: number;
19
+ frameRate?: number;
20
+ videoCodec?: string;
21
+ audioCodec?: string;
22
+ }
23
+ export declare class WontumFileInfo {
24
+ private file;
25
+ private videoElement;
26
+ private info;
27
+ constructor(file: File);
28
+ /**
29
+ * Check if the file is a valid video file
30
+ */
31
+ private isVideoFile;
32
+ /**
33
+ * Extract video metadata
34
+ */
35
+ extract(): Promise<VideoFileInfo>;
36
+ /**
37
+ * Calculate aspect ratio (e.g., "16:9", "4:3")
38
+ */
39
+ private calculateAspectRatio;
40
+ /**
41
+ * Get Greatest Common Divisor
42
+ */
43
+ private getGCD;
44
+ /**
45
+ * Format bytes to human-readable size
46
+ */
47
+ private formatBytes;
48
+ /**
49
+ * Format duration to HH:MM:SS
50
+ */
51
+ private formatDuration;
52
+ /**
53
+ * Get file extension
54
+ */
55
+ private getFileExtension;
56
+ get width(): number;
57
+ get height(): number;
58
+ get aspectRatio(): string;
59
+ get size(): number;
60
+ get sizeInBytes(): number;
61
+ get sizeFormatted(): string;
62
+ get duration(): number;
63
+ get durationInSeconds(): number;
64
+ get durationFormatted(): string;
65
+ get mimeType(): string;
66
+ get fileName(): string;
67
+ get fileExtension(): string;
68
+ get bitrate(): number | undefined;
69
+ get quality(): string;
70
+ /**
71
+ * Get all information as object
72
+ */
73
+ getInfo(): VideoFileInfo | null;
74
+ /**
75
+ * Clean up resources
76
+ */
77
+ destroy(): void;
78
+ }
@@ -2,6 +2,8 @@ export { WontumPlayer } from './player';
2
2
  export { Analytics } from './analytics';
3
3
  export { S3Handler } from './s3-handler';
4
4
  export { UIController } from './ui-controller';
5
+ export { WontumFileInfo } from './file-info';
5
6
  export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext } from './react';
6
- export type { WontumPlayerConfig, PlayerTheme, S3Config, AnalyticsConfig, PlayerState, PlayerEvent, PlayerEventType, AnalyticsEvent, QualityLevel } from './types';
7
+ export type { WontumPlayerConfig, PlayerTheme, S3Config, AnalyticsConfig, WebSocketAnalyticsHandler, SocketIOAnalyticsHandler, PlayerState, PlayerEvent, PlayerEventType, AnalyticsEvent, QualityLevel, } from './types';
8
+ export type { VideoFileInfo } from './file-info';
7
9
  export type { WontumPlayerReactProps } from './react';
@@ -1,3 +1,5 @@
1
+ import { Socket } from 'socket.io-client';
2
+
1
3
  /**
2
4
  * Player configuration options
3
5
  */
@@ -55,8 +57,10 @@ export interface S3Config {
55
57
  export interface AnalyticsConfig {
56
58
  /** Enable analytics */
57
59
  enabled?: boolean;
58
- /** Custom analytics endpoint */
60
+ /** Custom analytics endpoint (HTTP/HTTPS) */
59
61
  endpoint?: string;
62
+ /** WebSocket handler for real-time analytics streaming (supports both native WebSocket and Socket.IO) */
63
+ webSocket?: WebSocketAnalyticsHandler | SocketIOAnalyticsHandler;
60
64
  /** Session identifier */
61
65
  sessionId?: string;
62
66
  /** User identifier */
@@ -64,6 +68,48 @@ export interface AnalyticsConfig {
64
68
  /** Video identifier */
65
69
  videoId?: string;
66
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
+ }
67
113
  /**
68
114
  * Player state
69
115
  */