blaze-player-litee
Version:
A customizable HTML5 video player with modular controls and themed styling.
2 lines (1 loc) • 7.38 kB
JavaScript
class e{constructor(e,t={}){this.container="string"==typeof e?document.querySelector(e):e,this.options={controls:["play","progress","time","volume","speed","fullscreen","playerlogo"],...t},this.video=this.container.querySelector("video"),this.controls=null,this.init(),this.bindEvents()}init(){this.controls=document.createElement("div"),this.controls.className="controls";const e=document.createElement("div");e.className="controls-left";const t=document.createElement("div");t.className="controls-right";const s=document.createElement("div");if(s.className="progress-container",this.spinner=document.createElement("div"),this.spinner.className="loading-spinner",this.container.appendChild(this.spinner),this.video.addEventListener("waiting",(()=>this.spinner.style.display="block")),this.video.addEventListener("playing",(()=>this.spinner.style.display="none")),this.options.controls.includes("play")&&(this.playButton=document.createElement("button"),this.playButton.innerHTML='<i class="fa-solid fa-play"></i>',this.playButton.className="play-button",e.appendChild(this.playButton)),this.options.controls.includes("progress")&&(this.progress=document.createElement("input"),this.progress.type="range",this.progress.min="0",this.progress.max="100",this.progress.value="0",this.progress.className="progress",s.appendChild(this.progress)),this.options.controls.includes("time")&&(this.timeDisplay=document.createElement("div"),this.timeDisplay.className="time",this.timeDisplay.textContent="00:00 / 00:00",t.appendChild(this.timeDisplay)),this.options.controls.includes("volume")){this.volumeButton=document.createElement("button"),this.volumeButton.innerHTML='<i class="fa-solid fa-volume-high"></i>',this.volumeButton.className="volume-button",t.appendChild(this.volumeButton),this.volumeSlider=document.createElement("input"),this.volumeSlider.type="range",this.volumeSlider.min="0",this.volumeSlider.max="1",this.volumeSlider.step="0.05",this.volumeSlider.value="1",this.volumeSlider.className="volume-slider";const e=document.createElement("div");e.className="volume-container",e.appendChild(this.volumeButton),e.appendChild(this.volumeSlider),t.appendChild(e)}if(this.options.controls.includes("speed")){this.speedButton=document.createElement("button"),this.speedButton.innerHTML='<span>1x </span><i class="fa-solid fa-gauge-high"></i>',this.speedButton.className="speed-button",t.appendChild(this.speedButton),this.speedDropdown=document.createElement("div"),this.speedDropdown.className="speed-dropdown",this.speedDropdown.style.display="none";["0.5x","1x","2x"].forEach((e=>{const t=document.createElement("div");t.className="speed-option",t.textContent=e,t.dataset.speed=e.replace("x",""),this.speedDropdown.appendChild(t)})),this.controls.appendChild(this.speedDropdown)}this.options.controls.includes("fullscreen")&&(this.fullscreenButton=document.createElement("button"),this.fullscreenButton.innerHTML='<i class="fa-solid fa-expand"></i>',this.fullscreenButton.className="fullscreen-button",t.appendChild(this.fullscreenButton)),this.options.controls.includes("playerlogo")&&(this.playerLogo=document.createElement("div"),this.playerLogo.className="playerlogo",this.playerLogo.style.backgroundImage="url('img/logo.png')",this.playerLogo.style.width="32px",this.playerLogo.style.height="32px",this.playerLogo.style.backgroundSize="contain",t.appendChild(this.playerLogo)),this.controls.appendChild(e),this.controls.appendChild(s),this.controls.appendChild(t),this.container.appendChild(this.controls)}bindEvents(){this.playButton&&this.playButton.addEventListener("click",(()=>this.togglePlay())),this.progress&&this.progress.addEventListener("input",(()=>{this.video.currentTime=this.progress.value/100*this.video.duration})),this.volumeButton&&this.volumeButton.addEventListener("click",(()=>this.toggleMute())),this.volumeSlider&&this.volumeSlider.addEventListener("input",(()=>{this.video.volume=this.volumeSlider.value,this.updateVolumeIcon()})),this.fullscreenButton&&this.fullscreenButton.addEventListener("click",(()=>this.toggleFullscreen())),this.speedButton&&(this.speedButton.addEventListener("click",(e=>{e.stopPropagation(),this.toggleSpeedDropdown()})),this.speedDropdown&&this.speedDropdown.querySelectorAll(".speed-option").forEach((e=>{e.addEventListener("click",(()=>{const t=parseFloat(e.dataset.speed);this.video.playbackRate=t,this.speedDropdown.style.display="none",this.speedButton.innerHTML=`${t}x <i class="fa-solid fa-gauge-high"></i>`}))}))),this.video.addEventListener("play",(()=>{this.playButton&&(this.playButton.innerHTML='<i class="fa-solid fa-pause"></i>')})),this.video.addEventListener("pause",(()=>{this.playButton&&(this.playButton.innerHTML=this.video.ended?'<i class="fa-solid fa-rotate-right"></i>':'<i class="fa-solid fa-play"></i>')})),this.video.addEventListener("timeupdate",(()=>{this.updateTimeDisplay(),this.progress&&(this.progress.value=this.video.currentTime/this.video.duration*100)})),this.video.addEventListener("volumechange",(()=>{this.updateVolumeIcon(),this.volumeSlider&&(this.volumeSlider.value=this.video.volume)})),this.video.addEventListener("loadedmetadata",(()=>{this.updateTimeDisplay()})),document.addEventListener("keydown",(e=>{switch(e.code){case"Space":e.preventDefault(),this.togglePlay();break;case"ArrowRight":this.seekTo(this.video.currentTime+5);break;case"ArrowLeft":this.seekTo(this.video.currentTime-5);break;case"ArrowUp":this.setVolume(this.video.volume+.1);break;case"ArrowDown":this.setVolume(this.video.volume-.1);break;case"KeyM":this.toggleMute(),this.video.volume>0?this.setVolume(0):this.setVolume(1)}}))}togglePlay(){this.video.paused||this.video.ended?this.video.play():this.video.pause()}toggleMute(){this.video.muted=!this.video.muted}toggleSpeedDropdown(){"block"===this.speedDropdown.style.display?this.speedDropdown.style.display="none":this.speedDropdown.style.display="block"}updateVolumeIcon(){this.volumeButton&&(this.video.muted||0===this.video.volume?this.volumeButton.innerHTML='<i class="fa-solid fa-volume-xmark"></i>':this.video.volume<.5?this.volumeButton.innerHTML='<i class="fa-solid fa-volume-low"></i>':this.volumeButton.innerHTML='<i class="fa-solid fa-volume-high"></i>')}updateTimeDisplay(){this.timeDisplay&&(this.timeDisplay.textContent=`${this.formatTime(this.video.currentTime)} / ${this.formatTime(this.video.duration)}`)}formatTime(e){if(isNaN(e))return"00:00";const t=Math.floor(e/3600),s=Math.floor(e%3600/60),i=Math.floor(e%60);return t>0?[t.toString().padStart(2,"0"),s.toString().padStart(2,"0"),i.toString().padStart(2,"0")].join(":"):[s.toString().padStart(2,"0"),i.toString().padStart(2,"0")].join(":")}toggleFullscreen(){document.fullscreenElement?document.exitFullscreen():this.container.requestFullscreen().catch((e=>{console.error(`Error attempting to enable fullscreen: ${e.message}`)}))}play(){this.video.play()}pause(){this.video.pause()}stop(){this.video.pause(),this.video.currentTime=0}setVolume(e){this.video.volume=Math.min(1,Math.max(0,e)),this.updateVolumeIcon()}mute(){this.video.muted=!0}unmute(){this.video.muted=!1}seekTo(e){this.video.currentTime=e}destroy(){this.container.removeChild(this.controls),this.video.removeAttribute("controls")}}document.addEventListener("DOMContentLoaded",(()=>{const t=new e("#player1",{controls:["play","progress","time","volume","speed","fullscreen","playerlogo"]});window.player=t}));