@obipascal/player 1.0.9 → 1.0.10
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 -0
- package/dist/src/file-info.d.ts +23 -0
- package/dist/wontum-player.cjs.js +7 -7
- package/dist/wontum-player.esm.js +185 -117
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1421,11 +1421,20 @@ fileInput.addEventListener("change", async (event) => {
|
|
|
1421
1421
|
console.log("- File Name:", videoInfo.fileName) // e.g., "my-video.mp4"
|
|
1422
1422
|
console.log("- Extension:", videoInfo.fileExtension) // e.g., ".mp4"
|
|
1423
1423
|
console.log("- Bitrate:", videoInfo.bitrate, "kbps") // e.g., 3500
|
|
1424
|
+
console.log("- Frame Rate:", videoInfo.frameRate, "fps") // e.g., 30 or 60
|
|
1425
|
+
console.log("- Has Audio:", videoInfo.hasAudio) // e.g., true
|
|
1426
|
+
console.log("- Audio Channels:", videoInfo.audioChannels) // e.g., 2 (stereo)
|
|
1424
1427
|
|
|
1425
1428
|
// Get all info as object
|
|
1426
1429
|
const allInfo = videoInfo.getInfo()
|
|
1427
1430
|
console.log(allInfo)
|
|
1428
1431
|
|
|
1432
|
+
// Validate against platform requirements
|
|
1433
|
+
const isValid = validateVideo(videoInfo)
|
|
1434
|
+
if (!isValid.valid) {
|
|
1435
|
+
console.error("Validation errors:", isValid.errors)
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1429
1438
|
// Clean up when done
|
|
1430
1439
|
videoInfo.destroy()
|
|
1431
1440
|
} catch (error) {
|
|
@@ -1433,6 +1442,56 @@ fileInput.addEventListener("change", async (event) => {
|
|
|
1433
1442
|
// Throws error if file is not a video
|
|
1434
1443
|
}
|
|
1435
1444
|
})
|
|
1445
|
+
|
|
1446
|
+
// Example validation function for educational platform
|
|
1447
|
+
function validateVideo(info: VideoFileInfo) {
|
|
1448
|
+
const errors: string[] = []
|
|
1449
|
+
|
|
1450
|
+
// Aspect Ratio: 16:9 required
|
|
1451
|
+
if (info.aspectRatio !== "16:9") {
|
|
1452
|
+
errors.push(`Aspect ratio must be 16:9, got ${info.aspectRatio}`)
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// Resolution: Minimum 1280×720
|
|
1456
|
+
if (info.height < 720 || info.width < 1280) {
|
|
1457
|
+
errors.push(`Minimum resolution is 1280×720, got ${info.width}×${info.height}`)
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// File Format: .MP4 or .MOV
|
|
1461
|
+
if (![".mp4", ".mov"].includes(info.fileExtension.toLowerCase())) {
|
|
1462
|
+
errors.push(`File format must be MP4 or MOV, got ${info.fileExtension}`)
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Bitrate: 5-10 Mbps
|
|
1466
|
+
if (info.bitrate && (info.bitrate < 5000 || info.bitrate > 10000)) {
|
|
1467
|
+
errors.push(`Bitrate should be 5-10 Mbps, got ${info.bitrate} kbps`)
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
// Audio: Must be stereo (2 channels)
|
|
1471
|
+
if (!info.hasAudio) {
|
|
1472
|
+
errors.push("Video must have audio track")
|
|
1473
|
+
} else if (info.audioChannels && info.audioChannels !== 2) {
|
|
1474
|
+
errors.push(`Audio must be stereo (2 channels), got ${info.audioChannels}`)
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// File Size: ≤4.0 GB
|
|
1478
|
+
const maxSize = 4 * 1024 * 1024 * 1024 // 4GB in bytes
|
|
1479
|
+
if (info.sizeInBytes > maxSize) {
|
|
1480
|
+
errors.push(`File size must be ≤4GB, got ${info.sizeFormatted}`)
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// Duration: 2 minutes to 2 hours
|
|
1484
|
+
if (info.durationInSeconds < 120 || info.durationInSeconds > 7200) {
|
|
1485
|
+
errors.push(`Duration must be 2min-2hrs, got ${info.durationFormatted}`)
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// Frame Rate: 30 or 60 fps
|
|
1489
|
+
if (info.frameRate && ![30, 60].includes(info.frameRate)) {
|
|
1490
|
+
errors.push(`Frame rate should be 30 or 60 fps, got ${info.frameRate}`)
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
return { valid: errors.length === 0, errors }
|
|
1494
|
+
}
|
|
1436
1495
|
```
|
|
1437
1496
|
|
|
1438
1497
|
#### WontumFileInfo API
|
|
@@ -1467,6 +1526,13 @@ Throws an error if the file is not a valid video file.
|
|
|
1467
1526
|
- `fileName: string` - Original file name
|
|
1468
1527
|
- `fileExtension: string` - File extension (e.g., ".mp4")
|
|
1469
1528
|
- `bitrate: number | undefined` - Estimated bitrate in kbps
|
|
1529
|
+
- `frameRate: number | undefined` - Frame rate in fps (30, 60, etc.)
|
|
1530
|
+
- `hasAudio: boolean` - Whether video has an audio track
|
|
1531
|
+
- `audioChannels: number | undefined` - Number of audio channels (1=mono, 2=stereo)
|
|
1532
|
+
|
|
1533
|
+
**Validation Use Case:**
|
|
1534
|
+
|
|
1535
|
+
Perfect for validating videos against platform requirements (aspect ratio, resolution, format, bitrate, audio channels, file size, duration, frame rate).
|
|
1470
1536
|
|
|
1471
1537
|
**Supported Video Formats:**
|
|
1472
1538
|
|
package/dist/src/file-info.d.ts
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
* Video file information extractor
|
|
3
3
|
* Extracts metadata from video files (width, height, duration, size, etc.)
|
|
4
4
|
*/
|
|
5
|
+
declare global {
|
|
6
|
+
interface HTMLVideoElement {
|
|
7
|
+
mozHasAudio?: boolean;
|
|
8
|
+
webkitAudioDecodedByteCount?: number;
|
|
9
|
+
audioTracks?: {
|
|
10
|
+
length: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
5
14
|
export interface VideoFileInfo {
|
|
6
15
|
width: number;
|
|
7
16
|
height: number;
|
|
@@ -17,12 +26,15 @@ export interface VideoFileInfo {
|
|
|
17
26
|
fileExtension: string;
|
|
18
27
|
bitrate?: number;
|
|
19
28
|
frameRate?: number;
|
|
29
|
+
audioChannels?: number;
|
|
20
30
|
videoCodec?: string;
|
|
21
31
|
audioCodec?: string;
|
|
32
|
+
hasAudio?: boolean;
|
|
22
33
|
}
|
|
23
34
|
export declare class WontumFileInfo {
|
|
24
35
|
private file;
|
|
25
36
|
private videoElement;
|
|
37
|
+
private audioContext;
|
|
26
38
|
private info;
|
|
27
39
|
constructor(file: File);
|
|
28
40
|
/**
|
|
@@ -37,6 +49,14 @@ export declare class WontumFileInfo {
|
|
|
37
49
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
38
50
|
*/
|
|
39
51
|
private calculateAspectRatio;
|
|
52
|
+
/**
|
|
53
|
+
* Detect frame rate by analyzing video playback
|
|
54
|
+
*/
|
|
55
|
+
private detectFrameRate;
|
|
56
|
+
/**
|
|
57
|
+
* Detect audio channel information using Web Audio API
|
|
58
|
+
*/
|
|
59
|
+
private detectAudioInfo;
|
|
40
60
|
/**
|
|
41
61
|
* Get Greatest Common Divisor
|
|
42
62
|
*/
|
|
@@ -66,6 +86,9 @@ export declare class WontumFileInfo {
|
|
|
66
86
|
get fileName(): string;
|
|
67
87
|
get fileExtension(): string;
|
|
68
88
|
get bitrate(): number | undefined;
|
|
89
|
+
get frameRate(): number | undefined;
|
|
90
|
+
get audioChannels(): number | undefined;
|
|
91
|
+
get hasAudio(): boolean;
|
|
69
92
|
get quality(): string;
|
|
70
93
|
/**
|
|
71
94
|
* Get all information as object
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var W=Object.create;var S=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var Y=(l,t,e)=>t in l?S(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var X=(l,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _(t))!Q.call(l,n)&&n!==e&&S(l,n,{get:()=>t[n],enumerable:!(i=N(t,n))||i.enumerable});return l};var G=(l,t,e)=>(e=l!=null?W(j(l)):{},X(t||!l||!l.__esModule?S(e,"default",{value:l,enumerable:!0}):e,l));var r=(l,t,e)=>Y(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("hls.js"),F=require("react/jsx-runtime"),h=require("react");function K(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const B=K(h);class O{constructor(t){r(this,"config");r(this,"sessionId");r(this,"events",[]);r(this,"sessionStartTime");r(this,"playbackStartTime",null);r(this,"totalPlayTime",0);r(this,"totalBufferTime",0);r(this,"bufferStartTime",null);r(this,"rebufferCount",0);r(this,"seekCount",0);r(this,"webSocket",null);r(this,"socketIO",null);r(this,"wsReconnectTimeout",null);r(this,"isDestroyed",!1);var e,i;if(this.config=t,this.sessionId=(t==null?void 0:t.sessionId)||this.generateSessionId(),this.sessionStartTime=Date.now(),(e=this.config)!=null&&e.webSocket){const n=this.config.webSocket;"type"in n?n.type==="socket.io"?this.initializeSocketIO():this.initializeWebSocket():this.initializeWebSocket()}(i=this.config)!=null&&i.enabled&&this.trackEvent("session_start",this.getSessionData())}trackEvent(t,e={}){var n;if(!((n=this.config)!=null&&n.enabled))return;const i={eventType:t,timestamp:Date.now(),sessionId:this.sessionId,videoId:this.config.videoId,userId:this.config.userId,data:{...e,...this.getQoEMetrics()}};this.events.push(i),this.updateMetrics(t,e),this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&this.sendToWebSocket(i),this.socketIO&&this.socketIO.connected&&this.sendToSocketIO(i),this.config.endpoint&&this.sendEvent(i),process.env.NODE_ENV==="development"&&console.log("[Analytics]",t,i.data)}updateMetrics(t,e){switch(t){case"play":this.playbackStartTime=Date.now();break;case"pause":case"ended":this.playbackStartTime&&(this.totalPlayTime+=Date.now()-this.playbackStartTime,this.playbackStartTime=null);break;case"buffering_start":this.bufferStartTime=Date.now(),this.rebufferCount++;break;case"buffering_end":this.bufferStartTime&&(this.totalBufferTime+=Date.now()-this.bufferStartTime,this.bufferStartTime=null);break;case"seeked":this.seekCount++;break}}getQoEMetrics(){const t=Date.now()-this.sessionStartTime,e=this.totalPlayTime>0?this.totalBufferTime/this.totalPlayTime:0;return{sessionDuration:t,totalPlayTime:this.totalPlayTime,totalBufferTime:this.totalBufferTime,bufferingRatio:Math.round(e*1e3)/1e3,rebufferCount:this.rebufferCount,seekCount:this.seekCount}}getSessionData(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenResolution:`${screen.width}x${screen.height}`,viewport:`${window.innerWidth}x${window.innerHeight}`,connection:this.getConnectionInfo()}}getConnectionInfo(){const t=navigator,e=t.connection||t.mozConnection||t.webkitConnection;return e?{effectiveType:e.effectiveType,downlink:e.downlink,rtt:e.rtt,saveData:e.saveData}:null}async sendEvent(t){var e;if((e=this.config)!=null&&e.endpoint)try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(i){console.error("Failed to send analytics event:",i)}}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async initializeSocketIO(){var e;if(!((e=this.config)!=null&&e.webSocket)||!("type"in this.config.webSocket))return;const t=this.config.webSocket;if(t.type==="socket.io")try{if(typeof t.connection=="string"){const n=(await import("socket.io-client")).default;this.socketIO=n(t.connection,t.options||{})}else this.socketIO=t.connection;if(!this.socketIO)return;this.socketIO.on("connect",()=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Connected"),t.onConnect&&t.onConnect()}),this.socketIO.on("connect_error",i=>{console.error("[Analytics Socket.IO] Connection error:",i),t.onError&&t.onError(i)}),this.socketIO.on("disconnect",i=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Disconnected:",i),t.onDisconnect&&t.onDisconnect(i)}),this.socketIO.on("error",i=>{console.error("[Analytics Socket.IO] Error:",i),t.onError&&t.onError(i)})}catch(i){console.error("[Analytics Socket.IO] Failed to initialize:",i)}}sendToSocketIO(t){var e;if(!(!this.socketIO||!this.socketIO.connected))try{const i=(e=this.config)==null?void 0:e.webSocket,n=i!=null&&i.transform?i.transform(t):t,o=(i==null?void 0:i.eventName)||"analytics";this.socketIO.emit(o,n),process.env.NODE_ENV==="development"&&console.log(`[Analytics Socket.IO] Emitted (${o}):`,t.eventType)}catch(i){console.error("[Analytics Socket.IO] Failed to emit event:",i)}}initializeWebSocket(){var e;if(!((e=this.config)!=null&&e.webSocket))return;const t=this.config.webSocket;try{typeof t.connection=="string"?this.webSocket=new WebSocket(t.connection):this.webSocket=t.connection,this.webSocket.onopen=i=>{process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Connected"),t.onOpen&&t.onOpen(i)},this.webSocket.onerror=i=>{console.error("[Analytics WebSocket] Error:",i),t.onError&&t.onError(i)},this.webSocket.onclose=i=>{if(process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Disconnected"),t.onClose&&t.onClose(i),t.autoReconnect!==!1&&!this.isDestroyed){const o=t.reconnectDelay||3e3;process.env.NODE_ENV==="development"&&console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`),this.wsReconnectTimeout=window.setTimeout(()=>{this.initializeWebSocket()},o)}}}catch(i){console.error("[Analytics WebSocket] Failed to initialize:",i)}}sendToWebSocket(t){var e;if(!(!this.webSocket||this.webSocket.readyState!==WebSocket.OPEN))try{const i=(e=this.config)==null?void 0:e.webSocket,n=i!=null&&i.transform?i.transform(t):t;this.webSocket.send(JSON.stringify(n)),process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Sent:",t.eventType)}catch(i){console.error("[Analytics WebSocket] Failed to send event:",i)}}getEvents(){return[...this.events]}getMetrics(){return{sessionId:this.sessionId,...this.getQoEMetrics(),eventCount:this.events.length}}destroy(){var t;this.isDestroyed=!0,(t=this.config)!=null&&t.enabled&&this.trackEvent("session_end",this.getSessionData()),this.wsReconnectTimeout&&(clearTimeout(this.wsReconnectTimeout),this.wsReconnectTimeout=null),this.webSocket&&(this.webSocket.close(),this.webSocket=null),this.socketIO&&(this.socketIO.removeAllListeners(),this.socketIO.disconnect(),this.socketIO=null),this.events=[]}}class z{constructor(t,e){r(this,"container");r(this,"player");r(this,"controlsContainer");r(this,"progressContainer");r(this,"progressBar");r(this,"playButton");r(this,"skipBackwardButton");r(this,"skipForwardButton");r(this,"volumeButton");r(this,"volumeContainer");r(this,"fullscreenButton");r(this,"pipButton");r(this,"settingsButton");r(this,"volumeSlider");r(this,"progressInput");r(this,"hideControlsTimeout",null);r(this,"stickyControls",!1);r(this,"isVolumeSliderActive",!1);this.container=t,this.player=e,this.injectStyles(),this.createProgressBar(),this.controlsContainer=this.createControls(),this.container.appendChild(this.controlsContainer),this.playButton=this.controlsContainer.querySelector(".wontum-play-btn"),this.skipBackwardButton=this.controlsContainer.querySelector(".wontum-skip-backward-btn"),this.skipForwardButton=this.controlsContainer.querySelector(".wontum-skip-forward-btn"),this.volumeButton=this.controlsContainer.querySelector(".wontum-volume-btn"),this.volumeContainer=this.controlsContainer.querySelector(".wontum-volume-container"),this.fullscreenButton=this.controlsContainer.querySelector(".wontum-fullscreen-btn"),this.pipButton=this.controlsContainer.querySelector(".wontum-pip-btn"),this.settingsButton=this.controlsContainer.querySelector(".wontum-settings-btn"),this.volumeSlider=this.controlsContainer.querySelector(".wontum-volume-slider"),this.progressInput=this.container.querySelector(".wontum-progress-input"),this.progressBar=this.container.querySelector(".wontum-progress-filled"),this.stickyControls=this.player.config.stickyControls||!1,this.stickyControls&&this.controlsContainer.classList.add("sticky"),this.setupEventListeners(),this.setupPlayerEventListeners()}injectStyles(){const t="wontum-player-styles";if(document.getElementById(t))return;const e=this.player.config.theme||{},i=e.primaryColor||"#3b82f6",n=e.accentColor||"#2563eb",o=e.fontFamily||"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",s=e.controlsBackground||"linear-gradient(to top, rgba(0,0,0,0.8), transparent)",a=e.buttonHoverBg||"rgba(255, 255, 255, 0.1)",c=e.progressHeight||"6px",u=e.borderRadius||"4px",p=document.createElement("style");p.id=t,p.textContent=`
|
|
2
2
|
.wontum-player-container {
|
|
3
3
|
position: relative;
|
|
4
4
|
background: #000;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
overflow: hidden;
|
|
7
7
|
--primary-color: ${i};
|
|
8
8
|
--accent-color: ${n};
|
|
9
|
-
--controls-bg: ${
|
|
9
|
+
--controls-bg: ${s};
|
|
10
10
|
--button-hover: ${a};
|
|
11
11
|
--progress-height: ${c};
|
|
12
12
|
--border-radius: ${u};
|
|
@@ -562,18 +562,18 @@
|
|
|
562
562
|
<div class="wontum-loading" style="display: none;">
|
|
563
563
|
<div class="wontum-spinner"></div>
|
|
564
564
|
</div>
|
|
565
|
-
`,t}setupEventListeners(){this.playButton.addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.skipBackwardButton.addEventListener("click",()=>{this.player.skipBackward(10)}),this.skipForwardButton.addEventListener("click",()=>{this.player.skipForward(10)}),this.progressInput.addEventListener("input",i=>{const n=i.target,o=parseFloat(n.value),
|
|
565
|
+
`,t}setupEventListeners(){this.playButton.addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.skipBackwardButton.addEventListener("click",()=>{this.player.skipBackward(10)}),this.skipForwardButton.addEventListener("click",()=>{this.player.skipForward(10)}),this.progressInput.addEventListener("input",i=>{const n=i.target,o=parseFloat(n.value),s=this.player.getState(),a=o/100*s.duration;this.player.seek(a)}),this.volumeSlider.addEventListener("input",i=>{const n=i.target,o=parseFloat(n.value)/100;this.player.setVolume(o)}),this.volumeButton.addEventListener("click",()=>{this.player.getState().muted?this.player.unmute():this.player.mute()}),this.volumeContainer.addEventListener("mouseenter",()=>{this.isVolumeSliderActive=!0}),this.volumeContainer.addEventListener("mouseleave",()=>{this.isVolumeSliderActive=!1}),this.volumeSlider.addEventListener("input",()=>{this.isVolumeSliderActive=!0,this.resetHideControlsTimeout()}),this.volumeSlider.addEventListener("change",()=>{setTimeout(()=>{this.isVolumeSliderActive=!1},500)}),this.fullscreenButton.addEventListener("click",()=>{this.player.getState().fullscreen?this.player.exitFullscreen():this.player.enterFullscreen()}),this.pipButton.addEventListener("click",async()=>{try{await this.player.togglePictureInPicture()}catch(i){console.error("PiP error:",i)}}),this.settingsButton.addEventListener("click",()=>{const i=this.controlsContainer.querySelector(".wontum-settings-panel");i.classList.toggle("active"),i.classList.contains("active")&&(this.updateSettingsMenu(),this.updateQualityMenu(),this.updateSpeedMenu(),this.updateSubtitleMenu())});const t=this.controlsContainer.querySelectorAll(".wontum-tab");t.forEach(i=>{i.addEventListener("click",n=>{const o=n.currentTarget,s=o.getAttribute("data-tab");t.forEach(u=>u.classList.remove("active")),o.classList.add("active"),this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach(u=>u.classList.remove("active"));const c=this.controlsContainer.querySelector(`[data-panel="${s}"]`);c==null||c.classList.add("active")})}),this.player.getVideoElement().addEventListener("click",()=>{this.player.getState().playing?this.player.pause():this.player.play()}),this.container.addEventListener("mousemove",()=>{this.showControls(),this.resetHideControlsTimeout()}),this.container.addEventListener("mouseleave",()=>{this.hideControls()})}setupPlayerEventListeners(){this.player.on("play",()=>{this.playButton.innerHTML=this.getPauseIcon()}),this.player.on("pause",()=>{this.playButton.innerHTML=this.getPlayIcon()}),this.player.on("timeupdate",t=>{const{currentTime:e}=t.data,i=this.player.getState();if(i.duration>0){const o=e/i.duration*100;this.progressBar.style.width=`${o}%`,this.progressInput.value=o.toString()}const n=this.controlsContainer.querySelector(".wontum-current-time");n.textContent=this.formatTime(e)}),this.player.on("loadedmetadata",t=>{const{duration:e}=t.data,i=this.controlsContainer.querySelector(".wontum-duration");i.textContent=this.formatTime(e),t.data.qualities&&this.updateQualityMenu(t.data.qualities)}),this.player.on("volumechange",t=>{const{volume:e,muted:i}=t.data;this.volumeSlider.value=(e*100).toString(),this.volumeButton.innerHTML=i?this.getMutedIcon():this.getVolumeIcon()}),this.player.on("waiting",()=>{const t=this.controlsContainer.querySelector(".wontum-loading");t.style.display="block"}),this.player.on("canplay",()=>{const t=this.controlsContainer.querySelector(".wontum-loading");t.style.display="none"})}updateSubtitleMenu(){const t=this.controlsContainer.querySelector(".wontum-subtitle-menu"),e=this.player.getSubtitleTracks();if(e.length===0){t.innerHTML='<div class="wontum-subtitle-option">No subtitles available</div>';return}const i=e.findIndex(n=>n.mode==="showing");t.innerHTML=`
|
|
566
566
|
<div class="wontum-subtitle-option ${i===-1?"active":""}" data-track="-1">Off</div>
|
|
567
567
|
${e.map((n,o)=>`
|
|
568
568
|
<div class="wontum-subtitle-option ${o===i?"active":""}" data-track="${o}">
|
|
569
569
|
${n.label||n.language||`Track ${o+1}`}
|
|
570
570
|
</div>
|
|
571
571
|
`).join("")}
|
|
572
|
-
`,t.querySelectorAll(".wontum-subtitle-option").forEach(n=>{n.addEventListener("click",o=>{const
|
|
572
|
+
`,t.querySelectorAll(".wontum-subtitle-option").forEach(n=>{n.addEventListener("click",o=>{const s=o.target,a=parseInt(s.dataset.track||"-1");a===-1?this.player.disableSubtitles():this.player.enableSubtitles(a),t.querySelectorAll(".wontum-subtitle-option").forEach(c=>c.classList.remove("active")),s.classList.add("active")})})}updateSpeedMenu(){const t=this.controlsContainer.querySelector(".wontum-speed-menu"),i=this.player.getState().playbackRate||1,n=[.25,.5,.75,1,1.25,1.5,1.75,2];t.innerHTML=n.map(o=>`
|
|
573
573
|
<div class="wontum-speed-option ${i===o?"active":""}" data-speed="${o}">
|
|
574
574
|
${o===1?"Normal":o+"x"}
|
|
575
575
|
</div>
|
|
576
|
-
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(o=>{o.addEventListener("click",
|
|
576
|
+
`).join(""),t.querySelectorAll(".wontum-speed-option").forEach(o=>{o.addEventListener("click",s=>{const a=s.target,c=parseFloat(a.dataset.speed||"1");this.player.setPlaybackRate(c),t.querySelectorAll(".wontum-speed-option").forEach(u=>u.classList.remove("active")),a.classList.add("active")})})}updateSettingsMenu(){const t=this.controlsContainer.querySelector(".wontum-settings-menu");t.innerHTML=`
|
|
577
577
|
<div class="wontum-settings-option" data-setting="sticky-controls">
|
|
578
578
|
<span>Sticky Controls</span>
|
|
579
579
|
<div class="wontum-toggle-switch ${this.stickyControls?"active":""}"></div>
|
|
@@ -583,7 +583,7 @@
|
|
|
583
583
|
${i.map((n,o)=>`
|
|
584
584
|
<div class="wontum-quality-option" data-quality="${o}">${n.name}</div>
|
|
585
585
|
`).join("")}
|
|
586
|
-
`,e.querySelectorAll(".wontum-quality-option").forEach(n=>{n.addEventListener("click",o=>{const
|
|
586
|
+
`,e.querySelectorAll(".wontum-quality-option").forEach(n=>{n.addEventListener("click",o=>{const s=o.target,a=parseInt(s.dataset.quality||"-1");this.player.setQuality(a),e.querySelectorAll(".wontum-quality-option").forEach(c=>c.classList.remove("active")),s.classList.add("active")})})}showControls(){this.controlsContainer.classList.remove("hidden"),this.progressContainer.classList.remove("hidden")}hideControls(){if(this.stickyControls||this.isVolumeSliderActive)return;this.player.getState().playing&&(this.controlsContainer.classList.add("hidden"),this.progressContainer.classList.add("hidden"))}resetHideControlsTimeout(){this.stickyControls||(this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.hideControlsTimeout=window.setTimeout(()=>{this.hideControls()},1e4))}formatTime(t){if(isNaN(t))return"0:00";const e=Math.floor(t/60),i=Math.floor(t%60);return`${e}:${i.toString().padStart(2,"0")}`}getPlayIcon(){return'<svg viewBox="0 0 24 24"><path fill="white" d="M8 5v14l11-7z"/></svg>'}getPauseIcon(){return'<svg viewBox="0 0 24 24"><path fill="white" d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>'}getVolumeIcon(){return'<svg viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/></svg>'}getMutedIcon(){return'<svg viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>'}getFullscreenIcon(){return'<svg viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>'}getPipIcon(){return'<svg viewBox="0 0 24 24"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"/></svg>'}getSkipBackwardIcon(){return`<svg viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
587
587
|
<circle cx="30" cy="30" r="28" stroke="white" stroke-width="2"/>
|
|
588
588
|
<!-- Circular arrow backward -->
|
|
589
589
|
<path d="M30 12 A18 18 0 1 0 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
@@ -595,4 +595,4 @@
|
|
|
595
595
|
<path d="M30 12 A18 18 0 1 1 30 48" stroke="white" stroke-width="2.5" stroke-linecap="round" fill="none"/>
|
|
596
596
|
<path d="M35 12 L30 12 L30 17" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
597
597
|
<text x="30" y="35" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="white" text-anchor="middle">10</text>
|
|
598
|
-
</svg>`}getSettingsIcon(){return'<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>'}destroy(){this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.controlsContainer.remove()}}class z{constructor(t){s(this,"config");s(this,"urlCache",new Map);s(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const i=new URL(t);return this.config.cloudFrontDomains.some(n=>i.hostname.includes(n))}catch{return!1}}isS3Url(t){return t.includes(".s3.")||t.includes("s3.amazonaws.com")||t.startsWith("s3://")}async signCloudFrontUrl(t,e=0){var o,r;if(this.signedUrls.has(t))return t;if((o=this.config)!=null&&o.signUrl)try{const a=await this.config.signUrl(t);return this.signedUrls.add(t),a}catch(a){const c=(a==null?void 0:a.name)==="AbortError"||((r=a==null?void 0:a.message)==null?void 0:r.includes("aborted"));if(c&&e<2)return console.warn(`Sign URL aborted, retrying (${e+1}/2)...`),await new Promise(u=>setTimeout(u,300)),this.signCloudFrontUrl(t,e+1);throw console.error("Failed to sign CloudFront URL:",a),c?new Error("Failed to sign CloudFront URL: Request was aborted. If using Apollo Client or other GraphQL clients, consider moving the query outside component lifecycle or using useQuery with skip option."):new Error(`Failed to sign CloudFront URL: ${(a==null?void 0:a.message)||"Unknown error"}`)}return console.warn("No signUrl function provided. CloudFront cookies may not be set."),t}extractS3Key(t){if(t.startsWith("s3://"))return t.replace("s3://","").split("/").slice(1).join("/");const e=t.match(/s3[.-]([^.]+)\.amazonaws\.com\/(.+)/);if(e)return e[2];const i=t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);return i?i[2]:t}async getPresignedUrl(t){var n;const e=this.extractS3Key(t),i=this.urlCache.get(e);if(i&&i.expiresAt>Date.now())return i.url;if((n=this.config)!=null&&n.getPresignedUrl)try{const o=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:o,expiresAt:Date.now()+50*60*1e3}),o}catch(o){throw console.error("Failed to generate presigned URL:",o),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,i="us-east-1"){return`https://${t}.s3.${i}.amazonaws.com/${e}`}static parseS3Uri(t){if(!t.startsWith("s3://"))return null;const e=t.replace("s3://","").split("/"),i=e[0],n=e.slice(1).join("/");return{bucket:i,key:n}}clearCache(){this.urlCache.clear(),this.signedUrls.clear()}}class E{constructor(t){s(this,"container");s(this,"videoElement");s(this,"hls",null);s(this,"config");s(this,"eventListeners",new Map);s(this,"analytics");s(this,"s3Handler");s(this,"uiController");s(this,"qualities",[]);s(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new O(t.analytics),this.s3Handler=new z(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new $(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const i=document.createElement("track");i.kind="subtitles",i.label=e.label,i.src=e.src,i.srclang=e.srclang,e.default&&(i.default=!0),this.videoElement.appendChild(i)})}createVideoElement(){const t=document.createElement("video");return t.className="wontum-player-video",t.style.width="100%",t.style.height="100%",t.playsInline=!0,t.crossOrigin="use-credentials",t}setupVideoListeners(){this.videoElement.addEventListener("play",()=>{this.state.playing=!0,this.state.paused=!1,this.emit("play"),this.analytics.trackEvent("play",this.getAnalyticsData())}),this.videoElement.addEventListener("pause",()=>{this.state.playing=!1,this.state.paused=!0,this.emit("pause"),this.analytics.trackEvent("pause",this.getAnalyticsData())}),this.videoElement.addEventListener("ended",()=>{this.state.ended=!0,this.state.playing=!1,this.emit("ended"),this.analytics.trackEvent("ended",this.getAnalyticsData())}),this.videoElement.addEventListener("timeupdate",()=>{this.state.currentTime=this.videoElement.currentTime,this.emit("timeupdate",{currentTime:this.state.currentTime})}),this.videoElement.addEventListener("loadedmetadata",()=>{this.state.duration=this.videoElement.duration,this.emit("loadedmetadata",{duration:this.state.duration}),this.analytics.trackEvent("loadedmetadata",this.getAnalyticsData())}),this.videoElement.addEventListener("volumechange",()=>{this.state.volume=this.videoElement.volume,this.state.muted=this.videoElement.muted,this.emit("volumechange",{volume:this.state.volume,muted:this.state.muted})}),this.videoElement.addEventListener("ratechange",()=>{this.state.playbackRate=this.videoElement.playbackRate,this.emit("ratechange",{playbackRate:this.state.playbackRate})}),this.videoElement.addEventListener("waiting",()=>{this.state.buffering=!0,this.emit("waiting"),this.analytics.trackEvent("buffering_start",this.getAnalyticsData())}),this.videoElement.addEventListener("canplay",()=>{this.state.buffering=!1,this.emit("canplay"),this.analytics.trackEvent("buffering_end",this.getAnalyticsData())}),this.videoElement.addEventListener("seeking",()=>{this.emit("seeking")}),this.videoElement.addEventListener("seeked",()=>{this.emit("seeked",{currentTime:this.state.currentTime}),this.analytics.trackEvent("seeked",this.getAnalyticsData())}),this.videoElement.addEventListener("error",t=>{const e=this.videoElement.error;this.emit("error",{error:e}),this.analytics.trackEvent("error",{...this.getAnalyticsData(),error:e==null?void 0:e.message})}),this.videoElement.addEventListener("loadstart",()=>{this.emit("loadstart")}),this.videoElement.addEventListener("loadeddata",()=>{this.emit("loadeddata")}),this.videoElement.addEventListener("canplaythrough",()=>{this.emit("canplaythrough")}),this.videoElement.addEventListener("playing",()=>{this.state.playing=!0,this.state.buffering=!1,this.emit("playing")}),this.videoElement.addEventListener("durationchange",()=>{this.state.duration=this.videoElement.duration,this.emit("durationchange",{duration:this.state.duration})}),this.videoElement.addEventListener("progress",()=>{this.emit("progress",{buffered:this.videoElement.buffered})}),this.videoElement.addEventListener("stalled",()=>{this.emit("stalled")}),this.videoElement.addEventListener("suspend",()=>{this.emit("suspend")}),this.videoElement.addEventListener("abort",()=>{this.emit("abort")}),this.videoElement.addEventListener("emptied",()=>{this.emit("emptied")}),this.videoElement.addEventListener("resize",()=>{this.emit("resize",{videoWidth:this.videoElement.videoWidth,videoHeight:this.videoElement.videoHeight})})}async loadSource(t){var e;try{const i=await this.s3Handler.processUrl(t);if(g.isSupported()){const n=((e=this.config.s3Config)==null?void 0:e.withCredentials)??!1,o={...this.config.hlsConfig,xhrSetup:(r,a)=>{var c;n&&(r.withCredentials=!0),(c=this.config.hlsConfig)!=null&&c.xhrSetup&&this.config.hlsConfig.xhrSetup(r,a)}};this.hls=new g(o),this.hls.loadSource(i),this.hls.attachMedia(this.videoElement),this.hls.on(g.Events.MANIFEST_PARSED,(r,a)=>{const c=this.extractQualities(a.levels);this.qualities=c}),this.hls.on(g.Events.LEVEL_SWITCHED,(r,a)=>{var u;const c=(u=this.hls)==null?void 0:u.levels[a.level];c&&(this.state.quality=`${c.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(g.Events.ERROR,(r,a)=>{a.fatal&&this.handleHlsError(a)})}else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=i;else throw new Error("HLS is not supported in this browser")}catch(i){console.error("Failed to load video source:",i),this.emit("error",{error:i})}}extractQualities(t){return t.map(e=>({height:e.height,width:e.width,bitrate:e.bitrate,name:`${e.height}p`}))}handleHlsError(t){var e,i;switch(t.type){case g.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case g.ErrorTypes.MEDIA_ERROR:console.error("Media error occurred"),(i=this.hls)==null||i.recoverMediaError();break;default:console.error("Fatal error occurred:",t),this.destroy();break}}getAnalyticsData(){return{currentTime:this.state.currentTime,duration:this.state.duration,quality:this.state.quality,playbackRate:this.state.playbackRate,volume:this.state.volume,muted:this.state.muted}}play(){return this.videoElement.play()}pause(){this.videoElement.pause()}seek(t){this.videoElement.currentTime=t}skipForward(t=10){const e=Math.min(this.state.currentTime+t,this.state.duration);this.seek(e)}skipBackward(t=10){const e=Math.max(this.state.currentTime-t,0);this.seek(e)}setVolume(t){this.videoElement.volume=Math.max(0,Math.min(1,t))}mute(){this.videoElement.muted=!0}unmute(){this.videoElement.muted=!1}setPlaybackRate(t){this.videoElement.playbackRate=t}setQuality(t){this.hls&&(this.hls.currentLevel=t)}getQualities(){return this.qualities}enterFullscreen(){this.container.requestFullscreen&&(this.container.requestFullscreen(),this.state.fullscreen=!0,this.emit("fullscreenchange",{fullscreen:!0}))}exitFullscreen(){document.exitFullscreen&&(document.exitFullscreen(),this.state.fullscreen=!1,this.emit("fullscreenchange",{fullscreen:!1}))}async enterPictureInPicture(){if(document.pictureInPictureEnabled&&!this.videoElement.disablePictureInPicture)try{await this.videoElement.requestPictureInPicture(),this.emit("pictureinpictureenter",{})}catch(t){throw console.error("Failed to enter Picture-in-Picture:",t),t}}async exitPictureInPicture(){if(document.pictureInPictureElement)try{await document.exitPictureInPicture(),this.emit("pictureinpictureexit",{})}catch(t){throw console.error("Failed to exit Picture-in-Picture:",t),t}}async togglePictureInPicture(){document.pictureInPictureElement?await this.exitPictureInPicture():await this.enterPictureInPicture()}getState(){return{...this.state}}getVideoElement(){return this.videoElement}enableSubtitles(t){const e=this.videoElement.textTracks;for(let i=0;i<e.length;i++)e[i].mode=i===t?"showing":"hidden"}disableSubtitles(){const t=this.videoElement.textTracks;for(let e=0;e<t.length;e++)t[e].mode="hidden"}toggleSubtitles(){const t=this.videoElement.textTracks;return Array.from(t).some(i=>i.mode==="showing")?(this.disableSubtitles(),!1):t.length>0?(this.enableSubtitles(0),!0):!1}getSubtitleTracks(){return Array.from(this.videoElement.textTracks)}areSubtitlesEnabled(){const t=this.videoElement.textTracks;return Array.from(t).some(e=>e.mode==="showing")}on(t,e){this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e)}off(t,e){var i;(i=this.eventListeners.get(t))==null||i.delete(e)}emit(t,e){var n;const i={type:t,data:e,timestamp:Date.now()};(n=this.eventListeners.get(t))==null||n.forEach(o=>{o(i)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class J{constructor(t){s(this,"file");s(this,"videoElement",null);s(this,"info",null);if(!this.isVideoFile(t))throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);this.file=t}isVideoFile(t){if(t.type.startsWith("video/"))return!0;const e=[".mp4",".webm",".ogg",".mov",".avi",".mkv",".flv",".wmv",".m4v",".3gp",".ts",".m3u8"],i=t.name.toLowerCase();return e.some(n=>i.endsWith(n))}async extract(){return new Promise((t,e)=>{try{this.videoElement=document.createElement("video"),this.videoElement.preload="metadata",this.videoElement.muted=!0;const i=URL.createObjectURL(this.file);this.videoElement.onloadedmetadata=()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const n=this.videoElement.videoWidth,o=this.videoElement.videoHeight,r=this.videoElement.duration,a=this.calculateAspectRatio(n,o),c=this.file.size,u=this.formatBytes(c),p=this.formatDuration(r),v=this.getFileExtension(this.file.name),f=r>0?Math.round(c*8/r/1e3):void 0;this.info={width:n,height:o,aspectRatio:a,size:c,sizeInBytes:c,sizeFormatted:u,duration:r,durationInSeconds:r,durationFormatted:p,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:v,bitrate:f},URL.revokeObjectURL(i),this.videoElement.remove(),t(this.info)}catch(n){URL.revokeObjectURL(i),e(n)}},this.videoElement.onerror=()=>{URL.revokeObjectURL(i),e(new Error(`Failed to load video file: ${this.file.name}`))},this.videoElement.src=i}catch(i){e(i)}})}calculateAspectRatio(t,e){const i=this.getGCD(t,e),n=t/i,o=e/i,r=n/o;return Math.abs(r-16/9)<.01?"16:9":Math.abs(r-4/3)<.01?"4:3":Math.abs(r-21/9)<.01?"21:9":Math.abs(r-1)<.01?"1:1":`${n}:${o}`}getGCD(t,e){return e===0?t:this.getGCD(e,t%e)}formatBytes(t){if(t===0)return"0 Bytes";const e=1024,i=["Bytes","KB","MB","GB","TB"],n=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,n)).toFixed(2))} ${i[n]}`}formatDuration(t){if(!isFinite(t)||t<0)return"00:00";const e=Math.floor(t/3600),i=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}getFileExtension(t){const e=t.split(".");return e.length>1?`.${e[e.length-1].toLowerCase()}`:""}get width(){var t;return((t=this.info)==null?void 0:t.width)||0}get height(){var t;return((t=this.info)==null?void 0:t.height)||0}get aspectRatio(){var t;return((t=this.info)==null?void 0:t.aspectRatio)||"unknown"}get size(){var t;return((t=this.info)==null?void 0:t.size)||0}get sizeInBytes(){var t;return((t=this.info)==null?void 0:t.sizeInBytes)||0}get sizeFormatted(){var t;return((t=this.info)==null?void 0:t.sizeFormatted)||"0 Bytes"}get duration(){var t;return((t=this.info)==null?void 0:t.duration)||0}get durationInSeconds(){var t;return((t=this.info)==null?void 0:t.durationInSeconds)||0}get durationFormatted(){var t;return((t=this.info)==null?void 0:t.durationFormatted)||"00:00"}get mimeType(){var t;return((t=this.info)==null?void 0:t.mimeType)||this.file.type||"video/unknown"}get fileName(){return this.file.name}get fileExtension(){var t;return((t=this.info)==null?void 0:t.fileExtension)||""}get bitrate(){var t;return(t=this.info)==null?void 0:t.bitrate}get quality(){if(!this.info)return"unknown";const t=this.info.height;return t>=2160?"4K (2160p)":t>=1440?"2K (1440p)":t>=1080?"Full HD (1080p)":t>=720?"HD (720p)":t>=480?"SD (480p)":t>=360?"360p":"Low Quality"}getInfo(){return this.info}destroy(){this.videoElement&&(this.videoElement.remove(),this.videoElement=null),this.info=null}}const Z=l=>{const{src:t,autoplay:e,muted:i,controls:n=!0,poster:o,preload:r,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f,onReady:S,onPlay:x,onPause:C,onEnded:L,onTimeUpdate:T,onVolumeChange:I,onError:P,onLoadedMetadata:R,onQualityChange:M,style:U,className:H,width:y="100%",height:w="500px"}=l,b=h.useRef(null),q=h.useRef(null);return h.useEffect(()=>{if(!b.current)return;const W={src:t,container:b.current,autoplay:e,muted:i,controls:n,poster:o,preload:r,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:v,stickyControls:f},d=new E(W);return q.current=d,x&&d.on("play",x),C&&d.on("pause",C),L&&d.on("ended",L),P&&d.on("error",m=>{var A;return P((A=m.data)==null?void 0:A.error)}),R&&d.on("loadedmetadata",R),M&&d.on("qualitychange",m=>M(m.data.level)),T&&d.on("timeupdate",m=>T(m.data.currentTime)),I&&d.on("volumechange",m=>I(m.data.volume,m.data.muted)),S&&S(d),()=>{d.destroy(),q.current=null}},[t]),B.jsx("div",{ref:b,className:H,style:{width:typeof y=="number"?`${y}px`:y,height:typeof w=="number"?`${w}px`:w,...U}})},tt=l=>{const[t,e]=h.useState(null),[i,n]=h.useState(null),o=h.useRef(null);return h.useEffect(()=>{if(!o.current)return;const r=new E({...l,container:o.current});e(r);const a=()=>{n(r.getState())};return r.on("play",a),r.on("pause",a),r.on("timeupdate",a),r.on("volumechange",a),r.on("loadedmetadata",a),()=>{r.destroy()}},[l.src]),{containerRef:o,player:t,state:i}},D=F.createContext({player:null,state:null}),et=l=>{const{player:t,children:e}=l,[i,n]=h.useState(t.getState());return h.useEffect(()=>{const o=()=>{n(t.getState())};return t.on("play",o),t.on("pause",o),t.on("timeupdate",o),t.on("volumechange",o),t.on("loadedmetadata",o),()=>{}},[t]),B.jsx(D.Provider,{value:{player:t,state:i},children:e})},it=()=>{const l=F.useContext(D);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l};exports.Analytics=O;exports.S3Handler=z;exports.UIController=$;exports.WontumFileInfo=J;exports.WontumPlayer=E;exports.WontumPlayerProvider=et;exports.WontumPlayerReact=Z;exports.useWontumPlayer=tt;exports.useWontumPlayerContext=it;
|
|
598
|
+
</svg>`}getSettingsIcon(){return'<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>'}destroy(){this.hideControlsTimeout&&clearTimeout(this.hideControlsTimeout),this.controlsContainer.remove()}}class D{constructor(t){r(this,"config");r(this,"urlCache",new Map);r(this,"signedUrls",new Set);this.config=t}async processUrl(t){return this.isCloudFrontUrl(t)?this.signCloudFrontUrl(t):this.isS3Url(t)?this.getPresignedUrl(t):t}isCloudFrontUrl(t){var e;if(!((e=this.config)!=null&&e.cloudFrontDomains)||this.config.cloudFrontDomains.length===0)return!1;try{const i=new URL(t);return this.config.cloudFrontDomains.some(n=>i.hostname.includes(n))}catch{return!1}}isS3Url(t){return t.includes(".s3.")||t.includes("s3.amazonaws.com")||t.startsWith("s3://")}async signCloudFrontUrl(t,e=0){var o,s;if(this.signedUrls.has(t))return t;if((o=this.config)!=null&&o.signUrl)try{const a=await this.config.signUrl(t);return this.signedUrls.add(t),a}catch(a){const c=(a==null?void 0:a.name)==="AbortError"||((s=a==null?void 0:a.message)==null?void 0:s.includes("aborted"));if(c&&e<2)return console.warn(`Sign URL aborted, retrying (${e+1}/2)...`),await new Promise(u=>setTimeout(u,300)),this.signCloudFrontUrl(t,e+1);throw console.error("Failed to sign CloudFront URL:",a),c?new Error("Failed to sign CloudFront URL: Request was aborted. If using Apollo Client or other GraphQL clients, consider moving the query outside component lifecycle or using useQuery with skip option."):new Error(`Failed to sign CloudFront URL: ${(a==null?void 0:a.message)||"Unknown error"}`)}return console.warn("No signUrl function provided. CloudFront cookies may not be set."),t}extractS3Key(t){if(t.startsWith("s3://"))return t.replace("s3://","").split("/").slice(1).join("/");const e=t.match(/s3[.-]([^.]+)\.amazonaws\.com\/(.+)/);if(e)return e[2];const i=t.match(/([^.]+)\.s3\.amazonaws\.com\/(.+)/);return i?i[2]:t}async getPresignedUrl(t){var n;const e=this.extractS3Key(t),i=this.urlCache.get(e);if(i&&i.expiresAt>Date.now())return i.url;if((n=this.config)!=null&&n.getPresignedUrl)try{const o=await this.config.getPresignedUrl(e);return this.urlCache.set(e,{url:o,expiresAt:Date.now()+50*60*1e3}),o}catch(o){throw console.error("Failed to generate presigned URL:",o),new Error("Failed to generate presigned URL for S3 object")}return console.warn("No getPresignedUrl function provided. Using direct S3 URL (requires public bucket)"),t}static constructS3Url(t,e,i="us-east-1"){return`https://${t}.s3.${i}.amazonaws.com/${e}`}static parseS3Uri(t){if(!t.startsWith("s3://"))return null;const e=t.replace("s3://","").split("/"),i=e[0],n=e.slice(1).join("/");return{bucket:i,key:n}}clearCache(){this.urlCache.clear(),this.signedUrls.clear()}}class x{constructor(t){r(this,"container");r(this,"videoElement");r(this,"hls",null);r(this,"config");r(this,"eventListeners",new Map);r(this,"analytics");r(this,"s3Handler");r(this,"uiController");r(this,"qualities",[]);r(this,"state",{playing:!1,paused:!0,ended:!1,buffering:!1,currentTime:0,duration:0,volume:1,muted:!1,playbackRate:1,quality:"auto",availableQualities:[],fullscreen:!1});if(this.config=t,this.container=typeof t.container=="string"?document.querySelector(t.container):t.container,!this.container)throw new Error("Container element not found");this.analytics=new O(t.analytics),this.s3Handler=new D(t.s3Config),this.videoElement=this.createVideoElement(),this.container.appendChild(this.videoElement),this.uiController=new z(this.container,this),this.setupVideoListeners(),this.loadSource(t.src),t.autoplay&&(this.videoElement.autoplay=!0),t.muted&&this.mute(),t.poster&&(this.videoElement.poster=t.poster),t.preload&&(this.videoElement.preload=t.preload),t.subtitles&&this.addSubtitleTracks(t.subtitles)}addSubtitleTracks(t){t.forEach(e=>{const i=document.createElement("track");i.kind="subtitles",i.label=e.label,i.src=e.src,i.srclang=e.srclang,e.default&&(i.default=!0),this.videoElement.appendChild(i)})}createVideoElement(){const t=document.createElement("video");return t.className="wontum-player-video",t.style.width="100%",t.style.height="100%",t.playsInline=!0,t.crossOrigin="use-credentials",t}setupVideoListeners(){this.videoElement.addEventListener("play",()=>{this.state.playing=!0,this.state.paused=!1,this.emit("play"),this.analytics.trackEvent("play",this.getAnalyticsData())}),this.videoElement.addEventListener("pause",()=>{this.state.playing=!1,this.state.paused=!0,this.emit("pause"),this.analytics.trackEvent("pause",this.getAnalyticsData())}),this.videoElement.addEventListener("ended",()=>{this.state.ended=!0,this.state.playing=!1,this.emit("ended"),this.analytics.trackEvent("ended",this.getAnalyticsData())}),this.videoElement.addEventListener("timeupdate",()=>{this.state.currentTime=this.videoElement.currentTime,this.emit("timeupdate",{currentTime:this.state.currentTime})}),this.videoElement.addEventListener("loadedmetadata",()=>{this.state.duration=this.videoElement.duration,this.emit("loadedmetadata",{duration:this.state.duration}),this.analytics.trackEvent("loadedmetadata",this.getAnalyticsData())}),this.videoElement.addEventListener("volumechange",()=>{this.state.volume=this.videoElement.volume,this.state.muted=this.videoElement.muted,this.emit("volumechange",{volume:this.state.volume,muted:this.state.muted})}),this.videoElement.addEventListener("ratechange",()=>{this.state.playbackRate=this.videoElement.playbackRate,this.emit("ratechange",{playbackRate:this.state.playbackRate})}),this.videoElement.addEventListener("waiting",()=>{this.state.buffering=!0,this.emit("waiting"),this.analytics.trackEvent("buffering_start",this.getAnalyticsData())}),this.videoElement.addEventListener("canplay",()=>{this.state.buffering=!1,this.emit("canplay"),this.analytics.trackEvent("buffering_end",this.getAnalyticsData())}),this.videoElement.addEventListener("seeking",()=>{this.emit("seeking")}),this.videoElement.addEventListener("seeked",()=>{this.emit("seeked",{currentTime:this.state.currentTime}),this.analytics.trackEvent("seeked",this.getAnalyticsData())}),this.videoElement.addEventListener("error",t=>{const e=this.videoElement.error;this.emit("error",{error:e}),this.analytics.trackEvent("error",{...this.getAnalyticsData(),error:e==null?void 0:e.message})}),this.videoElement.addEventListener("loadstart",()=>{this.emit("loadstart")}),this.videoElement.addEventListener("loadeddata",()=>{this.emit("loadeddata")}),this.videoElement.addEventListener("canplaythrough",()=>{this.emit("canplaythrough")}),this.videoElement.addEventListener("playing",()=>{this.state.playing=!0,this.state.buffering=!1,this.emit("playing")}),this.videoElement.addEventListener("durationchange",()=>{this.state.duration=this.videoElement.duration,this.emit("durationchange",{duration:this.state.duration})}),this.videoElement.addEventListener("progress",()=>{this.emit("progress",{buffered:this.videoElement.buffered})}),this.videoElement.addEventListener("stalled",()=>{this.emit("stalled")}),this.videoElement.addEventListener("suspend",()=>{this.emit("suspend")}),this.videoElement.addEventListener("abort",()=>{this.emit("abort")}),this.videoElement.addEventListener("emptied",()=>{this.emit("emptied")}),this.videoElement.addEventListener("resize",()=>{this.emit("resize",{videoWidth:this.videoElement.videoWidth,videoHeight:this.videoElement.videoHeight})})}async loadSource(t){var e;try{const i=await this.s3Handler.processUrl(t);if(g.isSupported()){const n=((e=this.config.s3Config)==null?void 0:e.withCredentials)??!1,o={...this.config.hlsConfig,xhrSetup:(s,a)=>{var c;n&&(s.withCredentials=!0),(c=this.config.hlsConfig)!=null&&c.xhrSetup&&this.config.hlsConfig.xhrSetup(s,a)}};this.hls=new g(o),this.hls.loadSource(i),this.hls.attachMedia(this.videoElement),this.hls.on(g.Events.MANIFEST_PARSED,(s,a)=>{const c=this.extractQualities(a.levels);this.qualities=c}),this.hls.on(g.Events.LEVEL_SWITCHED,(s,a)=>{var u;const c=(u=this.hls)==null?void 0:u.levels[a.level];c&&(this.state.quality=`${c.height}p`,this.emit("qualitychange",{quality:this.state.quality}))}),this.hls.on(g.Events.ERROR,(s,a)=>{a.fatal&&this.handleHlsError(a)})}else if(this.videoElement.canPlayType("application/vnd.apple.mpegurl"))this.videoElement.src=i;else throw new Error("HLS is not supported in this browser")}catch(i){console.error("Failed to load video source:",i),this.emit("error",{error:i})}}extractQualities(t){return t.map(e=>({height:e.height,width:e.width,bitrate:e.bitrate,name:`${e.height}p`}))}handleHlsError(t){var e,i;switch(t.type){case g.ErrorTypes.NETWORK_ERROR:console.error("Network error occurred"),(e=this.hls)==null||e.startLoad();break;case g.ErrorTypes.MEDIA_ERROR:console.error("Media error occurred"),(i=this.hls)==null||i.recoverMediaError();break;default:console.error("Fatal error occurred:",t),this.destroy();break}}getAnalyticsData(){return{currentTime:this.state.currentTime,duration:this.state.duration,quality:this.state.quality,playbackRate:this.state.playbackRate,volume:this.state.volume,muted:this.state.muted}}play(){return this.videoElement.play()}pause(){this.videoElement.pause()}seek(t){this.videoElement.currentTime=t}skipForward(t=10){const e=Math.min(this.state.currentTime+t,this.state.duration);this.seek(e)}skipBackward(t=10){const e=Math.max(this.state.currentTime-t,0);this.seek(e)}setVolume(t){this.videoElement.volume=Math.max(0,Math.min(1,t))}mute(){this.videoElement.muted=!0}unmute(){this.videoElement.muted=!1}setPlaybackRate(t){this.videoElement.playbackRate=t}setQuality(t){this.hls&&(this.hls.currentLevel=t)}getQualities(){return this.qualities}enterFullscreen(){this.container.requestFullscreen&&(this.container.requestFullscreen(),this.state.fullscreen=!0,this.emit("fullscreenchange",{fullscreen:!0}))}exitFullscreen(){document.exitFullscreen&&(document.exitFullscreen(),this.state.fullscreen=!1,this.emit("fullscreenchange",{fullscreen:!1}))}async enterPictureInPicture(){if(document.pictureInPictureEnabled&&!this.videoElement.disablePictureInPicture)try{await this.videoElement.requestPictureInPicture(),this.emit("pictureinpictureenter",{})}catch(t){throw console.error("Failed to enter Picture-in-Picture:",t),t}}async exitPictureInPicture(){if(document.pictureInPictureElement)try{await document.exitPictureInPicture(),this.emit("pictureinpictureexit",{})}catch(t){throw console.error("Failed to exit Picture-in-Picture:",t),t}}async togglePictureInPicture(){document.pictureInPictureElement?await this.exitPictureInPicture():await this.enterPictureInPicture()}getState(){return{...this.state}}getVideoElement(){return this.videoElement}enableSubtitles(t){const e=this.videoElement.textTracks;for(let i=0;i<e.length;i++)e[i].mode=i===t?"showing":"hidden"}disableSubtitles(){const t=this.videoElement.textTracks;for(let e=0;e<t.length;e++)t[e].mode="hidden"}toggleSubtitles(){const t=this.videoElement.textTracks;return Array.from(t).some(i=>i.mode==="showing")?(this.disableSubtitles(),!1):t.length>0?(this.enableSubtitles(0),!0):!1}getSubtitleTracks(){return Array.from(this.videoElement.textTracks)}areSubtitlesEnabled(){const t=this.videoElement.textTracks;return Array.from(t).some(e=>e.mode==="showing")}on(t,e){this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e)}off(t,e){var i;(i=this.eventListeners.get(t))==null||i.delete(e)}emit(t,e){var n;const i={type:t,data:e,timestamp:Date.now()};(n=this.eventListeners.get(t))==null||n.forEach(o=>{o(i)})}destroy(){this.hls&&(this.hls.destroy(),this.hls=null),this.uiController.destroy(),this.videoElement.remove(),this.eventListeners.clear(),this.analytics.destroy()}}class J{constructor(t){r(this,"file");r(this,"videoElement",null);r(this,"audioContext",null);r(this,"info",null);if(!this.isVideoFile(t))throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);this.file=t}isVideoFile(t){if(t.type.startsWith("video/"))return!0;const e=[".mp4",".webm",".ogg",".mov",".avi",".mkv",".flv",".wmv",".m4v",".3gp",".ts",".m3u8"],i=t.name.toLowerCase();return e.some(n=>i.endsWith(n))}async extract(){return new Promise((t,e)=>{try{this.videoElement=document.createElement("video"),this.videoElement.preload="metadata",this.videoElement.muted=!0;const i=URL.createObjectURL(this.file);this.videoElement.onloadedmetadata=async()=>{try{if(!this.videoElement){e(new Error("Video element not initialized"));return}const n=this.videoElement.videoWidth,o=this.videoElement.videoHeight,s=this.videoElement.duration,a=this.calculateAspectRatio(n,o),c=this.file.size,u=this.formatBytes(c),p=this.formatDuration(s),y=this.getFileExtension(this.file.name),w=s>0?Math.round(c*8/s/1e3):void 0,f=await this.detectFrameRate(),v=await this.detectAudioInfo(i);this.info={width:n,height:o,aspectRatio:a,size:c,sizeInBytes:c,sizeFormatted:u,duration:s,durationInSeconds:s,durationFormatted:p,mimeType:this.file.type||"video/unknown",fileName:this.file.name,fileExtension:y,bitrate:w,frameRate:f,audioChannels:v.channels,hasAudio:v.hasAudio},URL.revokeObjectURL(i),this.videoElement.remove(),t(this.info)}catch(n){URL.revokeObjectURL(i),e(n)}},this.videoElement.onerror=()=>{URL.revokeObjectURL(i),e(new Error(`Failed to load video file: ${this.file.name}`))},this.videoElement.src=i}catch(i){e(i)}})}calculateAspectRatio(t,e){const i=this.getGCD(t,e),n=t/i,o=e/i,s=n/o;return Math.abs(s-16/9)<.01?"16:9":Math.abs(s-4/3)<.01?"4:3":Math.abs(s-21/9)<.01?"21:9":Math.abs(s-1)<.01?"1:1":`${n}:${o}`}async detectFrameRate(){if(this.videoElement)try{return"requestVideoFrameCallback"in this.videoElement?new Promise(t=>{let e=0,i=0;const n=10,o=(s,a)=>{if(!this.videoElement){t(void 0);return}if(e++,e===1)i=s,this.videoElement.requestVideoFrameCallback(o);else if(e<n)this.videoElement.requestVideoFrameCallback(o);else{const c=(s-i)/1e3,u=Math.round((e-1)/c);t(u)}};this.videoElement?(this.videoElement.currentTime=1,this.videoElement.play().catch(()=>t(void 0)),this.videoElement.requestVideoFrameCallback(o)):t(void 0)}):void 0}catch{return}}async detectAudioInfo(t){var e;if(!this.videoElement)return{hasAudio:!1};try{if(!(this.videoElement.mozHasAudio||(this.videoElement.webkitAudioDecodedByteCount??0)>0||(((e=this.videoElement.audioTracks)==null?void 0:e.length)??0)>0))return{hasAudio:!1};try{const n=window.AudioContext||window.webkitAudioContext;if(!n)return{hasAudio:!0};this.audioContext=new n;const o=this.audioContext.createMediaElementSource(this.videoElement),s=this.audioContext.createAnalyser();return o.connect(s),s.connect(this.audioContext.destination),{hasAudio:!0,channels:o.channelCount}}catch{return{hasAudio:!0}}}catch{return{hasAudio:!1}}}getGCD(t,e){return e===0?t:this.getGCD(e,t%e)}formatBytes(t){if(t===0)return"0 Bytes";const e=1024,i=["Bytes","KB","MB","GB","TB"],n=Math.floor(Math.log(t)/Math.log(e));return`${parseFloat((t/Math.pow(e,n)).toFixed(2))} ${i[n]}`}formatDuration(t){if(!isFinite(t)||t<0)return"00:00";const e=Math.floor(t/3600),i=Math.floor(t%3600/60),n=Math.floor(t%60);return e>0?`${e.toString().padStart(2,"0")}:${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`:`${i.toString().padStart(2,"0")}:${n.toString().padStart(2,"0")}`}getFileExtension(t){const e=t.split(".");return e.length>1?`.${e[e.length-1].toLowerCase()}`:""}get width(){var t;return((t=this.info)==null?void 0:t.width)||0}get height(){var t;return((t=this.info)==null?void 0:t.height)||0}get aspectRatio(){var t;return((t=this.info)==null?void 0:t.aspectRatio)||"unknown"}get size(){var t;return((t=this.info)==null?void 0:t.size)||0}get sizeInBytes(){var t;return((t=this.info)==null?void 0:t.sizeInBytes)||0}get sizeFormatted(){var t;return((t=this.info)==null?void 0:t.sizeFormatted)||"0 Bytes"}get duration(){var t;return((t=this.info)==null?void 0:t.duration)||0}get durationInSeconds(){var t;return((t=this.info)==null?void 0:t.durationInSeconds)||0}get durationFormatted(){var t;return((t=this.info)==null?void 0:t.durationFormatted)||"00:00"}get mimeType(){var t;return((t=this.info)==null?void 0:t.mimeType)||this.file.type||"video/unknown"}get fileName(){return this.file.name}get fileExtension(){var t;return((t=this.info)==null?void 0:t.fileExtension)||""}get bitrate(){var t;return(t=this.info)==null?void 0:t.bitrate}get frameRate(){var t;return(t=this.info)==null?void 0:t.frameRate}get audioChannels(){var t;return(t=this.info)==null?void 0:t.audioChannels}get hasAudio(){var t;return((t=this.info)==null?void 0:t.hasAudio)||!1}get quality(){if(!this.info)return"unknown";const t=this.info.height;return t>=2160?"4K (2160p)":t>=1440?"2K (1440p)":t>=1080?"Full HD (1080p)":t>=720?"HD (720p)":t>=480?"SD (480p)":t>=360?"360p":"Low Quality"}getInfo(){return this.info}destroy(){this.videoElement&&(this.videoElement.pause(),this.videoElement.remove(),this.videoElement=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.info=null}}const Z=l=>{const{src:t,autoplay:e,muted:i,controls:n=!0,poster:o,preload:s,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:y,stickyControls:w,onReady:f,onPlay:v,onPause:C,onEnded:L,onTimeUpdate:T,onVolumeChange:I,onError:A,onLoadedMetadata:R,onQualityChange:P,style:U,className:V,width:b="100%",height:k="500px"}=l,E=h.useRef(null),M=h.useRef(null);return h.useEffect(()=>{if(!E.current)return;const H={src:t,container:E.current,autoplay:e,muted:i,controls:n,poster:o,preload:s,theme:a,s3Config:c,analytics:u,hlsConfig:p,subtitles:y,stickyControls:w},d=new x(H);return M.current=d,v&&d.on("play",v),C&&d.on("pause",C),L&&d.on("ended",L),A&&d.on("error",m=>{var q;return A((q=m.data)==null?void 0:q.error)}),R&&d.on("loadedmetadata",R),P&&d.on("qualitychange",m=>P(m.data.level)),T&&d.on("timeupdate",m=>T(m.data.currentTime)),I&&d.on("volumechange",m=>I(m.data.volume,m.data.muted)),f&&f(d),()=>{d.destroy(),M.current=null}},[t]),F.jsx("div",{ref:E,className:V,style:{width:typeof b=="number"?`${b}px`:b,height:typeof k=="number"?`${k}px`:k,...U}})},tt=l=>{const[t,e]=h.useState(null),[i,n]=h.useState(null),o=h.useRef(null);return h.useEffect(()=>{if(!o.current)return;const s=new x({...l,container:o.current});e(s);const a=()=>{n(s.getState())};return s.on("play",a),s.on("pause",a),s.on("timeupdate",a),s.on("volumechange",a),s.on("loadedmetadata",a),()=>{s.destroy()}},[l.src]),{containerRef:o,player:t,state:i}},$=B.createContext({player:null,state:null}),et=l=>{const{player:t,children:e}=l,[i,n]=h.useState(t.getState());return h.useEffect(()=>{const o=()=>{n(t.getState())};return t.on("play",o),t.on("pause",o),t.on("timeupdate",o),t.on("volumechange",o),t.on("loadedmetadata",o),()=>{}},[t]),F.jsx($.Provider,{value:{player:t,state:i},children:e})},it=()=>{const l=B.useContext($);if(!l.player)throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");return l};exports.Analytics=O;exports.S3Handler=D;exports.UIController=z;exports.WontumFileInfo=J;exports.WontumPlayer=x;exports.WontumPlayerProvider=et;exports.WontumPlayerReact=Z;exports.useWontumPlayer=tt;exports.useWontumPlayerContext=it;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var V = Object.defineProperty;
|
|
2
|
+
var H = (c, t, e) => t in c ? V(c, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : c[t] = e;
|
|
3
|
+
var r = (c, t, e) => H(c, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import p from "hls.js";
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
7
|
-
import { useRef as
|
|
5
|
+
import { jsx as P } from "react/jsx-runtime";
|
|
6
|
+
import * as B from "react";
|
|
7
|
+
import { useRef as E, useEffect as x, useState as S } from "react";
|
|
8
8
|
class N {
|
|
9
9
|
constructor(t) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
r(this, "config");
|
|
11
|
+
r(this, "sessionId");
|
|
12
|
+
r(this, "events", []);
|
|
13
|
+
r(this, "sessionStartTime");
|
|
14
|
+
r(this, "playbackStartTime", null);
|
|
15
|
+
r(this, "totalPlayTime", 0);
|
|
16
|
+
r(this, "totalBufferTime", 0);
|
|
17
|
+
r(this, "bufferStartTime", null);
|
|
18
|
+
r(this, "rebufferCount", 0);
|
|
19
|
+
r(this, "seekCount", 0);
|
|
20
|
+
r(this, "webSocket", null);
|
|
21
|
+
r(this, "socketIO", null);
|
|
22
|
+
r(this, "wsReconnectTimeout", null);
|
|
23
|
+
r(this, "isDestroyed", !1);
|
|
24
24
|
var e, i;
|
|
25
25
|
if (this.config = t, this.sessionId = (t == null ? void 0 : t.sessionId) || this.generateSessionId(), this.sessionStartTime = Date.now(), (e = this.config) != null && e.webSocket) {
|
|
26
26
|
const n = this.config.webSocket;
|
|
@@ -195,32 +195,32 @@ class N {
|
|
|
195
195
|
}
|
|
196
196
|
class W {
|
|
197
197
|
constructor(t, e) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
198
|
+
r(this, "container");
|
|
199
|
+
r(this, "player");
|
|
200
|
+
r(this, "controlsContainer");
|
|
201
|
+
r(this, "progressContainer");
|
|
202
|
+
r(this, "progressBar");
|
|
203
|
+
r(this, "playButton");
|
|
204
|
+
r(this, "skipBackwardButton");
|
|
205
|
+
r(this, "skipForwardButton");
|
|
206
|
+
r(this, "volumeButton");
|
|
207
|
+
r(this, "volumeContainer");
|
|
208
|
+
r(this, "fullscreenButton");
|
|
209
|
+
r(this, "pipButton");
|
|
210
|
+
r(this, "settingsButton");
|
|
211
211
|
// private timeDisplay: HTMLElement
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
r(this, "volumeSlider");
|
|
213
|
+
r(this, "progressInput");
|
|
214
214
|
// private controlsVisible = true
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
r(this, "hideControlsTimeout", null);
|
|
216
|
+
r(this, "stickyControls", !1);
|
|
217
|
+
r(this, "isVolumeSliderActive", !1);
|
|
218
218
|
this.container = t, this.player = e, this.injectStyles(), this.createProgressBar(), this.controlsContainer = this.createControls(), this.container.appendChild(this.controlsContainer), this.playButton = this.controlsContainer.querySelector(".wontum-play-btn"), this.skipBackwardButton = this.controlsContainer.querySelector(".wontum-skip-backward-btn"), this.skipForwardButton = this.controlsContainer.querySelector(".wontum-skip-forward-btn"), this.volumeButton = this.controlsContainer.querySelector(".wontum-volume-btn"), this.volumeContainer = this.controlsContainer.querySelector(".wontum-volume-container"), this.fullscreenButton = this.controlsContainer.querySelector(".wontum-fullscreen-btn"), this.pipButton = this.controlsContainer.querySelector(".wontum-pip-btn"), this.settingsButton = this.controlsContainer.querySelector(".wontum-settings-btn"), this.volumeSlider = this.controlsContainer.querySelector(".wontum-volume-slider"), this.progressInput = this.container.querySelector(".wontum-progress-input"), this.progressBar = this.container.querySelector(".wontum-progress-filled"), this.stickyControls = this.player.config.stickyControls || !1, this.stickyControls && this.controlsContainer.classList.add("sticky"), this.setupEventListeners(), this.setupPlayerEventListeners();
|
|
219
219
|
}
|
|
220
220
|
injectStyles() {
|
|
221
221
|
const t = "wontum-player-styles";
|
|
222
222
|
if (document.getElementById(t)) return;
|
|
223
|
-
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = e.accentColor || "#2563eb", o = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
223
|
+
const e = this.player.config.theme || {}, i = e.primaryColor || "#3b82f6", n = e.accentColor || "#2563eb", o = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", s = e.controlsBackground || "linear-gradient(to top, rgba(0,0,0,0.8), transparent)", a = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", u = e.borderRadius || "4px", m = document.createElement("style");
|
|
224
224
|
m.id = t, m.textContent = `
|
|
225
225
|
.wontum-player-container {
|
|
226
226
|
position: relative;
|
|
@@ -229,7 +229,7 @@ class W {
|
|
|
229
229
|
overflow: hidden;
|
|
230
230
|
--primary-color: ${i};
|
|
231
231
|
--accent-color: ${n};
|
|
232
|
-
--controls-bg: ${
|
|
232
|
+
--controls-bg: ${s};
|
|
233
233
|
--button-hover: ${a};
|
|
234
234
|
--progress-height: ${l};
|
|
235
235
|
--border-radius: ${u};
|
|
@@ -803,7 +803,7 @@ class W {
|
|
|
803
803
|
}), this.skipForwardButton.addEventListener("click", () => {
|
|
804
804
|
this.player.skipForward(10);
|
|
805
805
|
}), this.progressInput.addEventListener("input", (i) => {
|
|
806
|
-
const n = i.target, o = parseFloat(n.value),
|
|
806
|
+
const n = i.target, o = parseFloat(n.value), s = this.player.getState(), a = o / 100 * s.duration;
|
|
807
807
|
this.player.seek(a);
|
|
808
808
|
}), this.volumeSlider.addEventListener("input", (i) => {
|
|
809
809
|
const n = i.target, o = parseFloat(n.value) / 100;
|
|
@@ -835,9 +835,9 @@ class W {
|
|
|
835
835
|
const t = this.controlsContainer.querySelectorAll(".wontum-tab");
|
|
836
836
|
t.forEach((i) => {
|
|
837
837
|
i.addEventListener("click", (n) => {
|
|
838
|
-
const o = n.currentTarget,
|
|
838
|
+
const o = n.currentTarget, s = o.getAttribute("data-tab");
|
|
839
839
|
t.forEach((u) => u.classList.remove("active")), o.classList.add("active"), this.controlsContainer.querySelectorAll(".wontum-tab-panel").forEach((u) => u.classList.remove("active"));
|
|
840
|
-
const l = this.controlsContainer.querySelector(`[data-panel="${
|
|
840
|
+
const l = this.controlsContainer.querySelector(`[data-panel="${s}"]`);
|
|
841
841
|
l == null || l.classList.add("active");
|
|
842
842
|
});
|
|
843
843
|
}), this.player.getVideoElement().addEventListener("click", () => {
|
|
@@ -893,8 +893,8 @@ class W {
|
|
|
893
893
|
).join("")}
|
|
894
894
|
`, t.querySelectorAll(".wontum-subtitle-option").forEach((n) => {
|
|
895
895
|
n.addEventListener("click", (o) => {
|
|
896
|
-
const
|
|
897
|
-
a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")),
|
|
896
|
+
const s = o.target, a = parseInt(s.dataset.track || "-1");
|
|
897
|
+
a === -1 ? this.player.disableSubtitles() : this.player.enableSubtitles(a), t.querySelectorAll(".wontum-subtitle-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
898
898
|
});
|
|
899
899
|
});
|
|
900
900
|
}
|
|
@@ -907,8 +907,8 @@ class W {
|
|
|
907
907
|
</div>
|
|
908
908
|
`
|
|
909
909
|
).join(""), t.querySelectorAll(".wontum-speed-option").forEach((o) => {
|
|
910
|
-
o.addEventListener("click", (
|
|
911
|
-
const a =
|
|
910
|
+
o.addEventListener("click", (s) => {
|
|
911
|
+
const a = s.target, l = parseFloat(a.dataset.speed || "1");
|
|
912
912
|
this.player.setPlaybackRate(l), t.querySelectorAll(".wontum-speed-option").forEach((u) => u.classList.remove("active")), a.classList.add("active");
|
|
913
913
|
});
|
|
914
914
|
});
|
|
@@ -941,8 +941,8 @@ class W {
|
|
|
941
941
|
).join("")}
|
|
942
942
|
`, e.querySelectorAll(".wontum-quality-option").forEach((n) => {
|
|
943
943
|
n.addEventListener("click", (o) => {
|
|
944
|
-
const
|
|
945
|
-
this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")),
|
|
944
|
+
const s = o.target, a = parseInt(s.dataset.quality || "-1");
|
|
945
|
+
this.player.setQuality(a), e.querySelectorAll(".wontum-quality-option").forEach((l) => l.classList.remove("active")), s.classList.add("active");
|
|
946
946
|
});
|
|
947
947
|
});
|
|
948
948
|
}
|
|
@@ -1009,9 +1009,9 @@ class W {
|
|
|
1009
1009
|
}
|
|
1010
1010
|
class _ {
|
|
1011
1011
|
constructor(t) {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1012
|
+
r(this, "config");
|
|
1013
|
+
r(this, "urlCache", /* @__PURE__ */ new Map());
|
|
1014
|
+
r(this, "signedUrls", /* @__PURE__ */ new Set());
|
|
1015
1015
|
this.config = t;
|
|
1016
1016
|
}
|
|
1017
1017
|
/**
|
|
@@ -1045,7 +1045,7 @@ class _ {
|
|
|
1045
1045
|
* The endpoint should set signed cookies and return the URL
|
|
1046
1046
|
*/
|
|
1047
1047
|
async signCloudFrontUrl(t, e = 0) {
|
|
1048
|
-
var o,
|
|
1048
|
+
var o, s;
|
|
1049
1049
|
if (this.signedUrls.has(t))
|
|
1050
1050
|
return t;
|
|
1051
1051
|
if ((o = this.config) != null && o.signUrl)
|
|
@@ -1053,7 +1053,7 @@ class _ {
|
|
|
1053
1053
|
const a = await this.config.signUrl(t);
|
|
1054
1054
|
return this.signedUrls.add(t), a;
|
|
1055
1055
|
} catch (a) {
|
|
1056
|
-
const l = (a == null ? void 0 : a.name) === "AbortError" || ((
|
|
1056
|
+
const l = (a == null ? void 0 : a.name) === "AbortError" || ((s = a == null ? void 0 : a.message) == null ? void 0 : s.includes("aborted"));
|
|
1057
1057
|
if (l && e < 2)
|
|
1058
1058
|
return console.warn(`Sign URL aborted, retrying (${e + 1}/2)...`), await new Promise((u) => setTimeout(u, 300)), this.signCloudFrontUrl(t, e + 1);
|
|
1059
1059
|
throw console.error("Failed to sign CloudFront URL:", a), l ? new Error(
|
|
@@ -1118,16 +1118,16 @@ class _ {
|
|
|
1118
1118
|
}
|
|
1119
1119
|
class $ {
|
|
1120
1120
|
constructor(t) {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1121
|
+
r(this, "container");
|
|
1122
|
+
r(this, "videoElement");
|
|
1123
|
+
r(this, "hls", null);
|
|
1124
|
+
r(this, "config");
|
|
1125
|
+
r(this, "eventListeners", /* @__PURE__ */ new Map());
|
|
1126
|
+
r(this, "analytics");
|
|
1127
|
+
r(this, "s3Handler");
|
|
1128
|
+
r(this, "uiController");
|
|
1129
|
+
r(this, "qualities", []);
|
|
1130
|
+
r(this, "state", {
|
|
1131
1131
|
playing: !1,
|
|
1132
1132
|
paused: !0,
|
|
1133
1133
|
ended: !1,
|
|
@@ -1215,19 +1215,19 @@ class $ {
|
|
|
1215
1215
|
if (p.isSupported()) {
|
|
1216
1216
|
const n = ((e = this.config.s3Config) == null ? void 0 : e.withCredentials) ?? !1, o = {
|
|
1217
1217
|
...this.config.hlsConfig,
|
|
1218
|
-
xhrSetup: (
|
|
1218
|
+
xhrSetup: (s, a) => {
|
|
1219
1219
|
var l;
|
|
1220
|
-
n && (
|
|
1220
|
+
n && (s.withCredentials = !0), (l = this.config.hlsConfig) != null && l.xhrSetup && this.config.hlsConfig.xhrSetup(s, a);
|
|
1221
1221
|
}
|
|
1222
1222
|
};
|
|
1223
|
-
this.hls = new p(o), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (
|
|
1223
|
+
this.hls = new p(o), this.hls.loadSource(i), this.hls.attachMedia(this.videoElement), this.hls.on(p.Events.MANIFEST_PARSED, (s, a) => {
|
|
1224
1224
|
const l = this.extractQualities(a.levels);
|
|
1225
1225
|
this.qualities = l;
|
|
1226
|
-
}), this.hls.on(p.Events.LEVEL_SWITCHED, (
|
|
1226
|
+
}), this.hls.on(p.Events.LEVEL_SWITCHED, (s, a) => {
|
|
1227
1227
|
var u;
|
|
1228
1228
|
const l = (u = this.hls) == null ? void 0 : u.levels[a.level];
|
|
1229
1229
|
l && (this.state.quality = `${l.height}p`, this.emit("qualitychange", { quality: this.state.quality }));
|
|
1230
|
-
}), this.hls.on(p.Events.ERROR, (
|
|
1230
|
+
}), this.hls.on(p.Events.ERROR, (s, a) => {
|
|
1231
1231
|
a.fatal && this.handleHlsError(a);
|
|
1232
1232
|
});
|
|
1233
1233
|
} else if (this.videoElement.canPlayType("application/vnd.apple.mpegurl"))
|
|
@@ -1397,9 +1397,10 @@ class $ {
|
|
|
1397
1397
|
}
|
|
1398
1398
|
class G {
|
|
1399
1399
|
constructor(t) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1400
|
+
r(this, "file");
|
|
1401
|
+
r(this, "videoElement", null);
|
|
1402
|
+
r(this, "audioContext", null);
|
|
1403
|
+
r(this, "info", null);
|
|
1403
1404
|
if (!this.isVideoFile(t))
|
|
1404
1405
|
throw new Error(`Invalid file type: ${t.type}. Expected a video file.`);
|
|
1405
1406
|
this.file = t;
|
|
@@ -1421,13 +1422,13 @@ class G {
|
|
|
1421
1422
|
try {
|
|
1422
1423
|
this.videoElement = document.createElement("video"), this.videoElement.preload = "metadata", this.videoElement.muted = !0;
|
|
1423
1424
|
const i = URL.createObjectURL(this.file);
|
|
1424
|
-
this.videoElement.onloadedmetadata = () => {
|
|
1425
|
+
this.videoElement.onloadedmetadata = async () => {
|
|
1425
1426
|
try {
|
|
1426
1427
|
if (!this.videoElement) {
|
|
1427
1428
|
e(new Error("Video element not initialized"));
|
|
1428
1429
|
return;
|
|
1429
1430
|
}
|
|
1430
|
-
const n = this.videoElement.videoWidth, o = this.videoElement.videoHeight,
|
|
1431
|
+
const n = this.videoElement.videoWidth, o = this.videoElement.videoHeight, s = this.videoElement.duration, a = this.calculateAspectRatio(n, o), l = this.file.size, u = this.formatBytes(l), m = this.formatDuration(s), f = this.getFileExtension(this.file.name), y = s > 0 ? Math.round(l * 8 / s / 1e3) : void 0, v = await this.detectFrameRate(), g = await this.detectAudioInfo(i);
|
|
1431
1432
|
this.info = {
|
|
1432
1433
|
width: n,
|
|
1433
1434
|
height: o,
|
|
@@ -1436,14 +1437,17 @@ class G {
|
|
|
1436
1437
|
sizeInBytes: l,
|
|
1437
1438
|
// raw value alias
|
|
1438
1439
|
sizeFormatted: u,
|
|
1439
|
-
duration:
|
|
1440
|
-
durationInSeconds:
|
|
1440
|
+
duration: s,
|
|
1441
|
+
durationInSeconds: s,
|
|
1441
1442
|
// raw value alias
|
|
1442
1443
|
durationFormatted: m,
|
|
1443
1444
|
mimeType: this.file.type || "video/unknown",
|
|
1444
1445
|
fileName: this.file.name,
|
|
1445
|
-
fileExtension:
|
|
1446
|
-
bitrate:
|
|
1446
|
+
fileExtension: f,
|
|
1447
|
+
bitrate: y,
|
|
1448
|
+
frameRate: v,
|
|
1449
|
+
audioChannels: g.channels,
|
|
1450
|
+
hasAudio: g.hasAudio
|
|
1447
1451
|
}, URL.revokeObjectURL(i), this.videoElement.remove(), t(this.info);
|
|
1448
1452
|
} catch (n) {
|
|
1449
1453
|
URL.revokeObjectURL(i), e(n);
|
|
@@ -1460,8 +1464,59 @@ class G {
|
|
|
1460
1464
|
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
1461
1465
|
*/
|
|
1462
1466
|
calculateAspectRatio(t, e) {
|
|
1463
|
-
const i = this.getGCD(t, e), n = t / i, o = e / i,
|
|
1464
|
-
return Math.abs(
|
|
1467
|
+
const i = this.getGCD(t, e), n = t / i, o = e / i, s = n / o;
|
|
1468
|
+
return Math.abs(s - 16 / 9) < 0.01 ? "16:9" : Math.abs(s - 4 / 3) < 0.01 ? "4:3" : Math.abs(s - 21 / 9) < 0.01 ? "21:9" : Math.abs(s - 1) < 0.01 ? "1:1" : `${n}:${o}`;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Detect frame rate by analyzing video playback
|
|
1472
|
+
*/
|
|
1473
|
+
async detectFrameRate() {
|
|
1474
|
+
if (this.videoElement)
|
|
1475
|
+
try {
|
|
1476
|
+
return "requestVideoFrameCallback" in this.videoElement ? new Promise((t) => {
|
|
1477
|
+
let e = 0, i = 0;
|
|
1478
|
+
const n = 10, o = (s, a) => {
|
|
1479
|
+
if (!this.videoElement) {
|
|
1480
|
+
t(void 0);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (e++, e === 1)
|
|
1484
|
+
i = s, this.videoElement.requestVideoFrameCallback(o);
|
|
1485
|
+
else if (e < n)
|
|
1486
|
+
this.videoElement.requestVideoFrameCallback(o);
|
|
1487
|
+
else {
|
|
1488
|
+
const l = (s - i) / 1e3, u = Math.round((e - 1) / l);
|
|
1489
|
+
t(u);
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
this.videoElement ? (this.videoElement.currentTime = 1, this.videoElement.play().catch(() => t(void 0)), this.videoElement.requestVideoFrameCallback(o)) : t(void 0);
|
|
1493
|
+
}) : void 0;
|
|
1494
|
+
} catch {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Detect audio channel information using Web Audio API
|
|
1500
|
+
*/
|
|
1501
|
+
async detectAudioInfo(t) {
|
|
1502
|
+
var e;
|
|
1503
|
+
if (!this.videoElement) return { hasAudio: !1 };
|
|
1504
|
+
try {
|
|
1505
|
+
if (!(this.videoElement.mozHasAudio || (this.videoElement.webkitAudioDecodedByteCount ?? 0) > 0 || (((e = this.videoElement.audioTracks) == null ? void 0 : e.length) ?? 0) > 0))
|
|
1506
|
+
return { hasAudio: !1 };
|
|
1507
|
+
try {
|
|
1508
|
+
const n = window.AudioContext || window.webkitAudioContext;
|
|
1509
|
+
if (!n)
|
|
1510
|
+
return { hasAudio: !0 };
|
|
1511
|
+
this.audioContext = new n();
|
|
1512
|
+
const o = this.audioContext.createMediaElementSource(this.videoElement), s = this.audioContext.createAnalyser();
|
|
1513
|
+
return o.connect(s), s.connect(this.audioContext.destination), { hasAudio: !0, channels: o.channelCount };
|
|
1514
|
+
} catch {
|
|
1515
|
+
return { hasAudio: !0 };
|
|
1516
|
+
}
|
|
1517
|
+
} catch {
|
|
1518
|
+
return { hasAudio: !1 };
|
|
1519
|
+
}
|
|
1465
1520
|
}
|
|
1466
1521
|
/**
|
|
1467
1522
|
* Get Greatest Common Divisor
|
|
@@ -1544,6 +1599,18 @@ class G {
|
|
|
1544
1599
|
var t;
|
|
1545
1600
|
return (t = this.info) == null ? void 0 : t.bitrate;
|
|
1546
1601
|
}
|
|
1602
|
+
get frameRate() {
|
|
1603
|
+
var t;
|
|
1604
|
+
return (t = this.info) == null ? void 0 : t.frameRate;
|
|
1605
|
+
}
|
|
1606
|
+
get audioChannels() {
|
|
1607
|
+
var t;
|
|
1608
|
+
return (t = this.info) == null ? void 0 : t.audioChannels;
|
|
1609
|
+
}
|
|
1610
|
+
get hasAudio() {
|
|
1611
|
+
var t;
|
|
1612
|
+
return ((t = this.info) == null ? void 0 : t.hasAudio) || !1;
|
|
1613
|
+
}
|
|
1547
1614
|
get quality() {
|
|
1548
1615
|
if (!this.info) return "unknown";
|
|
1549
1616
|
const t = this.info.height;
|
|
@@ -1559,7 +1626,8 @@ class G {
|
|
|
1559
1626
|
* Clean up resources
|
|
1560
1627
|
*/
|
|
1561
1628
|
destroy() {
|
|
1562
|
-
this.videoElement && (this.videoElement.remove(), this.videoElement = null), this.
|
|
1629
|
+
this.videoElement && (this.videoElement.pause(), this.videoElement.remove(), this.videoElement = null), this.audioContext && (this.audioContext.close().catch(() => {
|
|
1630
|
+
}), this.audioContext = null), this.info = null;
|
|
1563
1631
|
}
|
|
1564
1632
|
}
|
|
1565
1633
|
const K = (c) => {
|
|
@@ -1569,96 +1637,96 @@ const K = (c) => {
|
|
|
1569
1637
|
muted: i,
|
|
1570
1638
|
controls: n = !0,
|
|
1571
1639
|
poster: o,
|
|
1572
|
-
preload:
|
|
1640
|
+
preload: s,
|
|
1573
1641
|
theme: a,
|
|
1574
1642
|
s3Config: l,
|
|
1575
1643
|
analytics: u,
|
|
1576
1644
|
hlsConfig: m,
|
|
1577
|
-
subtitles:
|
|
1578
|
-
stickyControls:
|
|
1579
|
-
onReady:
|
|
1580
|
-
onPlay:
|
|
1645
|
+
subtitles: f,
|
|
1646
|
+
stickyControls: y,
|
|
1647
|
+
onReady: v,
|
|
1648
|
+
onPlay: g,
|
|
1581
1649
|
onPause: C,
|
|
1582
1650
|
onEnded: L,
|
|
1583
1651
|
onTimeUpdate: T,
|
|
1584
1652
|
onVolumeChange: I,
|
|
1585
|
-
onError:
|
|
1653
|
+
onError: A,
|
|
1586
1654
|
onLoadedMetadata: R,
|
|
1587
|
-
onQualityChange:
|
|
1655
|
+
onQualityChange: M,
|
|
1588
1656
|
style: D,
|
|
1589
1657
|
className: O,
|
|
1590
|
-
width:
|
|
1591
|
-
height:
|
|
1592
|
-
} = c,
|
|
1593
|
-
return
|
|
1594
|
-
if (!
|
|
1658
|
+
width: w = "100%",
|
|
1659
|
+
height: b = "500px"
|
|
1660
|
+
} = c, k = E(null), q = E(null);
|
|
1661
|
+
return x(() => {
|
|
1662
|
+
if (!k.current) return;
|
|
1595
1663
|
const U = {
|
|
1596
1664
|
src: t,
|
|
1597
|
-
container:
|
|
1665
|
+
container: k.current,
|
|
1598
1666
|
autoplay: e,
|
|
1599
1667
|
muted: i,
|
|
1600
1668
|
controls: n,
|
|
1601
1669
|
poster: o,
|
|
1602
|
-
preload:
|
|
1670
|
+
preload: s,
|
|
1603
1671
|
theme: a,
|
|
1604
1672
|
s3Config: l,
|
|
1605
1673
|
analytics: u,
|
|
1606
1674
|
hlsConfig: m,
|
|
1607
|
-
subtitles:
|
|
1608
|
-
stickyControls:
|
|
1675
|
+
subtitles: f,
|
|
1676
|
+
stickyControls: y
|
|
1609
1677
|
}, d = new $(U);
|
|
1610
|
-
return q.current = d,
|
|
1611
|
-
var
|
|
1612
|
-
return
|
|
1613
|
-
}), R && d.on("loadedmetadata", R),
|
|
1678
|
+
return q.current = d, g && d.on("play", g), C && d.on("pause", C), L && d.on("ended", L), A && d.on("error", (h) => {
|
|
1679
|
+
var F;
|
|
1680
|
+
return A((F = h.data) == null ? void 0 : F.error);
|
|
1681
|
+
}), R && d.on("loadedmetadata", R), M && d.on("qualitychange", (h) => M(h.data.level)), T && d.on("timeupdate", (h) => T(h.data.currentTime)), I && d.on("volumechange", (h) => I(h.data.volume, h.data.muted)), v && v(d), () => {
|
|
1614
1682
|
d.destroy(), q.current = null;
|
|
1615
1683
|
};
|
|
1616
|
-
}, [t]), /* @__PURE__ */
|
|
1684
|
+
}, [t]), /* @__PURE__ */ P(
|
|
1617
1685
|
"div",
|
|
1618
1686
|
{
|
|
1619
|
-
ref:
|
|
1687
|
+
ref: k,
|
|
1620
1688
|
className: O,
|
|
1621
1689
|
style: {
|
|
1622
|
-
width: typeof
|
|
1623
|
-
height: typeof
|
|
1690
|
+
width: typeof w == "number" ? `${w}px` : w,
|
|
1691
|
+
height: typeof b == "number" ? `${b}px` : b,
|
|
1624
1692
|
...D
|
|
1625
1693
|
}
|
|
1626
1694
|
}
|
|
1627
1695
|
);
|
|
1628
1696
|
}, J = (c) => {
|
|
1629
|
-
const [t, e] =
|
|
1630
|
-
return
|
|
1697
|
+
const [t, e] = S(null), [i, n] = S(null), o = E(null);
|
|
1698
|
+
return x(() => {
|
|
1631
1699
|
if (!o.current) return;
|
|
1632
|
-
const
|
|
1700
|
+
const s = new $({
|
|
1633
1701
|
...c,
|
|
1634
1702
|
container: o.current
|
|
1635
1703
|
});
|
|
1636
|
-
e(
|
|
1704
|
+
e(s);
|
|
1637
1705
|
const a = () => {
|
|
1638
|
-
n(
|
|
1706
|
+
n(s.getState());
|
|
1639
1707
|
};
|
|
1640
|
-
return
|
|
1641
|
-
|
|
1708
|
+
return s.on("play", a), s.on("pause", a), s.on("timeupdate", a), s.on("volumechange", a), s.on("loadedmetadata", a), () => {
|
|
1709
|
+
s.destroy();
|
|
1642
1710
|
};
|
|
1643
1711
|
}, [c.src]), {
|
|
1644
1712
|
containerRef: o,
|
|
1645
1713
|
player: t,
|
|
1646
1714
|
state: i
|
|
1647
1715
|
};
|
|
1648
|
-
}, z =
|
|
1716
|
+
}, z = B.createContext({
|
|
1649
1717
|
player: null,
|
|
1650
1718
|
state: null
|
|
1651
1719
|
}), Z = (c) => {
|
|
1652
|
-
const { player: t, children: e } = c, [i, n] =
|
|
1653
|
-
return
|
|
1720
|
+
const { player: t, children: e } = c, [i, n] = S(t.getState());
|
|
1721
|
+
return x(() => {
|
|
1654
1722
|
const o = () => {
|
|
1655
1723
|
n(t.getState());
|
|
1656
1724
|
};
|
|
1657
1725
|
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1658
1726
|
};
|
|
1659
|
-
}, [t]), /* @__PURE__ */
|
|
1727
|
+
}, [t]), /* @__PURE__ */ P(z.Provider, { value: { player: t, state: i }, children: e });
|
|
1660
1728
|
}, tt = () => {
|
|
1661
|
-
const c =
|
|
1729
|
+
const c = B.useContext(z);
|
|
1662
1730
|
if (!c.player)
|
|
1663
1731
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1664
1732
|
return c;
|
package/package.json
CHANGED