Skip to content
Advertisement

HTML + JavaScript custom player for multiple videos on a website page

EDIT: I have found the solution, posted and marked as the best answer below.

I’m coding a portfolio website for myself using HTML, CSS and JS and I need to add multiple videos on a lot of pages.

I followed some tutorials to learn how to customize the video player, but it only works for one specific video on the page. If I were to add more videos, I’d need to have one .js custom player file for each video and manually select them on the website.

How can I apply this single .js custom video player to all of my videos using purely javascript?

I have found similar topics about the subject here, but all of them uses jQuery and I’m struggling to make it work with javascript.

My HTML for the video player:

<section class="videoplayer">
<div class="c-video">
    <div id="video_player">
        <video src="./media/portfolio/videos/Show-Reel-2021.mp4" id="main-video"></video>
        <div class="progressAreaTime">00:00</div>
        <div class="controls">
            <div class="progress-area">
                <div class="progress-bar">
                    <span></span>
                </div>
                <div class="buffered-progress-bar"></div>
            </div>
            <div class="controls-list">
                <div class="controls-left">
                    <span class="icon">
                        <i class="material-icons fast-rewind" title="Retroceder 10 segundos">first_page</i>
                    </span>
                    <span class="icon">
                        <i class="material-icons play_pause" title="Reproduzir">play_arrow</i>
                    </span>
                    <span class="icon">
                        <i class="material-icons fast-forward" title="Avançar 10 segundos">last_page</i>
                    </span>
                    <span class="icon">
                        <i class="material-icons volume" title="Sem áudio">volume_up</i>
                        <input type="range" min="0" max="100" class="volume_range">
                    </span>
                    <div class="timer">
                        <span class="current">00:00</span> / <span class="duration">0:00</span>
                    </div>
                </div>
                <div class="controls-right">
                    <span class="icon">
                        <i class="material-icons auto-play" title="A repetição automática está desativada"></i>
                    </span>
                    <span class="icon">
                        <i class="material-icons settingsBtn" title="Detalhes">settings</i>
                    </span>
                    <span class="icon">
                        <i class="material-icons picture_in_picture" title="Miniplayer">picture_in_picture_alt</i>
                    </span>
                    <span class="icon">
                        <i class="material-icons fullscreen" title="Tela inteira">fullscreen</i>
                    </span>
                </div>
            </div>
        </div>
        <div id="settings">
            <div class="playback">
                <span>Velocidade da Reprodução</span>
                <ul>
                    <li data-speed="0.25">0.25</li>
                    <li data-speed="0.5">0.5</li>
                    <li data-speed="0.75">0.75</li>
                    <li data-speed="1" class="active">Normal</li>
                    <li data-speed="1.25">1.25</li>
                    <li data-speed="1.5">1.5</li>
                    <li data-speed="1.75">1.75</li>
                    <li data-speed="2">2</li>
                </ul>
            </div>
        </div>
    </div>
</div>

My JavaScript for the video player:

// Select elements
const vidsrc = document.querySelector('#main-video').src;
const video_player = document.querySelector('#video_player'),
mainVideo = video_player.querySelector('#main-video'),
progressAreaTime = video_player.querySelector('.progressAreaTime'),
controls = video_player.querySelector('.controls'),
progressArea = video_player.querySelector('.progress-area'),
progress_Bar = video_player.querySelector('.progress-bar'),
buffered_Bar = video_player.querySelector('.buffered-progress-bar'),
fast_rewind = video_player.querySelector('.fast-rewind'),
play_pause = video_player.querySelector('.play_pause'),
fast_forward = video_player.querySelector('.fast-forward'),
volume = video_player.querySelector('.volume'),
volume_range = video_player.querySelector('.volume_range'),
current = video_player.querySelector('.current'),
totalDuration = video_player.querySelector('.duration'),
auto_play = video_player.querySelector('.auto-play'),
settingsBtn = video_player.querySelector('.settingsBtn'),
picture_in_picture = video_player.querySelector('.picture_in_picture'),
fullscreen = video_player.querySelector('.fullscreen'),
settings = video_player.querySelector('#settings'),
playback = video_player.querySelectorAll('.playback li');

