@obipascal/player 1.0.13 → 1.0.15
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/dist/index.d.ts +9 -1
- package/dist/wontum-player.cjs.js +1 -1
- package/dist/wontum-player.esm.js +10 -8
- package/package.json +7 -2
- package/dist/examples/cloudfront-example.d.ts +0 -25
- package/dist/examples/custom-themes.d.ts +0 -124
- package/dist/examples/events-demo.d.ts +0 -52
- package/dist/examples/public-stream-test.d.ts +0 -38
- package/dist/examples/react-examples.d.ts +0 -32
- package/dist/examples/vanilla-js-examples.d.ts +0 -56
- package/dist/src/analytics.d.ts +0 -36
- package/dist/src/file-info.d.ts +0 -101
- package/dist/src/index.d.ts +0 -9
- package/dist/src/player.d.ts +0 -74
- package/dist/src/react.d.ts +0 -104
- package/dist/src/s3-handler.d.ts +0 -95
- package/dist/src/types.d.ts +0 -161
- package/dist/src/ui-controller.d.ts +0 -49
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { WontumPlayer } from './player';
|
|
2
|
+
export { Analytics } from './analytics';
|
|
3
|
+
export { S3Handler } from './s3-handler';
|
|
4
|
+
export { UIController } from './ui-controller';
|
|
5
|
+
export { WontumFileInfo } from './file-info';
|
|
6
|
+
export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext, useVideoFileInfo, useAnalytics } from './react';
|
|
7
|
+
export type { WontumPlayerConfig, PlayerTheme, S3Config, AnalyticsConfig, WebSocketAnalyticsHandler, SocketIOAnalyticsHandler, PlayerState, PlayerEvent, PlayerEventType, AnalyticsEvent, QualityLevel, } from './types';
|
|
8
|
+
export type { VideoFileInfo } from './file-info';
|
|
9
|
+
export type { WontumPlayerReactProps, UseVideoFileInfoResult, UseAnalyticsResult } from './react';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var j=Object.create;var q=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var K=(l,t,e)=>t in l?q(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var J=(l,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Y(t))!G.call(l,i)&&i!==e&&q(l,i,{get:()=>t[i],enumerable:!(n=Q(t,i))||n.enumerable});return l};var Z=(l,t,e)=>(e=l!=null?j(X(l)):{},J(t||!l||!l.__esModule?q(e,"default",{value:l,enumerable:!0}):e,l));var a=(l,t,e)=>K(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("hls.js"),O=require("react/jsx-runtime"),d=require("react");function tt(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,n.get?n:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const z=tt(d);class F{constructor(t){a(this,"config");a(this,"sessionId");a(this,"events",[]);a(this,"sessionStartTime");a(this,"playbackStartTime",null);a(this,"totalPlayTime",0);a(this,"totalBufferTime",0);a(this,"bufferStartTime",null);a(this,"rebufferCount",0);a(this,"seekCount",0);a(this,"webSocket",null);a(this,"socketIO",null);a(this,"wsReconnectTimeout",null);a(this,"isDestroyed",!1);var e,n;if(this.config=t,this.sessionId=(t==null?void 0:t.sessionId)||this.generateSessionId(),this.sessionStartTime=Date.now(),(e=this.config)!=null&&e.webSocket){const i=this.config.webSocket;"type"in i?i.type==="socket.io"?this.initializeSocketIO():this.initializeWebSocket():this.initializeWebSocket()}(n=this.config)!=null&&n.enabled&&this.trackEvent("session_start",this.getSessionData())}trackEvent(t,e={}){var i;if(!((i=this.config)!=null&&i.enabled))return;const n={eventType:t,timestamp:Date.now(),sessionId:this.sessionId,videoId:this.config.videoId,userId:this.config.userId,data:{...e,...this.getQoEMetrics()}};this.events.push(n),this.updateMetrics(t,e),this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&this.sendToWebSocket(n),this.socketIO&&this.socketIO.connected&&this.sendToSocketIO(n),this.config.endpoint&&this.sendEvent(n),process.env.NODE_ENV==="development"&&console.log("[Analytics]",t,n.data)}updateMetrics(t,e){switch(t){case"play":this.playbackStartTime=Date.now();break;case"pause":case"ended":this.playbackStartTime&&(this.totalPlayTime+=Date.now()-this.playbackStartTime,this.playbackStartTime=null);break;case"buffering_start":this.bufferStartTime=Date.now(),this.rebufferCount++;break;case"buffering_end":this.bufferStartTime&&(this.totalBufferTime+=Date.now()-this.bufferStartTime,this.bufferStartTime=null);break;case"seeked":this.seekCount++;break}}getQoEMetrics(){const t=Date.now()-this.sessionStartTime,e=this.totalPlayTime>0?this.totalBufferTime/this.totalPlayTime:0;return{sessionDuration:t,totalPlayTime:this.totalPlayTime,totalBufferTime:this.totalBufferTime,bufferingRatio:Math.round(e*1e3)/1e3,rebufferCount:this.rebufferCount,seekCount:this.seekCount}}getSessionData(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenResolution:`${screen.width}x${screen.height}`,viewport:`${window.innerWidth}x${window.innerHeight}`,connection:this.getConnectionInfo()}}getConnectionInfo(){const t=navigator,e=t.connection||t.mozConnection||t.webkitConnection;return e?{effectiveType:e.effectiveType,downlink:e.downlink,rtt:e.rtt,saveData:e.saveData}:null}async sendEvent(t){var e;if((e=this.config)!=null&&e.endpoint)try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(n){console.error("Failed to send analytics event:",n)}}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async initializeSocketIO(){var e;if(!((e=this.config)!=null&&e.webSocket)||!("type"in this.config.webSocket))return;const t=this.config.webSocket;if(t.type==="socket.io")try{if(typeof t.connection=="string"){const i=(await import("socket.io-client")).default;this.socketIO=i(t.connection,t.options||{})}else this.socketIO=t.connection;if(!this.socketIO)return;this.socketIO.on("connect",()=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Connected"),t.onConnect&&t.onConnect()}),this.socketIO.on("connect_error",n=>{console.error("[Analytics Socket.IO] Connection error:",n),t.onError&&t.onError(n)}),this.socketIO.on("disconnect",n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Disconnected:",n),t.onDisconnect&&t.onDisconnect(n)}),this.socketIO.on("error",n=>{console.error("[Analytics Socket.IO] Error:",n),t.onError&&t.onError(n)})}catch(n){console.error("[Analytics Socket.IO] Failed to initialize:",n)}}sendToSocketIO(t){var e;if(!(!this.socketIO||!this.socketIO.connected))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t,o=(n==null?void 0:n.eventName)||"analytics";this.socketIO.emit(o,i),process.env.NODE_ENV==="development"&&console.log(`[Analytics Socket.IO] Emitted (${o}):`,t.eventType)}catch(n){console.error("[Analytics Socket.IO] Failed to emit event:",n)}}initializeWebSocket(){var e;if(!((e=this.config)!=null&&e.webSocket))return;const t=this.config.webSocket;try{typeof t.connection=="string"?this.webSocket=new WebSocket(t.connection):this.webSocket=t.connection,this.webSocket.onopen=n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Connected"),t.onOpen&&t.onOpen(n)},this.webSocket.onerror=n=>{console.error("[Analytics WebSocket] Error:",n),t.onError&&t.onError(n)},this.webSocket.onclose=n=>{if(process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Disconnected"),t.onClose&&t.onClose(n),t.autoReconnect!==!1&&!this.isDestroyed){const o=t.reconnectDelay||3e3;process.env.NODE_ENV==="development"&&console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`),this.wsReconnectTimeout=window.setTimeout(()=>{this.initializeWebSocket()},o)}}}catch(n){console.error("[Analytics WebSocket] Failed to initialize:",n)}}sendToWebSocket(t){var e;if(!(!this.webSocket||this.webSocket.readyState!==WebSocket.OPEN))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t;this.webSocket.send(JSON.stringify(i)),process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Sent:",t.eventType)}catch(n){console.error("[Analytics WebSocket] Failed to send event:",n)}}getEvents(){return[...this.events]}getMetrics(){return{sessionId:this.sessionId,...this.getQoEMetrics(),eventCount:this.events.length}}destroy(){var t;this.isDestroyed=!0,(t=this.config)!=null&&t.enabled&&this.trackEvent("session_end",this.getSessionData()),this.wsReconnectTimeout&&(clearTimeout(this.wsReconnectTimeout),this.wsReconnectTimeout=null),this.webSocket&&(this.webSocket.close(),this.webSocket=null),this.socketIO&&(this.socketIO.removeAllListeners(),this.socketIO.disconnect(),this.socketIO=null),this.events=[]}}class D{constructor(t,e){a(this,"container");a(this,"player");a(this,"controlsContainer");a(this,"progressContainer");a(this,"progressBar");a(this,"playButton");a(this,"skipBackwardButton");a(this,"skipForwardButton");a(this,"volumeButton");a(this,"volumeContainer");a(this,"fullscreenButton");a(this,"pipButton");a(this,"settingsButton");a(this,"volumeSlider");a(this,"progressInput");a(this,"hideControlsTimeout",null);a(this,"stickyControls",!1);a(this,"isVolumeSliderActive",!1);this.container=t,this.player=e,this.injectStyles(),this.createProgressBar(),this.controlsContainer=this.createControls(),this.container.appendChild(this.controlsContainer),this.playButton=this.controlsContainer.querySelector(".wontum-play-btn"),this.skipBackwardButton=this.controlsContainer.querySelector(".wontum-skip-backward-btn"),this.skipForwardButton=this.controlsContainer.querySelector(".wontum-skip-forward-btn"),this.volumeButton=this.controlsContainer.querySelector(".wontum-volume-btn"),this.volumeContainer=this.controlsContainer.querySelector(".wontum-volume-container"),this.fullscreenButton=this.controlsContainer.querySelector(".wontum-fullscreen-btn"),this.pipButton=this.controlsContainer.querySelector(".wontum-pip-btn"),this.settingsButton=this.controlsContainer.querySelector(".wontum-settings-btn"),this.volumeSlider=this.controlsContainer.querySelector(".wontum-volume-slider"),this.progressInput=this.container.querySelector(".wontum-progress-input"),this.progressBar=this.container.querySelector(".wontum-progress-filled"),this.stickyControls=this.player.config.stickyControls||!1,this.stickyControls&&this.controlsContainer.classList.add("sticky"),this.setupEventListeners(),this.setupPlayerEventListeners()}injectStyles(){const t="wontum-player-styles";if(
|
|
1
|
+
"use strict";var j=Object.create;var q=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var K=(l,t,e)=>t in l?q(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var J=(l,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Y(t))!G.call(l,i)&&i!==e&&q(l,i,{get:()=>t[i],enumerable:!(n=Q(t,i))||n.enumerable});return l};var Z=(l,t,e)=>(e=l!=null?j(X(l)):{},J(t||!l||!l.__esModule?q(e,"default",{value:l,enumerable:!0}):e,l));var a=(l,t,e)=>K(l,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("hls.js"),O=require("react/jsx-runtime"),d=require("react");function tt(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,n.get?n:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const z=tt(d);class F{constructor(t){a(this,"config");a(this,"sessionId");a(this,"events",[]);a(this,"sessionStartTime");a(this,"playbackStartTime",null);a(this,"totalPlayTime",0);a(this,"totalBufferTime",0);a(this,"bufferStartTime",null);a(this,"rebufferCount",0);a(this,"seekCount",0);a(this,"webSocket",null);a(this,"socketIO",null);a(this,"wsReconnectTimeout",null);a(this,"isDestroyed",!1);var e,n;if(this.config=t,this.sessionId=(t==null?void 0:t.sessionId)||this.generateSessionId(),this.sessionStartTime=Date.now(),(e=this.config)!=null&&e.webSocket){const i=this.config.webSocket;"type"in i?i.type==="socket.io"?this.initializeSocketIO():this.initializeWebSocket():this.initializeWebSocket()}(n=this.config)!=null&&n.enabled&&this.trackEvent("session_start",this.getSessionData())}trackEvent(t,e={}){var i;if(!((i=this.config)!=null&&i.enabled))return;const n={eventType:t,timestamp:Date.now(),sessionId:this.sessionId,videoId:this.config.videoId,userId:this.config.userId,data:{...e,...this.getQoEMetrics()}};this.events.push(n),this.updateMetrics(t,e),this.webSocket&&this.webSocket.readyState===WebSocket.OPEN&&this.sendToWebSocket(n),this.socketIO&&this.socketIO.connected&&this.sendToSocketIO(n),this.config.endpoint&&this.sendEvent(n),process.env.NODE_ENV==="development"&&console.log("[Analytics]",t,n.data)}updateMetrics(t,e){switch(t){case"play":this.playbackStartTime=Date.now();break;case"pause":case"ended":this.playbackStartTime&&(this.totalPlayTime+=Date.now()-this.playbackStartTime,this.playbackStartTime=null);break;case"buffering_start":this.bufferStartTime=Date.now(),this.rebufferCount++;break;case"buffering_end":this.bufferStartTime&&(this.totalBufferTime+=Date.now()-this.bufferStartTime,this.bufferStartTime=null);break;case"seeked":this.seekCount++;break}}getQoEMetrics(){const t=Date.now()-this.sessionStartTime,e=this.totalPlayTime>0?this.totalBufferTime/this.totalPlayTime:0;return{sessionDuration:t,totalPlayTime:this.totalPlayTime,totalBufferTime:this.totalBufferTime,bufferingRatio:Math.round(e*1e3)/1e3,rebufferCount:this.rebufferCount,seekCount:this.seekCount}}getSessionData(){return{userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,screenResolution:`${screen.width}x${screen.height}`,viewport:`${window.innerWidth}x${window.innerHeight}`,connection:this.getConnectionInfo()}}getConnectionInfo(){const t=navigator,e=t.connection||t.mozConnection||t.webkitConnection;return e?{effectiveType:e.effectiveType,downlink:e.downlink,rtt:e.rtt,saveData:e.saveData}:null}async sendEvent(t){var e;if((e=this.config)!=null&&e.endpoint)try{await fetch(this.config.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(n){console.error("Failed to send analytics event:",n)}}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async initializeSocketIO(){var e;if(!((e=this.config)!=null&&e.webSocket)||!("type"in this.config.webSocket))return;const t=this.config.webSocket;if(t.type==="socket.io")try{if(typeof t.connection=="string"){const i=(await import("socket.io-client")).default;this.socketIO=i(t.connection,t.options||{})}else this.socketIO=t.connection;if(!this.socketIO)return;this.socketIO.on("connect",()=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Connected"),t.onConnect&&t.onConnect()}),this.socketIO.on("connect_error",n=>{console.error("[Analytics Socket.IO] Connection error:",n),t.onError&&t.onError(n)}),this.socketIO.on("disconnect",n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics Socket.IO] Disconnected:",n),t.onDisconnect&&t.onDisconnect(n)}),this.socketIO.on("error",n=>{console.error("[Analytics Socket.IO] Error:",n),t.onError&&t.onError(n)})}catch(n){console.error("[Analytics Socket.IO] Failed to initialize:",n)}}sendToSocketIO(t){var e;if(!(!this.socketIO||!this.socketIO.connected))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t,o=(n==null?void 0:n.eventName)||"analytics";this.socketIO.emit(o,i),process.env.NODE_ENV==="development"&&console.log(`[Analytics Socket.IO] Emitted (${o}):`,t.eventType)}catch(n){console.error("[Analytics Socket.IO] Failed to emit event:",n)}}initializeWebSocket(){var e;if(!((e=this.config)!=null&&e.webSocket))return;const t=this.config.webSocket;try{typeof t.connection=="string"?this.webSocket=new WebSocket(t.connection):this.webSocket=t.connection,this.webSocket.onopen=n=>{process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Connected"),t.onOpen&&t.onOpen(n)},this.webSocket.onerror=n=>{console.error("[Analytics WebSocket] Error:",n),t.onError&&t.onError(n)},this.webSocket.onclose=n=>{if(process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Disconnected"),t.onClose&&t.onClose(n),t.autoReconnect!==!1&&!this.isDestroyed){const o=t.reconnectDelay||3e3;process.env.NODE_ENV==="development"&&console.log(`[Analytics WebSocket] Reconnecting in ${o}ms...`),this.wsReconnectTimeout=window.setTimeout(()=>{this.initializeWebSocket()},o)}}}catch(n){console.error("[Analytics WebSocket] Failed to initialize:",n)}}sendToWebSocket(t){var e;if(!(!this.webSocket||this.webSocket.readyState!==WebSocket.OPEN))try{const n=(e=this.config)==null?void 0:e.webSocket,i=n!=null&&n.transform?n.transform(t):t;this.webSocket.send(JSON.stringify(i)),process.env.NODE_ENV==="development"&&console.log("[Analytics WebSocket] Sent:",t.eventType)}catch(n){console.error("[Analytics WebSocket] Failed to send event:",n)}}getEvents(){return[...this.events]}getMetrics(){return{sessionId:this.sessionId,...this.getQoEMetrics(),eventCount:this.events.length}}destroy(){var t;this.isDestroyed=!0,(t=this.config)!=null&&t.enabled&&this.trackEvent("session_end",this.getSessionData()),this.wsReconnectTimeout&&(clearTimeout(this.wsReconnectTimeout),this.wsReconnectTimeout=null),this.webSocket&&(this.webSocket.close(),this.webSocket=null),this.socketIO&&(this.socketIO.removeAllListeners(),this.socketIO.disconnect(),this.socketIO=null),this.events=[]}}class D{constructor(t,e){a(this,"container");a(this,"player");a(this,"controlsContainer");a(this,"progressContainer");a(this,"progressBar");a(this,"playButton");a(this,"skipBackwardButton");a(this,"skipForwardButton");a(this,"volumeButton");a(this,"volumeContainer");a(this,"fullscreenButton");a(this,"pipButton");a(this,"settingsButton");a(this,"volumeSlider");a(this,"progressInput");a(this,"hideControlsTimeout",null);a(this,"stickyControls",!1);a(this,"isVolumeSliderActive",!1);if(this.container=t,this.player=e,this.container.classList.add("wontum-player-container"),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.playButton||!this.progressInput||!this.progressBar)throw console.error("Failed to query UI elements. Container:",this.container),new Error("Failed to initialize UI controller - elements not found");this.stickyControls=this.player.config.stickyControls||!1,this.stickyControls&&this.controlsContainer.classList.add("sticky"),this.setupEventListeners(),this.setupPlayerEventListeners()}injectStyles(){const t="wontum-player-styles";if(document.getElementById(t))return;const e=this.player.config.theme||{},n=e.primaryColor||"#3b82f6",i=e.accentColor||"#2563eb",o=e.fontFamily||"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",s=e.controlsBackground||"linear-gradient(to top, rgba(0,0,0,0.8), transparent)",r=e.buttonHoverBg||"rgba(255, 255, 255, 0.1)",c=e.progressHeight||"6px",u=e.borderRadius||"4px",h=document.createElement("style");h.id=t,h.textContent=`
|
|
2
2
|
.wontum-player-container {
|
|
3
3
|
position: relative;
|
|
4
4
|
background: #000;
|
|
@@ -2,8 +2,8 @@ var _ = Object.defineProperty;
|
|
|
2
2
|
var j = (u, t, e) => t in u ? _(u, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : u[t] = e;
|
|
3
3
|
var a = (u, t, e) => j(u, typeof t != "symbol" ? t + "" : t, e);
|
|
4
4
|
import y from "hls.js";
|
|
5
|
-
import { jsx as
|
|
6
|
-
import * as
|
|
5
|
+
import { jsx as z } from "react/jsx-runtime";
|
|
6
|
+
import * as $ from "react";
|
|
7
7
|
import { useRef as E, useEffect as S, useState as v, useCallback as L } from "react";
|
|
8
8
|
class O {
|
|
9
9
|
constructor(t) {
|
|
@@ -215,11 +215,13 @@ class Q {
|
|
|
215
215
|
a(this, "hideControlsTimeout", null);
|
|
216
216
|
a(this, "stickyControls", !1);
|
|
217
217
|
a(this, "isVolumeSliderActive", !1);
|
|
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.
|
|
218
|
+
if (this.container = t, this.player = e, this.container.classList.add("wontum-player-container"), 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.playButton || !this.progressInput || !this.progressBar)
|
|
219
|
+
throw console.error("Failed to query UI elements. Container:", this.container), new Error("Failed to initialize UI controller - elements not found");
|
|
220
|
+
this.stickyControls = this.player.config.stickyControls || !1, this.stickyControls && this.controlsContainer.classList.add("sticky"), this.setupEventListeners(), this.setupPlayerEventListeners();
|
|
219
221
|
}
|
|
220
222
|
injectStyles() {
|
|
221
223
|
const t = "wontum-player-styles";
|
|
222
|
-
if (
|
|
224
|
+
if (document.getElementById(t)) return;
|
|
223
225
|
const e = this.player.config.theme || {}, n = e.primaryColor || "#3b82f6", i = e.accentColor || "#2563eb", o = e.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", s = e.controlsBackground || "linear-gradient(to top, rgba(0,0,0,0.8), transparent)", r = e.buttonHoverBg || "rgba(255, 255, 255, 0.1)", l = e.progressHeight || "6px", c = e.borderRadius || "4px", d = document.createElement("style");
|
|
224
226
|
d.id = t, d.textContent = `
|
|
225
227
|
.wontum-player-container {
|
|
@@ -1715,7 +1717,7 @@ const tt = (u) => {
|
|
|
1715
1717
|
A,
|
|
1716
1718
|
R,
|
|
1717
1719
|
b
|
|
1718
|
-
]), /* @__PURE__ */
|
|
1720
|
+
]), /* @__PURE__ */ z(
|
|
1719
1721
|
"div",
|
|
1720
1722
|
{
|
|
1721
1723
|
ref: f,
|
|
@@ -1747,7 +1749,7 @@ const tt = (u) => {
|
|
|
1747
1749
|
player: t,
|
|
1748
1750
|
state: n
|
|
1749
1751
|
};
|
|
1750
|
-
}, U =
|
|
1752
|
+
}, U = $.createContext({
|
|
1751
1753
|
player: null,
|
|
1752
1754
|
state: null
|
|
1753
1755
|
}), nt = (u) => {
|
|
@@ -1758,9 +1760,9 @@ const tt = (u) => {
|
|
|
1758
1760
|
};
|
|
1759
1761
|
return t.on("play", o), t.on("pause", o), t.on("timeupdate", o), t.on("volumechange", o), t.on("loadedmetadata", o), () => {
|
|
1760
1762
|
};
|
|
1761
|
-
}, [t]), /* @__PURE__ */
|
|
1763
|
+
}, [t]), /* @__PURE__ */ z(U.Provider, { value: { player: t, state: n }, children: e });
|
|
1762
1764
|
}, it = () => {
|
|
1763
|
-
const u =
|
|
1765
|
+
const u = $.useContext(U);
|
|
1764
1766
|
if (!u.player)
|
|
1765
1767
|
throw new Error("useWontumPlayerContext must be used within WontumPlayerProvider");
|
|
1766
1768
|
return u;
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obipascal/player",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "A modern HLS video player SDK for educational platforms with S3 integration",
|
|
5
5
|
"main": "dist/wontum-player.cjs.js",
|
|
6
6
|
"module": "dist/wontum-player.esm.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist/wontum-player.esm.js",
|
|
10
|
+
"dist/wontum-player.cjs.js",
|
|
11
|
+
"dist/index.d.ts",
|
|
12
|
+
"dist/src/**/*.d.ts",
|
|
13
|
+
"!dist/src/test-app.d.ts",
|
|
14
|
+
"!dist/examples"
|
|
10
15
|
],
|
|
11
16
|
"scripts": {
|
|
12
17
|
"dev": "vite",
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example 1: Basic CloudFront Setup
|
|
5
|
-
*/
|
|
6
|
-
export declare function basicCloudFrontExample(): WontumPlayer;
|
|
7
|
-
/**
|
|
8
|
-
* Example 2: With Error Handling and Retry
|
|
9
|
-
*/
|
|
10
|
-
export declare function cloudFrontWithRetryExample(): WontumPlayer;
|
|
11
|
-
/**
|
|
12
|
-
* Example 3: React Component with CloudFront
|
|
13
|
-
*
|
|
14
|
-
* Note: This is a code example as a string. For actual React usage,
|
|
15
|
-
* copy this to a .tsx file in your project.
|
|
16
|
-
*/
|
|
17
|
-
export declare const ReactCloudFrontPlayerExample = "\nimport React from \"react\"\nimport { WontumPlayerReact } from \"@obipascal/player\"\n\nexport function CloudFrontPlayer({ videoUrl, userId }: { videoUrl: string; userId: string }) {\n\t// Sign URL function\n\tasync function signUrl(url: string): Promise<string> {\n\t\tconst response = await fetch(\"/api/cloudfront/sign\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ url, userId }),\n\t\t\tcredentials: \"include\",\n\t\t})\n\n\t\tconst data = await response.json()\n\t\treturn data.url\n\t}\n\n\treturn (\n\t\t<WontumPlayerReact\n\t\t\tsrc={videoUrl}\n\t\t\twidth=\"100%\"\n\t\t\theight=\"500px\"\n\t\t\ts3Config={{\n\t\t\t\tsignUrl,\n\t\t\t\tcloudFrontDomains: [\"media.domain.com\", \"cdn.domain.com\"], // Multiple domains\n\t\t\t}}\n\t\t\tanalytics={{\n\t\t\t\tenabled: true,\n\t\t\t\tuserId,\n\t\t\t\tvideoId: videoUrl,\n\t\t\t}}\n\t\t\tonError={(error) => {\n\t\t\t\tconsole.error(\"Player error:\", error)\n\t\t\t\t// Handle signing errors\n\t\t\t\tif (error?.message?.includes(\"sign\")) {\n\t\t\t\t\talert(\"Failed to authenticate video. Please refresh and try again.\")\n\t\t\t\t}\n\t\t\t}}\n\t\t/>\n\t)\n}\n";
|
|
18
|
-
/**
|
|
19
|
-
* Example 4: Backend Implementation (Node.js/Express)
|
|
20
|
-
*/
|
|
21
|
-
export declare const backendExample = "\n// backend/routes/cloudfront.js\nconst express = require('express');\nconst AWS = require('aws-sdk');\nconst router = express.Router();\n\n// Initialize CloudFront signer\nconst cloudFront = new AWS.CloudFront.Signer(\n process.env.CLOUDFRONT_KEY_PAIR_ID,\n process.env.CLOUDFRONT_PRIVATE_KEY\n);\n\n// Middleware to verify user authentication\nfunction requireAuth(req, res, next) {\n if (!req.user) {\n return res.status(401).json({ error: 'Unauthorized' });\n }\n next();\n}\n\n// Middleware to verify user has access to video\nasync function verifyVideoAccess(req, res, next) {\n const { url } = req.body;\n const userId = req.user.id;\n \n // Extract video ID from URL\n const videoId = extractVideoIdFromUrl(url);\n \n // Check database if user has access\n const hasAccess = await checkUserVideoAccess(userId, videoId);\n \n if (!hasAccess) {\n return res.status(403).json({ error: 'Access denied to this video' });\n }\n \n next();\n}\n\n// Sign CloudFront URL endpoint\nrouter.post('/cloudfront/sign', requireAuth, verifyVideoAccess, (req, res) => {\n try {\n const { url } = req.body;\n \n if (!url) {\n return res.status(400).json({ error: 'URL is required' });\n }\n \n // Parse URL to get domain\n const urlObj = new URL(url);\n const domain = urlObj.hostname;\n \n // Create signed cookies\n const policy = JSON.stringify({\n Statement: [{\n Resource: `https://${domain}/*`,\n Condition: {\n DateLessThan: {\n 'AWS:EpochTime': Math.floor(Date.now() / 1000) + 3600 // 1 hour\n }\n }\n }]\n });\n \n const signedCookies = cloudFront.getSignedCookie({\n policy\n });\n \n // Set signed cookies\n const cookieOptions = {\n domain: domain,\n path: '/',\n secure: true,\n httpOnly: true,\n sameSite: 'none',\n maxAge: 3600000 // 1 hour\n };\n \n res.cookie('CloudFront-Policy', signedCookies['CloudFront-Policy'], cookieOptions);\n res.cookie('CloudFront-Signature', signedCookies['CloudFront-Signature'], cookieOptions);\n res.cookie('CloudFront-Key-Pair-Id', signedCookies['CloudFront-Key-Pair-Id'], cookieOptions);\n \n // Return the original URL\n // The cookies will authenticate subsequent requests\n res.json({ url });\n \n } catch (error) {\n console.error('Error signing CloudFront URL:', error);\n res.status(500).json({ error: 'Failed to sign URL' });\n }\n});\n\nmodule.exports = router;\n";
|
|
22
|
-
/**
|
|
23
|
-
* Example 5: Python/Django Backend
|
|
24
|
-
*/
|
|
25
|
-
export declare const pythonBackendExample = "\n# backend/videos/views.py\nfrom django.http import JsonResponse\nfrom django.views.decorators.csrf import csrf_exempt\nfrom django.contrib.auth.decorators import login_required\nimport json\nfrom datetime import datetime, timedelta\nfrom cryptography.hazmat.primitives import hashes, serialization\nfrom cryptography.hazmat.primitives.asymmetric import padding\nimport base64\n\n@csrf_exempt\n@login_required\ndef sign_cloudfront_url(request):\n if request.method != 'POST':\n return JsonResponse({'error': 'Method not allowed'}, status=405)\n \n try:\n data = json.loads(request.body)\n url = data.get('url')\n \n if not url:\n return JsonResponse({'error': 'URL is required'}, status=400)\n \n # Verify user has access to video\n video_id = extract_video_id_from_url(url)\n if not user_has_video_access(request.user, video_id):\n return JsonResponse({'error': 'Access denied'}, status=403)\n \n # Create CloudFront signed cookies\n expiration = datetime.utcnow() + timedelta(hours=1)\n \n policy = {\n \"Statement\": [{\n \"Resource\": f\"https://media.domain.com/*\",\n \"Condition\": {\n \"DateLessThan\": {\n \"AWS:EpochTime\": int(expiration.timestamp())\n }\n }\n }]\n }\n \n # Sign the policy\n signed_cookies = create_signed_cookies(policy)\n \n # Set cookies\n response = JsonResponse({'url': url})\n response.set_cookie(\n 'CloudFront-Policy',\n signed_cookies['CloudFront-Policy'],\n domain='media.domain.com',\n secure=True,\n httponly=True,\n samesite='None',\n max_age=3600\n )\n response.set_cookie(\n 'CloudFront-Signature',\n signed_cookies['CloudFront-Signature'],\n domain='media.domain.com',\n secure=True,\n httponly=True,\n samesite='None',\n max_age=3600\n )\n response.set_cookie(\n 'CloudFront-Key-Pair-Id',\n signed_cookies['CloudFront-Key-Pair-Id'],\n domain='media.domain.com',\n secure=True,\n httponly=True,\n samesite='None',\n max_age=3600\n )\n \n return response\n \n except Exception as e:\n return JsonResponse({'error': str(e)}, status=500)\n";
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example 1: Netflix-style Dark Theme
|
|
5
|
-
*/
|
|
6
|
-
export declare function netflixTheme(): WontumPlayer;
|
|
7
|
-
/**
|
|
8
|
-
* Example 2: YouTube-style Theme
|
|
9
|
-
*/
|
|
10
|
-
export declare function youtubeTheme(): WontumPlayer;
|
|
11
|
-
/**
|
|
12
|
-
* Example 3: Modern Purple/Pink Theme
|
|
13
|
-
*/
|
|
14
|
-
export declare function modernTheme(): WontumPlayer;
|
|
15
|
-
/**
|
|
16
|
-
* Example 4: Minimal Green Theme
|
|
17
|
-
*/
|
|
18
|
-
export declare function minimalGreenTheme(): WontumPlayer;
|
|
19
|
-
/**
|
|
20
|
-
* Example 5: Bold Cyberpunk Theme
|
|
21
|
-
*/
|
|
22
|
-
export declare function cyberpunkTheme(): WontumPlayer;
|
|
23
|
-
/**
|
|
24
|
-
* Example 6: Soft Pastel Theme
|
|
25
|
-
*/
|
|
26
|
-
export declare function pastelTheme(): WontumPlayer;
|
|
27
|
-
/**
|
|
28
|
-
* Example 7: Education Platform Theme
|
|
29
|
-
*/
|
|
30
|
-
export declare function educationTheme(): WontumPlayer;
|
|
31
|
-
/**
|
|
32
|
-
* React Example with Custom Theme
|
|
33
|
-
*/
|
|
34
|
-
export declare const ReactCustomThemeExample = "\nimport React from 'react';\nimport { WontumPlayerReact } from '@obipascal/player';\n\nfunction CustomStyledPlayer() {\n return (\n <WontumPlayerReact\n src=\"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8\"\n theme={{\n primaryColor: '#ff6b6b', // Coral red\n accentColor: '#ee5a6f',\n fontFamily: 'Helvetica, Arial, sans-serif',\n controlsBackground: 'linear-gradient(to top, rgba(0,0,0,0.85), transparent)',\n buttonHoverBg: 'rgba(255, 107, 107, 0.25)',\n progressHeight: '5px',\n borderRadius: '8px'\n }}\n />\n );\n}\n";
|
|
35
|
-
/**
|
|
36
|
-
* All Available Theme Options
|
|
37
|
-
*/
|
|
38
|
-
export declare const ThemeOptions: {
|
|
39
|
-
/**
|
|
40
|
-
* Primary color for progress bar, sliders, etc.
|
|
41
|
-
* Default: '#3b82f6' (blue)
|
|
42
|
-
*/
|
|
43
|
-
primaryColor: string;
|
|
44
|
-
/**
|
|
45
|
-
* Accent color for hover states
|
|
46
|
-
* Default: '#2563eb' (darker blue)
|
|
47
|
-
*/
|
|
48
|
-
accentColor: string;
|
|
49
|
-
/**
|
|
50
|
-
* Font family for all text
|
|
51
|
-
* Default: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
52
|
-
*/
|
|
53
|
-
fontFamily: string;
|
|
54
|
-
/**
|
|
55
|
-
* Background for controls overlay
|
|
56
|
-
* Can be solid color or gradient
|
|
57
|
-
* Default: 'linear-gradient(to top, rgba(0,0,0,0.8), transparent)'
|
|
58
|
-
*/
|
|
59
|
-
controlsBackground: string;
|
|
60
|
-
/**
|
|
61
|
-
* Button hover background color
|
|
62
|
-
* Default: 'rgba(255, 255, 255, 0.1)'
|
|
63
|
-
*/
|
|
64
|
-
buttonHoverBg: string;
|
|
65
|
-
/**
|
|
66
|
-
* Height of progress bar
|
|
67
|
-
* Default: '6px'
|
|
68
|
-
*/
|
|
69
|
-
progressHeight: string;
|
|
70
|
-
/**
|
|
71
|
-
* Border radius for buttons and progress bar
|
|
72
|
-
* Default: '4px'
|
|
73
|
-
*/
|
|
74
|
-
borderRadius: string;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Brand Color Presets
|
|
78
|
-
*/
|
|
79
|
-
export declare const BrandPresets: {
|
|
80
|
-
netflix: {
|
|
81
|
-
primary: string;
|
|
82
|
-
accent: string;
|
|
83
|
-
};
|
|
84
|
-
youtube: {
|
|
85
|
-
primary: string;
|
|
86
|
-
accent: string;
|
|
87
|
-
};
|
|
88
|
-
vimeo: {
|
|
89
|
-
primary: string;
|
|
90
|
-
accent: string;
|
|
91
|
-
};
|
|
92
|
-
spotify: {
|
|
93
|
-
primary: string;
|
|
94
|
-
accent: string;
|
|
95
|
-
};
|
|
96
|
-
twitch: {
|
|
97
|
-
primary: string;
|
|
98
|
-
accent: string;
|
|
99
|
-
};
|
|
100
|
-
disney: {
|
|
101
|
-
primary: string;
|
|
102
|
-
accent: string;
|
|
103
|
-
};
|
|
104
|
-
hulu: {
|
|
105
|
-
primary: string;
|
|
106
|
-
accent: string;
|
|
107
|
-
};
|
|
108
|
-
amazon: {
|
|
109
|
-
primary: string;
|
|
110
|
-
accent: string;
|
|
111
|
-
};
|
|
112
|
-
apple: {
|
|
113
|
-
primary: string;
|
|
114
|
-
accent: string;
|
|
115
|
-
};
|
|
116
|
-
hbo: {
|
|
117
|
-
primary: string;
|
|
118
|
-
accent: string;
|
|
119
|
-
};
|
|
120
|
-
};
|
|
121
|
-
/**
|
|
122
|
-
* Quick Setup Helper
|
|
123
|
-
*/
|
|
124
|
-
export declare function createThemedPlayer(containerId: string, streamUrl: string, brandName: keyof typeof BrandPresets): WontumPlayer;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* All available events in Wontum Player (Mux Player compatible)
|
|
5
|
-
*/
|
|
6
|
-
export declare function allEventsDemo(): WontumPlayer;
|
|
7
|
-
/**
|
|
8
|
-
* Event categories breakdown
|
|
9
|
-
*/
|
|
10
|
-
export declare const EventCategories: {
|
|
11
|
-
/**
|
|
12
|
-
* Playback Events - Control and playback state
|
|
13
|
-
*/
|
|
14
|
-
readonly playback: readonly ["play", "pause", "playing", "ended", "timeupdate"];
|
|
15
|
-
/**
|
|
16
|
-
* Seeking Events - User navigation
|
|
17
|
-
*/
|
|
18
|
-
readonly seeking: readonly ["seeking", "seeked"];
|
|
19
|
-
/**
|
|
20
|
-
* Loading Events - Media loading and buffering
|
|
21
|
-
*/
|
|
22
|
-
readonly loading: readonly ["loadstart", "loadeddata", "loadedmetadata", "canplay", "canplaythrough", "progress", "waiting", "durationchange"];
|
|
23
|
-
/**
|
|
24
|
-
* Media State Events - Volume, rate, dimensions
|
|
25
|
-
*/
|
|
26
|
-
readonly mediaState: readonly ["volumechange", "ratechange", "resize"];
|
|
27
|
-
/**
|
|
28
|
-
* Network/Error Events - Network issues and errors
|
|
29
|
-
*/
|
|
30
|
-
readonly network: readonly ["abort", "emptied", "stalled", "suspend", "error"];
|
|
31
|
-
/**
|
|
32
|
-
* Custom Player Events - Wontum Player specific
|
|
33
|
-
*/
|
|
34
|
-
readonly custom: readonly ["qualitychange", "fullscreenchange"];
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Minimal event listener example
|
|
38
|
-
*/
|
|
39
|
-
export declare function minimalEventExample(): void;
|
|
40
|
-
/**
|
|
41
|
-
* React example with all events
|
|
42
|
-
*/
|
|
43
|
-
export declare const ReactAllEventsExample = "\nimport React from 'react';\nimport { WontumPlayerReact } from '@obipascal/player';\n\nfunction VideoPlayerWithEvents() {\n return (\n <WontumPlayerReact\n src=\"https://media.domain.com/video.m3u8\"\n \n {/* Playback Events */}\n onPlay={(e) => console.log('Play', e)}\n onPause={(e) => console.log('Pause', e)}\n onPlaying={(e) => console.log('Playing', e)}\n onEnded={(e) => console.log('Ended', e)}\n onTimeupdate={(e) => console.log('Time:', e.data.currentTime)}\n \n {/* Seeking */}\n onSeeking={(e) => console.log('Seeking', e)}\n onSeeked={(e) => console.log('Seeked', e)}\n \n {/* Loading Events */}\n onLoadstart={(e) => console.log('Load Start', e)}\n onLoadeddata={(e) => console.log('Loaded Data', e)}\n onLoadedmetadata={(e) => console.log('Metadata', e)}\n onCanplay={(e) => console.log('Can Play', e)}\n onCanplaythrough={(e) => console.log('Can Play Through', e)}\n onProgress={(e) => console.log('Progress', e)}\n onWaiting={(e) => console.log('Buffering', e)}\n onDurationchange={(e) => console.log('Duration', e)}\n \n {/* Media State */}\n onVolumechange={(e) => console.log('Volume', e)}\n onRatechange={(e) => console.log('Rate', e)}\n onResize={(e) => console.log('Resize', e)}\n \n {/* Network/Error */}\n onAbort={(e) => console.log('Abort', e)}\n onEmptied={(e) => console.log('Emptied', e)}\n onStalled={(e) => console.log('Stalled', e)}\n onSuspend={(e) => console.log('Suspend', e)}\n onError={(e) => console.error('Error', e)}\n \n {/* Custom Events */}\n onQualitychange={(e) => console.log('Quality', e)}\n onFullscreenchange={(e) => console.log('Fullscreen', e)}\n />\n );\n}\n";
|
|
44
|
-
/**
|
|
45
|
-
* Compare with Mux Player events
|
|
46
|
-
*/
|
|
47
|
-
export declare const MuxPlayerCompatibility: {
|
|
48
|
-
muxPlayerEvents: string[];
|
|
49
|
-
wontumExtensions: string[];
|
|
50
|
-
allSupported: boolean;
|
|
51
|
-
totalEvents: number;
|
|
52
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example 1: Basic public stream
|
|
5
|
-
*/
|
|
6
|
-
export declare function basicPublicStream(): WontumPlayer;
|
|
7
|
-
/**
|
|
8
|
-
* Example 2: With event logging
|
|
9
|
-
*/
|
|
10
|
-
export declare function publicStreamWithEvents(): WontumPlayer;
|
|
11
|
-
/**
|
|
12
|
-
* Example 3: Multiple quality levels
|
|
13
|
-
*/
|
|
14
|
-
export declare function adaptiveStreamTest(): WontumPlayer;
|
|
15
|
-
/**
|
|
16
|
-
* Public HLS Test Streams
|
|
17
|
-
*/
|
|
18
|
-
export declare const PUBLIC_TEST_STREAMS: {
|
|
19
|
-
appleBasic: string;
|
|
20
|
-
apple4K: string;
|
|
21
|
-
muxDemo: string;
|
|
22
|
-
bigBuckBunny: string;
|
|
23
|
-
tearsOfSteel: string;
|
|
24
|
-
sintel: string;
|
|
25
|
-
multiBitrate: string;
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* Quick test function - just paste into console
|
|
29
|
-
*/
|
|
30
|
-
export declare function quickTest(streamUrl?: string): WontumPlayer;
|
|
31
|
-
/**
|
|
32
|
-
* HTML Example for quick testing
|
|
33
|
-
*/
|
|
34
|
-
export declare const htmlExample = "\n<!DOCTYPE html>\n<html>\n<head>\n <title>Wontum Player Test</title>\n <style>\n body { \n margin: 0; \n padding: 20px; \n font-family: Arial, sans-serif; \n background: #1a1a1a;\n color: white;\n }\n #player { \n width: 100%; \n max-width: 1200px; \n height: 600px; \n background: #000;\n margin: 20px auto;\n }\n .info {\n max-width: 1200px;\n margin: 0 auto;\n padding: 20px;\n }\n </style>\n</head>\n<body>\n <div class=\"info\">\n <h1>\uD83C\uDFAC Wontum Player Test</h1>\n <p>Testing with public HLS stream (no authentication required)</p>\n </div>\n \n <div id=\"player\"></div>\n\n <script type=\"module\">\n import { WontumPlayer } from './dist/index.js';\n \n const player = new WontumPlayer({\n src: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',\n container: '#player',\n autoplay: true,\n controls: true,\n analytics: {\n enabled: true\n }\n });\n\n // Log events\n player.on('loadedmetadata', (e) => {\n console.log('Duration:', e.data.duration);\n });\n \n player.on('play', () => console.log('Playing!'));\n player.on('pause', () => console.log('Paused'));\n player.on('error', (e) => console.error('Error:', e.data));\n \n // Make player available in console\n window.player = player;\n </script>\n</body>\n</html>\n";
|
|
35
|
-
/**
|
|
36
|
-
* React example with public stream
|
|
37
|
-
*/
|
|
38
|
-
export declare const reactPublicStreamExample = "\nimport React from 'react';\nimport { WontumPlayerReact } from '@obipascal/player';\n\nfunction App() {\n return (\n <div style={{ width: '100%', height: '600px', background: '#000' }}>\n <WontumPlayerReact\n src=\"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8\"\n autoplay\n onLoadedmetadata={(e) => console.log('Duration:', e.data.duration)}\n onPlay={() => console.log('Playing!')}\n onError={(e) => console.error('Error:', e.data)}\n />\n </div>\n );\n}\n\nexport default App;\n";
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example 1: Basic React Player
|
|
3
|
-
*/
|
|
4
|
-
export declare function BasicPlayer(): import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
/**
|
|
6
|
-
* Example 2: Player with Event Handlers
|
|
7
|
-
*/
|
|
8
|
-
export declare function PlayerWithEvents(): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
/**
|
|
10
|
-
* Example 3: Custom Controls with useWontumPlayer Hook
|
|
11
|
-
*/
|
|
12
|
-
export declare function CustomControls(): import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export declare function S3Player(): import("react/jsx-runtime").JSX.Element;
|
|
14
|
-
/**
|
|
15
|
-
* Example 5: Player with Analytics
|
|
16
|
-
*/
|
|
17
|
-
export declare function AnalyticsPlayer({ videoId, userId }: {
|
|
18
|
-
videoId: string;
|
|
19
|
-
userId: string;
|
|
20
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
21
|
-
/**
|
|
22
|
-
* Example 6: Playlist Player
|
|
23
|
-
*/
|
|
24
|
-
export declare function PlaylistPlayer(): import("react/jsx-runtime").JSX.Element;
|
|
25
|
-
/**
|
|
26
|
-
* Example 7: Player with Custom Theme
|
|
27
|
-
*/
|
|
28
|
-
export declare function ThemedPlayer(): import("react/jsx-runtime").JSX.Element;
|
|
29
|
-
/**
|
|
30
|
-
* Example 8: Responsive Player
|
|
31
|
-
*/
|
|
32
|
-
export declare function ResponsivePlayer(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from '../src/index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Example 1: Basic Player Setup
|
|
5
|
-
*/
|
|
6
|
-
declare function basicPlayerExample(): WontumPlayer;
|
|
7
|
-
/**
|
|
8
|
-
* Example 2: Player with Event Listeners
|
|
9
|
-
*/
|
|
10
|
-
declare function playerWithEventsExample(): WontumPlayer;
|
|
11
|
-
/**
|
|
12
|
-
* Example 3: Programmatic Control
|
|
13
|
-
*/
|
|
14
|
-
declare function programmaticControlExample(): WontumPlayer;
|
|
15
|
-
/**
|
|
16
|
-
* Example 4: S3 Integration
|
|
17
|
-
* Note: Install AWS SDK with: npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
|
|
18
|
-
*/
|
|
19
|
-
declare function s3IntegrationExample(): Promise<WontumPlayer>;
|
|
20
|
-
/**
|
|
21
|
-
* Example 5: Backend Presigned URL Generation
|
|
22
|
-
*/
|
|
23
|
-
declare function backendPresignedUrlExample(): Promise<WontumPlayer>;
|
|
24
|
-
/**
|
|
25
|
-
* Example 6: Analytics Integration
|
|
26
|
-
*/
|
|
27
|
-
declare function analyticsExample(): WontumPlayer;
|
|
28
|
-
/**
|
|
29
|
-
* Example 7: Quality Selection
|
|
30
|
-
*/
|
|
31
|
-
declare function qualitySelectionExample(): WontumPlayer;
|
|
32
|
-
/**
|
|
33
|
-
* Example 8: Multiple Players on One Page
|
|
34
|
-
*/
|
|
35
|
-
declare function multiplePlayersExample(): WontumPlayer[];
|
|
36
|
-
/**
|
|
37
|
-
* Example 9: Custom HLS Configuration
|
|
38
|
-
*/
|
|
39
|
-
declare function customHlsConfigExample(): WontumPlayer;
|
|
40
|
-
/**
|
|
41
|
-
* Example 10: Playlist with Auto-advance
|
|
42
|
-
*/
|
|
43
|
-
declare function playlistExample(): {
|
|
44
|
-
next: () => void;
|
|
45
|
-
previous: () => void;
|
|
46
|
-
goto: (index: number) => void;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Example 11: Save and Resume Playback Position
|
|
50
|
-
*/
|
|
51
|
-
declare function saveResumeExample(): WontumPlayer;
|
|
52
|
-
/**
|
|
53
|
-
* Example 12: Picture-in-Picture
|
|
54
|
-
*/
|
|
55
|
-
declare function pictureInPictureExample(): Promise<WontumPlayer>;
|
|
56
|
-
export { basicPlayerExample, playerWithEventsExample, programmaticControlExample, s3IntegrationExample, backendPresignedUrlExample, analyticsExample, qualitySelectionExample, multiplePlayersExample, customHlsConfigExample, playlistExample, saveResumeExample, pictureInPictureExample, };
|
package/dist/src/analytics.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { AnalyticsConfig, AnalyticsEvent } from './types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Analytics - Tracks player events and quality metrics
|
|
5
|
-
*/
|
|
6
|
-
export declare class Analytics {
|
|
7
|
-
private config;
|
|
8
|
-
private sessionId;
|
|
9
|
-
private events;
|
|
10
|
-
private sessionStartTime;
|
|
11
|
-
private playbackStartTime;
|
|
12
|
-
private totalPlayTime;
|
|
13
|
-
private totalBufferTime;
|
|
14
|
-
private bufferStartTime;
|
|
15
|
-
private rebufferCount;
|
|
16
|
-
private seekCount;
|
|
17
|
-
private webSocket;
|
|
18
|
-
private socketIO;
|
|
19
|
-
private wsReconnectTimeout;
|
|
20
|
-
private isDestroyed;
|
|
21
|
-
constructor(config?: AnalyticsConfig);
|
|
22
|
-
trackEvent(eventType: string, data?: Record<string, any>): void;
|
|
23
|
-
private updateMetrics;
|
|
24
|
-
private getQoEMetrics;
|
|
25
|
-
private getSessionData;
|
|
26
|
-
private getConnectionInfo;
|
|
27
|
-
private sendEvent;
|
|
28
|
-
private generateSessionId;
|
|
29
|
-
private initializeSocketIO;
|
|
30
|
-
private sendToSocketIO;
|
|
31
|
-
private initializeWebSocket;
|
|
32
|
-
private sendToWebSocket;
|
|
33
|
-
getEvents(): AnalyticsEvent[];
|
|
34
|
-
getMetrics(): Record<string, any>;
|
|
35
|
-
destroy(): void;
|
|
36
|
-
}
|
package/dist/src/file-info.d.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Video file information extractor
|
|
3
|
-
* Extracts metadata from video files (width, height, duration, size, etc.)
|
|
4
|
-
*/
|
|
5
|
-
declare global {
|
|
6
|
-
interface HTMLVideoElement {
|
|
7
|
-
mozHasAudio?: boolean;
|
|
8
|
-
webkitAudioDecodedByteCount?: number;
|
|
9
|
-
audioTracks?: {
|
|
10
|
-
length: number;
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export interface VideoFileInfo {
|
|
15
|
-
width: number;
|
|
16
|
-
height: number;
|
|
17
|
-
aspectRatio: string;
|
|
18
|
-
size: number;
|
|
19
|
-
sizeInBytes: number;
|
|
20
|
-
sizeFormatted: string;
|
|
21
|
-
duration: number;
|
|
22
|
-
durationInSeconds: number;
|
|
23
|
-
durationFormatted: string;
|
|
24
|
-
mimeType: string;
|
|
25
|
-
fileName: string;
|
|
26
|
-
fileExtension: string;
|
|
27
|
-
bitrate?: number;
|
|
28
|
-
frameRate?: number;
|
|
29
|
-
audioChannels?: number;
|
|
30
|
-
videoCodec?: string;
|
|
31
|
-
audioCodec?: string;
|
|
32
|
-
hasAudio?: boolean;
|
|
33
|
-
}
|
|
34
|
-
export declare class WontumFileInfo {
|
|
35
|
-
private file;
|
|
36
|
-
private videoElement;
|
|
37
|
-
private audioContext;
|
|
38
|
-
private info;
|
|
39
|
-
constructor(file: File);
|
|
40
|
-
/**
|
|
41
|
-
* Check if the file is a valid video file
|
|
42
|
-
*/
|
|
43
|
-
private isVideoFile;
|
|
44
|
-
/**
|
|
45
|
-
* Extract video metadata
|
|
46
|
-
*/
|
|
47
|
-
extract(): Promise<VideoFileInfo>;
|
|
48
|
-
/**
|
|
49
|
-
* Calculate aspect ratio (e.g., "16:9", "4:3")
|
|
50
|
-
*/
|
|
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;
|
|
60
|
-
/**
|
|
61
|
-
* Get Greatest Common Divisor
|
|
62
|
-
*/
|
|
63
|
-
private getGCD;
|
|
64
|
-
/**
|
|
65
|
-
* Format bytes to human-readable size
|
|
66
|
-
*/
|
|
67
|
-
private formatBytes;
|
|
68
|
-
/**
|
|
69
|
-
* Format duration to HH:MM:SS
|
|
70
|
-
*/
|
|
71
|
-
private formatDuration;
|
|
72
|
-
/**
|
|
73
|
-
* Get file extension
|
|
74
|
-
*/
|
|
75
|
-
private getFileExtension;
|
|
76
|
-
get width(): number;
|
|
77
|
-
get height(): number;
|
|
78
|
-
get aspectRatio(): string;
|
|
79
|
-
get size(): number;
|
|
80
|
-
get sizeInBytes(): number;
|
|
81
|
-
get sizeFormatted(): string;
|
|
82
|
-
get duration(): number;
|
|
83
|
-
get durationInSeconds(): number;
|
|
84
|
-
get durationFormatted(): string;
|
|
85
|
-
get mimeType(): string;
|
|
86
|
-
get fileName(): string;
|
|
87
|
-
get fileExtension(): string;
|
|
88
|
-
get bitrate(): number | undefined;
|
|
89
|
-
get frameRate(): number | undefined;
|
|
90
|
-
get audioChannels(): number | undefined;
|
|
91
|
-
get hasAudio(): boolean;
|
|
92
|
-
get quality(): string;
|
|
93
|
-
/**
|
|
94
|
-
* Get all information as object
|
|
95
|
-
*/
|
|
96
|
-
getInfo(): VideoFileInfo | null;
|
|
97
|
-
/**
|
|
98
|
-
* Clean up resources
|
|
99
|
-
*/
|
|
100
|
-
destroy(): void;
|
|
101
|
-
}
|
package/dist/src/index.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export { WontumPlayer } from './player';
|
|
2
|
-
export { Analytics } from './analytics';
|
|
3
|
-
export { S3Handler } from './s3-handler';
|
|
4
|
-
export { UIController } from './ui-controller';
|
|
5
|
-
export { WontumFileInfo } from './file-info';
|
|
6
|
-
export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext, useVideoFileInfo, useAnalytics } from './react';
|
|
7
|
-
export type { WontumPlayerConfig, PlayerTheme, S3Config, AnalyticsConfig, WebSocketAnalyticsHandler, SocketIOAnalyticsHandler, PlayerState, PlayerEvent, PlayerEventType, AnalyticsEvent, QualityLevel, } from './types';
|
|
8
|
-
export type { VideoFileInfo } from './file-info';
|
|
9
|
-
export type { WontumPlayerReactProps, UseVideoFileInfoResult, UseAnalyticsResult } from './react';
|
package/dist/src/player.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { WontumPlayerConfig, PlayerState, PlayerEvent, PlayerEventType, QualityLevel } from './types';
|
|
2
|
-
import { Analytics } from './analytics';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* WontumPlayer - A modern HLS video player for educational platforms
|
|
6
|
-
*/
|
|
7
|
-
export declare class WontumPlayer {
|
|
8
|
-
private container;
|
|
9
|
-
private videoElement;
|
|
10
|
-
private hls;
|
|
11
|
-
private config;
|
|
12
|
-
private eventListeners;
|
|
13
|
-
analytics: Analytics;
|
|
14
|
-
private s3Handler;
|
|
15
|
-
private uiController;
|
|
16
|
-
private qualities;
|
|
17
|
-
private state;
|
|
18
|
-
constructor(config: WontumPlayerConfig);
|
|
19
|
-
private addSubtitleTracks;
|
|
20
|
-
private createVideoElement;
|
|
21
|
-
private setupVideoListeners;
|
|
22
|
-
private loadSource;
|
|
23
|
-
private extractQualities;
|
|
24
|
-
private handleHlsError;
|
|
25
|
-
private getAnalyticsData;
|
|
26
|
-
play(): Promise<void>;
|
|
27
|
-
pause(): void;
|
|
28
|
-
seek(time: number): void;
|
|
29
|
-
skipForward(seconds?: number): void;
|
|
30
|
-
skipBackward(seconds?: number): void;
|
|
31
|
-
setVolume(volume: number): void;
|
|
32
|
-
mute(): void;
|
|
33
|
-
unmute(): void;
|
|
34
|
-
setPlaybackRate(rate: number): void;
|
|
35
|
-
setQuality(qualityIndex: number): void;
|
|
36
|
-
getQualities(): QualityLevel[];
|
|
37
|
-
enterFullscreen(): void;
|
|
38
|
-
exitFullscreen(): void;
|
|
39
|
-
enterPictureInPicture(): Promise<void>;
|
|
40
|
-
exitPictureInPicture(): Promise<void>;
|
|
41
|
-
togglePictureInPicture(): Promise<void>;
|
|
42
|
-
getState(): PlayerState;
|
|
43
|
-
getVideoElement(): HTMLVideoElement;
|
|
44
|
-
/**
|
|
45
|
-
* Enable subtitles for a specific track
|
|
46
|
-
*/
|
|
47
|
-
enableSubtitles(trackIndex: number): void;
|
|
48
|
-
/**
|
|
49
|
-
* Disable all subtitles
|
|
50
|
-
*/
|
|
51
|
-
disableSubtitles(): void;
|
|
52
|
-
/**
|
|
53
|
-
* Toggle subtitles on/off
|
|
54
|
-
*/
|
|
55
|
-
toggleSubtitles(): boolean;
|
|
56
|
-
/**
|
|
57
|
-
* Get available subtitle tracks
|
|
58
|
-
*/
|
|
59
|
-
getSubtitleTracks(): TextTrack[];
|
|
60
|
-
/**
|
|
61
|
-
* Check if subtitles are currently enabled
|
|
62
|
-
*/
|
|
63
|
-
areSubtitlesEnabled(): boolean;
|
|
64
|
-
on(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
|
|
65
|
-
off(eventType: PlayerEventType, callback: (event: PlayerEvent) => void): void;
|
|
66
|
-
private emit;
|
|
67
|
-
/**
|
|
68
|
-
* Update video source without recreating the entire player
|
|
69
|
-
* This is more efficient than destroying and recreating the player
|
|
70
|
-
* @param src - New video source URL
|
|
71
|
-
*/
|
|
72
|
-
updateSource(src: string): Promise<void>;
|
|
73
|
-
destroy(): void;
|
|
74
|
-
}
|
package/dist/src/react.d.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from './player';
|
|
2
|
-
import { WontumPlayerConfig, PlayerState, AnalyticsConfig, AnalyticsEvent } from './types';
|
|
3
|
-
import { VideoFileInfo } from './file-info';
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
export interface WontumPlayerReactProps extends Omit<WontumPlayerConfig, "container"> {
|
|
6
|
-
/** Callback when player is ready */
|
|
7
|
-
onReady?: (player: WontumPlayer) => void;
|
|
8
|
-
/** Callback for player events */
|
|
9
|
-
onPlay?: () => void;
|
|
10
|
-
onPause?: () => void;
|
|
11
|
-
onEnded?: () => void;
|
|
12
|
-
onTimeUpdate?: (currentTime: number) => void;
|
|
13
|
-
onVolumeChange?: (volume: number, muted: boolean) => void;
|
|
14
|
-
onError?: (error: any) => void;
|
|
15
|
-
onLoadedMetadata?: () => void;
|
|
16
|
-
onQualityChange?: (level: number) => void;
|
|
17
|
-
/** Container style */
|
|
18
|
-
style?: React.CSSProperties;
|
|
19
|
-
/** Container className */
|
|
20
|
-
className?: string;
|
|
21
|
-
/** Width of player */
|
|
22
|
-
width?: string | number;
|
|
23
|
-
/** Height of player */
|
|
24
|
-
height?: string | number;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* WontumPlayerReact - React component wrapper for WontumPlayer
|
|
28
|
-
*/
|
|
29
|
-
export declare const WontumPlayerReact: React.FC<WontumPlayerReactProps>;
|
|
30
|
-
/**
|
|
31
|
-
* useWontumPlayer - React hook for imperative player control
|
|
32
|
-
*/
|
|
33
|
-
export declare const useWontumPlayer: (config: Omit<WontumPlayerConfig, "container">) => {
|
|
34
|
-
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
35
|
-
player: WontumPlayer | null;
|
|
36
|
-
state: PlayerState | null;
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* WontumPlayerProvider - Context provider for player instance
|
|
40
|
-
*/
|
|
41
|
-
interface WontumPlayerContextValue {
|
|
42
|
-
player: WontumPlayer | null;
|
|
43
|
-
state: PlayerState | null;
|
|
44
|
-
}
|
|
45
|
-
export declare const WontumPlayerProvider: React.FC<{
|
|
46
|
-
player: WontumPlayer;
|
|
47
|
-
children: React.ReactNode;
|
|
48
|
-
}>;
|
|
49
|
-
export declare const useWontumPlayerContext: () => WontumPlayerContextValue;
|
|
50
|
-
/**
|
|
51
|
-
* Hook for extracting video file information
|
|
52
|
-
* @param file - The video file to analyze (File object or null)
|
|
53
|
-
* @returns Object containing loading state, error, and video info
|
|
54
|
-
*/
|
|
55
|
-
export interface UseVideoFileInfoResult {
|
|
56
|
-
/** Video file information (null if not loaded or error occurred) */
|
|
57
|
-
info: VideoFileInfo | null;
|
|
58
|
-
/** Whether extraction is in progress */
|
|
59
|
-
loading: boolean;
|
|
60
|
-
/** Error message if extraction failed */
|
|
61
|
-
error: string | null;
|
|
62
|
-
/** Re-extract file info (useful for retry after error) */
|
|
63
|
-
refetch: () => Promise<void>;
|
|
64
|
-
}
|
|
65
|
-
export declare const useVideoFileInfo: (file: File | null | undefined) => UseVideoFileInfoResult;
|
|
66
|
-
/**
|
|
67
|
-
* Result type for useAnalytics hook
|
|
68
|
-
*/
|
|
69
|
-
export interface UseAnalyticsResult {
|
|
70
|
-
/** Track a custom event */
|
|
71
|
-
trackEvent: (eventType: string, data?: Record<string, any>) => void;
|
|
72
|
-
/** Get all tracked events */
|
|
73
|
-
getEvents: () => AnalyticsEvent[];
|
|
74
|
-
/** Get analytics metrics (session duration, buffer time, etc.) */
|
|
75
|
-
getMetrics: () => Record<string, any>;
|
|
76
|
-
/** WebSocket connection status (for websocket/socket.io analytics) */
|
|
77
|
-
connected: boolean;
|
|
78
|
-
/** Session ID for this analytics instance */
|
|
79
|
-
sessionId: string;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* React hook for analytics tracking
|
|
83
|
-
* Automatically handles lifecycle management and cleanup
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```tsx
|
|
87
|
-
* const { trackEvent, getMetrics, connected } = useAnalytics({
|
|
88
|
-
* enabled: true,
|
|
89
|
-
* endpoint: "https://api.example.com/analytics",
|
|
90
|
-
* videoId: "video-123",
|
|
91
|
-
* userId: "user-456",
|
|
92
|
-
* webSocket: {
|
|
93
|
-
* type: "socket.io",
|
|
94
|
-
* url: "https://analytics.example.com",
|
|
95
|
-
* auth: { token: "your-token" }
|
|
96
|
-
* }
|
|
97
|
-
* })
|
|
98
|
-
*
|
|
99
|
-
* // Track custom events
|
|
100
|
-
* trackEvent("button_clicked", { buttonName: "share" })
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
export declare const useAnalytics: (config?: AnalyticsConfig) => UseAnalyticsResult;
|
|
104
|
-
export {};
|
package/dist/src/s3-handler.d.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { S3Config } from './types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* S3Handler - Manages S3/CloudFront URLs and signed cookie authentication
|
|
5
|
-
*/
|
|
6
|
-
export declare class S3Handler {
|
|
7
|
-
private config;
|
|
8
|
-
private urlCache;
|
|
9
|
-
private signedUrls;
|
|
10
|
-
constructor(config?: S3Config);
|
|
11
|
-
/**
|
|
12
|
-
* Process a URL - sign with CloudFront cookies or generate presigned URL for S3
|
|
13
|
-
*/
|
|
14
|
-
processUrl(url: string): Promise<string>;
|
|
15
|
-
/**
|
|
16
|
-
* Check if URL is a CloudFront URL that needs signing
|
|
17
|
-
*/
|
|
18
|
-
private isCloudFrontUrl;
|
|
19
|
-
/**
|
|
20
|
-
* Check if URL is an S3 URL
|
|
21
|
-
*/
|
|
22
|
-
private isS3Url;
|
|
23
|
-
/**
|
|
24
|
-
* Sign CloudFront URL by calling the signing endpoint
|
|
25
|
-
* The endpoint should set signed cookies and return the URL
|
|
26
|
-
*/
|
|
27
|
-
private signCloudFrontUrl;
|
|
28
|
-
/**
|
|
29
|
-
* Extract S3 key from URL
|
|
30
|
-
*/
|
|
31
|
-
private extractS3Key;
|
|
32
|
-
/**
|
|
33
|
-
* Get presigned URL from cache or generate new one
|
|
34
|
-
*/
|
|
35
|
-
private getPresignedUrl;
|
|
36
|
-
/**
|
|
37
|
-
* Helper to construct S3 URL from bucket and key
|
|
38
|
-
*/
|
|
39
|
-
static constructS3Url(bucket: string, key: string, region?: string): string;
|
|
40
|
-
/**
|
|
41
|
-
* Helper to parse S3 URI (s3://bucket/key)
|
|
42
|
-
*/
|
|
43
|
-
static parseS3Uri(uri: string): {
|
|
44
|
-
bucket: string;
|
|
45
|
-
key: string;
|
|
46
|
-
} | null;
|
|
47
|
-
/**
|
|
48
|
-
* Clear URL cache and signed URLs
|
|
49
|
-
*/
|
|
50
|
-
clearCache(): void;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Example CloudFront signed cookie implementation:
|
|
54
|
-
*
|
|
55
|
-
* async function signUrl(url: string): Promise<string> {
|
|
56
|
-
* const response = await fetch('/api/cloudfront/sign', {
|
|
57
|
-
* method: 'POST',
|
|
58
|
-
* headers: { 'Content-Type': 'application/json' },
|
|
59
|
-
* body: JSON.stringify({ url }),
|
|
60
|
-
* credentials: 'include' // Important: include cookies in request
|
|
61
|
-
* });
|
|
62
|
-
*
|
|
63
|
-
* const data = await response.json();
|
|
64
|
-
* // Backend sets CloudFront signed cookies in response
|
|
65
|
-
* // and returns the original URL
|
|
66
|
-
* return data.url;
|
|
67
|
-
* }
|
|
68
|
-
*
|
|
69
|
-
* const player = new WontumPlayer({
|
|
70
|
-
* src: 'https://media.domain.com/path/to/video/index.m3u8',
|
|
71
|
-
* container: '#player',
|
|
72
|
-
* s3Config: {
|
|
73
|
-
* signUrl,
|
|
74
|
-
* cloudFrontDomains: ['media.domain.com']
|
|
75
|
-
* }
|
|
76
|
-
* });
|
|
77
|
-
*
|
|
78
|
-
* ---
|
|
79
|
-
*
|
|
80
|
-
* Legacy S3 presigned URL example:
|
|
81
|
-
*
|
|
82
|
-
* import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
83
|
-
* import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
84
|
-
*
|
|
85
|
-
* const s3Client = new S3Client({ region: 'us-east-1' });
|
|
86
|
-
*
|
|
87
|
-
* async function getPresignedUrl(key: string): Promise<string> {
|
|
88
|
-
* const command = new GetObjectCommand({
|
|
89
|
-
* Bucket: 'your-bucket-name',
|
|
90
|
-
* Key: key,
|
|
91
|
-
* });
|
|
92
|
-
*
|
|
93
|
-
* return getSignedUrl(s3Client, command, { expiresIn: 3600 });
|
|
94
|
-
* }
|
|
95
|
-
*/
|
package/dist/src/types.d.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { Socket } from 'socket.io-client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Player configuration options
|
|
5
|
-
*/
|
|
6
|
-
export interface WontumPlayerConfig {
|
|
7
|
-
/** The S3 URL or HLS manifest URL */
|
|
8
|
-
src: string;
|
|
9
|
-
/** Container element or selector */
|
|
10
|
-
container: HTMLElement | string;
|
|
11
|
-
/** Autoplay video (subject to browser policies) */
|
|
12
|
-
autoplay?: boolean;
|
|
13
|
-
/** Start muted */
|
|
14
|
-
muted?: boolean;
|
|
15
|
-
/** Show player controls */
|
|
16
|
-
controls?: boolean;
|
|
17
|
-
/** Video poster image URL */
|
|
18
|
-
poster?: string;
|
|
19
|
-
/** Preload strategy: 'none' | 'metadata' | 'auto' */
|
|
20
|
-
preload?: "none" | "metadata" | "auto";
|
|
21
|
-
/** Custom player theme */
|
|
22
|
-
theme?: PlayerTheme;
|
|
23
|
-
/** S3 configuration for presigned URLs */
|
|
24
|
-
s3Config?: S3Config;
|
|
25
|
-
/** Analytics configuration */
|
|
26
|
-
analytics?: AnalyticsConfig;
|
|
27
|
-
/** HLS.js configuration override */
|
|
28
|
-
hlsConfig?: Partial<any>;
|
|
29
|
-
/** Subtitle tracks */
|
|
30
|
-
subtitles?: SubtitleTrack[];
|
|
31
|
-
/** Keep controls always visible (sticky) */
|
|
32
|
-
stickyControls?: boolean;
|
|
33
|
-
}
|
|
34
|
-
export interface PlayerTheme {
|
|
35
|
-
primaryColor?: string;
|
|
36
|
-
accentColor?: string;
|
|
37
|
-
fontFamily?: string;
|
|
38
|
-
controlsBackground?: string;
|
|
39
|
-
buttonHoverBg?: string;
|
|
40
|
-
progressHeight?: string;
|
|
41
|
-
borderRadius?: string;
|
|
42
|
-
}
|
|
43
|
-
export interface S3Config {
|
|
44
|
-
/** Function to sign URL and set CloudFront cookies (returns the original URL after setting cookies) */
|
|
45
|
-
signUrl?: (url: string) => Promise<string>;
|
|
46
|
-
/** Legacy: Function to generate presigned URL (for S3 direct access) */
|
|
47
|
-
getPresignedUrl?: (key: string) => Promise<string>;
|
|
48
|
-
/** CloudFront domain patterns to match (e.g., ['media.domain.com']) */
|
|
49
|
-
cloudFrontDomains?: string[];
|
|
50
|
-
/** Enable credentials (cookies) for HLS requests - required for CloudFront signed cookies */
|
|
51
|
-
withCredentials?: boolean;
|
|
52
|
-
/** S3 bucket region */
|
|
53
|
-
region?: string;
|
|
54
|
-
/** Custom S3 endpoint */
|
|
55
|
-
endpoint?: string;
|
|
56
|
-
}
|
|
57
|
-
export interface AnalyticsConfig {
|
|
58
|
-
/** Enable analytics */
|
|
59
|
-
enabled?: boolean;
|
|
60
|
-
/** Custom analytics endpoint (HTTP/HTTPS) */
|
|
61
|
-
endpoint?: string;
|
|
62
|
-
/** WebSocket handler for real-time analytics streaming (supports both native WebSocket and Socket.IO) */
|
|
63
|
-
webSocket?: WebSocketAnalyticsHandler | SocketIOAnalyticsHandler;
|
|
64
|
-
/** Session identifier */
|
|
65
|
-
sessionId?: string;
|
|
66
|
-
/** User identifier */
|
|
67
|
-
userId?: string;
|
|
68
|
-
/** Video identifier */
|
|
69
|
-
videoId?: string;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Native WebSocket handler for real-time analytics
|
|
73
|
-
*/
|
|
74
|
-
export interface WebSocketAnalyticsHandler {
|
|
75
|
-
/** Type identifier for native WebSocket */
|
|
76
|
-
type: "websocket";
|
|
77
|
-
/** WebSocket connection instance or URL to connect to */
|
|
78
|
-
connection: WebSocket | string;
|
|
79
|
-
/** Optional: Transform event before sending (allows filtering, formatting, etc.) */
|
|
80
|
-
transform?: (event: AnalyticsEvent) => any;
|
|
81
|
-
/** Optional: Error handler for WebSocket errors */
|
|
82
|
-
onError?: (error: Event) => void;
|
|
83
|
-
/** Optional: Handler for when WebSocket connection opens */
|
|
84
|
-
onOpen?: (event: Event) => void;
|
|
85
|
-
/** Optional: Handler for when WebSocket connection closes */
|
|
86
|
-
onClose?: (event: CloseEvent) => void;
|
|
87
|
-
/** Optional: Reconnect automatically on disconnect (default: true) */
|
|
88
|
-
autoReconnect?: boolean;
|
|
89
|
-
/** Optional: Reconnect delay in milliseconds (default: 3000) */
|
|
90
|
-
reconnectDelay?: number;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Socket.IO handler for real-time analytics
|
|
94
|
-
*/
|
|
95
|
-
export interface SocketIOAnalyticsHandler {
|
|
96
|
-
/** Type identifier for Socket.IO */
|
|
97
|
-
type: "socket.io";
|
|
98
|
-
/** Socket.IO client instance or URL to connect to */
|
|
99
|
-
connection: typeof Socket | string;
|
|
100
|
-
/** Optional: Socket.IO connection options (used when connection is a URL) */
|
|
101
|
-
options?: Record<string, any>;
|
|
102
|
-
/** Optional: Event name to emit (default: "analytics") */
|
|
103
|
-
eventName?: string;
|
|
104
|
-
/** Optional: Transform event before sending (allows filtering, formatting, etc.) */
|
|
105
|
-
transform?: (event: AnalyticsEvent) => any;
|
|
106
|
-
/** Optional: Error handler */
|
|
107
|
-
onError?: (error: Error) => void;
|
|
108
|
-
/** Optional: Handler for when connection is established */
|
|
109
|
-
onConnect?: () => void;
|
|
110
|
-
/** Optional: Handler for when connection is lost */
|
|
111
|
-
onDisconnect?: (reason: string) => void;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Player state
|
|
115
|
-
*/
|
|
116
|
-
export interface PlayerState {
|
|
117
|
-
playing: boolean;
|
|
118
|
-
paused: boolean;
|
|
119
|
-
ended: boolean;
|
|
120
|
-
buffering: boolean;
|
|
121
|
-
currentTime: number;
|
|
122
|
-
duration: number;
|
|
123
|
-
volume: number;
|
|
124
|
-
muted: boolean;
|
|
125
|
-
playbackRate: number;
|
|
126
|
-
quality: string;
|
|
127
|
-
availableQualities: string[];
|
|
128
|
-
fullscreen: boolean;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Player events (compatible with Mux Player and HTML5 MediaElement events)
|
|
132
|
-
*/
|
|
133
|
-
export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "pictureinpictureenter" | "pictureinpictureexit" | "resize" | "sourcechange";
|
|
134
|
-
export interface PlayerEvent {
|
|
135
|
-
type: PlayerEventType;
|
|
136
|
-
data?: any;
|
|
137
|
-
timestamp: number;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Analytics event types
|
|
141
|
-
*/
|
|
142
|
-
export interface AnalyticsEvent {
|
|
143
|
-
eventType: string;
|
|
144
|
-
timestamp: number;
|
|
145
|
-
sessionId: string;
|
|
146
|
-
videoId?: string;
|
|
147
|
-
userId?: string;
|
|
148
|
-
data: Record<string, any>;
|
|
149
|
-
}
|
|
150
|
-
export interface QualityLevel {
|
|
151
|
-
height: number;
|
|
152
|
-
width: number;
|
|
153
|
-
bitrate: number;
|
|
154
|
-
name: string;
|
|
155
|
-
}
|
|
156
|
-
export interface SubtitleTrack {
|
|
157
|
-
label: string;
|
|
158
|
-
src: string;
|
|
159
|
-
srclang: string;
|
|
160
|
-
default?: boolean;
|
|
161
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { WontumPlayer } from './player';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* UI Controller - Manages player controls and interface
|
|
5
|
-
*/
|
|
6
|
-
export declare class UIController {
|
|
7
|
-
private container;
|
|
8
|
-
private player;
|
|
9
|
-
private controlsContainer;
|
|
10
|
-
private progressContainer;
|
|
11
|
-
private progressBar;
|
|
12
|
-
private playButton;
|
|
13
|
-
private skipBackwardButton;
|
|
14
|
-
private skipForwardButton;
|
|
15
|
-
private volumeButton;
|
|
16
|
-
private volumeContainer;
|
|
17
|
-
private fullscreenButton;
|
|
18
|
-
private pipButton;
|
|
19
|
-
private settingsButton;
|
|
20
|
-
private volumeSlider;
|
|
21
|
-
private progressInput;
|
|
22
|
-
private hideControlsTimeout;
|
|
23
|
-
private stickyControls;
|
|
24
|
-
private isVolumeSliderActive;
|
|
25
|
-
constructor(container: HTMLElement, player: WontumPlayer);
|
|
26
|
-
private injectStyles;
|
|
27
|
-
private createProgressBar;
|
|
28
|
-
private createControls;
|
|
29
|
-
private setupEventListeners;
|
|
30
|
-
private setupPlayerEventListeners;
|
|
31
|
-
private updateSubtitleMenu;
|
|
32
|
-
private updateSpeedMenu;
|
|
33
|
-
private updateSettingsMenu;
|
|
34
|
-
private updateQualityMenu;
|
|
35
|
-
private showControls;
|
|
36
|
-
private hideControls;
|
|
37
|
-
private resetHideControlsTimeout;
|
|
38
|
-
private formatTime;
|
|
39
|
-
private getPlayIcon;
|
|
40
|
-
private getPauseIcon;
|
|
41
|
-
private getVolumeIcon;
|
|
42
|
-
private getMutedIcon;
|
|
43
|
-
private getFullscreenIcon;
|
|
44
|
-
private getPipIcon;
|
|
45
|
-
private getSkipBackwardIcon;
|
|
46
|
-
private getSkipForwardIcon;
|
|
47
|
-
private getSettingsIcon;
|
|
48
|
-
destroy(): void;
|
|
49
|
-
}
|