@obipascal/player 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -939,6 +939,77 @@ Each event includes Quality of Experience (QoE) metrics:
939
939
  - `rebufferCount` - Number of rebuffer events
940
940
  - `seekCount` - Number of seek operations
941
941
 
942
+ ### React Hook (useAnalytics)
943
+
944
+ For React applications, use the `useAnalytics` hook for automatic lifecycle management:
945
+
946
+ ```tsx
947
+ import { useAnalytics } from "@obipascal/player"
948
+ import { useEffect } from "react"
949
+
950
+ function VideoAnalyticsDashboard() {
951
+ const { trackEvent, getMetrics, connected, sessionId } = useAnalytics({
952
+ enabled: true,
953
+ endpoint: "https://api.example.com/analytics",
954
+ videoId: "video-123",
955
+ userId: "user-456",
956
+ webSocket: {
957
+ type: "socket.io",
958
+ url: "https://analytics.example.com",
959
+ auth: { token: "your-auth-token" },
960
+ eventName: "video_event",
961
+ },
962
+ })
963
+
964
+ // Track custom events
965
+ const handleShareClick = () => {
966
+ trackEvent("share_clicked", {
967
+ platform: "twitter",
968
+ videoTime: 125.5,
969
+ })
970
+ }
971
+
972
+ const handleBookmark = () => {
973
+ trackEvent("bookmark_added", {
974
+ timestamp: Date.now(),
975
+ })
976
+ }
977
+
978
+ // Display metrics
979
+ useEffect(() => {
980
+ const interval = setInterval(() => {
981
+ const metrics = getMetrics()
982
+ console.log("Session Metrics:", metrics)
983
+ }, 5000)
984
+
985
+ return () => clearInterval(interval)
986
+ }, [getMetrics])
987
+
988
+ return (
989
+ <div>
990
+ <h3>Analytics Dashboard</h3>
991
+ <p>Session ID: {sessionId}</p>
992
+ <p>WebSocket Status: {connected ? "🟢 Connected" : "🔴 Disconnected"}</p>
993
+
994
+ <button onClick={handleShareClick}>Share Video</button>
995
+ <button onClick={handleBookmark}>Bookmark</button>
996
+
997
+ {/* The hook automatically tracks session_start and session_end */}
998
+ {/* It cleans up on component unmount */}
999
+ </div>
1000
+ )
1001
+ }
1002
+ ```
1003
+
1004
+ **Hook Features:**
1005
+
1006
+ - ✅ Automatic lifecycle management (initialization and cleanup)
1007
+ - ✅ WebSocket/Socket.IO connection status monitoring
1008
+ - ✅ Track custom events with `trackEvent()`
1009
+ - ✅ Access metrics with `getMetrics()`
1010
+ - ✅ Access all events with `getEvents()`
1011
+ - ✅ Session ID available immediately
1012
+
942
1013
  ## API Reference
943
1014
 
944
1015
  ### WontumPlayer
@@ -1099,6 +1170,69 @@ type PlayerEventType =
1099
1170
  />
1100
1171
  ```
1101
1172
 
1173
+ **Important: Changing Video Source**
1174
+
1175
+ The `WontumPlayerReact` component properly handles video source changes. When you update the `src` prop, the player will:
1176
+
1177
+ - ✅ Clean up the previous player instance completely
1178
+ - ✅ Remove all DOM elements (controls, progress bars)
1179
+ - ✅ Reinitialize with the new video source
1180
+ - ✅ Maintain control visibility and functionality
1181
+
1182
+ ```tsx
1183
+ function VideoModal() {
1184
+ const [currentVideo, setCurrentVideo] = useState("video1.m3u8")
1185
+
1186
+ return (
1187
+ <WontumPlayerReact
1188
+ src={currentVideo} // ✅ Simply change the src - no need for React key tricks!
1189
+ width="100%"
1190
+ height="100%"
1191
+ controls
1192
+ stickyControls
1193
+ />
1194
+ )
1195
+ }
1196
+ ```
1197
+
1198
+ **Advanced: Using updateSource() for Better Performance**
1199
+
1200
+ For even better performance when changing sources, you can use the `updateSource()` method via the `onReady` callback:
1201
+
1202
+ ```tsx
1203
+ function VideoPlayer() {
1204
+ const [videos] = useState(["https://example.com/video1.m3u8", "https://example.com/video2.m3u8", "https://example.com/video3.m3u8"])
1205
+ const [currentIndex, setCurrentIndex] = useState(0)
1206
+ const playerRef = useRef<WontumPlayer | null>(null)
1207
+
1208
+ const handleReady = (player: WontumPlayer) => {
1209
+ playerRef.current = player
1210
+ }
1211
+
1212
+ const switchVideo = async (index: number) => {
1213
+ if (playerRef.current) {
1214
+ // Use updateSource for efficient source changes (no full reinitialization)
1215
+ await playerRef.current.updateSource(videos[index])
1216
+ setCurrentIndex(index)
1217
+ }
1218
+ }
1219
+
1220
+ return (
1221
+ <div>
1222
+ <WontumPlayerReact src={videos[currentIndex]} width="100%" height="500px" onReady={handleReady} />
1223
+
1224
+ <div>
1225
+ {videos.map((_, index) => (
1226
+ <button key={index} onClick={() => switchVideo(index)} disabled={index === currentIndex}>
1227
+ Video {index + 1}
1228
+ </button>
1229
+ ))}
1230
+ </div>
1231
+ </div>
1232
+ )
1233
+ }
1234
+ ```
1235
+
1102
1236
  #### useWontumPlayer Hook
1103
1237
 
1104
1238
  ```tsx
