@obipascal/player 1.0.4 → 1.0.5
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 +69 -0
- package/dist/wontum-player.cjs.js +9 -9
- package/dist/wontum-player.esm.js +73 -68
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,6 +215,75 @@ function ControlPanel() {
|
|
|
215
215
|
}
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
+
### Using with Apollo Client / GraphQL
|
|
219
|
+
|
|
220
|
+
If you're using Apollo Client or other GraphQL clients for URL signing, use `useQuery` instead of `useLazyQuery` to avoid abort errors:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import React from "react"
|
|
224
|
+
import { S3Config, WontumPlayerReact } from "@obipascal/player"
|
|
225
|
+
import { useQuery } from "@apollo/client"
|
|
226
|
+
import { GET_MEDIA_SIGNED_URL } from "@/graphql/queries/media.queries"
|
|
227
|
+
|
|
228
|
+
interface VideoPlayerProps {
|
|
229
|
+
videoUrl: string
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function VideoPlayer({ videoUrl }: VideoPlayerProps) {
|
|
233
|
+
// ✅ Use useQuery with skip option instead of useLazyQuery
|
|
234
|
+
const { refetch } = useQuery(GET_MEDIA_SIGNED_URL, {
|
|
235
|
+
skip: true, // Don't run on mount
|
|
236
|
+
fetchPolicy: "no-cache", // Always fetch fresh signed URLs
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
const url = new URL(videoUrl)
|
|
240
|
+
|
|
241
|
+
const s3config: S3Config = {
|
|
242
|
+
cloudFrontDomains: [url.hostname],
|
|
243
|
+
signUrl: async (resourceUrl: string) => {
|
|
244
|
+
try {
|
|
245
|
+
const { data } = await refetch({
|
|
246
|
+
signingMediaInput: {
|
|
247
|
+
resourceUrl,
|
|
248
|
+
isPublic: false,
|
|
249
|
+
type: "COOKIES",
|
|
250
|
+
},
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
console.log("Signed URL result:", data)
|
|
254
|
+
// For cookie-based signing, return the original URL
|
|
255
|
+
// The server sets cookies in the response
|
|
256
|
+
return resourceUrl
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error("Failed to sign URL:", error)
|
|
259
|
+
throw error
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<WontumPlayerReact
|
|
266
|
+
src={videoUrl}
|
|
267
|
+
width="100%"
|
|
268
|
+
height="500px"
|
|
269
|
+
autoplay={false}
|
|
270
|
+
controls
|
|
271
|
+
s3Config={s3config}
|
|
272
|
+
theme={{
|
|
273
|
+
primaryColor: "#3b82f6",
|
|
274
|
+
accentColor: "#60a5fa",
|
|
275
|
+
}}
|
|
276
|
+
/>
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Why `useQuery` with `skip` instead of `useLazyQuery`?**
|
|
282
|
+
|
|
283
|
+
- `useLazyQuery` creates a new AbortController on each call, which can be aborted during React lifecycle
|
|
284
|
+
- `useQuery` with `skip: true` and `refetch` persists across renders, avoiding abort issues
|
|
285
|
+
- The SDK includes retry logic for AbortErrors, but using `useQuery` prevents them entirely
|
|
286
|
+
|
|
218
287
|
## 🔒 CloudFront & S3 Integration
|
|
219
288
|
|
|
220
289
|
This player supports **three video hosting scenarios**. Choose the one that fits your needs:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var V=Object.defineProperty;var W=(
|
|
1
|
+
"use strict";var V=Object.defineProperty;var W=(l,t,e)=>t in l?V(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var o=(l,t,e)=>W(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("hls.js"),I=require("react/jsx-runtime"),h=require("react");function _(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 B=_(h);class P{constructor(t){o(this,"config");o(this,"sessionId");o(this,"events",[]);o(this,"sessionStartTime");o(this,"playbackStartTime",null);o(this,"totalPlayTime",0);o(this,"totalBufferTime",0);o(this,"bufferStartTime",null);o(this,"rebufferCount",0);o(this,"seekCount",0);var e;this.config=t,this.sessionId=(t==null?void 0:t.sessionId)||this.generateSessionId(),this.sessionStartTime=Date.now(),(e=this.config)!=null&&e.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.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)}`}getEvents(){return[...this.events]}getMetrics(){return{sessionId:this.sessionId,...this.getQoEMetrics(),eventCount:this.events.length}}destroy(){var t;(t=this.config)!=null&&t.enabled&&this.trackEvent("session_end",this.getSessionData()),this.events=[]}}class ${constructor(t,e){o(this,"container");o(this,"player");o(this,"controlsContainer");o(this,"progressContainer");o(this,"progressBar");o(this,"playButton");o(this,"skipBackwardButton");o(this,"skipForwardButton");o(this,"volumeButton");o(this,"fullscreenButton");o(this,"settingsButton");o(this,"volumeSlider");o(this,"progressInput");o(this,"hideControlsTimeout",null);o(this,"stickyControls",!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.fullscreenButton=this.controlsContainer.querySelector(".wontum-fullscreen-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",s=e.fontFamily||"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",a=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",g=document.createElement("style");g.id=t,g.textContent=`
|
|
2
2
|
.wontum-player-container {
|
|
3
3
|
position: relative;
|
|
4
4
|
background: #000;
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
--primary-color: ${n};
|
|
8
8
|
--accent-color: ${i};
|
|
9
|
-
--controls-bg: ${
|
|
10
|
-
--button-hover: ${
|
|
9
|
+
--controls-bg: ${a};
|
|
10
|
+
--button-hover: ${r};
|
|
11
11
|
--progress-height: ${c};
|
|
12
|
-
--border-radius: ${
|
|
12
|
+
--border-radius: ${u};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.wontum-player-video {
|
|
@@ -542,18 +542,18 @@
|
|
|
542
542
|
<div class="wontum-loading" style="display: none;">
|
|
543
543
|
<div class="wontum-spinner"></div>
|
|
544
544
|
</div>
|
|
545
|
-
`,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,s=parseFloat(i.value),
|
|
545
|
+
`,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,s=parseFloat(i.value),a=this.player.getState(),r=s/100*a.duration;this.player.seek(r)}),this.volumeSlider.addEventListener("input",n=>{const i=n.target,s=parseFloat(i.value)/100;this.player.setVolume(s)}),this.volumeButton.addEventListener("click",()=>{this.player.getState().muted?this.player.unmute():this.player.mute()}),this.fullscreenButton.addEventListener("click",()=>{this.player.getState().fullscreen?this.player.exitFullscreen():this.player.enterFullscreen()}),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 s=i.currentTarget,a=s.getAttribute("data-tab");t.forEach(u=>u.classList.remove("active")),s.classList.add("active"),this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach(u=>u.classList.remove("active"));const c=this.controlsContainer.querySelector(`[data-panel="${a}"]`);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 s=e/n.duration*100;this.progressBar.style.width=`${s}%`,this.progressInput.value=s.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=`
|
|
546
546
|
<div class="wontum-subtitle-option ${n===-1?"active":""}" data-track="-1">Off</div>
|
|
547
547
|
${e.map((i,s)=>`
|
|
548
548
|
<div class="wontum-subtitle-option ${s===n?"active":""}" data-track="${s}">
|
|
549
549
|
${i.label||i.language||`Track ${s+1}`}
|
|
550
550
|
</div>
|
|
551
551
|
`).join("")}
|
|
552
|
-
`,t.querySelectorAll(".wontum-subtitle-option").forEach(i=>{i.addEventListener("click",s=>{const
|
|
552
|
+
`,t.querySelectorAll(".wontum-subtitle-option").forEach(i=>{i.addEventListener("click",s=>{const a=s.target,r=parseInt(a.dataset.track||"-1");r===-1?this.player.disableSubtitles():this.player.enableSubtitles(r),t.querySelectorAll(".wontum-subtitle-option").forEach(c=>c.classList.remove("active")),a.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(s=>`
|
|
553
553
|
<div class="wontum-speed-option ${n===s?"active":""}" data-speed="${s}">
|
|
554
554
|
${s===1?"Normal":s+"x"}
|
|
555
555
|
</div>
|
|
556
|
-
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(s=>{s.addEventListener("click",
|
|
556
|
+
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(s=>{s.addEventListener("click",a=>{const r=a.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=`
|
|
557
557
|
<div class="wontum-settings-option" data-setting="sticky-controls">
|
|
558
558
|
<span>Sticky Controls</span>
|
|
559
559
|
<div class="wontum-toggle-switch ${this.stickyControls?"active":""}"></div>
|
|
@@ -563,7 +563,7 @@
|
|
|
563
563
|
${n.map((i,s)=>`
|
|
564
564
|
<div class="wontum-quality-option" data-quality="${s}">${i.name}</div>
|
|
565
565
|
`).join("")}
|
|
566
|
-
`,e.querySelectorAll(".wontum-quality-option").forEach(i=>{i.addEventListener("click",s=>{const
|
|
566
|
+
`,e.querySelectorAll(".wontum-quality-option").forEach(i=>{i.addEventListener("click",s=>{const a=s.target,r=parseInt(a.dataset.quality||"-1");this.player.setQuality(r),e.querySelectorAll(".wontum-quality-option").forEach(c=>c.classList.remove("active")),a.classList.add("active")})})}showControls(){this.controlsContainer.classList.remove("hidden"),this.progressContainer.classList.remove("hidden")}hideControls(){if(this.stickyControls)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>'}getSkipBackwardIcon(){return`<svg viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
567
567
|
<circle cx="30" cy="30" r="28" stroke="white" stroke-width="2"/>
|
|
568
568
|
<!-- Circular arrow backward -->
|
|
569
569
|
<path d="M30 12 A18 18 0 1 0 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
@@ -575,4 +575,4 @@
|
|
|
575
575
|
<path d="M30 12 A18 18 0 1 1 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
576
576
|
<path d="M35 12 L30 12 L30 17" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
577
577
|
<text x="30" y="35" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="white" text-anchor="middle">10</text>
|
|
578
|
-
</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 F{constructor(t){o(this,"config");o(this,"urlCache",new Map);o(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const 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){var e;if(this.signedUrls.has(t))return t;if((e=this.config)!=null&&e.signUrl)try{const n=await this.config.signUrl(t);return this.signedUrls.add(t),n}catch(n){throw console.error("Failed to sign CloudFront URL:",n),new Error("Failed to sign CloudFront URL")}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 s=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:s,expiresAt:Date.now()+50*60*1e3}),s}catch(s){throw console.error("Failed to generate presigned URL:",s),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,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){o(this,"container");o(this,"videoElement");o(this,"hls",null);o(this,"config");o(this,"eventListeners",new Map);o(this,"analytics");o(this,"s3Handler");o(this,"uiController");o(this,"qualities",[]);o(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new R(t.analytics),this.s3Handler=new F(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new $(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const 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}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){try{const e=await this.s3Handler.processUrl(t);if(m.isSupported())this.hls=new m(this.config.hlsConfig),this.hls.loadSource(e),this.hls.attachMedia(this.videoElement),this.hls.on(m.Events.MANIFEST_PARSED,(n,i)=>{const s=this.extractQualities(i.levels);this.qualities=s}),this.hls.on(m.Events.LEVEL_SWITCHED,(n,i)=>{var r;const s=(r=this.hls)==null?void 0:r.levels[i.level];s&&(this.state.quality=`${s.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(m.Events.ERROR,(n,i)=>{i.fatal&&this.handleHlsError(i)});else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=e;else throw new Error("HLS is not supported in this browser")}catch(e){console.error("Failed to load video source:",e),this.emit("error",{error:e})}}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 m.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case m.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}))}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(s=>{s(n)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}const O=a=>{const{src:t,autoplay:e,muted:n,controls:i=!0,poster:s,preload:r,theme:l,s3Config:c,analytics:h,hlsConfig:g,subtitles:A,stickyControls:H,onReady:f,onPlay:k,onPause:E,onEnded:x,onTimeUpdate:S,onVolumeChange:C,onError:L,onLoadedMetadata:T,onQualityChange:q,style:U,className:D,width:v="100%",height:y="500px"}=a,w=d.useRef(null),M=d.useRef(null);return d.useEffect(()=>{if(!w.current)return;const j={src:t,container:w.current,autoplay:e,muted:n,controls:i,poster:s,preload:r,theme:l,s3Config:c,analytics:h,hlsConfig:g,subtitles:A,stickyControls:H},u=new b(j);return M.current=u,k&&u.on("play",k),E&&u.on("pause",E),x&&u.on("ended",x),L&&u.on("error",p=>{var B;return L((B=p.data)==null?void 0:B.error)}),T&&u.on("loadedmetadata",T),q&&u.on("qualitychange",p=>q(p.data.level)),S&&u.on("timeupdate",p=>S(p.data.currentTime)),C&&u.on("volumechange",p=>C(p.data.volume,p.data.muted)),f&&f(u),()=>{u.destroy(),M.current=null}},[t]),I.jsx("div",{ref:w,className:D,style:{width:typeof v=="number"?`${v}px`:v,height:typeof y=="number"?`${y}px`:y,...U}})},_=a=>{const[t,e]=d.useState(null),[n,i]=d.useState(null),s=d.useRef(null);return d.useEffect(()=>{if(!s.current)return;const r=new b({...a,container:s.current});e(r);const l=()=>{i(r.getState())};return r.on("play",l),r.on("pause",l),r.on("timeupdate",l),r.on("volumechange",l),r.on("loadedmetadata",l),()=>{r.destroy()}},[a.src]),{containerRef:s,player:t,state:n}},z=P.createContext({player:null,state:null}),Q=a=>{const{player:t,children:e}=a,[n,i]=d.useState(t.getState());return d.useEffect(()=>{const s=()=>{i(t.getState())};return t.on("play",s),t.on("pause",s),t.on("timeupdate",s),t.on("volumechange",s),t.on("loadedmetadata",s),()=>{}},[t]),I.jsx(z.Provider,{value:{player:t,state:n},children:e})},Y=()=>{const a=P.useContext(z);if(!a.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return a};exports.Analytics=R;exports.S3Handler=F;exports.UIController=$;exports.WontumPlayer=b;exports.WontumPlayerProvider=Q;exports.WontumPlayerReact=O;exports.useWontumPlayer=_;exports.useWontumPlayerContext=Y;
|
|
578
|
+
</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 F{constructor(t){o(this,"config");o(this,"urlCache",new Map);o(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const 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 s,a;if(this.signedUrls.has(t))return t;if((s=this.config)!=null&&s.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"||((a=r==null?void 0:r.message)==null?void 0:a.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 s=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:s,expiresAt:Date.now()+50*60*1e3}),s}catch(s){throw console.error("Failed to generate presigned URL:",s),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,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){o(this,"container");o(this,"videoElement");o(this,"hls",null);o(this,"config");o(this,"eventListeners",new Map);o(this,"analytics");o(this,"s3Handler");o(this,"uiController");o(this,"qualities",[]);o(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new P(t.analytics),this.s3Handler=new F(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new $(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const 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}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){try{const e=await this.s3Handler.processUrl(t);if(m.isSupported())this.hls=new m(this.config.hlsConfig),this.hls.loadSource(e),this.hls.attachMedia(this.videoElement),this.hls.on(m.Events.MANIFEST_PARSED,(n,i)=>{const s=this.extractQualities(i.levels);this.qualities=s}),this.hls.on(m.Events.LEVEL_SWITCHED,(n,i)=>{var a;const s=(a=this.hls)==null?void 0:a.levels[i.level];s&&(this.state.quality=`${s.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(m.Events.ERROR,(n,i)=>{i.fatal&&this.handleHlsError(i)});else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=e;else throw new Error("HLS is not supported in this browser")}catch(e){console.error("Failed to load video source:",e),this.emit("error",{error:e})}}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 m.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case m.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}))}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(s=>{s(n)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}const N=l=>{const{src:t,autoplay:e,muted:n,controls:i=!0,poster:s,preload:a,theme:r,s3Config:c,analytics:u,hlsConfig:g,subtitles:U,stickyControls:D,onReady:f,onPlay:k,onPause:E,onEnded:x,onTimeUpdate:S,onVolumeChange:C,onError:L,onLoadedMetadata:T,onQualityChange:q,style:z,className:H,width:v="100%",height:y="500px"}=l,w=h.useRef(null),M=h.useRef(null);return h.useEffect(()=>{if(!w.current)return;const j={src:t,container:w.current,autoplay:e,muted:n,controls:i,poster:s,preload:a,theme:r,s3Config:c,analytics:u,hlsConfig:g,subtitles:U,stickyControls:D},d=new b(j);return M.current=d,k&&d.on("play",k),E&&d.on("pause",E),x&&d.on("ended",x),L&&d.on("error",p=>{var R;return L((R=p.data)==null?void 0:R.error)}),T&&d.on("loadedmetadata",T),q&&d.on("qualitychange",p=>q(p.data.level)),S&&d.on("timeupdate",p=>S(p.data.currentTime)),C&&d.on("volumechange",p=>C(p.data.volume,p.data.muted)),f&&f(d),()=>{d.destroy(),M.current=null}},[t]),I.jsx("div",{ref:w,className:H,style:{width:typeof v=="number"?`${v}px`:v,height:typeof y=="number"?`${y}px`:y,...z}})},Q=l=>{const[t,e]=h.useState(null),[n,i]=h.useState(null),s=h.useRef(null);return h.useEffect(()=>{if(!s.current)return;const a=new b({...l,container:s.current});e(a);const r=()=>{i(a.getState())};return a.on("play",r),a.on("pause",r),a.on("timeupdate",r),a.on("volumechange",r),a.on("loadedmetadata",r),()=>{a.destroy()}},[l.src]),{containerRef:s,player:t,state:n}},A=B.createContext({player:null,state:null}),O=l=>{const{player:t,children:e}=l,[n,i]=h.useState(t.getState());return h.useEffect(()=>{const s=()=>{i(t.getState())};return t.on("play",s),t.on("pause",s),t.on("timeupdate",s),t.on("volumechange",s),t.on("loadedmetadata",s),()=>{}},[t]),I.jsx(A.Provider,{value:{player:t,state:n},children:e})},Y=()=>{const l=B.useContext(A);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l};exports.Analytics=P;exports.S3Handler=F;exports.UIController=$;exports.WontumPlayer=b;exports.WontumPlayerProvider=O;exports.WontumPlayerReact=N;exports.useWontumPlayer=Q;exports.useWontumPlayerContext=Y;
|
|
@@ -2,10 +2,10 @@ var V = Object.defineProperty;
|
|
|
2
2
|
var N = (l, t, e) => t in l ? V(l, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : l[t] = e;
|
|
3
3
|
var o = (l, t, e) => N(l, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import p from "hls.js";
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
5
|
+
import { jsx as B } from "react/jsx-runtime";
|
|
6
|
+
import * as $ from "react";
|
|
7
7
|
import { useRef as w, useEffect as f, useState as b } from "react";
|
|
8
|
-
class
|
|
8
|
+
class _ {
|
|
9
9
|
constructor(t) {
|
|
10
10
|
o(this, "config");
|
|
11
11
|
o(this, "sessionId");
|
|
@@ -119,7 +119,7 @@ class j {
|
|
|
119
119
|
(t = this.config) != null && t.enabled && this.trackEvent("session_end", this.getSessionData()), this.events = [];
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
class
|
|
122
|
+
class Q {
|
|
123
123
|
constructor(t, e) {
|
|
124
124
|
o(this, "container");
|
|
125
125
|
o(this, "player");
|
|
@@ -143,7 +143,7 @@ class W {
|
|
|
143
143
|
injectStyles() {
|
|
144
144
|
const t = "wontum-player-styles";
|
|
145
145
|
if (document.getElementById(t)) return;
|
|
146
|
-
const e = this.player.config.theme || {}, n = e.primaryColor || "#3b82f6", i = e.accentColor || "#2563eb", s = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
146
|
+
const e = this.player.config.theme || {}, n = e.primaryColor || "#3b82f6", i = e.accentColor || "#2563eb", s = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", a = 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", m = document.createElement("style");
|
|
147
147
|
m.id = t, m.textContent = `
|
|
148
148
|
.wontum-player-container {
|
|
149
149
|
position: relative;
|
|
@@ -152,10 +152,10 @@ class W {
|
|
|
152
152
|
overflow: hidden;
|
|
153
153
|
--primary-color: ${n};
|
|
154
154
|
--accent-color: ${i};
|
|
155
|
-
--controls-bg: ${
|
|
156
|
-
--button-hover: ${
|
|
155
|
+
--controls-bg: ${a};
|
|
156
|
+
--button-hover: ${r};
|
|
157
157
|
--progress-height: ${c};
|
|
158
|
-
--border-radius: ${
|
|
158
|
+
--border-radius: ${u};
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
.wontum-player-video {
|
|
@@ -706,8 +706,8 @@ class W {
|
|
|
706
706
|
}), this.skipForwardButton.addEventListener("click", () => {
|
|
707
707
|
this.player.skipForward(10);
|
|
708
708
|
}), this.progressInput.addEventListener("input", (n) => {
|
|
709
|
-
const i = n.target, s = parseFloat(i.value),
|
|
710
|
-
this.player.seek(
|
|
709
|
+
const i = n.target, s = parseFloat(i.value), a = this.player.getState(), r = s / 100 * a.duration;
|
|
710
|
+
this.player.seek(r);
|
|
711
711
|
}), this.volumeSlider.addEventListener("input", (n) => {
|
|
712
712
|
const i = n.target, s = parseFloat(i.value) / 100;
|
|
713
713
|
this.player.setVolume(s);
|
|
@@ -722,9 +722,9 @@ class W {
|
|
|
722
722
|
const t = this.controlsContainer.querySelectorAll(".wontum-tab");
|
|
723
723
|
t.forEach((n) => {
|
|
724
724
|
n.addEventListener("click", (i) => {
|
|
725
|
-
const s = i.currentTarget,
|
|
726
|
-
t.forEach((
|
|
727
|
-
const c = this.controlsContainer.querySelector(`[data-panel="${
|
|
725
|
+
const s = i.currentTarget, a = s.getAttribute("data-tab");
|
|
726
|
+
t.forEach((u) => u.classList.remove("active")), s.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((u) => u.classList.remove("active"));
|
|
727
|
+
const c = this.controlsContainer.querySelector(`[data-panel="${a}"]`);
|
|
728
728
|
c == null || c.classList.add("active");
|
|
729
729
|
});
|
|
730
730
|
}), this.player.getVideoElement().addEventListener("click", () => {
|
|
@@ -780,8 +780,8 @@ class W {
|
|
|
780
780
|
).join("")}
|
|
781
781
|
`, t.querySelectorAll(".wontum-subtitle-option").forEach((i) => {
|
|
782
782
|
i.addEventListener("click", (s) => {
|
|
783
|
-
const
|
|
784
|
-
|
|
783
|
+
const a = s.target, r = parseInt(a.dataset.track || "-1");
|
|
784
|
+
r === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(r), t.querySelectorAll(".wontum-subtitle-option").forEach((c) => c.classList.remove("active")), a.classList.add("active");
|
|
785
785
|
});
|
|
786
786
|
});
|
|
787
787
|
}
|
|
@@ -794,9 +794,9 @@ class W {
|
|
|
794
794
|
</div>
|
|
795
795
|
`
|
|
796
796
|
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((s) => {
|
|
797
|
-
s.addEventListener("click", (
|
|
798
|
-
const
|
|
799
|
-
this.player.setPlaybackRate(c), t.querySelectorAll(".wontum-speed-option").forEach((
|
|
797
|
+
s.addEventListener("click", (a) => {
|
|
798
|
+
const r = a.target, c = parseFloat(r.dataset.speed || "1");
|
|
799
|
+
this.player.setPlaybackRate(c), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), r.classList.add("active");
|
|
800
800
|
});
|
|
801
801
|
});
|
|
802
802
|
}
|
|
@@ -828,8 +828,8 @@ class W {
|
|
|
828
828
|
).join("")}
|
|
829
829
|
`, e.querySelectorAll(".wontum-quality-option").forEach((i) => {
|
|
830
830
|
i.addEventListener("click", (s) => {
|
|
831
|
-
const
|
|
832
|
-
this.player.setQuality(
|
|
831
|
+
const a = s.target, r = parseInt(a.dataset.quality || "-1");
|
|
832
|
+
this.player.setQuality(r), e.querySelectorAll(".wontum-quality-option").forEach((c) => c.classList.remove("active")), a.classList.add("active");
|
|
833
833
|
});
|
|
834
834
|
});
|
|
835
835
|
}
|
|
@@ -891,7 +891,7 @@ class W {
|
|
|
891
891
|
this.hideControlsTimeout && clearTimeout(this.hideControlsTimeout), this.controlsContainer.remove();
|
|
892
892
|
}
|
|
893
893
|
}
|
|
894
|
-
class
|
|
894
|
+
class j {
|
|
895
895
|
constructor(t) {
|
|
896
896
|
o(this, "config");
|
|
897
897
|
o(this, "urlCache", /* @__PURE__ */ new Map());
|
|
@@ -928,16 +928,21 @@ class Q {
|
|
|
928
928
|
* Sign CloudFront URL by calling the signing endpoint
|
|
929
929
|
* The endpoint should set signed cookies and return the URL
|
|
930
930
|
*/
|
|
931
|
-
async signCloudFrontUrl(t) {
|
|
932
|
-
var
|
|
931
|
+
async signCloudFrontUrl(t, e = 0) {
|
|
932
|
+
var s, a;
|
|
933
933
|
if (this.signedUrls.has(t))
|
|
934
934
|
return t;
|
|
935
|
-
if ((
|
|
935
|
+
if ((s = this.config) != null && s.signUrl)
|
|
936
936
|
try {
|
|
937
|
-
const
|
|
938
|
-
return this.signedUrls.add(t),
|
|
939
|
-
} catch (
|
|
940
|
-
|
|
937
|
+
const r = await this.config.signUrl(t);
|
|
938
|
+
return this.signedUrls.add(t), r;
|
|
939
|
+
} catch (r) {
|
|
940
|
+
const c = (r == null ? void 0 : r.name) === "AbortError" || ((a = r == null ? void 0 : r.message) == null ? void 0 : a.includes("aborted"));
|
|
941
|
+
if (c && e < 2)
|
|
942
|
+
return console.warn(`Sign URL aborted, retrying (${e + 1}/2)...`), await new Promise((u) => setTimeout(u, 300)), this.signCloudFrontUrl(t, e + 1);
|
|
943
|
+
throw console.error("Failed to sign CloudFront URL:", r), c ? new Error(
|
|
944
|
+
"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."
|
|
945
|
+
) : new Error(`Failed to sign CloudFront URL: ${(r == null ? void 0 : r.message) || "Unknown error"}`);
|
|
941
946
|
}
|
|
942
947
|
return console.warn("No signUrl function provided. CloudFront cookies may not be set."), t;
|
|
943
948
|
}
|
|
@@ -995,7 +1000,7 @@ class Q {
|
|
|
995
1000
|
this.urlCache.clear(), this.signedUrls.clear();
|
|
996
1001
|
}
|
|
997
1002
|
}
|
|
998
|
-
class
|
|
1003
|
+
class F {
|
|
999
1004
|
constructor(t) {
|
|
1000
1005
|
o(this, "container");
|
|
1001
1006
|
o(this, "videoElement");
|
|
@@ -1022,7 +1027,7 @@ class R {
|
|
|
1022
1027
|
});
|
|
1023
1028
|
if (this.config = t, this.container = typeof t.container == "string" ? document.querySelector(t.container) : t.container, !this.container)
|
|
1024
1029
|
throw new Error("Container element not found");
|
|
1025
|
-
this.analytics = new
|
|
1030
|
+
this.analytics = new _(t.analytics), this.s3Handler = new j(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);
|
|
1026
1031
|
}
|
|
1027
1032
|
addSubtitleTracks(t) {
|
|
1028
1033
|
t.forEach((e) => {
|
|
@@ -1095,8 +1100,8 @@ class R {
|
|
|
1095
1100
|
const s = this.extractQualities(i.levels);
|
|
1096
1101
|
this.qualities = s;
|
|
1097
1102
|
}), this.hls.on(p.Events.LEVEL_SWITCHED, (n, i) => {
|
|
1098
|
-
var
|
|
1099
|
-
const s = (
|
|
1103
|
+
var a;
|
|
1104
|
+
const s = (a = this.hls) == null ? void 0 : a.levels[i.level];
|
|
1100
1105
|
s && (this.state.quality = `${s.height}p`, this.emit("qualitychange", { quality: this.state.quality }));
|
|
1101
1106
|
}), this.hls.on(p.Events.ERROR, (n, i) => {
|
|
1102
1107
|
i.fatal && this.handleHlsError(i);
|
|
@@ -1247,20 +1252,20 @@ class R {
|
|
|
1247
1252
|
this.hls && (this.hls.destroy(), this.hls = null), this.uiController.destroy(), this.videoElement.remove(), this.eventListeners.clear(), this.analytics.destroy();
|
|
1248
1253
|
}
|
|
1249
1254
|
}
|
|
1250
|
-
const
|
|
1255
|
+
const K = (l) => {
|
|
1251
1256
|
const {
|
|
1252
1257
|
src: t,
|
|
1253
1258
|
autoplay: e,
|
|
1254
1259
|
muted: n,
|
|
1255
1260
|
controls: i = !0,
|
|
1256
1261
|
poster: s,
|
|
1257
|
-
preload:
|
|
1258
|
-
theme:
|
|
1262
|
+
preload: a,
|
|
1263
|
+
theme: r,
|
|
1259
1264
|
s3Config: c,
|
|
1260
|
-
analytics:
|
|
1265
|
+
analytics: u,
|
|
1261
1266
|
hlsConfig: m,
|
|
1262
|
-
subtitles:
|
|
1263
|
-
stickyControls:
|
|
1267
|
+
subtitles: P,
|
|
1268
|
+
stickyControls: U,
|
|
1264
1269
|
onReady: k,
|
|
1265
1270
|
onPlay: E,
|
|
1266
1271
|
onPause: x,
|
|
@@ -1270,43 +1275,43 @@ const X = (l) => {
|
|
|
1270
1275
|
onError: T,
|
|
1271
1276
|
onLoadedMetadata: q,
|
|
1272
1277
|
onQualityChange: M,
|
|
1273
|
-
style:
|
|
1274
|
-
className:
|
|
1278
|
+
style: z,
|
|
1279
|
+
className: D,
|
|
1275
1280
|
width: g = "100%",
|
|
1276
1281
|
height: v = "500px"
|
|
1277
|
-
} = l, y = w(null),
|
|
1282
|
+
} = l, y = w(null), R = w(null);
|
|
1278
1283
|
return f(() => {
|
|
1279
1284
|
if (!y.current) return;
|
|
1280
|
-
const
|
|
1285
|
+
const H = {
|
|
1281
1286
|
src: t,
|
|
1282
1287
|
container: y.current,
|
|
1283
1288
|
autoplay: e,
|
|
1284
1289
|
muted: n,
|
|
1285
1290
|
controls: i,
|
|
1286
1291
|
poster: s,
|
|
1287
|
-
preload:
|
|
1288
|
-
theme:
|
|
1292
|
+
preload: a,
|
|
1293
|
+
theme: r,
|
|
1289
1294
|
s3Config: c,
|
|
1290
|
-
analytics:
|
|
1295
|
+
analytics: u,
|
|
1291
1296
|
hlsConfig: m,
|
|
1292
|
-
subtitles:
|
|
1293
|
-
stickyControls:
|
|
1294
|
-
},
|
|
1295
|
-
return
|
|
1297
|
+
subtitles: P,
|
|
1298
|
+
stickyControls: U
|
|
1299
|
+
}, d = new F(H);
|
|
1300
|
+
return R.current = d, E && d.on("play", E), x && d.on("pause", x), S && d.on("ended", S), T && d.on("error", (h) => {
|
|
1296
1301
|
var I;
|
|
1297
1302
|
return T((I = h.data) == null ? void 0 : I.error);
|
|
1298
|
-
}), q &&
|
|
1299
|
-
|
|
1303
|
+
}), q && d.on("loadedmetadata", q), M && d.on("qualitychange", (h) => M(h.data.level)), C && d.on("timeupdate", (h) => C(h.data.currentTime)), L && d.on("volumechange", (h) => L(h.data.volume, h.data.muted)), k && k(d), () => {
|
|
1304
|
+
d.destroy(), R.current = null;
|
|
1300
1305
|
};
|
|
1301
|
-
}, [t]), /* @__PURE__ */
|
|
1306
|
+
}, [t]), /* @__PURE__ */ B(
|
|
1302
1307
|
"div",
|
|
1303
1308
|
{
|
|
1304
1309
|
ref: y,
|
|
1305
|
-
className:
|
|
1310
|
+
className: D,
|
|
1306
1311
|
style: {
|
|
1307
1312
|
width: typeof g == "number" ? `${g}px` : g,
|
|
1308
1313
|
height: typeof v == "number" ? `${v}px` : v,
|
|
1309
|
-
...
|
|
1314
|
+
...z
|
|
1310
1315
|
}
|
|
1311
1316
|
}
|
|
1312
1317
|
);
|
|
@@ -1314,23 +1319,23 @@ const X = (l) => {
|
|
|
1314
1319
|
const [t, e] = b(null), [n, i] = b(null), s = w(null);
|
|
1315
1320
|
return f(() => {
|
|
1316
1321
|
if (!s.current) return;
|
|
1317
|
-
const
|
|
1322
|
+
const a = new F({
|
|
1318
1323
|
...l,
|
|
1319
1324
|
container: s.current
|
|
1320
1325
|
});
|
|
1321
|
-
e(
|
|
1322
|
-
const
|
|
1323
|
-
i(
|
|
1326
|
+
e(a);
|
|
1327
|
+
const r = () => {
|
|
1328
|
+
i(a.getState());
|
|
1324
1329
|
};
|
|
1325
|
-
return
|
|
1326
|
-
|
|
1330
|
+
return a.on("play", r), a.on("pause", r), a.on("timeupdate", r), a.on("volumechange", r), a.on("loadedmetadata", r), () => {
|
|
1331
|
+
a.destroy();
|
|
1327
1332
|
};
|
|
1328
1333
|
}, [l.src]), {
|
|
1329
1334
|
containerRef: s,
|
|
1330
1335
|
player: t,
|
|
1331
1336
|
state: n
|
|
1332
1337
|
};
|
|
1333
|
-
},
|
|
1338
|
+
}, A = $.createContext({
|
|
1334
1339
|
player: null,
|
|
1335
1340
|
state: null
|
|
1336
1341
|
}), J = (l) => {
|
|
@@ -1341,20 +1346,20 @@ const X = (l) => {
|
|
|
1341
1346
|
};
|
|
1342
1347
|
return t.on("play", s), t.on("pause", s), t.on("timeupdate", s), t.on("volumechange", s), t.on("loadedmetadata", s), () => {
|
|
1343
1348
|
};
|
|
1344
|
-
}, [t]), /* @__PURE__ */
|
|
1349
|
+
}, [t]), /* @__PURE__ */ B(A.Provider, { value: { player: t, state: n }, children: e });
|
|
1345
1350
|
}, Z = () => {
|
|
1346
|
-
const l =
|
|
1351
|
+
const l = $.useContext(A);
|
|
1347
1352
|
if (!l.player)
|
|
1348
1353
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1349
1354
|
return l;
|
|
1350
1355
|
};
|
|
1351
1356
|
export {
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1357
|
+
_ as Analytics,
|
|
1358
|
+
j as S3Handler,
|
|
1359
|
+
Q as UIController,
|
|
1360
|
+
F as WontumPlayer,
|
|
1356
1361
|
J as WontumPlayerProvider,
|
|
1357
|
-
|
|
1362
|
+
K as WontumPlayerReact,
|
|
1358
1363
|
G as useWontumPlayer,
|
|
1359
1364
|
Z as useWontumPlayerContext
|
|
1360
1365
|
};
|
package/package.json
CHANGED