@obipascal/player 1.0.8 → 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 +253 -1
- package/dist/src/analytics.d.ts +8 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/types.d.ts +47 -1
- package/dist/wontum-player.cjs.js +15 -15
- package/dist/wontum-player.esm.js +207 -133
- package/package.json +6 -1
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
|
package/dist/src/analytics.d.ts
CHANGED
|
@@ -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;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export { S3Handler } from './s3-handler';
|
|
|
4
4
|
export { UIController } from './ui-controller';
|
|
5
5
|
export { WontumFileInfo } from './file-info';
|
|
6
6
|
export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext } from './react';
|
|
7
|
-
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
8
|
export type { VideoFileInfo } from './file-info';
|
|
9
9
|
export type { WontumPlayerReactProps } from './react';
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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
|
*/
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var V=Object.create;var k=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var Y=(l,t,e)=>t in l?k(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var X=(l,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _(t))!Q.call(l,n)&&n!==e&&k(l,n,{get:()=>t[n],enumerable:!(i=N(t,n))||i.enumerable});return l};var G=(l,t,e)=>(e=l!=null?V(j(l)):{},X(t||!l||!l.__esModule?k(e,"default",{value:l,enumerable:!0}):e,l));var s=(l,t,e)=>Y(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("hls.js"),B=require("react/jsx-runtime"),h=require("react");function K(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const F=K(h);class O{constructor(t){s(this,"config");s(this,"sessionId");s(this,"events",[]);s(this,"sessionStartTime");s(this,"playbackStartTime",null);s(this,"totalPlayTime",0);s(this,"totalBufferTime",0);s(this,"bufferStartTime",null);s(this,"rebufferCount",0);s(this,"seekCount",0);s(this,"webSocket",null);s(this,"socketIO",null);s(this,"wsReconnectTimeout",null);s(this,"isDestroyed",!1);var e,i;if(this.config=t,this.sessionId=(t==null?void 0:t.sessionId)||this.generateSessionId(),this.sessionStartTime=Date.now(),(e=this.config)!=null&&e.webSocket){const n=this.config.webSocket;"type"in n?n.type==="socket.io"?this.initializeSocketIO():this.initializeWebSocket():this.initializeWebSocket()}(i=this.config)!=null&&i.enabled&&this.trackEvent("session_start",this.getSessionData())}trackEvent(t,e={}){var n;if(!((n=this.config)!=null&&n.enabled))return;const i={eventType:t,timestamp:Date.now(),sessionId:this.sessionId,videoId:this.config.videoId,userId:this.config.userId,data:{...e,...this.getQoEMetrics()}};this.events.push(i),this.updateMetrics(t,e),this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&this.sendToWebSocket(i),this.socketIO&&this.socketIO.connected&&this.sendToSocketIO(i),this.config.endpoint&&this.sendEvent(i),process.env.NODE_ENV==="development"&&console.log("[Analytics]",t,i.data)}updateMetrics(t,e){switch(t){case"play":this.playbackStartTime=Date.now();break;case"pause":case"ended":this.playbackStartTime&&(this.totalPlayTime+=Date.now()-this.playbackStartTime,this.playbackStartTime=null);break;case"buffering_start":this.bufferStartTime=Date.now(),this.rebufferCount++;break;case"buffering_end":this.bufferStartTime&&(this.totalBufferTime+=Date.now()-this.bufferStartTime,this.bufferStartTime=null);break;case"seeked":this.seekCount++;break}}getQoEMetrics(){const t=Date.now()-this.sessionStartTime,e=this.totalPlayTime>0?this.totalBufferTime/this.totalPlayTime:0;return{sessionDuration:t,totalPlayTime:this.totalPlayTime,totalBufferTime:this.totalBufferTime,bufferingRatio:Math.round(e*1e3)/1e3,rebufferCount:this.rebufferCount,seekCount:this.seekCount}}getSessionData(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenResolution:`${screen.width}x${screen.height}`,viewport:`${window.innerWidth}x${window.innerHeight}`,connection:this.getConnectionInfo()}}getConnectionInfo(){const t=navigator,e=t.connection||t.mozConnection||t.webkitConnection;return e?{effectiveType:e.effectiveType,downlink:e.downlink,rtt:e.rtt,saveData:e.saveData}:null}async sendEvent(t){var e;if((e=this.config)!=null&&e.endpoint)try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(i){console.error("Failed to send analytics event:",i)}}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async initializeSocketIO(){var e;if(!((e=this.config)!=null&&e.webSocket)||!("type"in this.config.webSocket))return;const t=this.config.webSocket;if(t.type==="socket.io")try{if(typeof t.connection=="string"){const n=(await import("socket.io-client")).default;this.socketIO=n(t.connection,t.options||{})}else this.socketIO=t.connection;if(!this.socketIO)return;this.socketIO.on("connect",()=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Connected"),t.onConnect&&t.onConnect()}),this.socketIO.on("connect_error",i=>{console.error("[Analytics Socket.IO] Connection error:",i),t.onError&&t.onError(i)}),this.socketIO.on("disconnect",i=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Disconnected:",i),t.onDisconnect&&t.onDisconnect(i)}),this.socketIO.on("error",i=>{console.error("[Analytics Socket.IO] Error:",i),t.onError&&t.onError(i)})}catch(i){console.error("[Analytics Socket.IO] Failed to initialize:",i)}}sendToSocketIO(t){var e;if(!(!this.socketIO||!this.socketIO.connected))try{const i=(e=this.config)==null?void 0:e.webSocket,n=i!=null&&i.transform?i.transform(t):t,o=(i==null?void 0:i.eventName)||"analytics";this.socketIO.emit(o,n),process.env.NODE_ENV==="development"&&console.log(`[Analytics Socket.IO] Emitted (${o}):`,t.eventType)}catch(i){console.error("[Analytics Socket.IO] Failed to emit event:",i)}}initializeWebSocket(){var e;if(!((e=this.config)!=null&&e.webSocket))return;const t=this.config.webSocket;try{typeof t.connection=="string"?this.webSocket=new WebSocket(t.connection):this.webSocket=t.connection,this.webSocket.onopen=i=>{process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Connected"),t.onOpen&&t.onOpen(i)},this.webSocket.onerror=i=>{console.error("[Analytics WebSocket] Error:",i),t.onError&&t.onError(i)},this.webSocket.onclose=i=>{if(process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Disconnected"),t.onClose&&t.onClose(i),t.autoReconnect!==!1&&!this.isDestroyed){const o=t.reconnectDelay||3e3;process.env.NODE_ENV==="development"&&console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`),this.wsReconnectTimeout=window.setTimeout(()=>{this.initializeWebSocket()},o)}}}catch(i){console.error("[Analytics WebSocket] Failed to initialize:",i)}}sendToWebSocket(t){var e;if(!(!this.webSocket||this.webSocket.readyState!==WebSocket.OPEN))try{const i=(e=this.config)==null?void 0:e.webSocket,n=i!=null&&i.transform?i.transform(t):t;this.webSocket.send(JSON.stringify(n)),process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Sent:",t.eventType)}catch(i){console.error("[Analytics WebSocket] Failed to send event:",i)}}getEvents(){return[...this.events]}getMetrics(){return{sessionId:this.sessionId,...this.getQoEMetrics(),eventCount:this.events.length}}destroy(){var t;this.isDestroyed=!0,(t=this.config)!=null&&t.enabled&&this.trackEvent("session_end",this.getSessionData()),this.wsReconnectTimeout&&(clearTimeout(this.wsReconnectTimeout),this.wsReconnectTimeout=null),this.webSocket&&(this.webSocket.close(),this.webSocket=null),this.socketIO&&(this.socketIO.removeAllListeners(),this.socketIO.disconnect(),this.socketIO=null),this.events=[]}}class ${constructor(t,e){s(this,"container");s(this,"player");s(this,"controlsContainer");s(this,"progressContainer");s(this,"progressBar");s(this,"playButton");s(this,"skipBackwardButton");s(this,"skipForwardButton");s(this,"volumeButton");s(this,"volumeContainer");s(this,"fullscreenButton");s(this,"pipButton");s(this,"settingsButton");s(this,"volumeSlider");s(this,"progressInput");s(this,"hideControlsTimeout",null);s(this,"stickyControls",!1);s(this,"isVolumeSliderActive",!1);this.container=t,this.player=e,this.injectStyles(),this.createProgressBar(),this.controlsContainer=this.createControls(),this.container.appendChild(this.controlsContainer),this.playButton=this.controlsContainer.querySelector(".wontum-play-btn"),this.skipBackwardButton=this.controlsContainer.querySelector(".wontum-skip-backward-btn"),this.skipForwardButton=this.controlsContainer.querySelector(".wontum-skip-forward-btn"),this.volumeButton=this.controlsContainer.querySelector(".wontum-volume-btn"),this.volumeContainer=this.controlsContainer.querySelector(".wontum-volume-container"),this.fullscreenButton=this.controlsContainer.querySelector(".wontum-fullscreen-btn"),this.pipButton=this.controlsContainer.querySelector(".wontum-pip-btn"),this.settingsButton=this.controlsContainer.querySelector(".wontum-settings-btn"),this.volumeSlider=this.controlsContainer.querySelector(".wontum-volume-slider"),this.progressInput=this.container.querySelector(".wontum-progress-input"),this.progressBar=this.container.querySelector(".wontum-progress-filled"),this.stickyControls=this.player.config.stickyControls||!1,this.stickyControls&&this.controlsContainer.classList.add("sticky"),this.setupEventListeners(),this.setupPlayerEventListeners()}injectStyles(){const t="wontum-player-styles";if(document.getElementById(t))return;const e=this.player.config.theme||{},i=e.primaryColor||"#3b82f6",n=e.accentColor||"#2563eb",o=e.fontFamily||"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",r=e.controlsBackground||"linear-gradient(to top, rgba(0,0,0,0.8), transparent)",a=e.buttonHoverBg||"rgba(255, 255, 255, 0.1)",c=e.progressHeight||"6px",u=e.borderRadius||"4px",p=document.createElement("style");p.id=t,p.textContent=`
|
|
2
2
|
.wontum-player-container {
|
|
3
3
|
position: relative;
|
|
4
4
|
background: #000;
|
|
5
|
-
font-family: ${
|
|
5
|
+
font-family: ${o};
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
--primary-color: ${i};
|
|
8
8
|
--accent-color: ${n};
|
|
9
9
|
--controls-bg: ${r};
|
|
10
10
|
--button-hover: ${a};
|
|
11
|
-
--progress-height: ${
|
|
11
|
+
--progress-height: ${c};
|
|
12
12
|
--border-radius: ${u};
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -562,28 +562,28 @@
|
|
|
562
562
|
<div class="wontum-loading" style="display: none;">
|
|
563
563
|
<div class="wontum-spinner"></div>
|
|
564
564
|
</div>
|
|
565
|
-
`,t}setupEventListeners(){this.playButton.addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.skipBackwardButton.addEventListener("click",()=>{this.player.skipBackward(10)}),this.skipForwardButton.addEventListener("click",()=>{this.player.skipForward(10)}),this.progressInput.addEventListener("input",i=>{const n=i.target,
|
|
565
|
+
`,t}setupEventListeners(){this.playButton.addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.skipBackwardButton.addEventListener("click",()=>{this.player.skipBackward(10)}),this.skipForwardButton.addEventListener("click",()=>{this.player.skipForward(10)}),this.progressInput.addEventListener("input",i=>{const n=i.target,o=parseFloat(n.value),r=this.player.getState(),a=o/100*r.duration;this.player.seek(a)}),this.volumeSlider.addEventListener("input",i=>{const n=i.target,o=parseFloat(n.value)/100;this.player.setVolume(o)}),this.volumeButton.addEventListener("click",()=>{this.player.getState().muted?this.player.unmute():this.player.mute()}),this.volumeContainer.addEventListener("mouseenter",()=>{this.isVolumeSliderActive=!0}),this.volumeContainer.addEventListener("mouseleave",()=>{this.isVolumeSliderActive=!1}),this.volumeSlider.addEventListener("input",()=>{this.isVolumeSliderActive=!0,this.resetHideControlsTimeout()}),this.volumeSlider.addEventListener("change",()=>{setTimeout(()=>{this.isVolumeSliderActive=!1},500)}),this.fullscreenButton.addEventListener("click",()=>{this.player.getState().fullscreen?this.player.exitFullscreen():this.player.enterFullscreen()}),this.pipButton.addEventListener("click",async()=>{try{await this.player.togglePictureInPicture()}catch(i){console.error("PiP error:",i)}}),this.settingsButton.addEventListener("click",()=>{const i=this.controlsContainer.querySelector(".wontum-settings-panel");i.classList.toggle("active"),i.classList.contains("active")&&(this.updateSettingsMenu(),this.updateQualityMenu(),this.updateSpeedMenu(),this.updateSubtitleMenu())});const t=this.controlsContainer.querySelectorAll(".wontum-tab");t.forEach(i=>{i.addEventListener("click",n=>{const o=n.currentTarget,r=o.getAttribute("data-tab");t.forEach(u=>u.classList.remove("active")),o.classList.add("active"),this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach(u=>u.classList.remove("active"));const c=this.controlsContainer.querySelector(`[data-panel="${r}"]`);c==null||c.classList.add("active")})}),this.player.getVideoElement().addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.container.addEventListener("mousemove",()=>{this.showControls(),this.resetHideControlsTimeout()}),this.container.addEventListener("mouseleave",()=>{this.hideControls()})}setupPlayerEventListeners(){this.player.on("play",()=>{this.playButton.innerHTML=this.getPauseIcon()}),this.player.on("pause",()=>{this.playButton.innerHTML=this.getPlayIcon()}),this.player.on("timeupdate",t=>{const{currentTime:e}=t.data,i=this.player.getState();if(i.duration>0){const o=e/i.duration*100;this.progressBar.style.width=`${o}%`,this.progressInput.value=o.toString()}const n=this.controlsContainer.querySelector(".wontum-current-time");n.textContent=this.formatTime(e)}),this.player.on("loadedmetadata",t=>{const{duration:e}=t.data,i=this.controlsContainer.querySelector(".wontum-duration");i.textContent=this.formatTime(e),t.data.qualities&&this.updateQualityMenu(t.data.qualities)}),this.player.on("volumechange",t=>{const{volume:e,muted:i}=t.data;this.volumeSlider.value=(e*100).toString(),this.volumeButton.innerHTML=i?this.getMutedIcon():this.getVolumeIcon()}),this.player.on("waiting",()=>{const t=this.controlsContainer.querySelector(".wontum-loading");t.style.display="block"}),this.player.on("canplay",()=>{const t=this.controlsContainer.querySelector(".wontum-loading");t.style.display="none"})}updateSubtitleMenu(){const t=this.controlsContainer.querySelector(".wontum-subtitle-menu"),e=this.player.getSubtitleTracks();if(e.length===0){t.innerHTML='<div class="wontum-subtitle-option">No subtitles available</div>';return}const i=e.findIndex(n=>n.mode==="showing");t.innerHTML=`
|
|
566
566
|
<div class="wontum-subtitle-option ${i===-1?"active":""}" data-track="-1">Off</div>
|
|
567
|
-
${e.map((n,
|
|
568
|
-
<div class="wontum-subtitle-option ${
|
|
569
|
-
${n.label||n.language||`Track ${
|
|
567
|
+
${e.map((n,o)=>`
|
|
568
|
+
<div class="wontum-subtitle-option ${o===i?"active":""}" data-track="${o}">
|
|
569
|
+
${n.label||n.language||`Track ${o+1}`}
|
|
570
570
|
</div>
|
|
571
571
|
`).join("")}
|
|
572
|
-
`,t.querySelectorAll(".wontum-subtitle-option").forEach(n=>{n.addEventListener("click",
|
|
573
|
-
<div class="wontum-speed-option ${i===
|
|
574
|
-
${
|
|
572
|
+
`,t.querySelectorAll(".wontum-subtitle-option").forEach(n=>{n.addEventListener("click",o=>{const r=o.target,a=parseInt(r.dataset.track||"-1");a===-1?this.player.disableSubtitles():this.player.enableSubtitles(a),t.querySelectorAll(".wontum-subtitle-option").forEach(c=>c.classList.remove("active")),r.classList.add("active")})})}updateSpeedMenu(){const t=this.controlsContainer.querySelector(".wontum-speed-menu"),i=this.player.getState().playbackRate||1,n=[.25,.5,.75,1,1.25,1.5,1.75,2];t.innerHTML=n.map(o=>`
|
|
573
|
+
<div class="wontum-speed-option ${i===o?"active":""}" data-speed="${o}">
|
|
574
|
+
${o===1?"Normal":o+"x"}
|
|
575
575
|
</div>
|
|
576
|
-
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(
|
|
576
|
+
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(o=>{o.addEventListener("click",r=>{const a=r.target,c=parseFloat(a.dataset.speed||"1");this.player.setPlaybackRate(c),t.querySelectorAll(".wontum-speed-option").forEach(u=>u.classList.remove("active")),a.classList.add("active")})})}updateSettingsMenu(){const t=this.controlsContainer.querySelector(".wontum-settings-menu");t.innerHTML=`
|
|
577
577
|
<div class="wontum-settings-option" data-setting="sticky-controls">
|
|
578
578
|
<span>Sticky Controls</span>
|
|
579
579
|
<div class="wontum-toggle-switch ${this.stickyControls?"active":""}"></div>
|
|
580
580
|
</div>
|
|
581
581
|
`;const e=t.querySelector('[data-setting="sticky-controls"]');e.addEventListener("click",()=>{this.stickyControls=!this.stickyControls,e.querySelector(".wontum-toggle-switch").classList.toggle("active"),this.stickyControls?(this.controlsContainer.classList.add("sticky"),this.progressContainer.classList.add("sticky")):(this.controlsContainer.classList.remove("sticky"),this.progressContainer.classList.remove("sticky"))})}updateQualityMenu(t){const e=this.controlsContainer.querySelector(".wontum-quality-menu"),i=t||this.player.getQualities();if(!i||i.length===0){e.innerHTML='<div class="wontum-quality-option">No qualities available</div>';return}e.innerHTML=`
|
|
582
582
|
<div class="wontum-quality-option active" data-quality="-1">Auto</div>
|
|
583
|
-
${i.map((n,
|
|
584
|
-
<div class="wontum-quality-option" data-quality="${
|
|
583
|
+
${i.map((n,o)=>`
|
|
584
|
+
<div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
|
|
585
585
|
`).join("")}
|
|
586
|
-
`,e.querySelectorAll(".wontum-quality-option").forEach(n=>{n.addEventListener("click",
|
|
586
|
+
`,e.querySelectorAll(".wontum-quality-option").forEach(n=>{n.addEventListener("click",o=>{const r=o.target,a=parseInt(r.dataset.quality||"-1");this.player.setQuality(a),e.querySelectorAll(".wontum-quality-option").forEach(c=>c.classList.remove("active")),r.classList.add("active")})})}showControls(){this.controlsContainer.classList.remove("hidden"),this.progressContainer.classList.remove("hidden")}hideControls(){if(this.stickyControls||this.isVolumeSliderActive)return;this.player.getState().playing&&(this.controlsContainer.classList.add("hidden"),this.progressContainer.classList.add("hidden"))}resetHideControlsTimeout(){this.stickyControls||(this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.hideControlsTimeout=window.setTimeout(()=>{this.hideControls()},1e4))}formatTime(t){if(isNaN(t))return"0:00";const e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}getPlayIcon(){return'<svg viewBox="0 0 24 24"><path fill="white" d="M8 5v14l11-7z"/></svg>'}getPauseIcon(){return'<svg viewBox="0 0 24 24"><path fill="white" d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>'}getVolumeIcon(){return'<svg viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/></svg>'}getMutedIcon(){return'<svg viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>'}getFullscreenIcon(){return'<svg viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>'}getPipIcon(){return'<svg viewBox="0 0 24 24"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"/></svg>'}getSkipBackwardIcon(){return`<svg viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
587
587
|
<circle cx="30" cy="30" r="28" stroke="white" stroke-width="2"/>
|
|
588
588
|
<!-- Circular arrow backward -->
|
|
589
589
|
<path d="M30 12 A18 18 0 1 0 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
@@ -595,4 +595,4 @@
|
|
|
595
595
|
<path d="M30 12 A18 18 0 1 1 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
596
596
|
<path d="M35 12 L30 12 L30 17" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
597
597
|
<text x="30" y="35" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="white" text-anchor="middle">10</text>
|
|
598
|
-
</svg>`}getSettingsIcon(){return'<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>'}destroy(){this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.controlsContainer.remove()}}class z{constructor(t){o(this,"config");o(this,"urlCache",new Map);o(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const i=new URL(t);return this.config.cloudFrontDomains.some(n=>i.hostname.includes(n))}catch{return!1}}isS3Url(t){return t.includes(".s3.")||t.includes("s3.amazonaws.com")||t.startsWith("s3://")}async signCloudFrontUrl(t,e=0){var s,r;if(this.signedUrls.has(t))return t;if((s=this.config)!=null&&s.signUrl)try{const a=await this.config.signUrl(t);return this.signedUrls.add(t),a}catch(a){const l=(a==null?void 0:a.name)==="AbortError"||((r=a==null?void 0:a.message)==null?void 0:r.includes("aborted"));if(l&&e<2)return console.warn(`Sign URL aborted, retrying (${e+1}/2)...`),await new Promise(u=>setTimeout(u,300)),this.signCloudFrontUrl(t,e+1);throw console.error("Failed to sign CloudFront URL:",a),l?new Error("Failed to sign CloudFront URL: Request was aborted. If using Apollo Client or other GraphQL clients, consider moving the query outside component lifecycle or using useQuery with skip option."):new Error(`Failed to sign CloudFront URL: ${(a==null?void 0:a.message)||"Unknown error"}`)}return console.warn("No signUrl function provided. CloudFront cookies may not be set."),t}extractS3Key(t){if(t.startsWith("s3://"))return t.replace("s3://","").split("/").slice(1).join("/");const e=t.match(/s3[.-]([^.]+)\.amazonaws\.com\/(.+)/);if(e)return e[2];const i=t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);return i?i[2]:t}async getPresignedUrl(t){var n;const e=this.extractS3Key(t),i=this.urlCache.get(e);if(i&&i.expiresAt>Date.now())return i.url;if((n=this.config)!=null&&n.getPresignedUrl)try{const s=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:s,expiresAt:Date.now()+50*60*1e3}),s}catch(s){throw console.error("Failed to generate presigned URL:",s),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,i="us-east-1"){return`https://${t}.s3.${i}.amazonaws.com/${e}`}static parseS3Uri(t){if(!t.startsWith("s3://"))return null;const e=t.replace("s3://","").split("/"),i=e[0],n=e.slice(1).join("/");return{bucket:i,key:n}}clearCache(){this.urlCache.clear(),this.signedUrls.clear()}}class k{constructor(t){o(this,"container");o(this,"videoElement");o(this,"hls",null);o(this,"config");o(this,"eventListeners",new Map);o(this,"analytics");o(this,"s3Handler");o(this,"uiController");o(this,"qualities",[]);o(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new $(t.analytics),this.s3Handler=new z(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new A(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const i=document.createElement("track");i.kind="subtitles",i.label=e.label,i.src=e.src,i.srclang=e.srclang,e.default&&(i.default=!0),this.videoElement.appendChild(i)})}createVideoElement(){const t=document.createElement("video");return t.className="wontum-player-video",t.style.width="100%",t.style.height="100%",t.playsInline=!0,t.crossOrigin="use-credentials",t}setupVideoListeners(){this.videoElement.addEventListener("play",()=>{this.state.playing=!0,this.state.paused=!1,this.emit("play"),this.analytics.trackEvent("play",this.getAnalyticsData())}),this.videoElement.addEventListener("pause",()=>{this.state.playing=!1,this.state.paused=!0,this.emit("pause"),this.analytics.trackEvent("pause",this.getAnalyticsData())}),this.videoElement.addEventListener("ended",()=>{this.state.ended=!0,this.state.playing=!1,this.emit("ended"),this.analytics.trackEvent("ended",this.getAnalyticsData())}),this.videoElement.addEventListener("timeupdate",()=>{this.state.currentTime=this.videoElement.currentTime,this.emit("timeupdate",{currentTime:this.state.currentTime})}),this.videoElement.addEventListener("loadedmetadata",()=>{this.state.duration=this.videoElement.duration,this.emit("loadedmetadata",{duration:this.state.duration}),this.analytics.trackEvent("loadedmetadata",this.getAnalyticsData())}),this.videoElement.addEventListener("volumechange",()=>{this.state.volume=this.videoElement.volume,this.state.muted=this.videoElement.muted,this.emit("volumechange",{volume:this.state.volume,muted:this.state.muted})}),this.videoElement.addEventListener("ratechange",()=>{this.state.playbackRate=this.videoElement.playbackRate,this.emit("ratechange",{playbackRate:this.state.playbackRate})}),this.videoElement.addEventListener("waiting",()=>{this.state.buffering=!0,this.emit("waiting"),this.analytics.trackEvent("buffering_start",this.getAnalyticsData())}),this.videoElement.addEventListener("canplay",()=>{this.state.buffering=!1,this.emit("canplay"),this.analytics.trackEvent("buffering_end",this.getAnalyticsData())}),this.videoElement.addEventListener("seeking",()=>{this.emit("seeking")}),this.videoElement.addEventListener("seeked",()=>{this.emit("seeked",{currentTime:this.state.currentTime}),this.analytics.trackEvent("seeked",this.getAnalyticsData())}),this.videoElement.addEventListener("error",t=>{const e=this.videoElement.error;this.emit("error",{error:e}),this.analytics.trackEvent("error",{...this.getAnalyticsData(),error:e==null?void 0:e.message})}),this.videoElement.addEventListener("loadstart",()=>{this.emit("loadstart")}),this.videoElement.addEventListener("loadeddata",()=>{this.emit("loadeddata")}),this.videoElement.addEventListener("canplaythrough",()=>{this.emit("canplaythrough")}),this.videoElement.addEventListener("playing",()=>{this.state.playing=!0,this.state.buffering=!1,this.emit("playing")}),this.videoElement.addEventListener("durationchange",()=>{this.state.duration=this.videoElement.duration,this.emit("durationchange",{duration:this.state.duration})}),this.videoElement.addEventListener("progress",()=>{this.emit("progress",{buffered:this.videoElement.buffered})}),this.videoElement.addEventListener("stalled",()=>{this.emit("stalled")}),this.videoElement.addEventListener("suspend",()=>{this.emit("suspend")}),this.videoElement.addEventListener("abort",()=>{this.emit("abort")}),this.videoElement.addEventListener("emptied",()=>{this.emit("emptied")}),this.videoElement.addEventListener("resize",()=>{this.emit("resize",{videoWidth:this.videoElement.videoWidth,videoHeight:this.videoElement.videoHeight})})}async loadSource(t){var e;try{const i=await this.s3Handler.processUrl(t);if(g.isSupported()){const n=((e=this.config.s3Config)==null?void 0:e.withCredentials)??!1,s={...this.config.hlsConfig,xhrSetup:(r,a)=>{var l;n&&(r.withCredentials=!0),(l=this.config.hlsConfig)!=null&&l.xhrSetup&&this.config.hlsConfig.xhrSetup(r,a)}};this.hls=new g(s),this.hls.loadSource(i),this.hls.attachMedia(this.videoElement),this.hls.on(g.Events.MANIFEST_PARSED,(r,a)=>{const l=this.extractQualities(a.levels);this.qualities=l}),this.hls.on(g.Events.LEVEL_SWITCHED,(r,a)=>{var u;const l=(u=this.hls)==null?void 0:u.levels[a.level];l&&(this.state.quality=`${l.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(g.Events.ERROR,(r,a)=>{a.fatal&&this.handleHlsError(a)})}else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=i;else throw new Error("HLS is not supported in this browser")}catch(i){console.error("Failed to load video source:",i),this.emit("error",{error:i})}}extractQualities(t){return t.map(e=>({height:e.height,width:e.width,bitrate:e.bitrate,name:`${e.height}p`}))}handleHlsError(t){var e,i;switch(t.type){case g.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case g.ErrorTypes.MEDIA_ERROR:console.error("Media error occurred"),(i=this.hls)==null||i.recoverMediaError();break;default:console.error("Fatal error occurred:",t),this.destroy();break}}getAnalyticsData(){return{currentTime:this.state.currentTime,duration:this.state.duration,quality:this.state.quality,playbackRate:this.state.playbackRate,volume:this.state.volume,muted:this.state.muted}}play(){return this.videoElement.play()}pause(){this.videoElement.pause()}seek(t){this.videoElement.currentTime=t}skipForward(t=10){const e=Math.min(this.state.currentTime+t,this.state.duration);this.seek(e)}skipBackward(t=10){const e=Math.max(this.state.currentTime-t,0);this.seek(e)}setVolume(t){this.videoElement.volume=Math.max(0,Math.min(1,t))}mute(){this.videoElement.muted=!0}unmute(){this.videoElement.muted=!1}setPlaybackRate(t){this.videoElement.playbackRate=t}setQuality(t){this.hls&&(this.hls.currentLevel=t)}getQualities(){return this.qualities}enterFullscreen(){this.container.requestFullscreen&&(this.container.requestFullscreen(),this.state.fullscreen=!0,this.emit("fullscreenchange",{fullscreen:!0}))}exitFullscreen(){document.exitFullscreen&&(document.exitFullscreen(),this.state.fullscreen=!1,this.emit("fullscreenchange",{fullscreen:!1}))}async enterPictureInPicture(){if(document.pictureInPictureEnabled&&!this.videoElement.disablePictureInPicture)try{await this.videoElement.requestPictureInPicture(),this.emit("pictureinpictureenter",{})}catch(t){throw console.error("Failed to enter Picture-in-Picture:",t),t}}async exitPictureInPicture(){if(document.pictureInPictureElement)try{await document.exitPictureInPicture(),this.emit("pictureinpictureexit",{})}catch(t){throw console.error("Failed to exit Picture-in-Picture:",t),t}}async togglePictureInPicture(){document.pictureInPictureElement?await this.exitPictureInPicture():await this.enterPictureInPicture()}getState(){return{...this.state}}getVideoElement(){return this.videoElement}enableSubtitles(t){const e=this.videoElement.textTracks;for(let i=0;i<e.length;i++)e[i].mode=i===t?"showing":"hidden"}disableSubtitles(){const t=this.videoElement.textTracks;for(let e=0;e<t.length;e++)t[e].mode="hidden"}toggleSubtitles(){const t=this.videoElement.textTracks;return Array.from(t).some(i=>i.mode==="showing")?(this.disableSubtitles(),!1):t.length>0?(this.enableSubtitles(0),!0):!1}getSubtitleTracks(){return Array.from(this.videoElement.textTracks)}areSubtitlesEnabled(){const t=this.videoElement.textTracks;return Array.from(t).some(e=>e.mode==="showing")}on(t,e){this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e)}off(t,e){var i;(i=this.eventListeners.get(t))==null||i.delete(e)}emit(t,e){var n;const i={type:t,data:e,timestamp:Date.now()};(n=this.eventListeners.get(t))==null||n.forEach(s=>{s(i)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class O{constructor(t){o(this,"file");o(this,"videoElement",null);o(this,"info",null);if(!this.isVideoFile(t))throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);this.file=t}isVideoFile(t){if(t.type.startsWith("video/"))return!0;const e=[".mp4",".webm",".ogg",".mov",".avi",".mkv",".flv",".wmv",".m4v",".3gp",".ts",".m3u8"],i=t.name.toLowerCase();return e.some(n=>i.endsWith(n))}async extract(){return new Promise((t,e)=>{try{this.videoElement=document.createElement("video"),this.videoElement.preload="metadata",this.videoElement.muted=!0;const i=URL.createObjectURL(this.file);this.videoElement.onloadedmetadata=()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const n=this.videoElement.videoWidth,s=this.videoElement.videoHeight,r=this.videoElement.duration,a=this.calculateAspectRatio(n,s),l=this.file.size,u=this.formatBytes(l),p=this.formatDuration(r),v=this.getFileExtension(this.file.name),f=r>0?Math.round(l*8/r/1e3):void 0;this.info={width:n,height:s,aspectRatio:a,size:l,sizeInBytes:l,sizeFormatted:u,duration:r,durationInSeconds:r,durationFormatted:p,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:v,bitrate:f},URL.revokeObjectURL(i),this.videoElement.remove(),t(this.info)}catch(n){URL.revokeObjectURL(i),e(n)}},this.videoElement.onerror=()=>{URL.revokeObjectURL(i),e(new Error(`Failed to load video file: ${this.file.name}`))},this.videoElement.src=i}catch(i){e(i)}})}calculateAspectRatio(t,e){const i=this.getGCD(t,e),n=t/i,s=e/i,r=n/s;return Math.abs(r-16/9)<.01?"16:9":Math.abs(r-4/3)<.01?"4:3":Math.abs(r-21/9)<.01?"21:9":Math.abs(r-1)<.01?"1:1":`${n}:${s}`}getGCD(t,e){return e===0?t:this.getGCD(e,t%e)}formatBytes(t){if(t===0)return"0 Bytes";const e=1024,i=["Bytes","KB","MB","GB","TB"],n=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,n)).toFixed(2))} ${i[n]}`}formatDuration(t){if(!isFinite(t)||t<0)return"00:00";const e=Math.floor(t/3600),i=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}getFileExtension(t){const e=t.split(".");return e.length>1?`.${e[e.length-1].toLowerCase()}`:""}get width(){var t;return((t=this.info)==null?void 0:t.width)||0}get height(){var t;return((t=this.info)==null?void 0:t.height)||0}get aspectRatio(){var t;return((t=this.info)==null?void 0:t.aspectRatio)||"unknown"}get size(){var t;return((t=this.info)==null?void 0:t.size)||0}get sizeInBytes(){var t;return((t=this.info)==null?void 0:t.sizeInBytes)||0}get sizeFormatted(){var t;return((t=this.info)==null?void 0:t.sizeFormatted)||"0 Bytes"}get duration(){var t;return((t=this.info)==null?void 0:t.duration)||0}get durationInSeconds(){var t;return((t=this.info)==null?void 0:t.durationInSeconds)||0}get durationFormatted(){var t;return((t=this.info)==null?void 0:t.durationFormatted)||"00:00"}get mimeType(){var t;return((t=this.info)==null?void 0:t.mimeType)||this.file.type||"video/unknown"}get fileName(){return this.file.name}get fileExtension(){var t;return((t=this.info)==null?void 0:t.fileExtension)||""}get bitrate(){var t;return(t=this.info)==null?void 0:t.bitrate}get quality(){if(!this.info)return"unknown";const t=this.info.height;return t>=2160?"4K (2160p)":t>=1440?"2K (1440p)":t>=1080?"Full HD (1080p)":t>=720?"HD (720p)":t>=480?"SD (480p)":t>=360?"360p":"Low Quality"}getInfo(){return this.info}destroy(){this.videoElement&&(this.videoElement.remove(),this.videoElement=null),this.info=null}}const _=c=>{const{src:t,autoplay:e,muted:i,controls:n=!0,poster:s,preload:r,theme:a,s3Config:l,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f,onReady:E,onPlay:x,onPause:S,onEnded:C,onTimeUpdate:L,onVolumeChange:T,onError:P,onLoadedMetadata:I,onQualityChange:M,style:D,className:H,width:y="100%",height:w="500px"}=c,b=h.useRef(null),q=h.useRef(null);return h.useEffect(()=>{if(!b.current)return;const V={src:t,container:b.current,autoplay:e,muted:i,controls:n,poster:s,preload:r,theme:a,s3Config:l,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f},d=new k(V);return q.current=d,x&&d.on("play",x),S&&d.on("pause",S),C&&d.on("ended",C),P&&d.on("error",m=>{var R;return P((R=m.data)==null?void 0:R.error)}),I&&d.on("loadedmetadata",I),M&&d.on("qualitychange",m=>M(m.data.level)),L&&d.on("timeupdate",m=>L(m.data.currentTime)),T&&d.on("volumechange",m=>T(m.data.volume,m.data.muted)),E&&E(d),()=>{d.destroy(),q.current=null}},[t]),B.jsx("div",{ref:b,className:H,style:{width:typeof y=="number"?`${y}px`:y,height:typeof w=="number"?`${w}px`:w,...D}})},Q=c=>{const[t,e]=h.useState(null),[i,n]=h.useState(null),s=h.useRef(null);return h.useEffect(()=>{if(!s.current)return;const r=new k({...c,container:s.current});e(r);const a=()=>{n(r.getState())};return r.on("play",a),r.on("pause",a),r.on("timeupdate",a),r.on("volumechange",a),r.on("loadedmetadata",a),()=>{r.destroy()}},[c.src]),{containerRef:s,player:t,state:i}},U=F.createContext({player:null,state:null}),Y=c=>{const{player:t,children:e}=c,[i,n]=h.useState(t.getState());return h.useEffect(()=>{const s=()=>{n(t.getState())};return t.on("play",s),t.on("pause",s),t.on("timeupdate",s),t.on("volumechange",s),t.on("loadedmetadata",s),()=>{}},[t]),B.jsx(U.Provider,{value:{player:t,state:i},children:e})},X=()=>{const c=F.useContext(U);if(!c.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return c};exports.Analytics=$;exports.S3Handler=z;exports.UIController=A;exports.WontumFileInfo=O;exports.WontumPlayer=k;exports.WontumPlayerProvider=Y;exports.WontumPlayerReact=_;exports.useWontumPlayer=Q;exports.useWontumPlayerContext=X;
|
|
598
|
+
</svg>`}getSettingsIcon(){return'<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>'}destroy(){this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.controlsContainer.remove()}}class z{constructor(t){s(this,"config");s(this,"urlCache",new Map);s(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const i=new URL(t);return this.config.cloudFrontDomains.some(n=>i.hostname.includes(n))}catch{return!1}}isS3Url(t){return t.includes(".s3.")||t.includes("s3.amazonaws.com")||t.startsWith("s3://")}async signCloudFrontUrl(t,e=0){var o,r;if(this.signedUrls.has(t))return t;if((o=this.config)!=null&&o.signUrl)try{const a=await this.config.signUrl(t);return this.signedUrls.add(t),a}catch(a){const c=(a==null?void 0:a.name)==="AbortError"||((r=a==null?void 0:a.message)==null?void 0:r.includes("aborted"));if(c&&e<2)return console.warn(`Sign URL aborted, retrying (${e+1}/2)...`),await new Promise(u=>setTimeout(u,300)),this.signCloudFrontUrl(t,e+1);throw console.error("Failed to sign CloudFront URL:",a),c?new Error("Failed to sign CloudFront URL: Request was aborted. If using Apollo Client or other GraphQL clients, consider moving the query outside component lifecycle or using useQuery with skip option."):new Error(`Failed to sign CloudFront URL: ${(a==null?void 0:a.message)||"Unknown error"}`)}return console.warn("No signUrl function provided. CloudFront cookies may not be set."),t}extractS3Key(t){if(t.startsWith("s3://"))return t.replace("s3://","").split("/").slice(1).join("/");const e=t.match(/s3[.-]([^.]+)\.amazonaws\.com\/(.+)/);if(e)return e[2];const i=t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);return i?i[2]:t}async getPresignedUrl(t){var n;const e=this.extractS3Key(t),i=this.urlCache.get(e);if(i&&i.expiresAt>Date.now())return i.url;if((n=this.config)!=null&&n.getPresignedUrl)try{const o=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:o,expiresAt:Date.now()+50*60*1e3}),o}catch(o){throw console.error("Failed to generate presigned URL:",o),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,i="us-east-1"){return`https://${t}.s3.${i}.amazonaws.com/${e}`}static parseS3Uri(t){if(!t.startsWith("s3://"))return null;const e=t.replace("s3://","").split("/"),i=e[0],n=e.slice(1).join("/");return{bucket:i,key:n}}clearCache(){this.urlCache.clear(),this.signedUrls.clear()}}class E{constructor(t){s(this,"container");s(this,"videoElement");s(this,"hls",null);s(this,"config");s(this,"eventListeners",new Map);s(this,"analytics");s(this,"s3Handler");s(this,"uiController");s(this,"qualities",[]);s(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new O(t.analytics),this.s3Handler=new z(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new $(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const i=document.createElement("track");i.kind="subtitles",i.label=e.label,i.src=e.src,i.srclang=e.srclang,e.default&&(i.default=!0),this.videoElement.appendChild(i)})}createVideoElement(){const t=document.createElement("video");return t.className="wontum-player-video",t.style.width="100%",t.style.height="100%",t.playsInline=!0,t.crossOrigin="use-credentials",t}setupVideoListeners(){this.videoElement.addEventListener("play",()=>{this.state.playing=!0,this.state.paused=!1,this.emit("play"),this.analytics.trackEvent("play",this.getAnalyticsData())}),this.videoElement.addEventListener("pause",()=>{this.state.playing=!1,this.state.paused=!0,this.emit("pause"),this.analytics.trackEvent("pause",this.getAnalyticsData())}),this.videoElement.addEventListener("ended",()=>{this.state.ended=!0,this.state.playing=!1,this.emit("ended"),this.analytics.trackEvent("ended",this.getAnalyticsData())}),this.videoElement.addEventListener("timeupdate",()=>{this.state.currentTime=this.videoElement.currentTime,this.emit("timeupdate",{currentTime:this.state.currentTime})}),this.videoElement.addEventListener("loadedmetadata",()=>{this.state.duration=this.videoElement.duration,this.emit("loadedmetadata",{duration:this.state.duration}),this.analytics.trackEvent("loadedmetadata",this.getAnalyticsData())}),this.videoElement.addEventListener("volumechange",()=>{this.state.volume=this.videoElement.volume,this.state.muted=this.videoElement.muted,this.emit("volumechange",{volume:this.state.volume,muted:this.state.muted})}),this.videoElement.addEventListener("ratechange",()=>{this.state.playbackRate=this.videoElement.playbackRate,this.emit("ratechange",{playbackRate:this.state.playbackRate})}),this.videoElement.addEventListener("waiting",()=>{this.state.buffering=!0,this.emit("waiting"),this.analytics.trackEvent("buffering_start",this.getAnalyticsData())}),this.videoElement.addEventListener("canplay",()=>{this.state.buffering=!1,this.emit("canplay"),this.analytics.trackEvent("buffering_end",this.getAnalyticsData())}),this.videoElement.addEventListener("seeking",()=>{this.emit("seeking")}),this.videoElement.addEventListener("seeked",()=>{this.emit("seeked",{currentTime:this.state.currentTime}),this.analytics.trackEvent("seeked",this.getAnalyticsData())}),this.videoElement.addEventListener("error",t=>{const e=this.videoElement.error;this.emit("error",{error:e}),this.analytics.trackEvent("error",{...this.getAnalyticsData(),error:e==null?void 0:e.message})}),this.videoElement.addEventListener("loadstart",()=>{this.emit("loadstart")}),this.videoElement.addEventListener("loadeddata",()=>{this.emit("loadeddata")}),this.videoElement.addEventListener("canplaythrough",()=>{this.emit("canplaythrough")}),this.videoElement.addEventListener("playing",()=>{this.state.playing=!0,this.state.buffering=!1,this.emit("playing")}),this.videoElement.addEventListener("durationchange",()=>{this.state.duration=this.videoElement.duration,this.emit("durationchange",{duration:this.state.duration})}),this.videoElement.addEventListener("progress",()=>{this.emit("progress",{buffered:this.videoElement.buffered})}),this.videoElement.addEventListener("stalled",()=>{this.emit("stalled")}),this.videoElement.addEventListener("suspend",()=>{this.emit("suspend")}),this.videoElement.addEventListener("abort",()=>{this.emit("abort")}),this.videoElement.addEventListener("emptied",()=>{this.emit("emptied")}),this.videoElement.addEventListener("resize",()=>{this.emit("resize",{videoWidth:this.videoElement.videoWidth,videoHeight:this.videoElement.videoHeight})})}async loadSource(t){var e;try{const i=await this.s3Handler.processUrl(t);if(g.isSupported()){const n=((e=this.config.s3Config)==null?void 0:e.withCredentials)??!1,o={...this.config.hlsConfig,xhrSetup:(r,a)=>{var c;n&&(r.withCredentials=!0),(c=this.config.hlsConfig)!=null&&c.xhrSetup&&this.config.hlsConfig.xhrSetup(r,a)}};this.hls=new g(o),this.hls.loadSource(i),this.hls.attachMedia(this.videoElement),this.hls.on(g.Events.MANIFEST_PARSED,(r,a)=>{const c=this.extractQualities(a.levels);this.qualities=c}),this.hls.on(g.Events.LEVEL_SWITCHED,(r,a)=>{var u;const c=(u=this.hls)==null?void 0:u.levels[a.level];c&&(this.state.quality=`${c.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(g.Events.ERROR,(r,a)=>{a.fatal&&this.handleHlsError(a)})}else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=i;else throw new Error("HLS is not supported in this browser")}catch(i){console.error("Failed to load video source:",i),this.emit("error",{error:i})}}extractQualities(t){return t.map(e=>({height:e.height,width:e.width,bitrate:e.bitrate,name:`${e.height}p`}))}handleHlsError(t){var e,i;switch(t.type){case g.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case g.ErrorTypes.MEDIA_ERROR:console.error("Media error occurred"),(i=this.hls)==null||i.recoverMediaError();break;default:console.error("Fatal error occurred:",t),this.destroy();break}}getAnalyticsData(){return{currentTime:this.state.currentTime,duration:this.state.duration,quality:this.state.quality,playbackRate:this.state.playbackRate,volume:this.state.volume,muted:this.state.muted}}play(){return this.videoElement.play()}pause(){this.videoElement.pause()}seek(t){this.videoElement.currentTime=t}skipForward(t=10){const e=Math.min(this.state.currentTime+t,this.state.duration);this.seek(e)}skipBackward(t=10){const e=Math.max(this.state.currentTime-t,0);this.seek(e)}setVolume(t){this.videoElement.volume=Math.max(0,Math.min(1,t))}mute(){this.videoElement.muted=!0}unmute(){this.videoElement.muted=!1}setPlaybackRate(t){this.videoElement.playbackRate=t}setQuality(t){this.hls&&(this.hls.currentLevel=t)}getQualities(){return this.qualities}enterFullscreen(){this.container.requestFullscreen&&(this.container.requestFullscreen(),this.state.fullscreen=!0,this.emit("fullscreenchange",{fullscreen:!0}))}exitFullscreen(){document.exitFullscreen&&(document.exitFullscreen(),this.state.fullscreen=!1,this.emit("fullscreenchange",{fullscreen:!1}))}async enterPictureInPicture(){if(document.pictureInPictureEnabled&&!this.videoElement.disablePictureInPicture)try{await this.videoElement.requestPictureInPicture(),this.emit("pictureinpictureenter",{})}catch(t){throw console.error("Failed to enter Picture-in-Picture:",t),t}}async exitPictureInPicture(){if(document.pictureInPictureElement)try{await document.exitPictureInPicture(),this.emit("pictureinpictureexit",{})}catch(t){throw console.error("Failed to exit Picture-in-Picture:",t),t}}async togglePictureInPicture(){document.pictureInPictureElement?await this.exitPictureInPicture():await this.enterPictureInPicture()}getState(){return{...this.state}}getVideoElement(){return this.videoElement}enableSubtitles(t){const e=this.videoElement.textTracks;for(let i=0;i<e.length;i++)e[i].mode=i===t?"showing":"hidden"}disableSubtitles(){const t=this.videoElement.textTracks;for(let e=0;e<t.length;e++)t[e].mode="hidden"}toggleSubtitles(){const t=this.videoElement.textTracks;return Array.from(t).some(i=>i.mode==="showing")?(this.disableSubtitles(),!1):t.length>0?(this.enableSubtitles(0),!0):!1}getSubtitleTracks(){return Array.from(this.videoElement.textTracks)}areSubtitlesEnabled(){const t=this.videoElement.textTracks;return Array.from(t).some(e=>e.mode==="showing")}on(t,e){this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e)}off(t,e){var i;(i=this.eventListeners.get(t))==null||i.delete(e)}emit(t,e){var n;const i={type:t,data:e,timestamp:Date.now()};(n=this.eventListeners.get(t))==null||n.forEach(o=>{o(i)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class J{constructor(t){s(this,"file");s(this,"videoElement",null);s(this,"info",null);if(!this.isVideoFile(t))throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);this.file=t}isVideoFile(t){if(t.type.startsWith("video/"))return!0;const e=[".mp4",".webm",".ogg",".mov",".avi",".mkv",".flv",".wmv",".m4v",".3gp",".ts",".m3u8"],i=t.name.toLowerCase();return e.some(n=>i.endsWith(n))}async extract(){return new Promise((t,e)=>{try{this.videoElement=document.createElement("video"),this.videoElement.preload="metadata",this.videoElement.muted=!0;const i=URL.createObjectURL(this.file);this.videoElement.onloadedmetadata=()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const n=this.videoElement.videoWidth,o=this.videoElement.videoHeight,r=this.videoElement.duration,a=this.calculateAspectRatio(n,o),c=this.file.size,u=this.formatBytes(c),p=this.formatDuration(r),v=this.getFileExtension(this.file.name),f=r>0?Math.round(c*8/r/1e3):void 0;this.info={width:n,height:o,aspectRatio:a,size:c,sizeInBytes:c,sizeFormatted:u,duration:r,durationInSeconds:r,durationFormatted:p,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:v,bitrate:f},URL.revokeObjectURL(i),this.videoElement.remove(),t(this.info)}catch(n){URL.revokeObjectURL(i),e(n)}},this.videoElement.onerror=()=>{URL.revokeObjectURL(i),e(new Error(`Failed to load video file: ${this.file.name}`))},this.videoElement.src=i}catch(i){e(i)}})}calculateAspectRatio(t,e){const i=this.getGCD(t,e),n=t/i,o=e/i,r=n/o;return Math.abs(r-16/9)<.01?"16:9":Math.abs(r-4/3)<.01?"4:3":Math.abs(r-21/9)<.01?"21:9":Math.abs(r-1)<.01?"1:1":`${n}:${o}`}getGCD(t,e){return e===0?t:this.getGCD(e,t%e)}formatBytes(t){if(t===0)return"0 Bytes";const e=1024,i=["Bytes","KB","MB","GB","TB"],n=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,n)).toFixed(2))} ${i[n]}`}formatDuration(t){if(!isFinite(t)||t<0)return"00:00";const e=Math.floor(t/3600),i=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}getFileExtension(t){const e=t.split(".");return e.length>1?`.${e[e.length-1].toLowerCase()}`:""}get width(){var t;return((t=this.info)==null?void 0:t.width)||0}get height(){var t;return((t=this.info)==null?void 0:t.height)||0}get aspectRatio(){var t;return((t=this.info)==null?void 0:t.aspectRatio)||"unknown"}get size(){var t;return((t=this.info)==null?void 0:t.size)||0}get sizeInBytes(){var t;return((t=this.info)==null?void 0:t.sizeInBytes)||0}get sizeFormatted(){var t;return((t=this.info)==null?void 0:t.sizeFormatted)||"0 Bytes"}get duration(){var t;return((t=this.info)==null?void 0:t.duration)||0}get durationInSeconds(){var t;return((t=this.info)==null?void 0:t.durationInSeconds)||0}get durationFormatted(){var t;return((t=this.info)==null?void 0:t.durationFormatted)||"00:00"}get mimeType(){var t;return((t=this.info)==null?void 0:t.mimeType)||this.file.type||"video/unknown"}get fileName(){return this.file.name}get fileExtension(){var t;return((t=this.info)==null?void 0:t.fileExtension)||""}get bitrate(){var t;return(t=this.info)==null?void 0:t.bitrate}get quality(){if(!this.info)return"unknown";const t=this.info.height;return t>=2160?"4K (2160p)":t>=1440?"2K (1440p)":t>=1080?"Full HD (1080p)":t>=720?"HD (720p)":t>=480?"SD (480p)":t>=360?"360p":"Low Quality"}getInfo(){return this.info}destroy(){this.videoElement&&(this.videoElement.remove(),this.videoElement=null),this.info=null}}const Z=l=>{const{src:t,autoplay:e,muted:i,controls:n=!0,poster:o,preload:r,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f,onReady:S,onPlay:x,onPause:C,onEnded:L,onTimeUpdate:T,onVolumeChange:I,onError:P,onLoadedMetadata:R,onQualityChange:M,style:U,className:H,width:y="100%",height:w="500px"}=l,b=h.useRef(null),q=h.useRef(null);return h.useEffect(()=>{if(!b.current)return;const W={src:t,container:b.current,autoplay:e,muted:i,controls:n,poster:o,preload:r,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f},d=new E(W);return q.current=d,x&&d.on("play",x),C&&d.on("pause",C),L&&d.on("ended",L),P&&d.on("error",m=>{var A;return P((A=m.data)==null?void 0:A.error)}),R&&d.on("loadedmetadata",R),M&&d.on("qualitychange",m=>M(m.data.level)),T&&d.on("timeupdate",m=>T(m.data.currentTime)),I&&d.on("volumechange",m=>I(m.data.volume,m.data.muted)),S&&S(d),()=>{d.destroy(),q.current=null}},[t]),B.jsx("div",{ref:b,className:H,style:{width:typeof y=="number"?`${y}px`:y,height:typeof w=="number"?`${w}px`:w,...U}})},tt=l=>{const[t,e]=h.useState(null),[i,n]=h.useState(null),o=h.useRef(null);return h.useEffect(()=>{if(!o.current)return;const r=new E({...l,container:o.current});e(r);const a=()=>{n(r.getState())};return r.on("play",a),r.on("pause",a),r.on("timeupdate",a),r.on("volumechange",a),r.on("loadedmetadata",a),()=>{r.destroy()}},[l.src]),{containerRef:o,player:t,state:i}},D=F.createContext({player:null,state:null}),et=l=>{const{player:t,children:e}=l,[i,n]=h.useState(t.getState());return h.useEffect(()=>{const o=()=>{n(t.getState())};return t.on("play",o),t.on("pause",o),t.on("timeupdate",o),t.on("volumechange",o),t.on("loadedmetadata",o),()=>{}},[t]),B.jsx(D.Provider,{value:{player:t,state:i},children:e})},it=()=>{const l=F.useContext(D);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l};exports.Analytics=O;exports.S3Handler=z;exports.UIController=$;exports.WontumFileInfo=J;exports.WontumPlayer=E;exports.WontumPlayerProvider=et;exports.WontumPlayerReact=Z;exports.useWontumPlayer=tt;exports.useWontumPlayerContext=it;
|
|
@@ -1,24 +1,32 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var H = Object.defineProperty;
|
|
2
|
+
var V = (c, t, e) => t in c ? H(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
|
|
3
|
+
var s = (c, t, e) => V(c, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import p from "hls.js";
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
5
|
+
import { jsx as A } from "react/jsx-runtime";
|
|
6
|
+
import * as F from "react";
|
|
7
7
|
import { useRef as b, useEffect as E, useState as k } from "react";
|
|
8
|
-
class
|
|
8
|
+
class N {
|
|
9
9
|
constructor(t) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
s(this, "config");
|
|
11
|
+
s(this, "sessionId");
|
|
12
|
+
s(this, "events", []);
|
|
13
|
+
s(this, "sessionStartTime");
|
|
14
|
+
s(this, "playbackStartTime", null);
|
|
15
|
+
s(this, "totalPlayTime", 0);
|
|
16
|
+
s(this, "totalBufferTime", 0);
|
|
17
|
+
s(this, "bufferStartTime", null);
|
|
18
|
+
s(this, "rebufferCount", 0);
|
|
19
|
+
s(this, "seekCount", 0);
|
|
20
|
+
s(this, "webSocket", null);
|
|
21
|
+
s(this, "socketIO", null);
|
|
22
|
+
s(this, "wsReconnectTimeout", null);
|
|
23
|
+
s(this, "isDestroyed", !1);
|
|
24
|
+
var e, i;
|
|
25
|
+
if (this.config = t, this.sessionId = (t == null ? void 0 : t.sessionId) || this.generateSessionId(), this.sessionStartTime = Date.now(), (e = this.config) != null && e.webSocket) {
|
|
26
|
+
const n = this.config.webSocket;
|
|
27
|
+
"type" in n ? n.type === "socket.io" ? this.initializeSocketIO() : this.initializeWebSocket() : this.initializeWebSocket();
|
|
28
|
+
}
|
|
29
|
+
(i = this.config) != null && i.enabled && this.trackEvent("session_start", this.getSessionData());
|
|
22
30
|
}
|
|
23
31
|
trackEvent(t, e = {}) {
|
|
24
32
|
var n;
|
|
@@ -34,7 +42,7 @@ class W {
|
|
|
34
42
|
...this.getQoEMetrics()
|
|
35
43
|
}
|
|
36
44
|
};
|
|
37
|
-
this.events.push(i), this.updateMetrics(t, e), this.config.endpoint && this.sendEvent(i), process.env.NODE_ENV === "development" && console.log("[Analytics]", t, i.data);
|
|
45
|
+
this.events.push(i), this.updateMetrics(t, e), this.webSocket && this.webSocket.readyState === WebSocket.OPEN && this.sendToWebSocket(i), this.socketIO && this.socketIO.connected && this.sendToSocketIO(i), this.config.endpoint && this.sendEvent(i), process.env.NODE_ENV === "development" && console.log("[Analytics]", t, i.data);
|
|
38
46
|
}
|
|
39
47
|
updateMetrics(t, e) {
|
|
40
48
|
switch (t) {
|
|
@@ -104,6 +112,72 @@ class W {
|
|
|
104
112
|
generateSessionId() {
|
|
105
113
|
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
106
114
|
}
|
|
115
|
+
async initializeSocketIO() {
|
|
116
|
+
var e;
|
|
117
|
+
if (!((e = this.config) != null && e.webSocket) || !("type" in this.config.webSocket)) return;
|
|
118
|
+
const t = this.config.webSocket;
|
|
119
|
+
if (t.type === "socket.io")
|
|
120
|
+
try {
|
|
121
|
+
if (typeof t.connection == "string") {
|
|
122
|
+
const n = (await import("socket.io-client")).default;
|
|
123
|
+
this.socketIO = n(t.connection, t.options || {});
|
|
124
|
+
} else
|
|
125
|
+
this.socketIO = t.connection;
|
|
126
|
+
if (!this.socketIO) return;
|
|
127
|
+
this.socketIO.on("connect", () => {
|
|
128
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Connected"), t.onConnect && t.onConnect();
|
|
129
|
+
}), this.socketIO.on("connect_error", (i) => {
|
|
130
|
+
console.error("[Analytics Socket.IO] Connection error:", i), t.onError && t.onError(i);
|
|
131
|
+
}), this.socketIO.on("disconnect", (i) => {
|
|
132
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics Socket.IO] Disconnected:", i), t.onDisconnect && t.onDisconnect(i);
|
|
133
|
+
}), this.socketIO.on("error", (i) => {
|
|
134
|
+
console.error("[Analytics Socket.IO] Error:", i), t.onError && t.onError(i);
|
|
135
|
+
});
|
|
136
|
+
} catch (i) {
|
|
137
|
+
console.error("[Analytics Socket.IO] Failed to initialize:", i);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
sendToSocketIO(t) {
|
|
141
|
+
var e;
|
|
142
|
+
if (!(!this.socketIO || !this.socketIO.connected))
|
|
143
|
+
try {
|
|
144
|
+
const i = (e = this.config) == null ? void 0 : e.webSocket, n = i != null && i.transform ? i.transform(t) : t, o = (i == null ? void 0 : i.eventName) || "analytics";
|
|
145
|
+
this.socketIO.emit(o, n), process.env.NODE_ENV === "development" && console.log(`[Analytics Socket.IO] Emitted (${o}):`, t.eventType);
|
|
146
|
+
} catch (i) {
|
|
147
|
+
console.error("[Analytics Socket.IO] Failed to emit event:", i);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
initializeWebSocket() {
|
|
151
|
+
var e;
|
|
152
|
+
if (!((e = this.config) != null && e.webSocket)) return;
|
|
153
|
+
const t = this.config.webSocket;
|
|
154
|
+
try {
|
|
155
|
+
typeof t.connection == "string" ? this.webSocket = new WebSocket(t.connection) : this.webSocket = t.connection, this.webSocket.onopen = (i) => {
|
|
156
|
+
process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Connected"), t.onOpen && t.onOpen(i);
|
|
157
|
+
}, this.webSocket.onerror = (i) => {
|
|
158
|
+
console.error("[Analytics WebSocket] Error:", i), t.onError && t.onError(i);
|
|
159
|
+
}, this.webSocket.onclose = (i) => {
|
|
160
|
+
if (process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Disconnected"), t.onClose && t.onClose(i), t.autoReconnect !== !1 && !this.isDestroyed) {
|
|
161
|
+
const o = t.reconnectDelay || 3e3;
|
|
162
|
+
process.env.NODE_ENV === "development" && console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`), this.wsReconnectTimeout = window.setTimeout(() => {
|
|
163
|
+
this.initializeWebSocket();
|
|
164
|
+
}, o);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
} catch (i) {
|
|
168
|
+
console.error("[Analytics WebSocket] Failed to initialize:", i);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
sendToWebSocket(t) {
|
|
172
|
+
var e;
|
|
173
|
+
if (!(!this.webSocket || this.webSocket.readyState !== WebSocket.OPEN))
|
|
174
|
+
try {
|
|
175
|
+
const i = (e = this.config) == null ? void 0 : e.webSocket, n = i != null && i.transform ? i.transform(t) : t;
|
|
176
|
+
this.webSocket.send(JSON.stringify(n)), process.env.NODE_ENV === "development" && console.log("[Analytics WebSocket] Sent:", t.eventType);
|
|
177
|
+
} catch (i) {
|
|
178
|
+
console.error("[Analytics WebSocket] Failed to send event:", i);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
107
181
|
getEvents() {
|
|
108
182
|
return [...this.events];
|
|
109
183
|
}
|
|
@@ -116,42 +190,42 @@ class W {
|
|
|
116
190
|
}
|
|
117
191
|
destroy() {
|
|
118
192
|
var t;
|
|
119
|
-
(t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.events = [];
|
|
193
|
+
this.isDestroyed = !0, (t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.wsReconnectTimeout && (clearTimeout(this.wsReconnectTimeout), this.wsReconnectTimeout = null), this.webSocket && (this.webSocket.close(), this.webSocket = null), this.socketIO && (this.socketIO.removeAllListeners(), this.socketIO.disconnect(), this.socketIO = null), this.events = [];
|
|
120
194
|
}
|
|
121
195
|
}
|
|
122
|
-
class
|
|
196
|
+
class W {
|
|
123
197
|
constructor(t, e) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
198
|
+
s(this, "container");
|
|
199
|
+
s(this, "player");
|
|
200
|
+
s(this, "controlsContainer");
|
|
201
|
+
s(this, "progressContainer");
|
|
202
|
+
s(this, "progressBar");
|
|
203
|
+
s(this, "playButton");
|
|
204
|
+
s(this, "skipBackwardButton");
|
|
205
|
+
s(this, "skipForwardButton");
|
|
206
|
+
s(this, "volumeButton");
|
|
207
|
+
s(this, "volumeContainer");
|
|
208
|
+
s(this, "fullscreenButton");
|
|
209
|
+
s(this, "pipButton");
|
|
210
|
+
s(this, "settingsButton");
|
|
137
211
|
// private timeDisplay: HTMLElement
|
|
138
|
-
|
|
139
|
-
|
|
212
|
+
s(this, "volumeSlider");
|
|
213
|
+
s(this, "progressInput");
|
|
140
214
|
// private controlsVisible = true
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
215
|
+
s(this, "hideControlsTimeout", null);
|
|
216
|
+
s(this, "stickyControls", !1);
|
|
217
|
+
s(this, "isVolumeSliderActive", !1);
|
|
144
218
|
this.container = t, this.player = e, this.injectStyles(), this.createProgressBar(), this.controlsContainer = this.createControls(), this.container.appendChild(this.controlsContainer), this.playButton = this.controlsContainer.querySelector(".wontum-play-btn"), this.skipBackwardButton = this.controlsContainer.querySelector(".wontum-skip-backward-btn"), this.skipForwardButton = this.controlsContainer.querySelector(".wontum-skip-forward-btn"), this.volumeButton = this.controlsContainer.querySelector(".wontum-volume-btn"), this.volumeContainer = this.controlsContainer.querySelector(".wontum-volume-container"), this.fullscreenButton = this.controlsContainer.querySelector(".wontum-fullscreen-btn"), this.pipButton = this.controlsContainer.querySelector(".wontum-pip-btn"), this.settingsButton = this.controlsContainer.querySelector(".wontum-settings-btn"), this.volumeSlider = this.controlsContainer.querySelector(".wontum-volume-slider"), this.progressInput = this.container.querySelector(".wontum-progress-input"), this.progressBar = this.container.querySelector(".wontum-progress-filled"), this.stickyControls = this.player.config.stickyControls || !1, this.stickyControls && this.controlsContainer.classList.add("sticky"), this.setupEventListeners(), this.setupPlayerEventListeners();
|
|
145
219
|
}
|
|
146
220
|
injectStyles() {
|
|
147
221
|
const t = "wontum-player-styles";
|
|
148
222
|
if (document.getElementById(t)) return;
|
|
149
|
-
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = e.accentColor || "#2563eb",
|
|
223
|
+
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = e.accentColor || "#2563eb", o = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", r = e.controlsBackground || "linear-gradient(to top, rgba(0,0,0,0.8), transparent)", a = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", u = e.borderRadius || "4px", m = document.createElement("style");
|
|
150
224
|
m.id = t, m.textContent = `
|
|
151
225
|
.wontum-player-container {
|
|
152
226
|
position: relative;
|
|
153
227
|
background: #000;
|
|
154
|
-
font-family: ${
|
|
228
|
+
font-family: ${o};
|
|
155
229
|
overflow: hidden;
|
|
156
230
|
--primary-color: ${i};
|
|
157
231
|
--accent-color: ${n};
|
|
@@ -729,11 +803,11 @@ class j {
|
|
|
729
803
|
}), this.skipForwardButton.addEventListener("click", () => {
|
|
730
804
|
this.player.skipForward(10);
|
|
731
805
|
}), this.progressInput.addEventListener("input", (i) => {
|
|
732
|
-
const n = i.target,
|
|
806
|
+
const n = i.target, o = parseFloat(n.value), r = this.player.getState(), a = o / 100 * r.duration;
|
|
733
807
|
this.player.seek(a);
|
|
734
808
|
}), this.volumeSlider.addEventListener("input", (i) => {
|
|
735
|
-
const n = i.target,
|
|
736
|
-
this.player.setVolume(
|
|
809
|
+
const n = i.target, o = parseFloat(n.value) / 100;
|
|
810
|
+
this.player.setVolume(o);
|
|
737
811
|
}), this.volumeButton.addEventListener("click", () => {
|
|
738
812
|
this.player.getState().muted ? this.player.unmute() : this.player.mute();
|
|
739
813
|
}), this.volumeContainer.addEventListener("mouseenter", () => {
|
|
@@ -761,8 +835,8 @@ class j {
|
|
|
761
835
|
const t = this.controlsContainer.querySelectorAll(".wontum-tab");
|
|
762
836
|
t.forEach((i) => {
|
|
763
837
|
i.addEventListener("click", (n) => {
|
|
764
|
-
const
|
|
765
|
-
t.forEach((u) => u.classList.remove("active")),
|
|
838
|
+
const o = n.currentTarget, r = o.getAttribute("data-tab");
|
|
839
|
+
t.forEach((u) => u.classList.remove("active")), o.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((u) => u.classList.remove("active"));
|
|
766
840
|
const l = this.controlsContainer.querySelector(`[data-panel="${r}"]`);
|
|
767
841
|
l == null || l.classList.add("active");
|
|
768
842
|
});
|
|
@@ -782,8 +856,8 @@ class j {
|
|
|
782
856
|
}), this.player.on("timeupdate", (t) => {
|
|
783
857
|
const { currentTime: e } = t.data, i = this.player.getState();
|
|
784
858
|
if (i.duration > 0) {
|
|
785
|
-
const
|
|
786
|
-
this.progressBar.style.width = `${
|
|
859
|
+
const o = e / i.duration * 100;
|
|
860
|
+
this.progressBar.style.width = `${o}%`, this.progressInput.value = o.toString();
|
|
787
861
|
}
|
|
788
862
|
const n = this.controlsContainer.querySelector(".wontum-current-time");
|
|
789
863
|
n.textContent = this.formatTime(e);
|
|
@@ -811,15 +885,15 @@ class j {
|
|
|
811
885
|
t.innerHTML = `
|
|
812
886
|
<div class="wontum-subtitle-option ${i === -1 ? "active" : ""}" data-track="-1">Off</div>
|
|
813
887
|
${e.map(
|
|
814
|
-
(n,
|
|
815
|
-
<div class="wontum-subtitle-option ${
|
|
816
|
-
${n.label || n.language || `Track ${
|
|
888
|
+
(n, o) => `
|
|
889
|
+
<div class="wontum-subtitle-option ${o === i ? "active" : ""}" data-track="${o}">
|
|
890
|
+
${n.label || n.language || `Track ${o + 1}`}
|
|
817
891
|
</div>
|
|
818
892
|
`
|
|
819
893
|
).join("")}
|
|
820
894
|
`, t.querySelectorAll(".wontum-subtitle-option").forEach((n) => {
|
|
821
|
-
n.addEventListener("click", (
|
|
822
|
-
const r =
|
|
895
|
+
n.addEventListener("click", (o) => {
|
|
896
|
+
const r = o.target, a = parseInt(r.dataset.track || "-1");
|
|
823
897
|
a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), r.classList.add("active");
|
|
824
898
|
});
|
|
825
899
|
});
|
|
@@ -827,13 +901,13 @@ class j {
|
|
|
827
901
|
updateSpeedMenu() {
|
|
828
902
|
const t = this.controlsContainer.querySelector(".wontum-speed-menu"), i = this.player.getState().playbackRate || 1, n = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
|
|
829
903
|
t.innerHTML = n.map(
|
|
830
|
-
(
|
|
831
|
-
<div class="wontum-speed-option ${i ===
|
|
832
|
-
${
|
|
904
|
+
(o) => `
|
|
905
|
+
<div class="wontum-speed-option ${i === o ? "active" : ""}" data-speed="${o}">
|
|
906
|
+
${o === 1 ? "Normal" : o + "x"}
|
|
833
907
|
</div>
|
|
834
908
|
`
|
|
835
|
-
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((
|
|
836
|
-
|
|
909
|
+
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((o) => {
|
|
910
|
+
o.addEventListener("click", (r) => {
|
|
837
911
|
const a = r.target, l = parseFloat(a.dataset.speed || "1");
|
|
838
912
|
this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), a.classList.add("active");
|
|
839
913
|
});
|
|
@@ -861,13 +935,13 @@ class j {
|
|
|
861
935
|
e.innerHTML = `
|
|
862
936
|
<div class="wontum-quality-option active" data-quality="-1">Auto</div>
|
|
863
937
|
${i.map(
|
|
864
|
-
(n,
|
|
865
|
-
<div class="wontum-quality-option" data-quality="${
|
|
938
|
+
(n, o) => `
|
|
939
|
+
<div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
|
|
866
940
|
`
|
|
867
941
|
).join("")}
|
|
868
942
|
`, e.querySelectorAll(".wontum-quality-option").forEach((n) => {
|
|
869
|
-
n.addEventListener("click", (
|
|
870
|
-
const r =
|
|
943
|
+
n.addEventListener("click", (o) => {
|
|
944
|
+
const r = o.target, a = parseInt(r.dataset.quality || "-1");
|
|
871
945
|
this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), r.classList.add("active");
|
|
872
946
|
});
|
|
873
947
|
});
|
|
@@ -933,11 +1007,11 @@ class j {
|
|
|
933
1007
|
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
934
1008
|
}
|
|
935
1009
|
}
|
|
936
|
-
class
|
|
1010
|
+
class _ {
|
|
937
1011
|
constructor(t) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1012
|
+
s(this, "config");
|
|
1013
|
+
s(this, "urlCache", /* @__PURE__ */ new Map());
|
|
1014
|
+
s(this, "signedUrls", /* @__PURE__ */ new Set());
|
|
941
1015
|
this.config = t;
|
|
942
1016
|
}
|
|
943
1017
|
/**
|
|
@@ -971,10 +1045,10 @@ class Q {
|
|
|
971
1045
|
* The endpoint should set signed cookies and return the URL
|
|
972
1046
|
*/
|
|
973
1047
|
async signCloudFrontUrl(t, e = 0) {
|
|
974
|
-
var
|
|
1048
|
+
var o, r;
|
|
975
1049
|
if (this.signedUrls.has(t))
|
|
976
1050
|
return t;
|
|
977
|
-
if ((
|
|
1051
|
+
if ((o = this.config) != null && o.signUrl)
|
|
978
1052
|
try {
|
|
979
1053
|
const a = await this.config.signUrl(t);
|
|
980
1054
|
return this.signedUrls.add(t), a;
|
|
@@ -1010,13 +1084,13 @@ class Q {
|
|
|
1010
1084
|
return i.url;
|
|
1011
1085
|
if ((n = this.config) != null && n.getPresignedUrl)
|
|
1012
1086
|
try {
|
|
1013
|
-
const
|
|
1087
|
+
const o = await this.config.getPresignedUrl(e);
|
|
1014
1088
|
return this.urlCache.set(e, {
|
|
1015
|
-
url:
|
|
1089
|
+
url: o,
|
|
1016
1090
|
expiresAt: Date.now() + 50 * 60 * 1e3
|
|
1017
|
-
}),
|
|
1018
|
-
} catch (
|
|
1019
|
-
throw console.error("Failed to generate presigned URL:",
|
|
1091
|
+
}), o;
|
|
1092
|
+
} catch (o) {
|
|
1093
|
+
throw console.error("Failed to generate presigned URL:", o), new Error("Failed to generate presigned URL for S3 object");
|
|
1020
1094
|
}
|
|
1021
1095
|
return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"), t;
|
|
1022
1096
|
}
|
|
@@ -1042,18 +1116,18 @@ class Q {
|
|
|
1042
1116
|
this.urlCache.clear(), this.signedUrls.clear();
|
|
1043
1117
|
}
|
|
1044
1118
|
}
|
|
1045
|
-
class
|
|
1119
|
+
class $ {
|
|
1046
1120
|
constructor(t) {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1121
|
+
s(this, "container");
|
|
1122
|
+
s(this, "videoElement");
|
|
1123
|
+
s(this, "hls", null);
|
|
1124
|
+
s(this, "config");
|
|
1125
|
+
s(this, "eventListeners", /* @__PURE__ */ new Map());
|
|
1126
|
+
s(this, "analytics");
|
|
1127
|
+
s(this, "s3Handler");
|
|
1128
|
+
s(this, "uiController");
|
|
1129
|
+
s(this, "qualities", []);
|
|
1130
|
+
s(this, "state", {
|
|
1057
1131
|
playing: !1,
|
|
1058
1132
|
paused: !0,
|
|
1059
1133
|
ended: !1,
|
|
@@ -1069,7 +1143,7 @@ class A {
|
|
|
1069
1143
|
});
|
|
1070
1144
|
if (this.config = t, this.container = typeof t.container == "string" ? document.querySelector(t.container) : t.container, !this.container)
|
|
1071
1145
|
throw new Error("Container element not found");
|
|
1072
|
-
this.analytics = new
|
|
1146
|
+
this.analytics = new N(t.analytics), this.s3Handler = new _(t.s3Config), this.videoElement = this.createVideoElement(), this.container.appendChild(this.videoElement), this.uiController = new W(this.container, this), this.setupVideoListeners(), this.loadSource(t.src), t.autoplay && (this.videoElement.autoplay = !0), t.muted && this.mute(), t.poster && (this.videoElement.poster = t.poster), t.preload && (this.videoElement.preload = t.preload), t.subtitles && this.addSubtitleTracks(t.subtitles);
|
|
1073
1147
|
}
|
|
1074
1148
|
addSubtitleTracks(t) {
|
|
1075
1149
|
t.forEach((e) => {
|
|
@@ -1139,14 +1213,14 @@ class A {
|
|
|
1139
1213
|
try {
|
|
1140
1214
|
const i = await this.s3Handler.processUrl(t);
|
|
1141
1215
|
if (p.isSupported()) {
|
|
1142
|
-
const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1,
|
|
1216
|
+
const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
|
|
1143
1217
|
...this.config.hlsConfig,
|
|
1144
1218
|
xhrSetup: (r, a) => {
|
|
1145
1219
|
var l;
|
|
1146
1220
|
n && (r.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(r, a);
|
|
1147
1221
|
}
|
|
1148
1222
|
};
|
|
1149
|
-
this.hls = new p(
|
|
1223
|
+
this.hls = new p(o), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (r, a) => {
|
|
1150
1224
|
const l = this.extractQualities(a.levels);
|
|
1151
1225
|
this.qualities = l;
|
|
1152
1226
|
}), this.hls.on(p.Events.LEVEL_SWITCHED, (r, a) => {
|
|
@@ -1313,8 +1387,8 @@ class A {
|
|
|
1313
1387
|
data: e,
|
|
1314
1388
|
timestamp: Date.now()
|
|
1315
1389
|
};
|
|
1316
|
-
(n = this.eventListeners.get(t)) == null || n.forEach((
|
|
1317
|
-
|
|
1390
|
+
(n = this.eventListeners.get(t)) == null || n.forEach((o) => {
|
|
1391
|
+
o(i);
|
|
1318
1392
|
});
|
|
1319
1393
|
}
|
|
1320
1394
|
destroy() {
|
|
@@ -1323,9 +1397,9 @@ class A {
|
|
|
1323
1397
|
}
|
|
1324
1398
|
class G {
|
|
1325
1399
|
constructor(t) {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1400
|
+
s(this, "file");
|
|
1401
|
+
s(this, "videoElement", null);
|
|
1402
|
+
s(this, "info", null);
|
|
1329
1403
|
if (!this.isVideoFile(t))
|
|
1330
1404
|
throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
|
|
1331
1405
|
this.file = t;
|
|
@@ -1353,10 +1427,10 @@ class G {
|
|
|
1353
1427
|
e(new Error("Video element not initialized"));
|
|
1354
1428
|
return;
|
|
1355
1429
|
}
|
|
1356
|
-
const n = this.videoElement.videoWidth,
|
|
1430
|
+
const n = this.videoElement.videoWidth, o = this.videoElement.videoHeight, r = this.videoElement.duration, a = this.calculateAspectRatio(n, o), l = this.file.size, u = this.formatBytes(l), m = this.formatDuration(r), g = this.getFileExtension(this.file.name), v = r > 0 ? Math.round(l * 8 / r / 1e3) : void 0;
|
|
1357
1431
|
this.info = {
|
|
1358
1432
|
width: n,
|
|
1359
|
-
height:
|
|
1433
|
+
height: o,
|
|
1360
1434
|
aspectRatio: a,
|
|
1361
1435
|
size: l,
|
|
1362
1436
|
sizeInBytes: l,
|
|
@@ -1386,8 +1460,8 @@ class G {
|
|
|
1386
1460
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
1387
1461
|
*/
|
|
1388
1462
|
calculateAspectRatio(t, e) {
|
|
1389
|
-
const i = this.getGCD(t, e), n = t / i,
|
|
1390
|
-
return Math.abs(r - 16 / 9) < 0.01 ? "16:9" : Math.abs(r - 4 / 3) < 0.01 ? "4:3" : Math.abs(r - 21 / 9) < 0.01 ? "21:9" : Math.abs(r - 1) < 0.01 ? "1:1" : `${n}:${
|
|
1463
|
+
const i = this.getGCD(t, e), n = t / i, o = e / i, r = n / o;
|
|
1464
|
+
return Math.abs(r - 16 / 9) < 0.01 ? "16:9" : Math.abs(r - 4 / 3) < 0.01 ? "4:3" : Math.abs(r - 21 / 9) < 0.01 ? "21:9" : Math.abs(r - 1) < 0.01 ? "1:1" : `${n}:${o}`;
|
|
1391
1465
|
}
|
|
1392
1466
|
/**
|
|
1393
1467
|
* Get Greatest Common Divisor
|
|
@@ -1494,7 +1568,7 @@ const K = (c) => {
|
|
|
1494
1568
|
autoplay: e,
|
|
1495
1569
|
muted: i,
|
|
1496
1570
|
controls: n = !0,
|
|
1497
|
-
poster:
|
|
1571
|
+
poster: o,
|
|
1498
1572
|
preload: r,
|
|
1499
1573
|
theme: a,
|
|
1500
1574
|
s3Config: l,
|
|
@@ -1502,29 +1576,29 @@ const K = (c) => {
|
|
|
1502
1576
|
hlsConfig: m,
|
|
1503
1577
|
subtitles: g,
|
|
1504
1578
|
stickyControls: v,
|
|
1505
|
-
onReady:
|
|
1506
|
-
onPlay:
|
|
1579
|
+
onReady: S,
|
|
1580
|
+
onPlay: x,
|
|
1507
1581
|
onPause: C,
|
|
1508
1582
|
onEnded: L,
|
|
1509
1583
|
onTimeUpdate: T,
|
|
1510
1584
|
onVolumeChange: I,
|
|
1511
1585
|
onError: M,
|
|
1512
|
-
onLoadedMetadata:
|
|
1586
|
+
onLoadedMetadata: R,
|
|
1513
1587
|
onQualityChange: P,
|
|
1514
|
-
style:
|
|
1515
|
-
className:
|
|
1588
|
+
style: D,
|
|
1589
|
+
className: O,
|
|
1516
1590
|
width: f = "100%",
|
|
1517
|
-
height:
|
|
1518
|
-
} = c,
|
|
1591
|
+
height: y = "500px"
|
|
1592
|
+
} = c, w = b(null), q = b(null);
|
|
1519
1593
|
return E(() => {
|
|
1520
|
-
if (!
|
|
1521
|
-
const
|
|
1594
|
+
if (!w.current) return;
|
|
1595
|
+
const U = {
|
|
1522
1596
|
src: t,
|
|
1523
|
-
container:
|
|
1597
|
+
container: w.current,
|
|
1524
1598
|
autoplay: e,
|
|
1525
1599
|
muted: i,
|
|
1526
1600
|
controls: n,
|
|
1527
|
-
poster:
|
|
1601
|
+
poster: o,
|
|
1528
1602
|
preload: r,
|
|
1529
1603
|
theme: a,
|
|
1530
1604
|
s3Config: l,
|
|
@@ -1532,32 +1606,32 @@ const K = (c) => {
|
|
|
1532
1606
|
hlsConfig: m,
|
|
1533
1607
|
subtitles: g,
|
|
1534
1608
|
stickyControls: v
|
|
1535
|
-
}, d = new
|
|
1536
|
-
return
|
|
1537
|
-
var
|
|
1538
|
-
return M((
|
|
1539
|
-
}),
|
|
1540
|
-
d.destroy(),
|
|
1609
|
+
}, d = new $(U);
|
|
1610
|
+
return q.current = d, x && d.on("play", x), C && d.on("pause", C), L && d.on("ended", L), M && d.on("error", (h) => {
|
|
1611
|
+
var B;
|
|
1612
|
+
return M((B = h.data) == null ? void 0 : B.error);
|
|
1613
|
+
}), R && d.on("loadedmetadata", R), P && d.on("qualitychange", (h) => P(h.data.level)), T && d.on("timeupdate", (h) => T(h.data.currentTime)), I && d.on("volumechange", (h) => I(h.data.volume, h.data.muted)), S && S(d), () => {
|
|
1614
|
+
d.destroy(), q.current = null;
|
|
1541
1615
|
};
|
|
1542
|
-
}, [t]), /* @__PURE__ */
|
|
1616
|
+
}, [t]), /* @__PURE__ */ A(
|
|
1543
1617
|
"div",
|
|
1544
1618
|
{
|
|
1545
|
-
ref:
|
|
1546
|
-
className:
|
|
1619
|
+
ref: w,
|
|
1620
|
+
className: O,
|
|
1547
1621
|
style: {
|
|
1548
1622
|
width: typeof f == "number" ? `${f}px` : f,
|
|
1549
|
-
height: typeof
|
|
1550
|
-
...
|
|
1623
|
+
height: typeof y == "number" ? `${y}px` : y,
|
|
1624
|
+
...D
|
|
1551
1625
|
}
|
|
1552
1626
|
}
|
|
1553
1627
|
);
|
|
1554
1628
|
}, J = (c) => {
|
|
1555
|
-
const [t, e] = k(null), [i, n] = k(null),
|
|
1629
|
+
const [t, e] = k(null), [i, n] = k(null), o = b(null);
|
|
1556
1630
|
return E(() => {
|
|
1557
|
-
if (!
|
|
1558
|
-
const r = new
|
|
1631
|
+
if (!o.current) return;
|
|
1632
|
+
const r = new $({
|
|
1559
1633
|
...c,
|
|
1560
|
-
container:
|
|
1634
|
+
container: o.current
|
|
1561
1635
|
});
|
|
1562
1636
|
e(r);
|
|
1563
1637
|
const a = () => {
|
|
@@ -1567,34 +1641,34 @@ const K = (c) => {
|
|
|
1567
1641
|
r.destroy();
|
|
1568
1642
|
};
|
|
1569
1643
|
}, [c.src]), {
|
|
1570
|
-
containerRef:
|
|
1644
|
+
containerRef: o,
|
|
1571
1645
|
player: t,
|
|
1572
1646
|
state: i
|
|
1573
1647
|
};
|
|
1574
|
-
}, z =
|
|
1648
|
+
}, z = F.createContext({
|
|
1575
1649
|
player: null,
|
|
1576
1650
|
state: null
|
|
1577
1651
|
}), Z = (c) => {
|
|
1578
1652
|
const { player: t, children: e } = c, [i, n] = k(t.getState());
|
|
1579
1653
|
return E(() => {
|
|
1580
|
-
const
|
|
1654
|
+
const o = () => {
|
|
1581
1655
|
n(t.getState());
|
|
1582
1656
|
};
|
|
1583
|
-
return t.on("play",
|
|
1657
|
+
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1584
1658
|
};
|
|
1585
|
-
}, [t]), /* @__PURE__ */
|
|
1659
|
+
}, [t]), /* @__PURE__ */ A(z.Provider, { value: { player: t, state: i }, children: e });
|
|
1586
1660
|
}, tt = () => {
|
|
1587
|
-
const c =
|
|
1661
|
+
const c = F.useContext(z);
|
|
1588
1662
|
if (!c.player)
|
|
1589
1663
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1590
1664
|
return c;
|
|
1591
1665
|
};
|
|
1592
1666
|
export {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1667
|
+
N as Analytics,
|
|
1668
|
+
_ as S3Handler,
|
|
1669
|
+
W as UIController,
|
|
1596
1670
|
G as WontumFileInfo,
|
|
1597
|
-
|
|
1671
|
+
$ as WontumPlayer,
|
|
1598
1672
|
Z as WontumPlayerProvider,
|
|
1599
1673
|
K as WontumPlayerReact,
|
|
1600
1674
|
J as useWontumPlayer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obipascal/player",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
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",
|
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
"@types/node": "^20.10.0",
|
|
34
34
|
"@types/react": "^19.2.8",
|
|
35
35
|
"@types/react-dom": "^19.2.3",
|
|
36
|
+
"@types/socket.io-client": "^1.4.36",
|
|
36
37
|
"react": "^19.2.3",
|
|
37
38
|
"react-dom": "^19.2.3",
|
|
39
|
+
"socket.io-client": "^4.8.3",
|
|
38
40
|
"typescript": "^5.3.3",
|
|
39
41
|
"vite": "^5.0.8",
|
|
40
42
|
"vite-plugin-dts": "^3.7.0"
|
|
@@ -53,5 +55,8 @@
|
|
|
53
55
|
"react-dom": {
|
|
54
56
|
"optional": true
|
|
55
57
|
}
|
|
58
|
+
},
|
|
59
|
+
"optionalDependencies": {
|
|
60
|
+
"socket.io-client": "^4.8.3"
|
|
56
61
|
}
|
|
57
62
|
}
|