Create Your Own Javascript Video Player

ยท

9 min read

I know, that there are a lot of third-party libraries for a Video player, but recently I created a video library in React, and there like every single project of mine I wanted to create something cool and do an experiment. So I ended up creating a Video Player, you can check it out here, now this one is made up in React but, I'm going to make one in vanilla javascript for you guys so that you can have a better understanding for yourselves and then later convert it into the framework of your choice.

Getting Started

First thing first, here is the codeSandbox for the starter project, it only consists of the HTML as well as the CSS, no javascript applied to it yet.

HTML5 Video API

So out of the box HTML5 is shipped with video API which you can use to control the video presentation on the DOM, You can read more about it here, There you go, finished, hope you enjoyed it and got value from my sweat breaking hard work, now please follow the documentation and you will be able to create a custom Video Player in about a month, Thank You...

Although I wanted to do this to every single one of you I just can't bring myself to it, don't worry I will explain further. So as I was saying out of the box you get a lot of APIs as well as 'DOM events', to interact with the video tag, like to control playback rate (Boi, I like that), to get the progress of the video, to play or pause the video and many more. Our job is to verify and construct a sort of architecture based on functions that are going to control the Video Tag.

Play/Pause Video

First thing first let us add the functionality of pausing and playing a video. I will recommend making an object here which can store all data of the current status of the video, which you can later use to change the video settings (this is going to be difficult in javascript, but as you shift to a framework like reactJS, there you can use a state which will automatically render based on state, but for now vanilla JS will do the job) Just take the play button node in the JS file using querySelector (personal preference) and add the following click event to it.

const play = document.querySelector('.play')
const video = document.querySelector('video')

const playToggle = () => {
    if(video.paused) video.play()
    else video.pause()
}

play.addEventListener('click', playToggle)

Now the video.paused is a property of the video tag and will tell you whether or not the video is paused, if paused then will return true. And the video.play() and video.pause() are the methods of the tag which have the self-explanatory utility.

This below is an extra step and you can do that if you want but is optional, its basically to change the icon of the play button based on the state of the video and also toggle play/pause if clicked on the video itself.

const play = document.querySelector('.play')
const video = document.querySelector('video')

const playToggle = () => {
    if(video.paused) {
      video.play()
      play.innerHTML = '<i class="fas fa-pause"></i>'
    }
    else {
      video.pause()
      play.innerHTML = '<i class="fas fa-play"></i>'
    }
}

play.addEventListener('click', playToggle)
video.addEventListener('click', playToggle)

Volume Control

Now this is one doesn't make any kind of sense to me as nowadays it's very easy to do so from the keyboard especially controlling the system audio output volume, but still, the feature can be built therefore we will. We will take the input tag and will put the function there to change the volume based on the value of the input tag, the type of input tag will be a range with some pre denied properties to make life easier for us.

const volumeInput = document.querySelector(".volume");
const video = document.querySelector("video");

const videoState = {
  volume: 0.5
};

video.volume = videoState.volume;

const volumeChage = (e) => {
  video.volume = e.target.value;
};

volumeInput.addEventListener("change", volumeChage);

As I said before I will be using a state object which will store the settings of the video tag and will make changes to the video tag as the value of the object changes. video.volume is a property of the tag and will receive a float value from 0.0 to 1.0 which will change the volume in accordance. I still think it is useless ๐Ÿ˜

Forward and Backward Button

Now, this is something I personally use a lot while a tutorial and skip important parts to end up being watching the video altogether from the start, this is a really helpful feature. Now again this is very easy to do, will take the DOM nodes for the forward as well as backward button and will give a very small function to them. I am going to make a 10sec gap.

const video = document.querySelector("video");

//backward and forward button nodes
const backward = document.querySelector(".backward");
const forward = document.querySelector(".forward");

const videoState = {
  volume: 0.5,
  timeGap: 10
};

//backward and forward button functions
const backwardByClick = () => {
  video.currentTime -= videoState.timeGap;
};
const forwardByClick = () => {
  video.currentTime += videoState.timeGap;
};

//backward and forward button functions
backward.addEventListener("click", backwardByClick);
forward.addEventListener("click", forwardByClick);

Again very simple just add the functions to the backward and forward button and the video tag has a property in video tag video.currentTime and the value is an integer and it has the minimum value of 0 and maximum the length of the video in secs.

The DOM keeps note of all the properties of the video tag and therefore when we change any single one of it the tag changes

Playback Rate Controller

I have a confession, I never thought of sharing it but it's high time I let people in and tell my dark secrets, I watch videos only at 2x playback speed ๐Ÿ˜ฌ, Will society accept me? Take all the buttons of the playback rate and add a click event, as the options are invisible by default, we also need to have a toggle for that first.

//playback rate
const playbackWrapper = document.querySelector(".playback_dropdown");
const playbackButtons = playbackWrapper.querySelectorAll("button");
const playbackToggleButton = document.querySelector(".playback_icon");