@@ -1390,6 +1524,66 @@ pipButton.addEventListener("click", async () => {
1390
1524
 
1391
1525
  The SDK includes a `WontumFileInfo` utility class to extract metadata from video files before uploading or processing them.
1392
1526
 
1527
+ #### React Hook (useVideoFileInfo)
1528
+
1529
+ For React applications, use the `useVideoFileInfo` hook for automatic state management:
1530
+
1531
+ ```tsx
1532
+ import { useVideoFileInfo } from "@obipascal/player"
1533
+ import { useState } from "react"
1534
+
1535
+ function VideoUploader() {
1536
+ const [selectedFile, setSelectedFile] = useState<File | null>(null)
1537
+ const { info, loading, error, refetch } = useVideoFileInfo(selectedFile)
1538
+
1539
+ const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
1540
+ const file = event.target.files?.[0]
1541
+ setSelectedFile(file || null)
1542
+ }
1543
+
1544
+ return (
1545
+ <div>
1546
+ <input type="file" accept="video/*" onChange={handleFileChange} />
1547
+
1548
+ {loading && <p>Analyzing video...</p>}
1549
+
1550
+ {error && (
1551
+ <div>
1552
+ <p style={{ color: "red" }}>Error: {error}</p>
1553
+ <button onClick={refetch}>Retry</button>
1554
+ </div>
1555
+ )}
1556
+
1557
+ {info && (
1558
+ <div>
1559
+ <h3>Video Information</h3>
1560
+ <ul>
1561
+ <li>
1562
+ Resolution: {info.width} × {info.height}
1563
+ </li>
1564
+ <li>Aspect Ratio: {info.aspectRatio}</li>
1565
+ <li>Quality: {info.quality}</li>
1566
+ <li>Duration: {info.durationFormatted}</li>
1567
+ <li>Size: {info.sizeFormatted}</li>
1568
+ <li>Bitrate: {info.bitrate} kbps</li>
1569
+ <li>Frame Rate: {info.frameRate} fps</li>
1570
+ <li>Audio: {info.hasAudio ? `${info.audioChannels} channels` : "No audio"}</li>
1571
+ </ul>
1572
+
1573
+ {/* Validation example */}
1574
+ {info.aspectRatio !== "16:9" && <p style={{ color: "orange" }}>⚠️ Video should be 16:9 aspect ratio</p>}
1575
+ {info.height < 720 && <p style={{ color: "red" }}>❌ Minimum resolution is 720p</p>}
1576
+ {!info.hasAudio && <p style={{ color: "red" }}>❌ Video must have audio</p>}
1577
+ {info.audioChannels !== 2 && <p style={{ color: "orange" }}>⚠️ Audio should be stereo (2 channels)</p>}
1578
+ </div>
1579
+ )}
1580
+ </div>
1581
+ )
1582
+ }
1583
+ ```
1584
+
1585
+ #### Vanilla JavaScript
1586
+
1393
1587
  ```typescript
1394
1588
  import { WontumFileInfo } from "@obipascal/player"
1395
1589
 
@@ -1553,10 +1747,11 @@ For detailed API documentation including all methods, events, types, and configu
1553
1747
  - **Playback Rate:** `setPlaybackRate(rate)`
1554
1748
  - **Fullscreen:** `enterFullscreen()`, `exitFullscreen()`
1555
1749
  - **Picture-in-Picture:** `enterPictureInPicture()`, `exitPictureInPicture()`, `togglePictureInPicture()`
1750
+ - **Source Management:** `updateSource(src)` - _Efficiently change video source without full reinitialization_
1556
1751
  - **State:** `getState()`, `getCurrentTime()`, `getDuration()`
1557
1752
  - **Lifecycle:** `destroy()`
1558
1753
 
1559
- **Events (25 total):**
1754
+ **Events (26 total):**
1560
1755
 
1561
1756
  - **Playback:** `play`, `pause`, `ended`, `timeupdate`, `durationchange`
1562
1757
  - **Loading:** `loadstart`, `loadedmetadata`, `loadeddata`, `canplay`, `canplaythrough`
@@ -1564,6 +1759,7 @@ For detailed API documentation including all methods, events, types, and configu
1564
1759
  - **Seeking:** `seeking`, `seeked`
1565
1760
  - **Volume:** `volumechange`
1566
1761
  - **Quality:** `qualitychange`, `renditionchange`
1762
+ - **Source:** `sourcechange` - _Fires when video source is changed via updateSource()_
1567
1763
  - **Errors:** `error`
1568
1764
  - **Playback Rate:** `ratechange`
1569
1765
  - **Fullscreen:** `fullscreenchange`
@@ -3,7 +3,7 @@ export { Analytics } from './analytics';
3
3
  export { S3Handler } from './s3-handler';
4
4
  export { UIController } from './ui-controller';
5
5
  export { WontumFileInfo } from './file-info';
6
- export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext } from './react';
6
+ export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext, useVideoFileInfo, useAnalytics } from './react';
7
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
- export type { WontumPlayerReactProps } from './react';
9
+ export type { WontumPlayerReactProps, UseVideoFileInfoResult, UseAnalyticsResult } from './react';
@@ -64,5 +64,11 @@ export declare class WontumPlayer {
64
64
  on(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
65
65
  off(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
66
66
  private emit;
67
+ /**
68
+ * Update video source without recreating the entire player
69
+ * This is more efficient than destroying and recreating the player
70
+ * @param src - New video source URL
71
+ */
72
+ updateSource(src: string): Promise<void>;
67
73
  destroy(): void;
68
74
  }
@@ -1,5 +1,6 @@
1
1
  import { WontumPlayer } from './player';
2
- import { WontumPlayerConfig, PlayerState } from './types';
2
+ import { WontumPlayerConfig, PlayerState, AnalyticsConfig, AnalyticsEvent } from './types';
3
+ import { VideoFileInfo } from './file-info';
3
4
  import * as React from "react";
4
5
  export interface WontumPlayerReactProps extends Omit<WontumPlayerConfig, "container"> {
5
6
  /** Callback when player is ready */
@@ -46,4 +47,58 @@ export declare const WontumPlayerProvider: React.FC<{
46
47
  children: React.ReactNode;
47
48
  }>;
48
49
  export declare const useWontumPlayerContext: () => WontumPlayerContextValue;
50
+ /**
51
+ * Hook for extracting video file information
52
+ * @param file - The video file to analyze (File object or null)
53
+ * @returns Object containing loading state, error, and video info
54
+ */
55
+ export interface UseVideoFileInfoResult {
56
+ /** Video file information (null if not loaded or error occurred) */
57
+ info: VideoFileInfo | null;
58
+ /** Whether extraction is in progress */
59
+ loading: boolean;
60
+ /** Error message if extraction failed */
61
+ error: string | null;
62
+ /** Re-extract file info (useful for retry after error) */
63
+ refetch: () => Promise<void>;
64
+ }
65
+ export declare const useVideoFileInfo: (file: File | null | undefined) => UseVideoFileInfoResult;
66
+ /**
67
+ * Result type for useAnalytics hook
68
+ */
69
+ export interface UseAnalyticsResult {
70
+ /** Track a custom event */
71
+ trackEvent: (eventType: string, data?: Record<string, any>) => void;
72
+ /** Get all tracked events */
73
+ getEvents: () => AnalyticsEvent[];
74
+ /** Get analytics metrics (session duration, buffer time, etc.) */
75
+ getMetrics: () => Record<string, any>;
76
+ /** WebSocket connection status (for websocket/socket.io analytics) */
77
+ connected: boolean;
78
+ /** Session ID for this analytics instance */
79
+ sessionId: string;
80
+ }
81
+ /**
82
+ * React hook for analytics tracking
83
+ * Automatically handles lifecycle management and cleanup
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * const { trackEvent, getMetrics, connected } = useAnalytics({
88
+ * enabled: true,
89
+ * endpoint: "https://api.example.com/analytics",
90
+ * videoId: "video-123",
91
+ * userId: "user-456",
92
+ * webSocket: {
93
+ * type: "socket.io",
94
+ * url: "https://analytics.example.com",
95
+ * auth: { token: "your-token" }
96
+ * }
97
+ * })
98
+ *
99
+ * // Track custom events
100
+ * trackEvent("button_clicked", { buttonName: "share" })
101
+ * ```
102
+ */
103
+ export declare const useAnalytics: (config?: AnalyticsConfig) => UseAnalyticsResult;
49
104
  export {};
@@ -130,7 +130,7 @@ export interface PlayerState {
130
130
  /**
131
131
  * Player events (compatible with Mux Player and HTML5 MediaElement events)
132
132
  */
133
- export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "pictureinpictureenter" | "pictureinpictureexit" | "resize";
133
+ export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "pictureinpictureenter" | "pictureinpictureexit" | "resize" | "sourcechange";
134
134
  export interface PlayerEvent {
135
135
  type: PlayerEventType;
136
136
  data?: any;
@@ -1,13 +1,13 @@
1
- "use strict";var W=Object.create;var S=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?S(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&&S(l,n,{get:()=>t[n],enumerable:!(i=N(t,n))||i.enumerable});return l};var G=(l,t,e)=>(e=l!=null?W(j(l)):{},X(t||!l||!l.__esModule?S(e,"default",{value:l,enumerable:!0}):e,l));var r=(l,t,e)=>Y(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("hls.js"),F=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 B=K(h);class O{constructor(t){r(this,"config");r(this,"sessionId");r(this,"events",[]);r(this,"sessionStartTime");r(this,"playbackStartTime",null);r(this,"totalPlayTime",0);r(this,"totalBufferTime",0);r(this,"bufferStartTime",null);r(this,"rebufferCount",0);r(this,"seekCount",0);r(this,"webSocket",null);r(this,"socketIO",null);r(this,"wsReconnectTimeout",null);r(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 z{constructor(t,e){r(this,"container");r(this,"player");r(this,"controlsContainer");r(this,"progressContainer");r(this,"progressBar");r(this,"playButton");r(this,"skipBackwardButton");r(this,"skipForwardButton");r(this,"volumeButton");r(this,"volumeContainer");r(this,"fullscreenButton");r(this,"pipButton");r(this,"settingsButton");r(this,"volumeSlider");r(this,"progressInput");r(this,"hideControlsTimeout",null);r(this,"stickyControls",!1);r(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",s=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=`
1
+ "use strict";var j=Object.create;var q=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var K=(l,t,e)=>t in l?q(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var J=(l,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Y(t))!G.call(l,i)&&i!==e&&q(l,i,{get:()=>t[i],enumerable:!(n=Q(t,i))||n.enumerable});return l};var Z=(l,t,e)=>(e=l!=null?j(X(l)):{},J(t||!l||!l.__esModule?q(e,"default",{value:l,enumerable:!0}):e,l));var a=(l,t,e)=>K(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("hls.js"),O=require("react/jsx-runtime"),d=require("react");function tt(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,n.get?n:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const z=tt(d);class F{constructor(t){a(this,"config");a(this,"sessionId");a(this,"events",[]);a(this,"sessionStartTime");a(this,"playbackStartTime",null);a(this,"totalPlayTime",0);a(this,"totalBufferTime",0);a(this,"bufferStartTime",null);a(this,"rebufferCount",0);a(this,"seekCount",0);a(this,"webSocket",null);a(this,"socketIO",null);a(this,"wsReconnectTimeout",null);a(this,"isDestroyed",!1);var e,n;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 i=this.config.webSocket;"type"in i?i.type==="socket.io"?this.initializeSocketIO():this.initializeWebSocket():this.initializeWebSocket()}(n=this.config)!=null&&n.enabled&&this.trackEvent("session_start",this.getSessionData())}trackEvent(t,e={}){var i;if(!((i=this.config)!=null&&i.enabled))return;const n={eventType:t,timestamp:Date.now(),sessionId:this.sessionId,videoId:this.config.videoId,userId:this.config.userId,data:{...e,...this.getQoEMetrics()}};this.events.push(n),this.updateMetrics(t,e),this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&this.sendToWebSocket(n),this.socketIO&&this.socketIO.connected&&this.sendToSocketIO(n),this.config.endpoint&&this.sendEvent(n),process.env.NODE_ENV==="development"&&console.log("[Analytics]",t,n.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(n){console.error("Failed to send analytics event:",n)}}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 i=(await import("socket.io-client")).default;this.socketIO=i(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",n=>{console.error("[Analytics Socket.IO] Connection error:",n),t.onError&&t.onError(n)}),this.socketIO.on("disconnect",n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Disconnected:",n),t.onDisconnect&&t.onDisconnect(n)}),this.socketIO.on("error",n=>{console.error("[Analytics Socket.IO] Error:",n),t.onError&&t.onError(n)})}catch(n){console.error("[Analytics Socket.IO] Failed to initialize:",n)}}sendToSocketIO(t){var e;if(!(!this.socketIO||!this.socketIO.connected))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t,o=(n==null?void 0:n.eventName)||"analytics";this.socketIO.emit(o,i),process.env.NODE_ENV==="development"&&console.log(`[Analytics Socket.IO] Emitted (${o}):`,t.eventType)}catch(n){console.error("[Analytics Socket.IO] Failed to emit event:",n)}}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=n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Connected"),t.onOpen&&t.onOpen(n)},this.webSocket.onerror=n=>{console.error("[Analytics WebSocket] Error:",n),t.onError&&t.onError(n)},this.webSocket.onclose=n=>{if(process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Disconnected"),t.onClose&&t.onClose(n),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(n){console.error("[Analytics WebSocket] Failed to initialize:",n)}}sendToWebSocket(t){var e;if(!(!this.webSocket||this.webSocket.readyState!==WebSocket.OPEN))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t;this.webSocket.send(JSON.stringify(i)),process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Sent:",t.eventType)}catch(n){console.error("[Analytics WebSocket] Failed to send event:",n)}}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 D{constructor(t,e){a(this,"container");a(this,"player");a(this,"controlsContainer");a(this,"progressContainer");a(this,"progressBar");a(this,"playButton");a(this,"skipBackwardButton");a(this,"skipForwardButton");a(this,"volumeButton");a(this,"volumeContainer");a(this,"fullscreenButton");a(this,"pipButton");a(this,"settingsButton");a(this,"volumeSlider");a(this,"progressInput");a(this,"hideControlsTimeout",null);a(this,"stickyControls",!1);a(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||{},n=e.primaryColor||"#3b82f6",i=e.accentColor||"#2563eb",o=e.fontFamily||"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",s=e.controlsBackground||"linear-gradient(to top, rgba(0,0,0,0.8), transparent)",r=e.buttonHoverBg||"rgba(255, 255, 255, 0.1)",c=e.progressHeight||"6px",u=e.borderRadius||"4px",h=document.createElement("style");h.id=t,h.textContent=`
2
2
  .wontum-player-container {
3
3
  position: relative;
4
4
  background: #000;
5
5
  font-family: ${o};
6
6
  overflow: hidden;
7
- --primary-color: ${i};
8
- --accent-color: ${n};
7
+ --primary-color: ${n};
8
+ --accent-color: ${i};
9
9
  --controls-bg: ${s};
10
- --button-hover: ${a};
10
+ --button-hover: ${r};
11
11
  --progress-height: ${c};
12
12
  --border-radius: ${u};
13
13
  }
@@ -486,7 +486,7 @@
486
486
  transform: translateY(0) !important;
487
487
  pointer-events: all !important;
488
488
  }
489
- `,document.head.appendChild(p),this.container.classList.add("wontum-player-container")}createProgressBar(){const t=document.createElement("div");t.className="wontum-progress-container",t.innerHTML=`
489
+ `,document.head.appendChild(h),this.container.classList.add("wontum-player-container")}createProgressBar(){const t=document.createElement("div");t.className="wontum-progress-container",t.innerHTML=`
490
490
  <div class="wontum-progress-track"></div>
491
491
  <div class="wontum-progress-filled"></div>
492
492
  <input type="range" class="wontum-progress-input" min="0" max="100" value="0" step="0.1">
@@ -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,o=parseFloat(n.value),s=this.player.getState(),a=o/100*s.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,s=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="${s}"]`);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
- <div class="wontum-subtitle-option ${i===-1?"active":""}" data-track="-1">Off</div>
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}`}
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",n=>{const i=n.target,o=parseFloat(i.value),s=this.player.getState(),r=o/100*s.duration;this.player.seek(r)}),this.volumeSlider.addEventListener("input",n=>{const i=n.target,o=parseFloat(i.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(n){console.error("PiP error:",n)}}),this.settingsButton.addEventListener("click",()=>{const n=this.controlsContainer.querySelector(".wontum-settings-panel");n.classList.toggle("active"),n.classList.contains("active")&&(this.updateSettingsMenu(),this.updateQualityMenu(),this.updateSpeedMenu(),this.updateSubtitleMenu())});const t=this.controlsContainer.querySelectorAll(".wontum-tab");t.forEach(n=>{n.addEventListener("click",i=>{const o=i.currentTarget,s=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="${s}"]`);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,n=this.player.getState();if(n.duration>0){const o=e/n.duration*100;this.progressBar.style.width=`${o}%`,this.progressInput.value=o.toString()}const i=this.controlsContainer.querySelector(".wontum-current-time");i.textContent=this.formatTime(e)}),this.player.on("loadedmetadata",t=>{const{duration:e}=t.data,n=this.controlsContainer.querySelector(".wontum-duration");n.textContent=this.formatTime(e),t.data.qualities&&this.updateQualityMenu(t.data.qualities)}),this.player.on("volumechange",t=>{const{volume:e,muted:n}=t.data;this.volumeSlider.value=(e*100).toString(),this.volumeButton.innerHTML=n?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 n=e.findIndex(i=>i.mode==="showing");t.innerHTML=`
566
+ <div class="wontum-subtitle-option ${n===-1?"active":""}" data-track="-1">Off</div>
567
+ ${e.map((i,o)=>`
568
+ <div class="wontum-subtitle-option ${o===n?"active":""}" data-track="${o}">
569
+ ${i.label||i.language||`Track ${o+1}`}
570
570
  </div>
571
571
  `).join("")}
572
- `,t.querySelectorAll(".wontum-subtitle-option").forEach(n=>{n.addEventListener("click",o=>{const s=o.target,a=parseInt(s.dataset.track||"-1");a===-1?this.player.disableSubtitles():this.player.enableSubtitles(a),t.querySelectorAll(".wontum-subtitle-option").forEach(c=>c.classList.remove("active")),s.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}">
572
+ `,t.querySelectorAll(".wontum-subtitle-option").forEach(i=>{i.addEventListener("click",o=>{const s=o.target,r=parseInt(s.dataset.track||"-1");r===-1?this.player.disableSubtitles():this.player.enableSubtitles(r),t.querySelectorAll(".wontum-subtitle-option").forEach(c=>c.classList.remove("active")),s.classList.add("active")})})}updateSpeedMenu(){const t=this.controlsContainer.querySelector(".wontum-speed-menu"),n=this.player.getState().playbackRate||1,i=[.25,.5,.75,1,1.25,1.5,1.75,2];t.innerHTML=i.map(o=>`
573
+ <div class="wontum-speed-option ${n===o?"active":""}" data-speed="${o}">
574
574
  ${o===1?"Normal":o+"x"}
575
575
  </div>
576
- `).join(""),t.querySelectorAll(".wontum-speed-option").forEach(o=>{o.addEventListener("click",s=>{const a=s.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=`
576
+ `).join(""),t.querySelectorAll(".wontum-speed-option").forEach(o=>{o.addEventListener("click",s=>{const r=s.target,c=parseFloat(r.dataset.speed||"1");this.player.setPlaybackRate(c),t.querySelectorAll(".wontum-speed-option").forEach(u=>u.classList.remove("active")),r.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
- `;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=`
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"),n=t||this.player.getQualities();if(!n||n.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,o)=>`
584
- <div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
583
+ ${n.map((i,o)=>`
584
+ <div class="wontum-quality-option" data-quality="${o}">${i.name}</div>
585
585
  `).join("")}
586
- `,e.querySelectorAll(".wontum-quality-option").forEach(n=>{n.addEventListener("click",o=>{const s=o.target,a=parseInt(s.dataset.quality||"-1");this.player.setQuality(a),e.querySelectorAll(".wontum-quality-option").forEach(c=>c.classList.remove("active")),s.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">
586
+ `,e.querySelectorAll(".wontum-quality-option").forEach(i=>{i.addEventListener("click",o=>{const s=o.target,r=parseInt(s.dataset.quality||"-1");this.player.setQuality(r),e.querySelectorAll(".wontum-quality-option").forEach(c=>c.classList.remove("active")),s.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),n=Math.floor(t%60);return`${e}:${n.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 D{constructor(t){r(this,"config");r(this,"urlCache",new Map);r(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,s;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"||((s=a==null?void 0:a.message)==null?void 0:s.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 x{constructor(t){r(this,"container");r(this,"videoElement");r(this,"hls",null);r(this,"config");r(this,"eventListeners",new Map);r(this,"analytics");r(this,"s3Handler");r(this,"uiController");r(this,"qualities",[]);r(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 D(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new z(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:(s,a)=>{var c;n&&(s.withCredentials=!0),(c=this.config.hlsConfig)!=null&&c.xhrSetup&&this.config.hlsConfig.xhrSetup(s,a)}};this.hls=new g(o),this.hls.loadSource(i),this.hls.attachMedia(this.videoElement),this.hls.on(g.Events.MANIFEST_PARSED,(s,a)=>{const c=this.extractQualities(a.levels);this.qualities=c}),this.hls.on(g.Events.LEVEL_SWITCHED,(s,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,(s,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){r(this,"file");r(this,"videoElement",null);r(this,"audioContext",null);r(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=async()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const n=this.videoElement.videoWidth,o=this.videoElement.videoHeight,s=this.videoElement.duration,a=this.calculateAspectRatio(n,o),c=this.file.size,u=this.formatBytes(c),p=this.formatDuration(s),y=this.getFileExtension(this.file.name),w=s>0?Math.round(c*8/s/1e3):void 0,f=await this.detectFrameRate(),v=await this.detectAudioInfo(i);this.info={width:n,height:o,aspectRatio:a,size:c,sizeInBytes:c,sizeFormatted:u,duration:s,durationInSeconds:s,durationFormatted:p,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:y,bitrate:w,frameRate:f,audioChannels:v.channels,hasAudio:v.hasAudio},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,s=n/o;return Math.abs(s-16/9)<.01?"16:9":Math.abs(s-4/3)<.01?"4:3":Math.abs(s-21/9)<.01?"21:9":Math.abs(s-1)<.01?"1:1":`${n}:${o}`}async detectFrameRate(){if(this.videoElement)try{return"requestVideoFrameCallback"in this.videoElement?new Promise(t=>{let e=0,i=0;const n=10,o=(s,a)=>{if(!this.videoElement){t(void 0);return}if(e++,e===1)i=s,this.videoElement.requestVideoFrameCallback(o);else if(e<n)this.videoElement.requestVideoFrameCallback(o);else{const c=(s-i)/1e3,u=Math.round((e-1)/c);t(u)}};this.videoElement?(this.videoElement.currentTime=1,this.videoElement.play().catch(()=>t(void 0)),this.videoElement.requestVideoFrameCallback(o)):t(void 0)}):void 0}catch{return}}async detectAudioInfo(t){var e;if(!this.videoElement)return{hasAudio:!1};try{if(!(this.videoElement.mozHasAudio||(this.videoElement.webkitAudioDecodedByteCount??0)>0||(((e=this.videoElement.audioTracks)==null?void 0:e.length)??0)>0))return{hasAudio:!1};try{const n=window.AudioContext||window.webkitAudioContext;if(!n)return{hasAudio:!0};this.audioContext=new n;const o=this.audioContext.createMediaElementSource(this.videoElement),s=this.audioContext.createAnalyser();return o.connect(s),s.connect(this.audioContext.destination),{hasAudio:!0,channels:o.channelCount}}catch{return{hasAudio:!0}}}catch{return{hasAudio:!1}}}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 frameRate(){var t;return(t=this.info)==null?void 0:t.frameRate}get audioChannels(){var t;return(t=this.info)==null?void 0:t.audioChannels}get hasAudio(){var t;return((t=this.info)==null?void 0:t.hasAudio)||!1}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.pause(),this.videoElement.remove(),this.videoElement=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.info=null}}const Z=l=>{const{src:t,autoplay:e,muted:i,controls:n=!0,poster:o,preload:s,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:y,stickyControls:w,onReady:f,onPlay:v,onPause:C,onEnded:L,onTimeUpdate:T,onVolumeChange:I,onError:A,onLoadedMetadata:R,onQualityChange:P,style:U,className:V,width:b="100%",height:k="500px"}=l,E=h.useRef(null),M=h.useRef(null);return h.useEffect(()=>{if(!E.current)return;const H={src:t,container:E.current,autoplay:e,muted:i,controls:n,poster:o,preload:s,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:y,stickyControls:w},d=new x(H);return M.current=d,v&&d.on("play",v),C&&d.on("pause",C),L&&d.on("ended",L),A&&d.on("error",m=>{var q;return A((q=m.data)==null?void 0:q.error)}),R&&d.on("loadedmetadata",R),P&&d.on("qualitychange",m=>P(m.data.level)),T&&d.on("timeupdate",m=>T(m.data.currentTime)),I&&d.on("volumechange",m=>I(m.data.volume,m.data.muted)),f&&f(d),()=>{d.destroy(),M.current=null}},[t]),F.jsx("div",{ref:E,className:V,style:{width:typeof b=="number"?`${b}px`:b,height:typeof k=="number"?`${k}px`:k,...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 s=new x({...l,container:o.current});e(s);const a=()=>{n(s.getState())};return s.on("play",a),s.on("pause",a),s.on("timeupdate",a),s.on("volumechange",a),s.on("loadedmetadata",a),()=>{s.destroy()}},[l.src]),{containerRef:o,player:t,state:i}},$=B.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]),F.jsx($.Provider,{value:{player:t,state:i},children:e})},it=()=>{const l=B.useContext($);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l};exports.Analytics=O;exports.S3Handler=D;exports.UIController=z;exports.WontumFileInfo=J;exports.WontumPlayer=x;exports.WontumPlayerProvider=et;exports.WontumPlayerReact=Z;exports.useWontumPlayer=tt;exports.useWontumPlayerContext=it;
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&&this.controlsContainer.remove(),this.progressContainer&&this.progressContainer.remove()}}class ${constructor(t){a(this,"config");a(this,"urlCache",new Map);a(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 n=new URL(t);return this.config.cloudFrontDomains.some(i=>n.hostname.includes(i))}catch{return!1}}isS3Url(t){return t.includes(".s3.")||t.includes("s3.amazonaws.com")||t.startsWith("s3://")}async signCloudFrontUrl(t,e=0){var o,s;if(this.signedUrls.has(t))return t;if((o=this.config)!=null&&o.signUrl)try{const r=await this.config.signUrl(t);return this.signedUrls.add(t),r}catch(r){const c=(r==null?void 0:r.name)==="AbortError"||((s=r==null?void 0:r.message)==null?void 0:s.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:",r),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: ${(r==null?void 0:r.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 n=t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);return n?n[2]:t}async getPresignedUrl(t){var i;const e=this.extractS3Key(t),n=this.urlCache.get(e);if(n&&n.expiresAt>Date.now())return n.url;if((i=this.config)!=null&&i.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,n="us-east-1"){return`https://${t}.s3.${n}.amazonaws.com/${e}`}static parseS3Uri(t){if(!t.startsWith("s3://"))return null;const e=t.replace("s3://","").split("/"),n=e[0],i=e.slice(1).join("/");return{bucket:n,key:i}}clearCache(){this.urlCache.clear(),this.signedUrls.clear()}}class B{constructor(t){a(this,"container");a(this,"videoElement");a(this,"hls",null);a(this,"config");a(this,"eventListeners",new Map);a(this,"analytics");a(this,"s3Handler");a(this,"uiController");a(this,"qualities",[]);a(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 F(t.analytics),this.s3Handler=new $(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new D(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 n=document.createElement("track");n.kind="subtitles",n.label=e.label,n.src=e.src,n.srclang=e.srclang,e.default&&(n.default=!0),this.videoElement.appendChild(n)})}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 n=await this.s3Handler.processUrl(t);if(y.isSupported()){const i=((e=this.config.s3Config)==null?void 0:e.withCredentials)??!1,o={...this.config.hlsConfig,xhrSetup:(s,r)=>{var c;i&&(s.withCredentials=!0),(c=this.config.hlsConfig)!=null&&c.xhrSetup&&this.config.hlsConfig.xhrSetup(s,r)}};this.hls=new y(o),this.hls.loadSource(n),this.hls.attachMedia(this.videoElement),this.hls.on(y.Events.MANIFEST_PARSED,(s,r)=>{const c=this.extractQualities(r.levels);this.qualities=c}),this.hls.on(y.Events.LEVEL_SWITCHED,(s,r)=>{var u;const c=(u=this.hls)==null?void 0:u.levels[r.level];c&&(this.state.quality=`${c.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(y.Events.ERROR,(s,r)=>{r.fatal&&this.handleHlsError(r)})}else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=n;else throw new Error("HLS is not supported in this browser")}catch(n){console.error("Failed to load video source:",n),this.emit("error",{error:n})}}extractQualities(t){return t.map(e=>({height:e.height,width:e.width,bitrate:e.bitrate,name:`${e.height}p`}))}handleHlsError(t){var e,n;switch(t.type){case y.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case y.ErrorTypes.MEDIA_ERROR:console.error("Media error occurred"),(n=this.hls)==null||n.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 n=0;n<e.length;n++)e[n].mode=n===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(n=>n.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 n;(n=this.eventListeners.get(t))==null||n.delete(e)}emit(t,e){var i;const n={type:t,data:e,timestamp:Date.now()};(i=this.eventListeners.get(t))==null||i.forEach(o=>{o(n)})}async updateSource(t){this.pause(),this.state.currentTime=0,this.state.ended=!1,this.state.buffering=!1,this.hls&&(this.hls.destroy(),this.hls=null),this.config.src=t,await this.loadSource(t),this.emit("sourcechange",{src:t})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class U{constructor(t){a(this,"file");a(this,"videoElement",null);a(this,"audioContext",null);a(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"],n=t.name.toLowerCase();return e.some(i=>n.endsWith(i))}async extract(){return new Promise((t,e)=>{try{this.videoElement=document.createElement("video"),this.videoElement.preload="metadata",this.videoElement.muted=!0;const n=URL.createObjectURL(this.file);this.videoElement.onloadedmetadata=async()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const i=this.videoElement.videoWidth,o=this.videoElement.videoHeight,s=this.videoElement.duration,r=this.calculateAspectRatio(i,o),c=this.file.size,u=this.formatBytes(c),h=this.formatDuration(s),p=this.getFileExtension(this.file.name),m=s>0?Math.round(c*8/s/1e3):void 0,b=await this.detectFrameRate(),w=await this.detectAudioInfo(n);this.info={width:i,height:o,aspectRatio:r,size:c,sizeInBytes:c,sizeFormatted:u,duration:s,durationInSeconds:s,durationFormatted:h,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:p,bitrate:m,frameRate:b,audioChannels:w.channels,hasAudio:w.hasAudio},URL.revokeObjectURL(n),this.videoElement.remove(),t(this.info)}catch(i){URL.revokeObjectURL(n),e(i)}},this.videoElement.onerror=()=>{URL.revokeObjectURL(n),e(new Error(`Failed to load video file: ${this.file.name}`))},this.videoElement.src=n}catch(n){e(n)}})}calculateAspectRatio(t,e){const n=this.getGCD(t,e),i=t/n,o=e/n,s=i/o;return Math.abs(s-16/9)<.01?"16:9":Math.abs(s-4/3)<.01?"4:3":Math.abs(s-21/9)<.01?"21:9":Math.abs(s-1)<.01?"1:1":`${i}:${o}`}async detectFrameRate(){if(this.videoElement)try{return"requestVideoFrameCallback"in this.videoElement?new Promise(t=>{let e=0,n=0;const i=10,o=(s,r)=>{if(!this.videoElement){t(void 0);return}if(e++,e===1)n=s,this.videoElement.requestVideoFrameCallback(o);else if(e<i)this.videoElement.requestVideoFrameCallback(o);else{const c=(s-n)/1e3,u=Math.round((e-1)/c);t(u)}};this.videoElement?(this.videoElement.currentTime=1,this.videoElement.play().catch(()=>t(void 0)),this.videoElement.requestVideoFrameCallback(o)):t(void 0)}):void 0}catch{return}}async detectAudioInfo(t){var e;if(!this.videoElement)return{hasAudio:!1};try{if(!(this.videoElement.mozHasAudio||(this.videoElement.webkitAudioDecodedByteCount??0)>0||(((e=this.videoElement.audioTracks)==null?void 0:e.length)??0)>0))return{hasAudio:!1};try{const i=window.AudioContext||window.webkitAudioContext;if(!i)return{hasAudio:!0};this.audioContext=new i;const o=this.audioContext.createMediaElementSource(this.videoElement),s=this.audioContext.createAnalyser();return o.connect(s),s.connect(this.audioContext.destination),{hasAudio:!0,channels:o.channelCount}}catch{return{hasAudio:!0}}}catch{return{hasAudio:!1}}}getGCD(t,e){return e===0?t:this.getGCD(e,t%e)}formatBytes(t){if(t===0)return"0 Bytes";const e=1024,n=["Bytes","KB","MB","GB","TB"],i=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,i)).toFixed(2))} ${n[i]}`}formatDuration(t){if(!isFinite(t)||t<0)return"00:00";const e=Math.floor(t/3600),n=Math.floor(t%3600/60),i=Math.floor(t%60);return e>0?`${e.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}`:`${n.toString().padStart(2,"0")}:${i.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 frameRate(){var t;return(t=this.info)==null?void 0:t.frameRate}get audioChannels(){var t;return(t=this.info)==null?void 0:t.audioChannels}get hasAudio(){var t;return((t=this.info)==null?void 0:t.hasAudio)||!1}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.pause(),this.videoElement.remove(),this.videoElement=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.info=null}}const et=l=>{const{src:t,autoplay:e,muted:n,controls:i=!0,poster:o,preload:s,theme:r,s3Config:c,analytics:u,hlsConfig:h,subtitles:p,stickyControls:m,onReady:b,onPlay:w,onPause:x,onEnded:C,onTimeUpdate:L,onVolumeChange:I,onError:T,onLoadedMetadata:A,onQualityChange:R,style:W,className:H,width:P="100%",height:M="500px"}=l,v=d.useRef(null),E=d.useRef(null);return d.useEffect(()=>{if(!v.current)return;if(v.current){const f=v.current.querySelectorAll(".wontum-player-video"),S=v.current.querySelectorAll(".wontum-controls"),_=v.current.querySelectorAll(".wontum-progress-container");f.forEach(k=>k.remove()),S.forEach(k=>k.remove()),_.forEach(k=>k.remove())}const N={src:t,container:v.current,autoplay:e,muted:n,controls:i,poster:o,preload:s,theme:r,s3Config:c,analytics:u,hlsConfig:h,subtitles:p,stickyControls:m},g=new B(N);return E.current=g,w&&g.on("play",w),x&&g.on("pause",x),C&&g.on("ended",C),T&&g.on("error",f=>{var S;return T((S=f.data)==null?void 0:S.error)}),A&&g.on("loadedmetadata",A),R&&g.on("qualitychange",f=>R(f.data.level)),L&&g.on("timeupdate",f=>L(f.data.currentTime)),I&&g.on("volumechange",f=>I(f.data.volume,f.data.muted)),b&&b(g),()=>{E.current&&(E.current.destroy(),E.current=null)}},[t,e,n,i,o,s,r,c,u,h,p,m,w,x,C,T,A,R,L,I,b]),O.jsx("div",{ref:v,className:H,style:{width:typeof P=="number"?`${P}px`:P,height:typeof M=="number"?`${M}px`:M,...W}})},nt=l=>{const[t,e]=d.useState(null),[n,i]=d.useState(null),o=d.useRef(null);return d.useEffect(()=>{if(!o.current)return;const s=new B({...l,container:o.current});e(s);const r=()=>{i(s.getState())};return s.on("play",r),s.on("pause",r),s.on("timeupdate",r),s.on("volumechange",r),s.on("loadedmetadata",r),()=>{s.destroy()}},[l.src]),{containerRef:o,player:t,state:n}},V=z.createContext({player:null,state:null}),it=l=>{const{player:t,children:e}=l,[n,i]=d.useState(t.getState());return d.useEffect(()=>{const o=()=>{i(t.getState())};return t.on("play",o),t.on("pause",o),t.on("timeupdate",o),t.on("volumechange",o),t.on("loadedmetadata",o),()=>{}},[t]),O.jsx(V.Provider,{value:{player:t,state:n},children:e})},ot=()=>{const l=z.useContext(V);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l},st=l=>{const[t,e]=d.useState(null),[n,i]=d.useState(!1),[o,s]=d.useState(null),r=d.useRef(null),c=d.useCallback(async()=>{if(!l){e(null),s(null),i(!1);return}i(!0),s(null);try{r.current&&(r.current.destroy(),r.current=null);const u=new U(l);r.current=u;const h=await u.extract();e(h),s(null)}catch(u){const h=u instanceof Error?u.message:"Failed to extract video information";s(h),e(null)}finally{i(!1)}},[l]);return d.useEffect(()=>(c(),()=>{r.current&&(r.current.destroy(),r.current=null)}),[c]),{info:t,loading:n,error:o,refetch:c}},rt=l=>{const t=d.useRef(null),[e,n]=d.useState(!1),[i,o]=d.useState("");d.useEffect(()=>{const u=new F(l);if(t.current=u,o(u.getMetrics().sessionId),l!=null&&l.webSocket){const h=setInterval(()=>{if(!t.current){n(!1);return}const p=l.webSocket;if(p&&"type"in p&&p.type==="websocket"){const m=t.current.webSocket;n((m==null?void 0:m.readyState)===WebSocket.OPEN)}else if(p&&"type"in p&&p.type==="socket.io"){const m=t.current.socketIO;n((m==null?void 0:m.connected)??!1)}else if(p){const m=t.current.webSocket;n((m==null?void 0:m.readyState)===WebSocket.OPEN)}},1e3);return()=>{clearInterval(h),t.current&&(t.current.destroy(),t.current=null)}}return()=>{t.current&&(t.current.destroy(),t.current=null)}},[l]);const s=d.useCallback((u,h)=>{var p;(p=t.current)==null||p.trackEvent(u,h)},[]),r=d.useCallback(()=>{var u;return((u=t.current)==null?void 0:u.getEvents())??[]},[]),c=d.useCallback(()=>{var u;return((u=t.current)==null?void 0:u.getMetrics())??{}},[]);return{trackEvent:s,getEvents:r,getMetrics:c,connected:e,sessionId:i}};exports.Analytics=F;exports.S3Handler=$;exports.UIController=D;exports.WontumFileInfo=U;exports.WontumPlayer=B;exports.WontumPlayerProvider=it;exports.WontumPlayerReact=et;exports.useAnalytics=rt;exports.useVideoFileInfo=st;exports.useWontumPlayer=nt;exports.useWontumPlayerContext=ot;