mainVideo.addEventListener('loadeddata',()=>{
    setInterval(() => {
        let bufferedTime = mainVideo.buffered.end(0);
        let duration = mainVideo.duration;
        let width = (bufferedTime / duration) * 100;
        buffered_Bar.style.width = `${width}%`
    }, 500);
})

// Play
function playVideo() {
    play_pause.innerHTML = "pause";
    play_pause.title = "Pausar";
    video_player.classList.add('paused')
    mainVideo.play();
}

// Pause
function pauseVideo() {
    play_pause.innerHTML = "play_arrow";
    play_pause.title = "Reproduzir";
    video_player.classList.remove('paused')
    mainVideo.pause();
}

play_pause.addEventListener('click',()=>{
    const isVideoPaused = video_player.classList.contains('paused');
    isVideoPaused ? pauseVideo() : playVideo();
})

mainVideo.addEventListener('play',()=>{
    playVideo();
})

mainVideo.addEventListener('pause',()=>{
    pauseVideo();
})

// Rewind
fast_rewind.addEventListener('click',()=>{
    mainVideo.currentTime -= 10;
})

// Forward
fast_forward.addEventListener('click',()=>{
    mainVideo.currentTime += 10;
})

// Total duration
mainVideo.addEventListener("loadeddata",(e)=>{
    let videoDuration = e.target.duration;
    let totalMin = Math.floor(videoDuration / 60);
    let totalSec = Math.floor(videoDuration % 60);

    // Complete with zero at beggining
    totalSec < 10 ? totalSec = "0"+totalSec:totalSec;
    totalMin < 10 ? totalMin = "0"+totalMin:totalMin;
    totalDuration.innerHTML = `${totalMin}:${totalSec}`;
})

// Current duration
mainVideo.addEventListener('timeupdate',(e)=>{
    let currentVideoTime = e.target.currentTime;
    let currentMin = Math.floor(currentVideoTime / 60);
    let currentSec = Math.floor(currentVideoTime % 60);
   // Complete with zero at beggining
    currentSec < 10 ? currentSec = "0"+currentSec:currentSec; 
    currentMin < 10 ? currentMin = "0"+currentMin:currentMin; 
    current.innerHTML = `${currentMin}:${currentSec}`;

    let videoDuration = e.target.duration
    // Seek bar
    let progressWidth = (currentVideoTime / videoDuration) * 100;
    progress_Bar.style.width = `${progressWidth}%`;
})

// Update current duration
progressArea.addEventListener('click',(e)=>{
    let videoDuration = mainVideo.duration;
    let progressWidthval = progressArea.clientWidth;
    let ClickOffsetX = e.offsetX;
    mainVideo.currentTime = (ClickOffsetX / progressWidthval) * videoDuration;
})

// Volume
function changeVolume() {
    mainVideo.volume = volume_range.value / 100;
    if (volume_range.value == 0) {
        volume.innerHTML = "volume_off";
    }else if(volume_range.value < 40){
        volume.innerHTML = "volume_down";
    }else{
        volume.innerHTML = "volume_up";
    }
}

function muteVolume() {
    if (volume_range.value == 0) {
        volume_range.value = 80;
        mainVideo.volume = 0.8;
        volume.innerHTML = "volume_up";
        volume.title = "Sem áudio";
    }else{
        volume_range.value = 0;
        mainVideo.volume = 0;
        volume.innerHTML = "volume_off";
        volume.title = "Reativar o som";
    }
}

volume_range.addEventListener('change',()=>{
    changeVolume();
})

volume.addEventListener('click',()=>{
    muteVolume();
})

// Update on mouse move
progressArea.addEventListener('mousemove',(e)=>{
    let progressWidthval = progressArea.clientWidth;
    let x = e.offsetX;
    progressAreaTime.style.setProperty('--x',`${x}px`);
    progressAreaTime.style.display = "block";
    let videoDuration = mainVideo.duration;
    let progressTime = Math.floor((x/progressWidthval)*videoDuration);
    let currentMin = Math.floor(progressTime / 60);
    let currentSec = Math.floor(progressTime % 60);
   // Complete with zero at beggining
    currentSec < 10 ? currentSec = "0"+currentSec:currentSec; 
    currentMin < 10 ? currentMin = "0"+currentMin:currentMin; 
    progressAreaTime.innerHTML = `${currentMin}:${currentSec}`;
})

progressArea.addEventListener('mouseleave',()=>{
    progressAreaTime.style.display = "none";
})