//playback rate
const playbackToggler = () => {
  playbackWrapper.classList.toggle("playback_dropdownActive");
};
const playbackRateChange = (e) => {
  video.playbackRate = e.target.attributes["speed"].value;
  playbackToggler();
};

//playback rate
playbackToggleButton.addEventListener("click", playbackToggler);
playbackButtons.forEach((btn) =>
  btn.addEventListener("click", playbackRateChange)
);

Very simple Right, I know this is overwhelming but just give it some time and it will fall into the picture. We are taking a toggle button which is an icon and adding a click event that toggles a class (add and remove a class) for the playback dropdown container. We are also taking all the buttons present under the playbackWrapper container and adding a click event which basically takes the value from a button attribute and changes the property of video video.playbackRate into that.

Full-Screen Mode

This stays between being completely useless and completely useful, I know a strange place to be in kinda like my writing skills which I'm cursing right now, Boi this is joyful. This is probably the simplest of all, just add the click event to the corresponding button with the following function and done. No explanation is needed!

//fullscreen
const fullScreenButton = document.querySelector("button.fullScreen");

//fullscreen
const fullScreenToggle = () => {
  if (video.requestFullscreen) {
    video.requestFullscreen();
  } else if (video.webkitRequestFullscreen) {
    /* Safari */
    video.webkitRequestFullscreen();
  } else if (video.msRequestFullscreen) {
    /* IE11 */
    video.msRequestFullscreen();
  }
};

//fullscreen
fullScreenButton.addEventListener("click", fullScreenToggle);

Progess Bar

Now the things are getting Interesting (super hard), this is something very cool, believe me if you just write this below code by hand to be exact, and watch it work, you will definitely feel that you have created something cool, that's how I felt. So first let's talk about the cycle of events to get a good grasp on this, as this is my debut blog and I don't want any complaints ๐Ÿค—. First, the event is going to get fired every time the duration of the video changes(means every second), then we will calculate the percent of video played already and store it in a state, and then use the state to re-render the progress bar. Cool? let's go!

//progress bar
const progressBar = document.querySelector(".progress_filled");

const videoState = {
  volume: 0.5,
  timeGap: 10,
  progress: 0
};

//progress of video
const timeUpdateHandler = (e) => {
  const time = e.target.currentTime;
  if (time === 0 || time === e.target.duration) {
    video.pause();
  }
  const progressInPercent = (e.target.currentTime / e.target.duration) * 100;
  videoState.progress = progressInPercent;
  updateProgressBar();
};

const updateProgressBar = () => {
  progressBar.style.width = `${videoState.progress}%`;
};
updateProgressBar();


//progress of video
video.addEventListener("timeupdate", timeUpdateHandler);

Let's just talk about the main stuff other than that it's all self-explanatory. So we have a dom event timeupdate for the video-tag which will run every sec as long as the video is not paused. so we have basically taken the currentTime of the tag and duration and just divide them to get the progress percent and use that to change the style width of the progress width and done.

Great now you have created your own blog and it's amazing too, hope you enjoyed it... ok, let's also make one to update the progress based on where you clicked on the progress bar. Warning:- you might want to rip your head off or more likely to curse me ๐Ÿ‘

Click to change progress

This has some custom workaround and will have a huge explanation, so first, let's talk about the basics of how it's done. You will click on the progress bar and will check what is the x position(calculated from the left) and then delete the space between the player and the left side of the browser window from the value you got before this will give you the length of the progress bar on the left side of your click, now you use this to calculate the percent that particular point represents and done.

//progress bar
const progressBar = document.querySelector(".progress_filled");
const progressWrapper = document.querySelector(".progress");

const videoState = {
  volume: 0.5,
  timeGap: 10,
  progress: 0
};

const clickToSkip = (e) => {
  const client = e.target.getBoundingClientRect();
  const progress = (e.clientX - client.x) / progressWrapper.offsetWidth;
  video.currentTime = progress * video.duration;
};

progressWrapper.addEventListener("click", clickToSkip);

I know that four lines of "simple" function are making you want to punch your monitor, but before you do something so ruthless and cruel it can result in you getting beaten up by your parents kindly let me explain. The "client" variable has all sorts of information about the "progress wrapped node" like its position in the X, Y plane, its height and width also, and the event "e" also has information like the X, Y position of where the event happened, in our case where we clicked., so basically we are calculating (the width of progresswarpper on the left side of where we clicked) / the total actual width of the progressWrapper, which returns the percentage of progress. The Best way to understand them is to meditate for 5 minutes, read it, curse it and then repeat the progress you will succeed ๐Ÿ‘.

Conclusion

Before you fell into complete despair you don't need to do this, you can also use a library known as 'video.js' which makes the process much simpler. I know but still you cant curse me for that right? Before you get agonized I'm leaving hope you enjoyed it (right?).

full code with here

check out React Example Here

ย