@obipascal/player 1.0.11 → 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 +66 -1
- package/dist/src/player.d.ts +6 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/wontum-player.cjs.js +2 -2
- package/dist/wontum-player.esm.js +120 -86
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1170,6 +1170,69 @@ type PlayerEventType =
|
|
|
1170
1170
|
/>
|
|
1171
1171
|
```
|
|
1172
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
|
+
|
|
1173
1236
|
#### useWontumPlayer Hook
|
|
1174
1237
|
|
|
1175
1238
|
```tsx
|
|
@@ -1684,10 +1747,11 @@ For detailed API documentation including all methods, events, types, and configu
|
|
|
1684
1747
|
- **Playback Rate:** `setPlaybackRate(rate)`
|
|
1685
1748
|
- **Fullscreen:** `enterFullscreen()`, `exitFullscreen()`
|
|
1686
1749
|
- **Picture-in-Picture:** `enterPictureInPicture()`, `exitPictureInPicture()`, `togglePictureInPicture()`
|
|
1750
|
+
- **Source Management:** `updateSource(src)` - _Efficiently change video source without full reinitialization_
|
|
1687
1751
|
- **State:** `getState()`, `getCurrentTime()`, `getDuration()`
|
|
1688
1752
|
- **Lifecycle:** `destroy()`
|
|
1689
1753
|
|
|
1690
|
-
**Events (
|
|
1754
|
+
**Events (26 total):**
|
|
1691
1755
|
|
|
1692
1756
|
- **Playback:** `play`, `pause`, `ended`, `timeupdate`, `durationchange`
|
|
1693
1757
|
- **Loading:** `loadstart`, `loadedmetadata`, `loadeddata`, `canplay`, `canplaythrough`
|
|
@@ -1695,6 +1759,7 @@ For detailed API documentation including all methods, events, types, and configu
|
|
|
1695
1759
|
- **Seeking:** `seeking`, `seeked`
|
|
1696
1760
|
- **Volume:** `volumechange`
|
|
1697
1761
|
- **Quality:** `qualitychange`, `renditionchange`
|
|
1762
|
+
- **Source:** `sourcechange` - _Fires when video source is changed via updateSource()_
|
|
1698
1763
|
- **Errors:** `error`
|
|
1699
1764
|
- **Playback Rate:** `ratechange`
|
|
1700
1765
|
- **Fullscreen:** `fullscreenchange`
|
package/dist/src/player.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
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;
|
|
@@ -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){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 C{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 x(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 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(f.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 f(o),this.hls.loadSource(n),this.hls.attachMedia(this.videoElement),this.hls.on(f.Events.MANIFEST_PARSED,(s,r)=>{const c=this.extractQualities(r.levels);this.qualities=c}),this.hls.on(f.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(f.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 f.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case f.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)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class ${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,w=await this.detectFrameRate(),y=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:w,audioChannels:y.channels,hasAudio:y.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 Z=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:w,onPlay:y,onPause:L,onEnded:I,onTimeUpdate:T,onVolumeChange:R,onError:A,onLoadedMetadata:P,onQualityChange:M,style:V,className:W,width:b="100%",height:k="500px"}=l,E=d.useRef(null),q=d.useRef(null);return d.useEffect(()=>{if(!E.current)return;const H={src:t,container:E.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 C(H);return q.current=g,y&&g.on("play",y),L&&g.on("pause",L),I&&g.on("ended",I),A&&g.on("error",v=>{var F;return A((F=v.data)==null?void 0:F.error)}),P&&g.on("loadedmetadata",P),M&&g.on("qualitychange",v=>M(v.data.level)),T&&g.on("timeupdate",v=>T(v.data.currentTime)),R&&g.on("volumechange",v=>R(v.data.volume,v.data.muted)),w&&w(g),()=>{g.destroy(),q.current=null}},[t]),B.jsx("div",{ref:E,className:W,style:{width:typeof b=="number"?`${b}px`:b,height:typeof k=="number"?`${k}px`:k,...V}})},tt=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 C({...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}},U=O.createContext({player:null,state:null}),et=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]),B.jsx(U.Provider,{value:{player:t,state:n},children:e})},nt=()=>{const l=O.useContext(U);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l},it=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 $(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}},ot=l=>{const t=d.useRef(null),[e,n]=d.useState(!1),[i,o]=d.useState("");d.useEffect(()=>{const u=new x(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=x;exports.S3Handler=D;exports.UIController=z;exports.WontumFileInfo=$;exports.WontumPlayer=C;exports.WontumPlayerProvider=et;exports.WontumPlayerReact=Z;exports.useAnalytics=ot;exports.useVideoFileInfo=it;exports.useWontumPlayer=tt;exports.useWontumPlayerContext=nt;
|
|
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;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var a = (u, t, e) =>
|
|
4
|
-
import
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
7
|
-
import { useRef as
|
|
8
|
-
class
|
|
1
|
+
var _ = Object.defineProperty;
|
|
2
|
+
var j = (u, t, e) => t in u ? _(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
|
+
var a = (u, t, e) => j(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import y from "hls.js";
|
|
5
|
+
import { jsx as $ } from "react/jsx-runtime";
|
|
6
|
+
import * as z from "react";
|
|
7
|
+
import { useRef as E, useEffect as S, useState as v, useCallback as L } from "react";
|
|
8
|
+
class O {
|
|
9
9
|
constructor(t) {
|
|
10
10
|
a(this, "config");
|
|
11
11
|
a(this, "sessionId");
|
|
@@ -193,7 +193,7 @@ class z {
|
|
|
193
193
|
this.isDestroyed = !0, (t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.wsReconnectTimeout && (clearTimeout(this.wsReconnectTimeout), this.wsReconnectTimeout = null), this.webSocket && (this.webSocket.close(), this.webSocket = null), this.socketIO && (this.socketIO.removeAllListeners(), this.socketIO.disconnect(), this.socketIO = null), this.events = [];
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
class
|
|
196
|
+
class Q {
|
|
197
197
|
constructor(t, e) {
|
|
198
198
|
a(this, "container");
|
|
199
199
|
a(this, "player");
|
|
@@ -1004,10 +1004,10 @@ class _ {
|
|
|
1004
1004
|
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>';
|
|
1005
1005
|
}
|
|
1006
1006
|
destroy() {
|
|
1007
|
-
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
1007
|
+
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer && this.controlsContainer.remove(), this.progressContainer && this.progressContainer.remove();
|
|
1008
1008
|
}
|
|
1009
1009
|
}
|
|
1010
|
-
class
|
|
1010
|
+
class Y {
|
|
1011
1011
|
constructor(t) {
|
|
1012
1012
|
a(this, "config");
|
|
1013
1013
|
a(this, "urlCache", /* @__PURE__ */ new Map());
|
|
@@ -1116,7 +1116,7 @@ class j {
|
|
|
1116
1116
|
this.urlCache.clear(), this.signedUrls.clear();
|
|
1117
1117
|
}
|
|
1118
1118
|
}
|
|
1119
|
-
class
|
|
1119
|
+
class D {
|
|
1120
1120
|
constructor(t) {
|
|
1121
1121
|
a(this, "container");
|
|
1122
1122
|
a(this, "videoElement");
|
|
@@ -1143,7 +1143,7 @@ class O {
|
|
|
1143
1143
|
});
|
|
1144
1144
|
if (this.config = t, this.container = typeof t.container == "string" ? document.querySelector(t.container) : t.container, !this.container)
|
|
1145
1145
|
throw new Error("Container element not found");
|
|
1146
|
-
this.analytics = new
|
|
1146
|
+
this.analytics = new O(t.analytics), this.s3Handler = new Y(t.s3Config), this.videoElement = this.createVideoElement(), this.container.appendChild(this.videoElement), this.uiController = new Q(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);
|
|
1147
1147
|
}
|
|
1148
1148
|
addSubtitleTracks(t) {
|
|
1149
1149
|
t.forEach((e) => {
|
|
@@ -1212,7 +1212,7 @@ class O {
|
|
|
1212
1212
|
var e;
|
|
1213
1213
|
try {
|
|
1214
1214
|
const n = await this.s3Handler.processUrl(t);
|
|
1215
|
-
if (
|
|
1215
|
+
if (y.isSupported()) {
|
|
1216
1216
|
const i = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
|
|
1217
1217
|
...this.config.hlsConfig,
|
|
1218
1218
|
xhrSetup: (s, r) => {
|
|
@@ -1220,14 +1220,14 @@ class O {
|
|
|
1220
1220
|
i && (s.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(s, r);
|
|
1221
1221
|
}
|
|
1222
1222
|
};
|
|
1223
|
-
this.hls = new
|
|
1223
|
+
this.hls = new y(o), this.hls.loadSource(n), this.hls.attachMedia(this.videoElement), this.hls.on(y.Events.MANIFEST_PARSED, (s, r) => {
|
|
1224
1224
|
const l = this.extractQualities(r.levels);
|
|
1225
1225
|
this.qualities = l;
|
|
1226
|
-
}), this.hls.on(
|
|
1226
|
+
}), this.hls.on(y.Events.LEVEL_SWITCHED, (s, r) => {
|
|
1227
1227
|
var c;
|
|
1228
1228
|
const l = (c = this.hls) == null ? void 0 : c.levels[r.level];
|
|
1229
1229
|
l && (this.state.quality = `${l.height}p`, this.emit("qualitychange", { quality: this.state.quality }));
|
|
1230
|
-
}), this.hls.on(
|
|
1230
|
+
}), this.hls.on(y.Events.ERROR, (s, r) => {
|
|
1231
1231
|
r.fatal && this.handleHlsError(r);
|
|
1232
1232
|
});
|
|
1233
1233
|
} else if (this.videoElement.canPlayType("application/vnd.apple.mpegurl"))
|
|
@@ -1249,10 +1249,10 @@ class O {
|
|
|
1249
1249
|
handleHlsError(t) {
|
|
1250
1250
|
var e, n;
|
|
1251
1251
|
switch (t.type) {
|
|
1252
|
-
case
|
|
1252
|
+
case y.ErrorTypes.NETWORK_ERROR:
|
|
1253
1253
|
console.error("Network error occurred"), (e = this.hls) == null || e.startLoad();
|
|
1254
1254
|
break;
|
|
1255
|
-
case
|
|
1255
|
+
case y.ErrorTypes.MEDIA_ERROR:
|
|
1256
1256
|
console.error("Media error occurred"), (n = this.hls) == null || n.recoverMediaError();
|
|
1257
1257
|
break;
|
|
1258
1258
|
default:
|
|
@@ -1391,11 +1391,19 @@ class O {
|
|
|
1391
1391
|
o(n);
|
|
1392
1392
|
});
|
|
1393
1393
|
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Update video source without recreating the entire player
|
|
1396
|
+
* This is more efficient than destroying and recreating the player
|
|
1397
|
+
* @param src - New video source URL
|
|
1398
|
+
*/
|
|
1399
|
+
async updateSource(t) {
|
|
1400
|
+
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 });
|
|
1401
|
+
}
|
|
1394
1402
|
destroy() {
|
|
1395
1403
|
this.hls && (this.hls.destroy(), this.hls = null), this.uiController.destroy(), this.videoElement.remove(), this.eventListeners.clear(), this.analytics.destroy();
|
|
1396
1404
|
}
|
|
1397
1405
|
}
|
|
1398
|
-
class
|
|
1406
|
+
class X {
|
|
1399
1407
|
constructor(t) {
|
|
1400
1408
|
a(this, "file");
|
|
1401
1409
|
a(this, "videoElement", null);
|
|
@@ -1428,7 +1436,7 @@ class Q {
|
|
|
1428
1436
|
e(new Error("Video element not initialized"));
|
|
1429
1437
|
return;
|
|
1430
1438
|
}
|
|
1431
|
-
const i = this.videoElement.videoWidth, o = this.videoElement.videoHeight, s = this.videoElement.duration, r = this.calculateAspectRatio(i, o), l = this.file.size, c = this.formatBytes(l), d = this.formatDuration(s), m = this.getFileExtension(this.file.name), h = s > 0 ? Math.round(l * 8 / s / 1e3) : void 0,
|
|
1439
|
+
const i = this.videoElement.videoWidth, o = this.videoElement.videoHeight, s = this.videoElement.duration, r = this.calculateAspectRatio(i, o), l = this.file.size, c = this.formatBytes(l), d = this.formatDuration(s), m = this.getFileExtension(this.file.name), h = s > 0 ? Math.round(l * 8 / s / 1e3) : void 0, b = await this.detectFrameRate(), w = await this.detectAudioInfo(n);
|
|
1432
1440
|
this.info = {
|
|
1433
1441
|
width: i,
|
|
1434
1442
|
height: o,
|
|
@@ -1445,9 +1453,9 @@ class Q {
|
|
|
1445
1453
|
fileName: this.file.name,
|
|
1446
1454
|
fileExtension: m,
|
|
1447
1455
|
bitrate: h,
|
|
1448
|
-
frameRate:
|
|
1449
|
-
audioChannels:
|
|
1450
|
-
hasAudio:
|
|
1456
|
+
frameRate: b,
|
|
1457
|
+
audioChannels: w.channels,
|
|
1458
|
+
hasAudio: w.hasAudio
|
|
1451
1459
|
}, URL.revokeObjectURL(n), this.videoElement.remove(), t(this.info);
|
|
1452
1460
|
} catch (i) {
|
|
1453
1461
|
URL.revokeObjectURL(n), e(i);
|
|
@@ -1630,7 +1638,7 @@ class Q {
|
|
|
1630
1638
|
}), this.audioContext = null), this.info = null;
|
|
1631
1639
|
}
|
|
1632
1640
|
}
|
|
1633
|
-
const
|
|
1641
|
+
const tt = (u) => {
|
|
1634
1642
|
const {
|
|
1635
1643
|
src: t,
|
|
1636
1644
|
autoplay: e,
|
|
@@ -1644,25 +1652,29 @@ const J = (u) => {
|
|
|
1644
1652
|
hlsConfig: d,
|
|
1645
1653
|
subtitles: m,
|
|
1646
1654
|
stickyControls: h,
|
|
1647
|
-
onReady:
|
|
1648
|
-
onPlay:
|
|
1649
|
-
onPause:
|
|
1650
|
-
onEnded:
|
|
1651
|
-
onTimeUpdate:
|
|
1652
|
-
onVolumeChange:
|
|
1653
|
-
onError:
|
|
1654
|
-
onLoadedMetadata:
|
|
1655
|
+
onReady: b,
|
|
1656
|
+
onPlay: w,
|
|
1657
|
+
onPause: I,
|
|
1658
|
+
onEnded: T,
|
|
1659
|
+
onTimeUpdate: A,
|
|
1660
|
+
onVolumeChange: R,
|
|
1661
|
+
onError: M,
|
|
1662
|
+
onLoadedMetadata: q,
|
|
1655
1663
|
onQualityChange: F,
|
|
1656
|
-
style:
|
|
1657
|
-
className:
|
|
1658
|
-
width:
|
|
1659
|
-
height:
|
|
1660
|
-
} = u,
|
|
1661
|
-
return
|
|
1662
|
-
if (!
|
|
1663
|
-
|
|
1664
|
+
style: V,
|
|
1665
|
+
className: H,
|
|
1666
|
+
width: P = "100%",
|
|
1667
|
+
height: B = "500px"
|
|
1668
|
+
} = u, f = E(null), x = E(null);
|
|
1669
|
+
return S(() => {
|
|
1670
|
+
if (!f.current) return;
|
|
1671
|
+
if (f.current) {
|
|
1672
|
+
const g = f.current.querySelectorAll(".wontum-player-video"), C = f.current.querySelectorAll(".wontum-controls"), W = f.current.querySelectorAll(".wontum-progress-container");
|
|
1673
|
+
g.forEach((k) => k.remove()), C.forEach((k) => k.remove()), W.forEach((k) => k.remove());
|
|
1674
|
+
}
|
|
1675
|
+
const N = {
|
|
1664
1676
|
src: t,
|
|
1665
|
-
container:
|
|
1677
|
+
container: f.current,
|
|
1666
1678
|
autoplay: e,
|
|
1667
1679
|
muted: n,
|
|
1668
1680
|
controls: i,
|
|
@@ -1674,30 +1686,52 @@ const J = (u) => {
|
|
|
1674
1686
|
hlsConfig: d,
|
|
1675
1687
|
subtitles: m,
|
|
1676
1688
|
stickyControls: h
|
|
1677
|
-
}, p = new
|
|
1678
|
-
return
|
|
1679
|
-
var
|
|
1680
|
-
return
|
|
1681
|
-
}),
|
|
1682
|
-
|
|
1689
|
+
}, p = new D(N);
|
|
1690
|
+
return x.current = p, w && p.on("play", w), I && p.on("pause", I), T && p.on("ended", T), M && p.on("error", (g) => {
|
|
1691
|
+
var C;
|
|
1692
|
+
return M((C = g.data) == null ? void 0 : C.error);
|
|
1693
|
+
}), q && p.on("loadedmetadata", q), F && p.on("qualitychange", (g) => F(g.data.level)), A && p.on("timeupdate", (g) => A(g.data.currentTime)), R && p.on("volumechange", (g) => R(g.data.volume, g.data.muted)), b && b(p), () => {
|
|
1694
|
+
x.current && (x.current.destroy(), x.current = null);
|
|
1683
1695
|
};
|
|
1684
|
-
}, [
|
|
1696
|
+
}, [
|
|
1697
|
+
t,
|
|
1698
|
+
e,
|
|
1699
|
+
n,
|
|
1700
|
+
i,
|
|
1701
|
+
o,
|
|
1702
|
+
s,
|
|
1703
|
+
r,
|
|
1704
|
+
l,
|
|
1705
|
+
c,
|
|
1706
|
+
d,
|
|
1707
|
+
m,
|
|
1708
|
+
h,
|
|
1709
|
+
w,
|
|
1710
|
+
I,
|
|
1711
|
+
T,
|
|
1712
|
+
M,
|
|
1713
|
+
q,
|
|
1714
|
+
F,
|
|
1715
|
+
A,
|
|
1716
|
+
R,
|
|
1717
|
+
b
|
|
1718
|
+
]), /* @__PURE__ */ $(
|
|
1685
1719
|
"div",
|
|
1686
1720
|
{
|
|
1687
|
-
ref:
|
|
1688
|
-
className:
|
|
1721
|
+
ref: f,
|
|
1722
|
+
className: H,
|
|
1689
1723
|
style: {
|
|
1690
|
-
width: typeof
|
|
1691
|
-
height: typeof
|
|
1692
|
-
...
|
|
1724
|
+
width: typeof P == "number" ? `${P}px` : P,
|
|
1725
|
+
height: typeof B == "number" ? `${B}px` : B,
|
|
1726
|
+
...V
|
|
1693
1727
|
}
|
|
1694
1728
|
}
|
|
1695
1729
|
);
|
|
1696
|
-
},
|
|
1697
|
-
const [t, e] = v(null), [n, i] = v(null), o =
|
|
1698
|
-
return
|
|
1730
|
+
}, et = (u) => {
|
|
1731
|
+
const [t, e] = v(null), [n, i] = v(null), o = E(null);
|
|
1732
|
+
return S(() => {
|
|
1699
1733
|
if (!o.current) return;
|
|
1700
|
-
const s = new
|
|
1734
|
+
const s = new D({
|
|
1701
1735
|
...u,
|
|
1702
1736
|
container: o.current
|
|
1703
1737
|
});
|
|
@@ -1713,25 +1747,25 @@ const J = (u) => {
|
|
|
1713
1747
|
player: t,
|
|
1714
1748
|
state: n
|
|
1715
1749
|
};
|
|
1716
|
-
},
|
|
1750
|
+
}, U = z.createContext({
|
|
1717
1751
|
player: null,
|
|
1718
1752
|
state: null
|
|
1719
|
-
}),
|
|
1753
|
+
}), nt = (u) => {
|
|
1720
1754
|
const { player: t, children: e } = u, [n, i] = v(t.getState());
|
|
1721
|
-
return
|
|
1755
|
+
return S(() => {
|
|
1722
1756
|
const o = () => {
|
|
1723
1757
|
i(t.getState());
|
|
1724
1758
|
};
|
|
1725
1759
|
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1726
1760
|
};
|
|
1727
|
-
}, [t]), /* @__PURE__ */
|
|
1728
|
-
},
|
|
1729
|
-
const u =
|
|
1761
|
+
}, [t]), /* @__PURE__ */ $(U.Provider, { value: { player: t, state: n }, children: e });
|
|
1762
|
+
}, it = () => {
|
|
1763
|
+
const u = z.useContext(U);
|
|
1730
1764
|
if (!u.player)
|
|
1731
1765
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1732
1766
|
return u;
|
|
1733
|
-
},
|
|
1734
|
-
const [t, e] = v(null), [n, i] = v(!1), [o, s] = v(null), r =
|
|
1767
|
+
}, ot = (u) => {
|
|
1768
|
+
const [t, e] = v(null), [n, i] = v(!1), [o, s] = v(null), r = E(null), l = L(async () => {
|
|
1735
1769
|
if (!u) {
|
|
1736
1770
|
e(null), s(null), i(!1);
|
|
1737
1771
|
return;
|
|
@@ -1739,7 +1773,7 @@ const J = (u) => {
|
|
|
1739
1773
|
i(!0), s(null);
|
|
1740
1774
|
try {
|
|
1741
1775
|
r.current && (r.current.destroy(), r.current = null);
|
|
1742
|
-
const c = new
|
|
1776
|
+
const c = new X(u);
|
|
1743
1777
|
r.current = c;
|
|
1744
1778
|
const d = await c.extract();
|
|
1745
1779
|
e(d), s(null);
|
|
@@ -1750,13 +1784,13 @@ const J = (u) => {
|
|
|
1750
1784
|
i(!1);
|
|
1751
1785
|
}
|
|
1752
1786
|
}, [u]);
|
|
1753
|
-
return
|
|
1787
|
+
return S(() => (l(), () => {
|
|
1754
1788
|
r.current && (r.current.destroy(), r.current = null);
|
|
1755
1789
|
}), [l]), { info: t, loading: n, error: o, refetch: l };
|
|
1756
|
-
},
|
|
1757
|
-
const t =
|
|
1758
|
-
|
|
1759
|
-
const c = new
|
|
1790
|
+
}, st = (u) => {
|
|
1791
|
+
const t = E(null), [e, n] = v(!1), [i, o] = v("");
|
|
1792
|
+
S(() => {
|
|
1793
|
+
const c = new O(u);
|
|
1760
1794
|
if (t.current = c, o(c.getMetrics().sessionId), u != null && u.webSocket) {
|
|
1761
1795
|
const d = setInterval(() => {
|
|
1762
1796
|
if (!t.current) {
|
|
@@ -1783,13 +1817,13 @@ const J = (u) => {
|
|
|
1783
1817
|
t.current && (t.current.destroy(), t.current = null);
|
|
1784
1818
|
};
|
|
1785
1819
|
}, [u]);
|
|
1786
|
-
const s =
|
|
1820
|
+
const s = L((c, d) => {
|
|
1787
1821
|
var m;
|
|
1788
1822
|
(m = t.current) == null || m.trackEvent(c, d);
|
|
1789
|
-
}, []), r =
|
|
1823
|
+
}, []), r = L(() => {
|
|
1790
1824
|
var c;
|
|
1791
1825
|
return ((c = t.current) == null ? void 0 : c.getEvents()) ?? [];
|
|
1792
|
-
}, []), l =
|
|
1826
|
+
}, []), l = L(() => {
|
|
1793
1827
|
var c;
|
|
1794
1828
|
return ((c = t.current) == null ? void 0 : c.getMetrics()) ?? {};
|
|
1795
1829
|
}, []);
|
|
@@ -1802,15 +1836,15 @@ const J = (u) => {
|
|
|
1802
1836
|
};
|
|
1803
1837
|
};
|
|
1804
1838
|
export {
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1839
|
+
O as Analytics,
|
|
1840
|
+
Y as S3Handler,
|
|
1841
|
+
Q as UIController,
|
|
1842
|
+
X as WontumFileInfo,
|
|
1843
|
+
D as WontumPlayer,
|
|
1844
|
+
nt as WontumPlayerProvider,
|
|
1845
|
+
tt as WontumPlayerReact,
|
|
1846
|
+
st as useAnalytics,
|
|
1847
|
+
ot as useVideoFileInfo,
|
|
1848
|
+
et as useWontumPlayer,
|
|
1849
|
+
it as useWontumPlayerContext
|
|
1816
1850
|
};
|
package/package.json
CHANGED