// Loop
auto_play.addEventListener('click',()=>{
    auto_play.classList.toggle('active')
    if(auto_play.classList.contains('active')){
        auto_play.title = "A repetição automática está ativada";
    }else{
        auto_play.title = "A repetição automática está desativada";
    }
});

mainVideo.addEventListener("ended",()=>{
    if (auto_play.classList.contains('active')) {
        playVideo();
    }else{
        play_pause.innerHTML = "replay";
        play_pause.title = "Reproduzir novamente";
    }
});

// Picture in picture
picture_in_picture.addEventListener('click',()=>{
    mainVideo.requestPictureInPicture();
})

// Full screen
fullscreen.addEventListener('click',()=>{
    if (!video_player.classList.contains('openFullScreen')) {
        video_player.classList.add('openFullScreen');
        fullscreen.innerHTML = "fullscreen_exit";
        fullscreen.title = "Sair da tela inteira";
        video_player.requestFullscreen();
    }else{
        video_player.classList.remove('openFullScreen');
        fullscreen.innerHTML = "fullscreen";
        fullscreen.title = "Tela inteira";
        document.exitFullscreen();
    }
});

// Settings
settingsBtn.addEventListener('click',()=>{
    settings.classList.toggle('active');
    settingsBtn.classList.toggle('active');
})

// Speed
playback.forEach((event)=>{
    event.addEventListener('click',()=>{
        removeActiveClasses();
        event.classList.add('active');
        let speed = event.getAttribute('data-speed');
        mainVideo.playbackRate = speed;
    })
})

function removeActiveClasses() {
    playback.forEach(event => {
        event.classList.remove('active')
    });
}

// Get URL
let xhr = new XMLHttpRequest();
xhr.open("GET",vidsrc);
xhr.responseType = "arraybuffer";
xhr.onload = (e)=>{
    let blob = new Blob([xhr.response]);
    let url = URL.createObjectURL(blob);
    mainVideo.src = url;
}
xhr.send();

// Store duration
window.addEventListener('unload',()=>{
    let setDuration = localStorage.setItem('duration',`${mainVideo.currentTime}`);
    let setSrc = localStorage.setItem('src',`${mainVideo.getAttribute('src')}`);
})

window.addEventListener('load',()=>{
    let getDuration = localStorage.getItem('duration');
    let getSrc = localStorage.getItem('src');
    if (getSrc) {
        mainVideo.src = getSrc;
        mainVideo.currentTime = getDuration;
    }
})

mainVideo.addEventListener('contextmenu',(e)=>{
    e.preventDefault();
})

// Hide and show controls (mouse)
video_player.addEventListener('mouseover',()=>{
    controls.classList.add('active');
})

video_player.addEventListener('mouseleave',()=>{
    if (video_player.classList.contains('paused')) {
        if (settingsBtn.classList.contains('active')) {
            controls.classList.add('active');
        }else{
            controls.classList.remove('active')
        }
    }else{
        controls.classList.add('active')
    }
})

if (video_player.classList.contains('paused')) {
    if (settingsBtn.classList.contains('active')) {
        controls.classList.add('active');
    }else{
        controls.classList.remove('active')
    }
}else{
    controls.classList.add('active')
}

// Hide and show controls (mobile)
video_player.addEventListener('touchstart',()=>{
    controls.classList.add('active');
    setTimeout(() => {
        controls.classList.remove('active')
    }, 8000);
})

video_player.addEventListener('touchmove',()=>{
    if (video_player.classList.contains('paused')) {
        controls.classList.remove('active')
    }else{
        controls.classList.add('active')
    }
})

Advertisement

Answer

I HAVE FOUND THE SOLUTION

For anyone in the future seeking for the same solution, I was able to make it work by first selecting every videoplayer div:

const videoContainers = document.querySelectorAll(".video-container")

Then using the .forEach() function so that the code will generate a button for every individual videoplayer:

videoContainers.forEach((container) => {
  let playPauseBtn = container.querySelector(".play-pause-btn");
  let theaterBtn = container.querySelector(".theater-btn");
  let fullScreenBtn = container.querySelector(".full-screen-btn");
...

// The entire code for one videoplayer
}

You can reference “container” for the individual videoplayer or “document” for every videoplayer at once. It just works like magic!

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement