@viewlift/player-backup 1.0.0-lighteningjs → 1.0.1-lighteningjs
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.cjs.css +2 -0
- package/dist/index.cjs.css.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -15
- package/dist/index.esm.css +2 -0
- package/dist/index.esm.css.map +1 -0
- package/dist/index.esm.js +1 -1
- package/dist/main-player/player-ui.d.ts +19 -0
- package/dist/player-components/player-buttons/playerButtons.d.ts +38 -0
- package/dist/player-components/player-seekbar/playerSeekbar.d.ts +25 -0
- package/dist/player-ui/player-ui.d.ts +18 -0
- package/dist/playerInitializer.d.ts +13 -0
- package/package.json +3 -2
- package/rollup.config.mjs +7 -1
- package/src/index.ts +36 -55
- package/src/main-player/player-ui.ts +65 -0
- package/src/player-components/player-buttons/playerButtons.css +0 -0
- package/src/player-components/player-buttons/playerButtons.ts +127 -0
- package/src/player-components/player-seekbar/playerSeekbar.css +75 -0
- package/src/player-components/player-seekbar/playerSeekbar.ts +158 -0
- package/src/player-ui/player-ui.css +8 -0
- package/src/player-ui/player-ui.ts +79 -0
- package/src/playerInitializer.ts +54 -0
- package/tsconfig.json +3 -2
- package/dist/utility.d.ts +0 -6
- package/src/utility.ts +0 -109
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.seekbar-container{background:#444;border-radius:6px;bottom:50px;cursor:pointer;height:12px;left:50%;margin:0;position:absolute;transform:translateX(-50%);user-select:none;width:90%;z-index:20}.seekbar-buffer{background:#888;z-index:1}.seekbar-buffer,.seekbar-progress{border-radius:6px;height:100%;position:absolute;width:0}.seekbar-progress{background:#4169e1;transition:width .1s linear;z-index:2}.seekbar-thumb{background:#fff;border:2px solid #4169e1;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.2);cursor:pointer;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s;width:16px;z-index:3}.seekbar-thumb:hover{background:#ffeaea}.seekbar-tooltip{background:#222;border-radius:4px;bottom:24px;color:#fff;font-size:12px;left:0;padding:2px 8px;pointer-events:none;position:absolute;transform:translateX(-50%);white-space:nowrap;z-index:10}.seekbar-duration-label,.seekbar-time-label{color:#eee;font-size:13px;margin-right:4px;position:relative;top:18px;z-index:5}.play-pause-btn{left:50%;position:absolute!important;top:50%;transform:translate(-50%,-50%);z-index:30}
|
|
2
|
+
/*# sourceMappingURL=index.cjs.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["playerSeekbar.css","player-ui.css"],"names":[],"mappings":"AAAA,mBAME,eAAgB,CAGhB,iBAAkB,CALlB,WAAY,CAIZ,cAAe,CAHf,WAAY,CAHZ,QAAS,CAQT,QAAS,CATT,iBAAkB,CAElB,0BAA2B,CAQ3B,gBAAiB,CAJjB,SAAU,CAKV,UACF,CAEA,gBAGE,eAAgB,CAGhB,SACF,CAEA,kCAJE,iBAAkB,CAHlB,WAAY,CADZ,iBAAkB,CAGlB,OAaF,CARA,kBAGE,kBAAmB,CAInB,2BAA6B,CAD7B,SAEF,CAEA,eAME,eAAgB,CAEhB,wBAAyB,CADzB,iBAAkB,CAGlB,mCAAqC,CACrC,cAAe,CANf,WAAY,CAJZ,iBAAkB,CAClB,OAAQ,CACR,8BAAgC,CAShC,yBAA2B,CAR3B,UAAW,CAKX,SAIF,CACA,qBACE,kBACF,CAEA,iBAKE,eAAgB,CAGhB,iBAAkB,CANlB,WAAY,CAIZ,UAAW,CAGX,cAAe,CANf,MAAO,CAIP,eAAgB,CAIhB,mBAAoB,CAVpB,iBAAkB,CAGlB,0BAA2B,CAM3B,kBAAmB,CAEnB,UACF,CAEA,4CAIE,UAAW,CADX,cAAe,CAEf,gBAAiB,CAJjB,iBAAkB,CAClB,QAAS,CAIT,SACF,CCzEA,gBAEE,QAAS,CADT,2BAA6B,CAE7B,OAAQ,CACR,8BAAgC,CAChC,UACF","file":"index.cjs.css","sourcesContent":[".seekbar-container {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: 50px;\n height: 12px;\n background: #444;\n width: 90%;\n cursor: pointer;\n border-radius: 6px;\n margin: 0;\n user-select: none;\n z-index: 20;\n}\n\n.seekbar-buffer {\n position: absolute;\n height: 100%;\n background: #888;\n width: 0;\n border-radius: 6px;\n z-index: 1;\n}\n\n.seekbar-progress {\n position: absolute;\n height: 100%;\n background: #4169E1;\n width: 0;\n border-radius: 6px;\n z-index: 2;\n transition: width 0.1s linear;\n}\n\n.seekbar-thumb {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 16px;\n height: 16px;\n background: #fff;\n border-radius: 50%;\n border: 2px solid #4169E1;\n z-index: 3;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n cursor: pointer;\n transition: background 0.2s;\n}\n.seekbar-thumb:hover {\n background: #ffeaea;\n}\n\n.seekbar-tooltip {\n position: absolute;\n bottom: 24px;\n left: 0;\n transform: translateX(-50%);\n background: #222;\n color: #fff;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 12px;\n white-space: nowrap;\n pointer-events: none;\n z-index: 10;\n}\n\n.seekbar-time-label, .seekbar-duration-label {\n position: relative;\n top: 18px;\n font-size: 13px;\n color: #eee;\n margin-right: 4px;\n z-index: 5;\n}\n","/* Center play/pause button absolutely in the middle of the player */\n.play-pause-btn {\n position: absolute !important;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n z-index: 30;\n} "]}
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";var t=function(){return t=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var s in e=arguments[n])Object.prototype.hasOwnProperty.call(e,s)&&(t[s]=e[s]);return t},t.apply(this,arguments)};"function"==typeof SuppressedError&&SuppressedError;var e=function(){function t(t){if(this.imgSrc=t.imgSrc||"",this.imgAltText=t.imgAltText||"",this.buttonText=t.buttonText||"",this.klassname=t.klassname||"default-button",this.width=t.width||100,this.height=t.height||50,this.focused=t.focused||!1,this.disabled=t.disabled||!1,this.handleClick=t.handleClick||function(){},"function"!=typeof t.handleClick)throw new Error("Button Class: handleClick must be a function");this.disabled&&(this.klassname+=" disabled"),this.focused&&(this.klassname+=" focused"),this.handleClick=this.handleClick.bind(this)}return t.prototype.mount=function(t){var e=this,n=document.createElement("button");if(n.className=this.klassname,n.style.width="".concat(this.width,"px"),n.style.height="".concat(this.height,"px"),n.disabled=this.disabled,n.tabIndex=0,this.imgSrc){var i=document.createElement("img");i.src=this.imgSrc,i.alt=this.imgAltText,n.appendChild(i)}else{var s=document.createElement("span");s.textContent=this.buttonText,n.appendChild(s)}n.addEventListener("click",this.handleClick),n.addEventListener("focus",function(){e.focused=!0,n.classList.add("focused")}),n.addEventListener("blur",function(){e.focused=!1,n.classList.remove("focused")}),this.buttonElement=n,t.appendChild(n)},t.prototype.unmount=function(){this.buttonElement&&(this.buttonElement.removeEventListener("click",this.handleClick),this.buttonElement.removeEventListener("focus",this.handleClick),this.buttonElement.removeEventListener("blur",this.handleClick),this.buttonElement=void 0)},t.prototype.focus=function(){this.buttonElement&&(this.buttonElement.focus(),this.buttonElement.classList.add("focused"),this.focused=!0)},t.prototype.blur=function(){this.buttonElement&&(this.buttonElement.blur(),this.buttonElement.classList.remove("focused"),this.focused=!1)},t}(),n=function(){function t(t){var e=this;this.isDragging=!1,this.focused=!1,this.video=t,this.container=document.createElement("div"),this.container.className="seekbar-container",this.container.tabIndex=0,this.buffer=document.createElement("div"),this.buffer.className="seekbar-buffer",this.progress=document.createElement("div"),this.progress.className="seekbar-progress",this.thumb=document.createElement("div"),this.thumb.className="seekbar-thumb",this.tooltip=document.createElement("div"),this.tooltip.className="seekbar-tooltip",this.tooltip.style.display="none",this.timeLabel=document.createElement("span"),this.timeLabel.className="seekbar-time-label",this.durationLabel=document.createElement("span"),this.durationLabel.className="seekbar-duration-label",this.container.appendChild(this.buffer),this.container.appendChild(this.progress),this.container.appendChild(this.thumb),this.container.appendChild(this.tooltip),this.container.appendChild(this.timeLabel),this.container.appendChild(this.durationLabel),this.video.addEventListener("timeupdate",function(){return e.update()}),this.video.addEventListener("progress",function(){return e.updateBuffer()}),this.video.addEventListener("durationchange",function(){return e.update()}),this.container.addEventListener("click",function(t){return e.seek(t)}),this.thumb.addEventListener("mousedown",function(t){return e.startDrag(t)}),this.container.addEventListener("mousemove",function(t){return e.showTooltip(t)}),this.container.addEventListener("mouseleave",function(){return e.hideTooltip()}),this.container.addEventListener("focus",function(){e.focused=!0,e.container.classList.add("focused")}),this.container.addEventListener("blur",function(){e.focused=!1,e.container.classList.remove("focused")})}return t.prototype.focus=function(){this.container.focus(),this.container.classList.add("focused"),this.focused=!0},t.prototype.blur=function(){this.container.blur(),this.container.classList.remove("focused"),this.focused=!1},t.prototype.formatTime=function(t){if(isNaN(t))return"0:00";var e=Math.floor(t/60),n=Math.floor(t%60);return"".concat(e,":").concat(String(n).padStart(2,"0"))},t.prototype.update=function(){var t=this.video.currentTime/this.video.duration*100;this.progress.style.width=t+"%",this.thumb.style.left=t+"%",this.timeLabel.textContent=this.formatTime(this.video.currentTime),this.durationLabel.textContent=" / "+this.formatTime(this.video.duration)},t.prototype.updateBuffer=function(){if(this.video.buffered.length){var t=this.video.buffered.end(this.video.buffered.length-1)/this.video.duration*100;this.buffer.style.width=t+"%"}},t.prototype.seek=function(t){if(!this.isDragging){var e=this.container.getBoundingClientRect(),n=(t.clientX-e.left)/e.width;this.video.currentTime=n*this.video.duration}},t.prototype.startDrag=function(t){var e=this;t.preventDefault(),this.isDragging=!0;var n=function(t){var n=e.container.getBoundingClientRect(),i=(t.clientX-n.left)/n.width;i=Math.max(0,Math.min(1,i)),e.progress.style.width=100*i+"%",e.thumb.style.left=100*i+"%",e.timeLabel.textContent=e.formatTime(i*e.video.duration)},i=function(t){var s=e.container.getBoundingClientRect(),o=(t.clientX-s.left)/s.width;o=Math.max(0,Math.min(1,o)),e.video.currentTime=o*e.video.duration,e.isDragging=!1,document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",i)};document.addEventListener("mousemove",n),document.addEventListener("mouseup",i)},t.prototype.showTooltip=function(t){var e=this.container.getBoundingClientRect(),n=(t.clientX-e.left)/e.width,i=n*this.video.duration;this.tooltip.textContent=this.formatTime(i),this.tooltip.style.display="block",this.tooltip.style.left="".concat(100*n,"%")},t.prototype.hideTooltip=function(){this.tooltip.style.display="none"},t.prototype.mount=function(t){t.appendChild(this.container),this.update(),this.updateBuffer()},t.prototype.getElement=function(){return this.container},t}(),i=function(){function t(t){var e=t.player;this.player=e,this.container=document.createElement("div"),this.container.className="video-player-ui",this.createControls()}return t.prototype.createControls=function(){var t,i,s,o=this;this.playPauseBtn=new e({imgSrc:"",imgAltText:"Play/Pause",buttonText:"Play",width:80,height:40,klassname:"play-pause-btn",focused:!1,disabled:!1,handleClick:function(){o.player.video.paused?(o.player.play(),o.playPauseBtn&&o.playPauseBtn.buttonElement&&(o.playPauseBtn.buttonElement.textContent="Pause")):(o.player.pause(),o.playPauseBtn&&o.playPauseBtn.buttonElement&&(o.playPauseBtn.buttonElement.textContent="Play"))}}),this.playPauseBtn.mount(this.container),this.container.appendChild(this.player.video),this.seekbar=new n(this.player.video),this.seekbar.mount(this.container),(null===(t=this.playPauseBtn)||void 0===t?void 0:t.buttonElement)&&this.seekbar&&(this.playPauseBtn.buttonElement.addEventListener("keydown",function(t){var e;"ArrowDown"===t.key&&(t.preventDefault(),null===(e=o.seekbar)||void 0===e||e.focus())}),null===(s=null===(i=this.seekbar)||void 0===i?void 0:i.getElement())||void 0===s||s.addEventListener("keydown",function(t){var e;"ArrowUp"===t.key&&(t.preventDefault(),null===(e=o.playPauseBtn)||void 0===e||e.focus())}))},t.prototype.attachTo=function(t){t.appendChild(this.container)},t.prototype.getElement=function(){return this.container},t}();exports.createHlsPlayer=function(e,n){var s=document.createElement("video");s.controls=!1,s.style.width="100%",s.style.height="100%";var o=null;if(window.Hls&&window.Hls.isSupported())(o=new window.Hls).loadSource(n),o.attachMedia(s),o.on(window.Hls.Events.MANIFEST_PARSED,function(){s.play()});else{if(!s.canPlayType("application/vnd.apple.mpegurl"))throw new Error("HLS is not supported in this browser.");s.src=n,s.addEventListener("loadedmetadata",function(){s.play()})}var a={video:s,play:function(){return s.play()},pause:function(){return s.pause()}},r=new i({player:a});return r.attachTo(e),t(t({},a),{ui:r})};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,12 @@
|
|
|
1
|
-
import '@viewlift/player-backup/esm/bundle.css';
|
|
2
1
|
export interface VideoPlayerOptions {
|
|
3
2
|
onPlaybackSuccess?: () => void;
|
|
4
3
|
onPlaybackEnded?: () => void;
|
|
5
4
|
onPlaybackError?: (error?: any) => void;
|
|
6
|
-
|
|
7
|
-
contentId: string;
|
|
8
|
-
profileId: string;
|
|
9
|
-
deviceId: string;
|
|
10
|
-
authToken: string;
|
|
5
|
+
src: string;
|
|
11
6
|
autoplay?: boolean;
|
|
12
7
|
controls?: boolean;
|
|
13
8
|
width?: number;
|
|
14
9
|
height?: number;
|
|
15
|
-
deviceName: DeviceType;
|
|
16
|
-
}
|
|
17
|
-
declare enum DeviceType {
|
|
18
|
-
LG = "lgTv",
|
|
19
|
-
Vizio = "vizioTv",
|
|
20
|
-
XfinityX1 = "xfinityX1",
|
|
21
|
-
Xbox = "xbox",
|
|
22
|
-
Samsung = "samsungTv"
|
|
23
10
|
}
|
|
24
11
|
type EventHandler = (...args: any[]) => void;
|
|
25
12
|
type VideoPlayerEvent = 'play' | 'pause' | 'ended' | 'timeupdate' | 'error' | 'loadedmetadata' | 'seeking' | 'seeked' | 'volumechange';
|
|
@@ -27,13 +14,13 @@ export declare class LightningVideoPlayer {
|
|
|
27
14
|
/**
|
|
28
15
|
* Reinitialize the current videoElement with a new set of options and handle autoplay.
|
|
29
16
|
*/
|
|
17
|
+
reinitialize(options: VideoPlayerOptions): void;
|
|
30
18
|
private videoElement;
|
|
31
19
|
private options;
|
|
32
20
|
private listeners;
|
|
33
21
|
private boundEmitters;
|
|
34
22
|
private boundHandlerMap;
|
|
35
23
|
constructor(options: VideoPlayerOptions);
|
|
36
|
-
initialize(): boolean;
|
|
37
24
|
attachTo(container: HTMLElement): void;
|
|
38
25
|
play(): void;
|
|
39
26
|
pause(): void;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.seekbar-container{background:#444;border-radius:6px;bottom:50px;cursor:pointer;height:12px;left:50%;margin:0;position:absolute;transform:translateX(-50%);user-select:none;width:90%;z-index:20}.seekbar-buffer{background:#888;z-index:1}.seekbar-buffer,.seekbar-progress{border-radius:6px;height:100%;position:absolute;width:0}.seekbar-progress{background:#4169e1;transition:width .1s linear;z-index:2}.seekbar-thumb{background:#fff;border:2px solid #4169e1;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.2);cursor:pointer;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s;width:16px;z-index:3}.seekbar-thumb:hover{background:#ffeaea}.seekbar-tooltip{background:#222;border-radius:4px;bottom:24px;color:#fff;font-size:12px;left:0;padding:2px 8px;pointer-events:none;position:absolute;transform:translateX(-50%);white-space:nowrap;z-index:10}.seekbar-duration-label,.seekbar-time-label{color:#eee;font-size:13px;margin-right:4px;position:relative;top:18px;z-index:5}.play-pause-btn{left:50%;position:absolute!important;top:50%;transform:translate(-50%,-50%);z-index:30}
|
|
2
|
+
/*# sourceMappingURL=index.esm.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["playerSeekbar.css","player-ui.css"],"names":[],"mappings":"AAAA,mBAME,eAAgB,CAGhB,iBAAkB,CALlB,WAAY,CAIZ,cAAe,CAHf,WAAY,CAHZ,QAAS,CAQT,QAAS,CATT,iBAAkB,CAElB,0BAA2B,CAQ3B,gBAAiB,CAJjB,SAAU,CAKV,UACF,CAEA,gBAGE,eAAgB,CAGhB,SACF,CAEA,kCAJE,iBAAkB,CAHlB,WAAY,CADZ,iBAAkB,CAGlB,OAaF,CARA,kBAGE,kBAAmB,CAInB,2BAA6B,CAD7B,SAEF,CAEA,eAME,eAAgB,CAEhB,wBAAyB,CADzB,iBAAkB,CAGlB,mCAAqC,CACrC,cAAe,CANf,WAAY,CAJZ,iBAAkB,CAClB,OAAQ,CACR,8BAAgC,CAShC,yBAA2B,CAR3B,UAAW,CAKX,SAIF,CACA,qBACE,kBACF,CAEA,iBAKE,eAAgB,CAGhB,iBAAkB,CANlB,WAAY,CAIZ,UAAW,CAGX,cAAe,CANf,MAAO,CAIP,eAAgB,CAIhB,mBAAoB,CAVpB,iBAAkB,CAGlB,0BAA2B,CAM3B,kBAAmB,CAEnB,UACF,CAEA,4CAIE,UAAW,CADX,cAAe,CAEf,gBAAiB,CAJjB,iBAAkB,CAClB,QAAS,CAIT,SACF,CCzEA,gBAEE,QAAS,CADT,2BAA6B,CAE7B,OAAQ,CACR,8BAAgC,CAChC,UACF","file":"index.esm.css","sourcesContent":[".seekbar-container {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: 50px;\n height: 12px;\n background: #444;\n width: 90%;\n cursor: pointer;\n border-radius: 6px;\n margin: 0;\n user-select: none;\n z-index: 20;\n}\n\n.seekbar-buffer {\n position: absolute;\n height: 100%;\n background: #888;\n width: 0;\n border-radius: 6px;\n z-index: 1;\n}\n\n.seekbar-progress {\n position: absolute;\n height: 100%;\n background: #4169E1;\n width: 0;\n border-radius: 6px;\n z-index: 2;\n transition: width 0.1s linear;\n}\n\n.seekbar-thumb {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 16px;\n height: 16px;\n background: #fff;\n border-radius: 50%;\n border: 2px solid #4169E1;\n z-index: 3;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n cursor: pointer;\n transition: background 0.2s;\n}\n.seekbar-thumb:hover {\n background: #ffeaea;\n}\n\n.seekbar-tooltip {\n position: absolute;\n bottom: 24px;\n left: 0;\n transform: translateX(-50%);\n background: #222;\n color: #fff;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: 12px;\n white-space: nowrap;\n pointer-events: none;\n z-index: 10;\n}\n\n.seekbar-time-label, .seekbar-duration-label {\n position: relative;\n top: 18px;\n font-size: 13px;\n color: #eee;\n margin-right: 4px;\n z-index: 5;\n}\n","/* Center play/pause button absolutely in the middle of the player */\n.play-pause-btn {\n position: absolute !important;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n z-index: 30;\n} "]}
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
var t=function(){return t=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var o in e=arguments[n])Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t},t.apply(this,arguments)};"function"==typeof SuppressedError&&SuppressedError;var e=function(){function t(t){if(this.imgSrc=t.imgSrc||"",this.imgAltText=t.imgAltText||"",this.buttonText=t.buttonText||"",this.klassname=t.klassname||"default-button",this.width=t.width||100,this.height=t.height||50,this.focused=t.focused||!1,this.disabled=t.disabled||!1,this.handleClick=t.handleClick||function(){},"function"!=typeof t.handleClick)throw new Error("Button Class: handleClick must be a function");this.disabled&&(this.klassname+=" disabled"),this.focused&&(this.klassname+=" focused"),this.handleClick=this.handleClick.bind(this)}return t.prototype.mount=function(t){var e=this,n=document.createElement("button");if(n.className=this.klassname,n.style.width="".concat(this.width,"px"),n.style.height="".concat(this.height,"px"),n.disabled=this.disabled,n.tabIndex=0,this.imgSrc){var i=document.createElement("img");i.src=this.imgSrc,i.alt=this.imgAltText,n.appendChild(i)}else{var o=document.createElement("span");o.textContent=this.buttonText,n.appendChild(o)}n.addEventListener("click",this.handleClick),n.addEventListener("focus",function(){e.focused=!0,n.classList.add("focused")}),n.addEventListener("blur",function(){e.focused=!1,n.classList.remove("focused")}),this.buttonElement=n,t.appendChild(n)},t.prototype.unmount=function(){this.buttonElement&&(this.buttonElement.removeEventListener("click",this.handleClick),this.buttonElement.removeEventListener("focus",this.handleClick),this.buttonElement.removeEventListener("blur",this.handleClick),this.buttonElement=void 0)},t.prototype.focus=function(){this.buttonElement&&(this.buttonElement.focus(),this.buttonElement.classList.add("focused"),this.focused=!0)},t.prototype.blur=function(){this.buttonElement&&(this.buttonElement.blur(),this.buttonElement.classList.remove("focused"),this.focused=!1)},t}(),n=function(){function t(t){var e=this;this.isDragging=!1,this.focused=!1,this.video=t,this.container=document.createElement("div"),this.container.className="seekbar-container",this.container.tabIndex=0,this.buffer=document.createElement("div"),this.buffer.className="seekbar-buffer",this.progress=document.createElement("div"),this.progress.className="seekbar-progress",this.thumb=document.createElement("div"),this.thumb.className="seekbar-thumb",this.tooltip=document.createElement("div"),this.tooltip.className="seekbar-tooltip",this.tooltip.style.display="none",this.timeLabel=document.createElement("span"),this.timeLabel.className="seekbar-time-label",this.durationLabel=document.createElement("span"),this.durationLabel.className="seekbar-duration-label",this.container.appendChild(this.buffer),this.container.appendChild(this.progress),this.container.appendChild(this.thumb),this.container.appendChild(this.tooltip),this.container.appendChild(this.timeLabel),this.container.appendChild(this.durationLabel),this.video.addEventListener("timeupdate",function(){return e.update()}),this.video.addEventListener("progress",function(){return e.updateBuffer()}),this.video.addEventListener("durationchange",function(){return e.update()}),this.container.addEventListener("click",function(t){return e.seek(t)}),this.thumb.addEventListener("mousedown",function(t){return e.startDrag(t)}),this.container.addEventListener("mousemove",function(t){return e.showTooltip(t)}),this.container.addEventListener("mouseleave",function(){return e.hideTooltip()}),this.container.addEventListener("focus",function(){e.focused=!0,e.container.classList.add("focused")}),this.container.addEventListener("blur",function(){e.focused=!1,e.container.classList.remove("focused")})}return t.prototype.focus=function(){this.container.focus(),this.container.classList.add("focused"),this.focused=!0},t.prototype.blur=function(){this.container.blur(),this.container.classList.remove("focused"),this.focused=!1},t.prototype.formatTime=function(t){if(isNaN(t))return"0:00";var e=Math.floor(t/60),n=Math.floor(t%60);return"".concat(e,":").concat(String(n).padStart(2,"0"))},t.prototype.update=function(){var t=this.video.currentTime/this.video.duration*100;this.progress.style.width=t+"%",this.thumb.style.left=t+"%",this.timeLabel.textContent=this.formatTime(this.video.currentTime),this.durationLabel.textContent=" / "+this.formatTime(this.video.duration)},t.prototype.updateBuffer=function(){if(this.video.buffered.length){var t=this.video.buffered.end(this.video.buffered.length-1)/this.video.duration*100;this.buffer.style.width=t+"%"}},t.prototype.seek=function(t){if(!this.isDragging){var e=this.container.getBoundingClientRect(),n=(t.clientX-e.left)/e.width;this.video.currentTime=n*this.video.duration}},t.prototype.startDrag=function(t){var e=this;t.preventDefault(),this.isDragging=!0;var n=function(t){var n=e.container.getBoundingClientRect(),i=(t.clientX-n.left)/n.width;i=Math.max(0,Math.min(1,i)),e.progress.style.width=100*i+"%",e.thumb.style.left=100*i+"%",e.timeLabel.textContent=e.formatTime(i*e.video.duration)},i=function(t){var o=e.container.getBoundingClientRect(),s=(t.clientX-o.left)/o.width;s=Math.max(0,Math.min(1,s)),e.video.currentTime=s*e.video.duration,e.isDragging=!1,document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",i)};document.addEventListener("mousemove",n),document.addEventListener("mouseup",i)},t.prototype.showTooltip=function(t){var e=this.container.getBoundingClientRect(),n=(t.clientX-e.left)/e.width,i=n*this.video.duration;this.tooltip.textContent=this.formatTime(i),this.tooltip.style.display="block",this.tooltip.style.left="".concat(100*n,"%")},t.prototype.hideTooltip=function(){this.tooltip.style.display="none"},t.prototype.mount=function(t){t.appendChild(this.container),this.update(),this.updateBuffer()},t.prototype.getElement=function(){return this.container},t}(),i=function(){function t(t){var e=t.player;this.player=e,this.container=document.createElement("div"),this.container.className="video-player-ui",this.createControls()}return t.prototype.createControls=function(){var t,i,o,s=this;this.playPauseBtn=new e({imgSrc:"",imgAltText:"Play/Pause",buttonText:"Play",width:80,height:40,klassname:"play-pause-btn",focused:!1,disabled:!1,handleClick:function(){s.player.video.paused?(s.player.play(),s.playPauseBtn&&s.playPauseBtn.buttonElement&&(s.playPauseBtn.buttonElement.textContent="Pause")):(s.player.pause(),s.playPauseBtn&&s.playPauseBtn.buttonElement&&(s.playPauseBtn.buttonElement.textContent="Play"))}}),this.playPauseBtn.mount(this.container),this.container.appendChild(this.player.video),this.seekbar=new n(this.player.video),this.seekbar.mount(this.container),(null===(t=this.playPauseBtn)||void 0===t?void 0:t.buttonElement)&&this.seekbar&&(this.playPauseBtn.buttonElement.addEventListener("keydown",function(t){var e;"ArrowDown"===t.key&&(t.preventDefault(),null===(e=s.seekbar)||void 0===e||e.focus())}),null===(o=null===(i=this.seekbar)||void 0===i?void 0:i.getElement())||void 0===o||o.addEventListener("keydown",function(t){var e;"ArrowUp"===t.key&&(t.preventDefault(),null===(e=s.playPauseBtn)||void 0===e||e.focus())}))},t.prototype.attachTo=function(t){t.appendChild(this.container)},t.prototype.getElement=function(){return this.container},t}();function o(e,n){var o=document.createElement("video");o.controls=!1,o.style.width="100%",o.style.height="100%";var s=null;if(window.Hls&&window.Hls.isSupported())(s=new window.Hls).loadSource(n),s.attachMedia(o),s.on(window.Hls.Events.MANIFEST_PARSED,function(){o.play()});else{if(!o.canPlayType("application/vnd.apple.mpegurl"))throw new Error("HLS is not supported in this browser.");o.src=n,o.addEventListener("loadedmetadata",function(){o.play()})}var a={video:o,play:function(){return o.play()},pause:function(){return o.pause()}},r=new i({player:a});return r.attachTo(e),t(t({},a),{ui:r})}export{o as createHlsPlayer};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface VideoPlayerUIOptions {
|
|
2
|
+
player: {
|
|
3
|
+
video: HTMLVideoElement;
|
|
4
|
+
play: () => void;
|
|
5
|
+
pause: () => void;
|
|
6
|
+
};
|
|
7
|
+
width?: string;
|
|
8
|
+
height?: string;
|
|
9
|
+
}
|
|
10
|
+
declare class VideoPlayerUI {
|
|
11
|
+
private player;
|
|
12
|
+
private container;
|
|
13
|
+
private playPauseBtn?;
|
|
14
|
+
private seekbar?;
|
|
15
|
+
constructor({ player, width, height }: VideoPlayerUIOptions);
|
|
16
|
+
private createControls;
|
|
17
|
+
attachTo(parent: HTMLElement): void;
|
|
18
|
+
}
|
|
19
|
+
export default VideoPlayerUI;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import './playerButtons.css';
|
|
2
|
+
type EventHandler = (event?: any) => void;
|
|
3
|
+
type ButtonProps = {
|
|
4
|
+
imgSrc: string;
|
|
5
|
+
imgAltText: string;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
klassname: string;
|
|
9
|
+
buttonText: string;
|
|
10
|
+
focused: boolean;
|
|
11
|
+
disabled: boolean;
|
|
12
|
+
handleClick: EventHandler;
|
|
13
|
+
};
|
|
14
|
+
export declare class Button {
|
|
15
|
+
private imgSrc;
|
|
16
|
+
private imgAltText;
|
|
17
|
+
private klassname;
|
|
18
|
+
private width;
|
|
19
|
+
private height;
|
|
20
|
+
private focused;
|
|
21
|
+
private disabled;
|
|
22
|
+
private handleClick;
|
|
23
|
+
private buttonText;
|
|
24
|
+
buttonElement?: HTMLButtonElement;
|
|
25
|
+
constructor(props: ButtonProps);
|
|
26
|
+
/**
|
|
27
|
+
* Mounts the button to the specified mount point
|
|
28
|
+
* @param mountPoint The HTML element to which the button will be appended
|
|
29
|
+
*/
|
|
30
|
+
mount(mountPoint: HTMLElement): void;
|
|
31
|
+
/**
|
|
32
|
+
* Removes the click event listener from the button
|
|
33
|
+
*/
|
|
34
|
+
unmount(): void;
|
|
35
|
+
focus(): void;
|
|
36
|
+
blur(): void;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import './playerSeekbar.css';
|
|
2
|
+
export declare class PlayerSeekbar {
|
|
3
|
+
private container;
|
|
4
|
+
private progress;
|
|
5
|
+
private buffer;
|
|
6
|
+
private thumb;
|
|
7
|
+
private tooltip;
|
|
8
|
+
private video;
|
|
9
|
+
private timeLabel;
|
|
10
|
+
private durationLabel;
|
|
11
|
+
private isDragging;
|
|
12
|
+
private focused;
|
|
13
|
+
constructor(video: HTMLVideoElement);
|
|
14
|
+
focus(): void;
|
|
15
|
+
blur(): void;
|
|
16
|
+
private formatTime;
|
|
17
|
+
private update;
|
|
18
|
+
private updateBuffer;
|
|
19
|
+
private seek;
|
|
20
|
+
private startDrag;
|
|
21
|
+
private showTooltip;
|
|
22
|
+
private hideTooltip;
|
|
23
|
+
mount(parent: HTMLElement): void;
|
|
24
|
+
getElement(): HTMLDivElement;
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import './player-ui.css';
|
|
2
|
+
declare class VideoPlayerUI {
|
|
3
|
+
private player;
|
|
4
|
+
private container;
|
|
5
|
+
private playPauseBtn?;
|
|
6
|
+
private seekbar?;
|
|
7
|
+
constructor({ player }: {
|
|
8
|
+
player: {
|
|
9
|
+
video: HTMLVideoElement;
|
|
10
|
+
play: () => void;
|
|
11
|
+
pause: () => void;
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
private createControls;
|
|
15
|
+
attachTo(parent: HTMLElement): void;
|
|
16
|
+
getElement(): HTMLDivElement;
|
|
17
|
+
}
|
|
18
|
+
export default VideoPlayerUI;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import VideoPlayerUI from './player-ui/player-ui';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
Hls: any;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export interface PlayerInstance {
|
|
8
|
+
video: HTMLVideoElement;
|
|
9
|
+
play: () => void;
|
|
10
|
+
pause: () => void;
|
|
11
|
+
ui: VideoPlayerUI;
|
|
12
|
+
}
|
|
13
|
+
export declare function createHlsPlayer(mountPoint: HTMLElement, streamUrl: string): PlayerInstance;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viewlift/player-backup",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-lighteningjs",
|
|
4
4
|
"description": "A LightningJS video player component for Smart TV apps.",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
28
28
|
"rollup": "^4.16.4",
|
|
29
29
|
"tslib": "^2.6.2",
|
|
30
|
-
"typescript": "^5.4.5"
|
|
30
|
+
"typescript": "^5.4.5",
|
|
31
|
+
"rollup-plugin-postcss": "^4.0.2"
|
|
31
32
|
}
|
|
32
33
|
}
|
package/rollup.config.mjs
CHANGED
|
@@ -3,9 +3,10 @@ import commonjs from '@rollup/plugin-commonjs';
|
|
|
3
3
|
import terser from '@rollup/plugin-terser';
|
|
4
4
|
import typescript from '@rollup/plugin-typescript';
|
|
5
5
|
import babel from '@rollup/plugin-babel';
|
|
6
|
+
import postcss from 'rollup-plugin-postcss';
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
|
-
input: 'src/
|
|
9
|
+
input: 'src/playerInitializer.ts',
|
|
9
10
|
output: [
|
|
10
11
|
{
|
|
11
12
|
file: 'dist/index.cjs.js',
|
|
@@ -26,6 +27,11 @@ export default {
|
|
|
26
27
|
extensions: ['.js', '.ts'],
|
|
27
28
|
exclude: 'node_modules/**',
|
|
28
29
|
}),
|
|
30
|
+
postcss({
|
|
31
|
+
extract: true, // creates a separate CSS file
|
|
32
|
+
minimize: true,
|
|
33
|
+
sourceMap: true,
|
|
34
|
+
}),
|
|
29
35
|
terser(),
|
|
30
36
|
],
|
|
31
37
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
1
|
// LightningJS-compatible Video Player Component (ES5 compatible)
|
|
2
2
|
|
|
3
|
-
import '@viewlift/player-backup/esm/bundle.css'
|
|
4
|
-
import { getDeviceFullName, getDeviceShortName,getMacros } from './utility';
|
|
5
3
|
export interface VideoPlayerOptions {
|
|
6
4
|
// Optional playback callbacks
|
|
7
5
|
onPlaybackSuccess?: () => void;
|
|
8
6
|
onPlaybackEnded?: () => void;
|
|
9
7
|
onPlaybackError?: (error?: any) => void;
|
|
10
|
-
|
|
11
|
-
contentId: string;
|
|
12
|
-
profileId: string;
|
|
13
|
-
deviceId:string;
|
|
14
|
-
authToken: string
|
|
8
|
+
src: string;
|
|
15
9
|
autoplay?: boolean;
|
|
16
10
|
controls?: boolean;
|
|
17
11
|
width?: number;
|
|
18
|
-
|
|
19
12
|
height?: number;
|
|
20
|
-
deviceName: DeviceType
|
|
21
13
|
// Event callbacks
|
|
22
14
|
}
|
|
23
15
|
|
|
24
|
-
enum DeviceType {
|
|
25
|
-
LG = 'lgTv',
|
|
26
|
-
Vizio = 'vizioTv',
|
|
27
|
-
XfinityX1 = 'xfinityX1',
|
|
28
|
-
Xbox = 'xbox',
|
|
29
|
-
Samsung = 'samsungTv'
|
|
30
|
-
}
|
|
31
16
|
type EventHandler = (...args: any[]) => void;
|
|
32
17
|
|
|
33
18
|
type VideoPlayerEvent =
|
|
@@ -45,7 +30,39 @@ export class LightningVideoPlayer {
|
|
|
45
30
|
/**
|
|
46
31
|
* Reinitialize the current videoElement with a new set of options and handle autoplay.
|
|
47
32
|
*/
|
|
48
|
-
|
|
33
|
+
reinitialize(options: VideoPlayerOptions) {
|
|
34
|
+
this.options = options;
|
|
35
|
+
this.videoElement.src = options.src;
|
|
36
|
+
this.videoElement.autoplay = !!options.autoplay;
|
|
37
|
+
this.videoElement.controls = !!options.controls;
|
|
38
|
+
if (options.width) {
|
|
39
|
+
this.videoElement.width = options.width;
|
|
40
|
+
} else {
|
|
41
|
+
this.videoElement.removeAttribute('width');
|
|
42
|
+
}
|
|
43
|
+
if (options.height) {
|
|
44
|
+
this.videoElement.height = options.height;
|
|
45
|
+
} else {
|
|
46
|
+
this.videoElement.removeAttribute('height');
|
|
47
|
+
}
|
|
48
|
+
// Reset playback state
|
|
49
|
+
this.videoElement.currentTime = 0;
|
|
50
|
+
this.videoElement.pause();
|
|
51
|
+
// If autoplay is set, start playback
|
|
52
|
+
if (options.autoplay) {
|
|
53
|
+
// Wait for metadata to be loaded before playing (for some browsers)
|
|
54
|
+
const playOnLoaded = () => {
|
|
55
|
+
this.videoElement.play();
|
|
56
|
+
this.videoElement.removeEventListener('loadedmetadata', playOnLoaded);
|
|
57
|
+
};
|
|
58
|
+
this.videoElement.addEventListener('loadedmetadata', playOnLoaded);
|
|
59
|
+
// If already loaded, play immediately
|
|
60
|
+
if (this.videoElement.readyState >= 1) {
|
|
61
|
+
this.videoElement.play();
|
|
62
|
+
this.videoElement.removeEventListener('loadedmetadata', playOnLoaded);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
49
66
|
private videoElement: HTMLVideoElement;
|
|
50
67
|
private options: VideoPlayerOptions;
|
|
51
68
|
private listeners: { [event: string]: EventHandler[] } = {};
|
|
@@ -55,8 +72,9 @@ export class LightningVideoPlayer {
|
|
|
55
72
|
constructor(options: VideoPlayerOptions) {
|
|
56
73
|
this.options = options;
|
|
57
74
|
this.videoElement = document.createElement('video');
|
|
58
|
-
this.videoElement.
|
|
75
|
+
this.videoElement.src = options.src;
|
|
59
76
|
this.videoElement.autoplay = !!options.autoplay;
|
|
77
|
+
this.videoElement.controls = !!options.controls;
|
|
60
78
|
if (options.width) this.videoElement.width = options.width;
|
|
61
79
|
if (options.height) this.videoElement.height = options.height;
|
|
62
80
|
this.videoElement.style.display = 'block';
|
|
@@ -81,43 +99,6 @@ export class LightningVideoPlayer {
|
|
|
81
99
|
});
|
|
82
100
|
}
|
|
83
101
|
|
|
84
|
-
initialize() {
|
|
85
|
-
let configurationObject = {
|
|
86
|
-
apiBaseUrl: (window as any).appMainConfig.apiBaseUrl,
|
|
87
|
-
playerId: this.options.playerId,
|
|
88
|
-
videoId: this.options.contentId,
|
|
89
|
-
token: this.options.authToken,
|
|
90
|
-
disableControls: true,
|
|
91
|
-
autoplay:this.options.autoplay,
|
|
92
|
-
watchHistory:{
|
|
93
|
-
enable:false,
|
|
94
|
-
interval:30,
|
|
95
|
-
profileId:this.options.profileId,
|
|
96
|
-
apiVersion:'v2'
|
|
97
|
-
},
|
|
98
|
-
customData: {
|
|
99
|
-
entitlement: {
|
|
100
|
-
deviceType: getDeviceFullName(this.options.deviceName),
|
|
101
|
-
contentConsumption: getDeviceShortName(this.options.deviceName),
|
|
102
|
-
// hba_status: localStorage?.getItem("hba_status")?JSON.stringify(localStorage?.getItem("hba_status")):false,
|
|
103
|
-
// householdID: localStorage?.getItem(window?.appMainConfig?.internalName + "_householdID"),
|
|
104
|
-
},
|
|
105
|
-
beacon: {
|
|
106
|
-
params: {
|
|
107
|
-
pfm: (window as any).appSettings.device
|
|
108
|
-
},
|
|
109
|
-
url: (window as any).appMainConfig.internalName,
|
|
110
|
-
},
|
|
111
|
-
// macros:getMacros(videoPlayBackObject,1920,1080,this.options.deviceName,this.options.deviceId),
|
|
112
|
-
overrideNative:true,
|
|
113
|
-
nativeAudioTracks:false,
|
|
114
|
-
nativeVideoTracks:false,
|
|
115
|
-
onlyPlayReadyDRM:true,
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
return true
|
|
119
|
-
}
|
|
120
|
-
|
|
121
102
|
attachTo(container: HTMLElement) {
|
|
122
103
|
container.appendChild(this.videoElement);
|
|
123
104
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Button } from '../player-components/player-buttons/playerButtons';
|
|
2
|
+
import { PlayerSeekbar } from '../player-components/player-seekbar/playerSeekbar';
|
|
3
|
+
|
|
4
|
+
interface VideoPlayerUIOptions {
|
|
5
|
+
player: { video: HTMLVideoElement; play: () => void; pause: () => void };
|
|
6
|
+
width?: string;
|
|
7
|
+
height?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class VideoPlayerUI {
|
|
11
|
+
private player: { video: HTMLVideoElement; play: () => void; pause: () => void };
|
|
12
|
+
private container: HTMLDivElement;
|
|
13
|
+
private playPauseBtn?: Button;
|
|
14
|
+
private seekbar?: PlayerSeekbar;
|
|
15
|
+
|
|
16
|
+
constructor({ player, width = '1280px', height = '720px' }: VideoPlayerUIOptions) {
|
|
17
|
+
this.player = player;
|
|
18
|
+
this.container = document.createElement('div');
|
|
19
|
+
this.container.className = 'video-player-ui';
|
|
20
|
+
if (width) this.container.style.width = width;
|
|
21
|
+
if (height) this.container.style.height = height;
|
|
22
|
+
this.createControls(width, height);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private createControls(width?: string, height?: string) {
|
|
26
|
+
// Play/Pause button using Button class
|
|
27
|
+
this.playPauseBtn = new Button({
|
|
28
|
+
imgSrc: '', // Optionally provide an image
|
|
29
|
+
imgAltText: 'Play/Pause',
|
|
30
|
+
buttonText: 'Play',
|
|
31
|
+
width: 80,
|
|
32
|
+
height: 40,
|
|
33
|
+
klassname: 'play-pause-btn',
|
|
34
|
+
focused: false,
|
|
35
|
+
disabled: false,
|
|
36
|
+
handleClick: () => {
|
|
37
|
+
if (this.player.video.paused) {
|
|
38
|
+
this.player.play();
|
|
39
|
+
if (this.playPauseBtn && this.playPauseBtn.buttonElement) {
|
|
40
|
+
this.playPauseBtn.buttonElement.textContent = 'Pause';
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
this.player.pause();
|
|
44
|
+
if (this.playPauseBtn && this.playPauseBtn.buttonElement) {
|
|
45
|
+
this.playPauseBtn.buttonElement.textContent = 'Play';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
this.playPauseBtn.mount(this.container);
|
|
51
|
+
// Attach the video element
|
|
52
|
+
if (width) this.player.video.style.width = width;
|
|
53
|
+
if (height) this.player.video.style.height = height;
|
|
54
|
+
this.container.appendChild(this.player.video);
|
|
55
|
+
// Add the seekbar below the video
|
|
56
|
+
this.seekbar = new PlayerSeekbar(this.player.video);
|
|
57
|
+
this.seekbar.mount(this.container);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
attachTo(parent: HTMLElement) {
|
|
61
|
+
parent.appendChild(this.container);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default VideoPlayerUI;
|
|
File without changes
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import './playerButtons.css';
|
|
2
|
+
|
|
3
|
+
type EventHandler = (event?: any) => void;
|
|
4
|
+
|
|
5
|
+
type ButtonProps = {
|
|
6
|
+
imgSrc: string;
|
|
7
|
+
imgAltText: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
klassname: string;
|
|
11
|
+
buttonText: string;
|
|
12
|
+
focused: boolean;
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
handleClick: EventHandler
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class Button {
|
|
18
|
+
|
|
19
|
+
private imgSrc: string;
|
|
20
|
+
private imgAltText: string;
|
|
21
|
+
private klassname: string;
|
|
22
|
+
private width: number;
|
|
23
|
+
private height: number;
|
|
24
|
+
private focused: boolean;
|
|
25
|
+
private disabled: boolean;
|
|
26
|
+
private handleClick: EventHandler;
|
|
27
|
+
private buttonText: string;
|
|
28
|
+
public buttonElement?: HTMLButtonElement;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
constructor(props: ButtonProps) {
|
|
33
|
+
this.imgSrc = props.imgSrc || '';
|
|
34
|
+
this.imgAltText = props.imgAltText || '';
|
|
35
|
+
this.buttonText = props.buttonText || '';
|
|
36
|
+
this.klassname = props.klassname || 'default-button';
|
|
37
|
+
this.width = props.width || 100;
|
|
38
|
+
this.height = props.height || 50;
|
|
39
|
+
this.focused = props.focused || false;
|
|
40
|
+
this.disabled = props.disabled || false;
|
|
41
|
+
this.handleClick = props.handleClick || (() => {});
|
|
42
|
+
|
|
43
|
+
if (typeof props.handleClick !== 'function') {
|
|
44
|
+
throw new Error('Button Class: handleClick must be a function');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (this.disabled) {
|
|
48
|
+
this.klassname += ' disabled';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (this.focused) {
|
|
52
|
+
this.klassname += ' focused';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.handleClick = this.handleClick.bind(this);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Mounts the button to the specified mount point
|
|
60
|
+
* @param mountPoint The HTML element to which the button will be appended
|
|
61
|
+
*/
|
|
62
|
+
mount(mountPoint: HTMLElement) {
|
|
63
|
+
// Create the button element
|
|
64
|
+
const button = document.createElement('button');
|
|
65
|
+
button.className = this.klassname;
|
|
66
|
+
button.style.width = `${this.width}px`;
|
|
67
|
+
button.style.height = `${this.height}px`;
|
|
68
|
+
button.disabled = this.disabled;
|
|
69
|
+
button.tabIndex = 0;
|
|
70
|
+
|
|
71
|
+
// Add image or text
|
|
72
|
+
if (this.imgSrc) {
|
|
73
|
+
const img = document.createElement('img');
|
|
74
|
+
img.src = this.imgSrc;
|
|
75
|
+
img.alt = this.imgAltText;
|
|
76
|
+
button.appendChild(img);
|
|
77
|
+
} else {
|
|
78
|
+
const span = document.createElement('span');
|
|
79
|
+
span.textContent = this.buttonText;
|
|
80
|
+
button.appendChild(span);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Attach event listeners
|
|
84
|
+
button.addEventListener('click', this.handleClick);
|
|
85
|
+
button.addEventListener('focus', () => {
|
|
86
|
+
this.focused = true;
|
|
87
|
+
button.classList.add('focused');
|
|
88
|
+
});
|
|
89
|
+
button.addEventListener('blur', () => {
|
|
90
|
+
this.focused = false;
|
|
91
|
+
button.classList.remove('focused');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Store reference and append
|
|
95
|
+
this.buttonElement = button;
|
|
96
|
+
mountPoint.appendChild(button);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Removes the click event listener from the button
|
|
101
|
+
*/
|
|
102
|
+
unmount() {
|
|
103
|
+
if (this.buttonElement) {
|
|
104
|
+
this.buttonElement.removeEventListener('click', this.handleClick);
|
|
105
|
+
this.buttonElement.removeEventListener('focus', this.handleClick);
|
|
106
|
+
this.buttonElement.removeEventListener('blur', this.handleClick);
|
|
107
|
+
this.buttonElement = undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
focus() {
|
|
112
|
+
if (this.buttonElement) {
|
|
113
|
+
this.buttonElement.focus();
|
|
114
|
+
this.buttonElement.classList.add('focused');
|
|
115
|
+
this.focused = true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
blur() {
|
|
120
|
+
if (this.buttonElement) {
|
|
121
|
+
this.buttonElement.blur();
|
|
122
|
+
this.buttonElement.classList.remove('focused');
|
|
123
|
+
this.focused = false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
.seekbar-container {
|
|
2
|
+
position: absolute;
|
|
3
|
+
left: 50%;
|
|
4
|
+
transform: translateX(-50%);
|
|
5
|
+
bottom: 50px;
|
|
6
|
+
height: 12px;
|
|
7
|
+
background: #444;
|
|
8
|
+
width: 90%;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
border-radius: 6px;
|
|
11
|
+
margin: 0;
|
|
12
|
+
user-select: none;
|
|
13
|
+
z-index: 20;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.seekbar-buffer {
|
|
17
|
+
position: absolute;
|
|
18
|
+
height: 100%;
|
|
19
|
+
background: #888;
|
|
20
|
+
width: 0;
|
|
21
|
+
border-radius: 6px;
|
|
22
|
+
z-index: 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.seekbar-progress {
|
|
26
|
+
position: absolute;
|
|
27
|
+
height: 100%;
|
|
28
|
+
background: #4169E1;
|
|
29
|
+
width: 0;
|
|
30
|
+
border-radius: 6px;
|
|
31
|
+
z-index: 2;
|
|
32
|
+
transition: width 0.1s linear;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.seekbar-thumb {
|
|
36
|
+
position: absolute;
|
|
37
|
+
top: 50%;
|
|
38
|
+
transform: translate(-50%, -50%);
|
|
39
|
+
width: 16px;
|
|
40
|
+
height: 16px;
|
|
41
|
+
background: #fff;
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
border: 2px solid #4169E1;
|
|
44
|
+
z-index: 3;
|
|
45
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
transition: background 0.2s;
|
|
48
|
+
}
|
|
49
|
+
.seekbar-thumb:hover {
|
|
50
|
+
background: #ffeaea;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.seekbar-tooltip {
|
|
54
|
+
position: absolute;
|
|
55
|
+
bottom: 24px;
|
|
56
|
+
left: 0;
|
|
57
|
+
transform: translateX(-50%);
|
|
58
|
+
background: #222;
|
|
59
|
+
color: #fff;
|
|
60
|
+
padding: 2px 8px;
|
|
61
|
+
border-radius: 4px;
|
|
62
|
+
font-size: 12px;
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
z-index: 10;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.seekbar-time-label, .seekbar-duration-label {
|
|
69
|
+
position: relative;
|
|
70
|
+
top: 18px;
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
color: #eee;
|
|
73
|
+
margin-right: 4px;
|
|
74
|
+
z-index: 5;
|
|
75
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import './playerSeekbar.css';
|
|
2
|
+
|
|
3
|
+
export class PlayerSeekbar {
|
|
4
|
+
private container: HTMLDivElement;
|
|
5
|
+
private progress: HTMLDivElement;
|
|
6
|
+
private buffer: HTMLDivElement;
|
|
7
|
+
private thumb: HTMLDivElement;
|
|
8
|
+
private tooltip: HTMLDivElement;
|
|
9
|
+
private video: HTMLVideoElement;
|
|
10
|
+
private timeLabel: HTMLSpanElement;
|
|
11
|
+
private durationLabel: HTMLSpanElement;
|
|
12
|
+
private isDragging: boolean = false;
|
|
13
|
+
private focused: boolean = false;
|
|
14
|
+
|
|
15
|
+
constructor(video: HTMLVideoElement) {
|
|
16
|
+
this.video = video;
|
|
17
|
+
this.container = document.createElement('div');
|
|
18
|
+
this.container.className = 'seekbar-container';
|
|
19
|
+
this.container.tabIndex = 0; // Make focusable
|
|
20
|
+
|
|
21
|
+
this.buffer = document.createElement('div');
|
|
22
|
+
this.buffer.className = 'seekbar-buffer';
|
|
23
|
+
|
|
24
|
+
this.progress = document.createElement('div');
|
|
25
|
+
this.progress.className = 'seekbar-progress';
|
|
26
|
+
|
|
27
|
+
this.thumb = document.createElement('div');
|
|
28
|
+
this.thumb.className = 'seekbar-thumb';
|
|
29
|
+
|
|
30
|
+
this.tooltip = document.createElement('div');
|
|
31
|
+
this.tooltip.className = 'seekbar-tooltip';
|
|
32
|
+
this.tooltip.style.display = 'none';
|
|
33
|
+
|
|
34
|
+
this.timeLabel = document.createElement('span');
|
|
35
|
+
this.timeLabel.className = 'seekbar-time-label';
|
|
36
|
+
this.durationLabel = document.createElement('span');
|
|
37
|
+
this.durationLabel.className = 'seekbar-duration-label';
|
|
38
|
+
|
|
39
|
+
this.container.appendChild(this.buffer);
|
|
40
|
+
this.container.appendChild(this.progress);
|
|
41
|
+
this.container.appendChild(this.thumb);
|
|
42
|
+
this.container.appendChild(this.tooltip);
|
|
43
|
+
this.container.appendChild(this.timeLabel);
|
|
44
|
+
this.container.appendChild(this.durationLabel);
|
|
45
|
+
|
|
46
|
+
// Update UI as video plays
|
|
47
|
+
this.video.addEventListener('timeupdate', () => this.update());
|
|
48
|
+
this.video.addEventListener('progress', () => this.updateBuffer());
|
|
49
|
+
this.video.addEventListener('durationchange', () => this.update());
|
|
50
|
+
|
|
51
|
+
// Seek on click
|
|
52
|
+
this.container.addEventListener('click', (e) => this.seek(e));
|
|
53
|
+
// Dragging
|
|
54
|
+
this.thumb.addEventListener('mousedown', (e) => this.startDrag(e));
|
|
55
|
+
// Tooltip on hover
|
|
56
|
+
this.container.addEventListener('mousemove', (e) => this.showTooltip(e));
|
|
57
|
+
this.container.addEventListener('mouseleave', () => this.hideTooltip());
|
|
58
|
+
|
|
59
|
+
// Focus/blur events for accessibility and visual feedback
|
|
60
|
+
this.container.addEventListener('focus', () => {
|
|
61
|
+
this.focused = true;
|
|
62
|
+
this.container.classList.add('focused');
|
|
63
|
+
});
|
|
64
|
+
this.container.addEventListener('blur', () => {
|
|
65
|
+
this.focused = false;
|
|
66
|
+
this.container.classList.remove('focused');
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public focus() {
|
|
71
|
+
this.container.focus();
|
|
72
|
+
this.container.classList.add('focused');
|
|
73
|
+
this.focused = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public blur() {
|
|
77
|
+
this.container.blur();
|
|
78
|
+
this.container.classList.remove('focused');
|
|
79
|
+
this.focused = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private formatTime(seconds: number): string {
|
|
83
|
+
if (isNaN(seconds)) return '0:00';
|
|
84
|
+
const m = Math.floor(seconds / 60);
|
|
85
|
+
const s = Math.floor(seconds % 60);
|
|
86
|
+
return `${m}:${String(s).padStart(2, '0')}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private update() {
|
|
90
|
+
const percent = (this.video.currentTime / this.video.duration) * 100;
|
|
91
|
+
this.progress.style.width = percent + '%';
|
|
92
|
+
this.thumb.style.left = percent + '%';
|
|
93
|
+
this.timeLabel.textContent = this.formatTime(this.video.currentTime);
|
|
94
|
+
this.durationLabel.textContent = ' / ' + this.formatTime(this.video.duration);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private updateBuffer() {
|
|
98
|
+
if (this.video.buffered.length) {
|
|
99
|
+
const end = this.video.buffered.end(this.video.buffered.length - 1);
|
|
100
|
+
const percent = (end / this.video.duration) * 100;
|
|
101
|
+
this.buffer.style.width = percent + '%';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private seek(e: MouseEvent) {
|
|
106
|
+
if (this.isDragging) return;
|
|
107
|
+
const rect = this.container.getBoundingClientRect();
|
|
108
|
+
const percent = (e.clientX - rect.left) / rect.width;
|
|
109
|
+
this.video.currentTime = percent * this.video.duration;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private startDrag(e: MouseEvent) {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
this.isDragging = true;
|
|
115
|
+
const onMove = (moveEvent: MouseEvent) => {
|
|
116
|
+
const rect = this.container.getBoundingClientRect();
|
|
117
|
+
let percent = (moveEvent.clientX - rect.left) / rect.width;
|
|
118
|
+
percent = Math.max(0, Math.min(1, percent));
|
|
119
|
+
this.progress.style.width = percent * 100 + '%';
|
|
120
|
+
this.thumb.style.left = percent * 100 + '%';
|
|
121
|
+
this.timeLabel.textContent = this.formatTime(percent * this.video.duration);
|
|
122
|
+
};
|
|
123
|
+
const onUp = (upEvent: MouseEvent) => {
|
|
124
|
+
const rect = this.container.getBoundingClientRect();
|
|
125
|
+
let percent = (upEvent.clientX - rect.left) / rect.width;
|
|
126
|
+
percent = Math.max(0, Math.min(1, percent));
|
|
127
|
+
this.video.currentTime = percent * this.video.duration;
|
|
128
|
+
this.isDragging = false;
|
|
129
|
+
document.removeEventListener('mousemove', onMove);
|
|
130
|
+
document.removeEventListener('mouseup', onUp);
|
|
131
|
+
};
|
|
132
|
+
document.addEventListener('mousemove', onMove);
|
|
133
|
+
document.addEventListener('mouseup', onUp);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private showTooltip(e: MouseEvent) {
|
|
137
|
+
const rect = this.container.getBoundingClientRect();
|
|
138
|
+
const percent = (e.clientX - rect.left) / rect.width;
|
|
139
|
+
const time = percent * this.video.duration;
|
|
140
|
+
this.tooltip.textContent = this.formatTime(time);
|
|
141
|
+
this.tooltip.style.display = 'block';
|
|
142
|
+
this.tooltip.style.left = `${percent * 100}%`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private hideTooltip() {
|
|
146
|
+
this.tooltip.style.display = 'none';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public mount(parent: HTMLElement) {
|
|
150
|
+
parent.appendChild(this.container);
|
|
151
|
+
this.update();
|
|
152
|
+
this.updateBuffer();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public getElement() {
|
|
156
|
+
return this.container;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Button } from '../player-components/player-buttons/playerButtons';
|
|
2
|
+
import { PlayerSeekbar } from '../player-components/player-seekbar/playerSeekbar';
|
|
3
|
+
import './player-ui.css';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class VideoPlayerUI {
|
|
7
|
+
private player: { video: HTMLVideoElement; play: () => void; pause: () => void };
|
|
8
|
+
private container: HTMLDivElement;
|
|
9
|
+
private playPauseBtn?: Button;
|
|
10
|
+
private seekbar?: PlayerSeekbar;
|
|
11
|
+
|
|
12
|
+
constructor({ player }: { player: { video: HTMLVideoElement; play: () => void; pause: () => void } }) {
|
|
13
|
+
this.player = player;
|
|
14
|
+
this.container = document.createElement('div');
|
|
15
|
+
this.container.className = 'video-player-ui';
|
|
16
|
+
this.createControls();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private createControls() {
|
|
20
|
+
|
|
21
|
+
this.playPauseBtn = new Button({
|
|
22
|
+
imgSrc: '',
|
|
23
|
+
imgAltText: 'Play/Pause',
|
|
24
|
+
buttonText: 'Play',
|
|
25
|
+
width: 80,
|
|
26
|
+
height: 40,
|
|
27
|
+
klassname: 'play-pause-btn',
|
|
28
|
+
focused: false,
|
|
29
|
+
disabled: false,
|
|
30
|
+
handleClick: () => {
|
|
31
|
+
if (this.player.video.paused) {
|
|
32
|
+
this.player.play();
|
|
33
|
+
if (this.playPauseBtn && this.playPauseBtn.buttonElement) {
|
|
34
|
+
this.playPauseBtn.buttonElement.textContent = 'Pause';
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
this.player.pause();
|
|
38
|
+
if (this.playPauseBtn && this.playPauseBtn.buttonElement) {
|
|
39
|
+
this.playPauseBtn.buttonElement.textContent = 'Play';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
this.playPauseBtn.mount(this.container);
|
|
45
|
+
// Attach the video element
|
|
46
|
+
this.container.appendChild(this.player.video);
|
|
47
|
+
// Add the seekbar below the video
|
|
48
|
+
this.seekbar = new PlayerSeekbar(this.player.video);
|
|
49
|
+
this.seekbar.mount(this.container);
|
|
50
|
+
|
|
51
|
+
if (this.playPauseBtn?.buttonElement && this.seekbar) {
|
|
52
|
+
// Down arrow from play button focuses seekbar
|
|
53
|
+
this.playPauseBtn.buttonElement.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
54
|
+
if (e.key === 'ArrowDown') {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
this.seekbar?.focus();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Up arrow from seekbar focuses play button
|
|
61
|
+
this.seekbar?.getElement()?.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
62
|
+
if (e.key === 'ArrowUp') {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
this.playPauseBtn?.focus();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
attachTo(parent: HTMLElement) {
|
|
71
|
+
parent.appendChild(this.container);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public getElement() {
|
|
75
|
+
return this.container;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default VideoPlayerUI;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import VideoPlayerUI from './player-ui/player-ui';
|
|
2
|
+
|
|
3
|
+
// Declare Hls type for CDN usage
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
Hls: any;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PlayerInstance {
|
|
11
|
+
video: HTMLVideoElement;
|
|
12
|
+
play: () => void;
|
|
13
|
+
pause: () => void;
|
|
14
|
+
ui: VideoPlayerUI;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createHlsPlayer(
|
|
18
|
+
mountPoint: HTMLElement,
|
|
19
|
+
streamUrl: string
|
|
20
|
+
): PlayerInstance {
|
|
21
|
+
const video = document.createElement('video');
|
|
22
|
+
video.controls = false;
|
|
23
|
+
video.style.width = '100%';
|
|
24
|
+
video.style.height = '100%';
|
|
25
|
+
|
|
26
|
+
let hls: any = null;
|
|
27
|
+
|
|
28
|
+
if (window.Hls && window.Hls.isSupported()) {
|
|
29
|
+
hls = new window.Hls();
|
|
30
|
+
hls.loadSource(streamUrl);
|
|
31
|
+
hls.attachMedia(video);
|
|
32
|
+
hls.on(window.Hls.Events.MANIFEST_PARSED, function () {
|
|
33
|
+
video.play();
|
|
34
|
+
});
|
|
35
|
+
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
36
|
+
video.src = streamUrl;
|
|
37
|
+
video.addEventListener('loadedmetadata', function () {
|
|
38
|
+
video.play();
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error('HLS is not supported in this browser.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const player = {
|
|
45
|
+
video,
|
|
46
|
+
play: () => video.play(),
|
|
47
|
+
pause: () => video.pause(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const ui = new VideoPlayerUI({ player });
|
|
51
|
+
ui.attachTo(mountPoint);
|
|
52
|
+
|
|
53
|
+
return { ...player, ui };
|
|
54
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
"module": "ESNext",
|
|
5
5
|
"declaration": true,
|
|
6
6
|
"outDir": "dist",
|
|
7
|
-
"strict":
|
|
7
|
+
"strict": true,
|
|
8
8
|
"esModuleInterop": true,
|
|
9
9
|
"moduleResolution": "node",
|
|
10
|
-
"skipLibCheck": true
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"lib": ["dom", "es2017"]
|
|
11
12
|
},
|
|
12
13
|
"include": ["src/**/*"]
|
|
13
14
|
}
|
package/dist/utility.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const getDeviceMaker: (deviceName: string) => "LG" | "Vizio" | "xfinityX1" | "Microsoft" | "Samsung";
|
|
2
|
-
export declare const getUserAgent: (deviceName: string) => "xfinityX1" | "SmartTV_LG_WebOS" | "SmartTV_Vizio_SmartCast" | "xboxOne" | "SmartTV_Samsung_Tizen";
|
|
3
|
-
export declare const getOSName: (deviceName: string) => "xfinityX1" | "WebOS" | "SmartCast" | "Windows" | "Tizen";
|
|
4
|
-
export declare const getDeviceShortName: (deviceName: string) => "xfinityX1" | "lg" | "vizio" | "xBox" | "samsung";
|
|
5
|
-
export declare const getDeviceFullName: (deviceName: string) => "xfinityX1" | "vizioTv" | "smart_tv_lg" | "windows_xbox" | "smart_tv_samsung";
|
|
6
|
-
export declare const getMacros: (width: any, height: any, deviceName: any, deviceId: any) => {};
|
package/src/utility.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
export const getDeviceMaker = (deviceName:string) => {
|
|
2
|
-
if (deviceName == "lgTv") {
|
|
3
|
-
return "LG";
|
|
4
|
-
} else if (deviceName == "vizioTv") {
|
|
5
|
-
return "Vizio";
|
|
6
|
-
} else if(deviceName == "xfinityX1"){
|
|
7
|
-
return "xfinityX1"
|
|
8
|
-
}else if(deviceName == "xbox"){
|
|
9
|
-
return "Microsoft"
|
|
10
|
-
}else {
|
|
11
|
-
return "Samsung";
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export const getUserAgent = (deviceName:string) => {
|
|
17
|
-
if (deviceName == "lgTv") {
|
|
18
|
-
return "SmartTV_LG_WebOS";
|
|
19
|
-
} else if (deviceName == "vizioTv") {
|
|
20
|
-
return "SmartTV_Vizio_SmartCast";
|
|
21
|
-
} else if(deviceName == "xfinityX1"){
|
|
22
|
-
return "xfinityX1"
|
|
23
|
-
}else if(deviceName == "xbox"){
|
|
24
|
-
return "xboxOne"
|
|
25
|
-
}else {
|
|
26
|
-
return "SmartTV_Samsung_Tizen";
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export const getOSName = (deviceName:string) => {
|
|
30
|
-
if (deviceName == "lgTv") {
|
|
31
|
-
return "WebOS";
|
|
32
|
-
} else if (deviceName == "vizioTv") {
|
|
33
|
-
return "SmartCast";
|
|
34
|
-
} else if(deviceName == "xfinityX1"){
|
|
35
|
-
return "xfinityX1"
|
|
36
|
-
}else if(deviceName == "xbox"){
|
|
37
|
-
return "Windows"
|
|
38
|
-
}else {
|
|
39
|
-
return "Tizen";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export const getDeviceShortName = (deviceName:string) => {
|
|
43
|
-
if (deviceName == "lgTv") {
|
|
44
|
-
return "lg";
|
|
45
|
-
} else if (deviceName == "vizioTv") {
|
|
46
|
-
return "vizio";
|
|
47
|
-
} else if(deviceName == "xfinityX1"){
|
|
48
|
-
return "xfinityX1"
|
|
49
|
-
}else if(deviceName == "xbox"){
|
|
50
|
-
return "xBox"
|
|
51
|
-
}else {
|
|
52
|
-
return "samsung";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export const getDeviceFullName = (deviceName:string) => {
|
|
56
|
-
if (deviceName == "lgTv") {
|
|
57
|
-
return "smart_tv_lg";
|
|
58
|
-
} else if (deviceName == "vizioTv") {
|
|
59
|
-
return "vizioTv";
|
|
60
|
-
} else if(deviceName == "xfinityX1"){
|
|
61
|
-
return "xfinityX1"
|
|
62
|
-
}else if(deviceName == "xbox"){
|
|
63
|
-
return "windows_xbox"
|
|
64
|
-
}else {
|
|
65
|
-
return "smart_tv_samsung";
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const getMacros=(width, height,deviceName,deviceId)=>{
|
|
70
|
-
let objMacros = {};
|
|
71
|
-
try{
|
|
72
|
-
objMacros["VIEWLIFT_WIDTH"] = width;
|
|
73
|
-
objMacros["VIEWLIFT_HEIGHT"] = height;
|
|
74
|
-
objMacros["VIEWLIFT_SIZE"] = width + "x" + height;
|
|
75
|
-
objMacros["VIEWLIFT_DOMAIN"] = (window as any).appMainConfig.domainName;
|
|
76
|
-
|
|
77
|
-
objMacros["VIEWLIFT_CACHEBUSTER"] = (new Date()).getTime();
|
|
78
|
-
objMacros["VIEWLIFT_TIMESTAMP"] = Math.floor((new Date()).getTime() % 1000);
|
|
79
|
-
objMacros["VIEWLIFT_TIMESTAMP_MS"] = (new Date()).getTime();
|
|
80
|
-
objMacros["VIEWLIFT_USER_AGENT"] = window.navigator.userAgent;
|
|
81
|
-
|
|
82
|
-
// objMacros["VIEWLIFT_DURATION"] = time;
|
|
83
|
-
objMacros["VIEWLIFT_MIN_DURATION"] = "0";
|
|
84
|
-
|
|
85
|
-
objMacros["VIEWLIFT_AUTOPLAY"] = "1";
|
|
86
|
-
objMacros["VIEWLIFT_DNT"] = "0";
|
|
87
|
-
objMacros["VIEWLIFT_AD_POS"] = "1";
|
|
88
|
-
objMacros["VIEWLIFT_MUTE"] = "0";
|
|
89
|
-
objMacros["VIEWLIFT_DEVICE_MAKE"] = getDeviceMaker(deviceName);
|
|
90
|
-
objMacros["VIEWLIFT_OS"] = getOSName(deviceName);
|
|
91
|
-
objMacros["VIEWLIFT_LAT"] = (window as any).geoLocation?.latitude;
|
|
92
|
-
objMacros["VIEWLIFT_LON"] = (window as any).geoLocation?.longitude;
|
|
93
|
-
objMacros["VIEWLIFT_KEYWORDS"] = "720";
|
|
94
|
-
objMacros["VIEWLIFT_CONSENT"] = "0";
|
|
95
|
-
objMacros["VIEWLIFT_US_PRIVACY"] = "1";
|
|
96
|
-
objMacros["VIEWLIFT_COPPA"] = "0";
|
|
97
|
-
objMacros["VIEWLIFT_BRAND_NAME"] = getDeviceMaker(deviceName);
|
|
98
|
-
objMacros["VIEWLIFT_IP"] = (window as any).geoLocation?.origip;
|
|
99
|
-
objMacros["VIEWLIFT_MAX_POD_DURATION"] = "120";
|
|
100
|
-
objMacros["VIEWLIFT_MAX_POD_DURATION_MS"] = "120000";
|
|
101
|
-
|
|
102
|
-
// objMacros["VIEWLIFT_APP_ID"] = "";
|
|
103
|
-
objMacros["VIEWLIFT_DEVICE_ID"] = deviceId;
|
|
104
|
-
objMacros["VIEWLIFT_DID"] = deviceId;
|
|
105
|
-
//objMacros["VIEWLIFT_APP_NAME"] = "";
|
|
106
|
-
objMacros["VIEWLIFT_GDPR"] = "0";
|
|
107
|
-
}catch(e){}
|
|
108
|
-
return objMacros;
|
|
109
|
-
}
|