JS Video Player
Tags: javascript, beginners, webdev, tutorial
Published: 2023-01-04 01:45:13

_This is an exercise from the [JS30-challange](https://javascript30.com/)_

---

So, for todays challenge we'll be making a video player in JavaScript.

For reference, this is the HTML skeleton that I'll be using when selecting my different elements.

```HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>HTML Video Player</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="player">
      <video class="player__video viewer" src="video.mp4"></video>

      <div class="player__controls">
        <div class="progress">
          <div class="progress__filled"></div>
        </div>
        <button class="player__button play-toggle" title="Toggle Play">►</button>
        <input
          type="range"
          name="volume"
          class="player__slider"
          min="0"
          max="1"
          step="0.05"
          value="1"
        />
        <input
          type="range"
          name="playbackRate"
          class="player__slider"
          min="0.5"
          max="2"
          step="0.1"
          value="1"
        />
        <button data-skip="-15" class="player__button">« 15s</button>
        <button data-skip="15" class="player__button">15s »</button>
        <button class="player__button fullscreenToggle">[ ]</button>
      </div>
    </div>

    <script src="scripts.js"></script>
  </body>
</html>
```


## Challenges & Goals

As this is my first time trying to build something like this, my main challenges and goal will be:

- Understanding the different components needed
- Targeting the correct elements
- Understanding the logic needed for time, rate and progressbar.


<img width="100%" style="width:100%" src="https://media.tenor.com/r3XdvPsAV3kAAAAC/despicable-me-minions.gif">

___

For this specific player, the settings available will be:
- Skipping forward/backwards
- Toggling fullscreen
- Setting playback rate
- Changing volume
- Tracking video progress

## 1. Getting the elements needed

First, I'll make variables for a bunch of elements I need.

```javascript
const player = document.querySelector(".player");
const video = document.querySelector(".viewer");
const play = document.querySelector(".play-toggle");
const sliders = document.querySelectorAll(".player__slider");
const skipButtons = document.querySelectorAll("[data-skip]");
const progressBar = document.querySelector(".progress__filled");
const progress = document.querySelector(".progress");
const fullScreenToggle = document.querySelector(".fullscreenToggle");
```

## 2. Adding Play / Pause

Create the function.
```javascript
function togglePlay() {
 // console.log("Play/Pause");
  const method = video.paused ? "play" : "pause";
  video[method]();
}
```
`Play the video if it's paused, pause it if it's playing.`

In this player, I want the user to be able to click anywhere on the video, as well as using the play/pause button. So I'll be making two event listeners for this.

```javascript
video.addEventListener("click", togglePlay);
play.addEventListener("click", togglePlay);
```

And that should do it. Play/Pause should now be working.


## 3. Adding Volume / Playbackspeed


Create the function and logic.
```javascript
function handleRangeUpdate() {
  video[this.name] = this.value;
}
```
`"this" refers to the element/object this was called on. Take the video attribute and update it's value.`

I have two sliders, both of which I selected with one query earlier. So, I'll iterate over them to get a listener on both.

```javascript
sliders.forEach((slider) =>
  slider.addEventListener("change", handleRangeUpdate)
);
```
And now, changes on the slider will call the handleRangeUpdate function, and update the value accordingly.

## 4. Adding Skipping/Rewinding 15s

This one is pretty much the same as the last one, just with a bit of logic.


Creating the function
 ```javascript
 function skip() {
  video.currentTime += parseFloat(this.dataset.skip);
 }
 ```
`Takes the value of the buttons dataset.skip(see HTML)and adds it to the current time of the video. `

Adding a listener
```javascript
skipButtons.forEach((button) => button.addEventListener("click", skip));
```
Now, whichever button i click, depending on the value of the dataset.skip, it will either rewind or skip 10s on click.

##5. Adding Fullscreen

This was pretty straight forward, as all the instructions could quickly be found in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen).

Creating the function
```javascript
function handleFullscreen() {
  if (video.requestFullscreen) {
    video.requestFullscreen();
  } else if (video.webkitRequestFullscreen) {
    video.webkitRequestFullscreen();
  } else if (video.msRequestFullscreen) {
    video.msRequestFullscreen();
  }
}
```
`else if conditions to support other browsers.`

Adding a listener
```javascript
fullScreenToggle.addEventListener("click", handleFullscreen);
```

And that's it. There's no need to add any conditions for closing fullscreen, as this is already added in the browsers built in fullscreen video player.

## 6. Updating Progressbar

This one is a tiny bit different as it's an ongoing event as long as the video is playing. 

Create the function
```javascript
function handleProgress() {
  const percent = (video.currentTime / video.duration) * 100;
  progressBar.style.flexBasis = `${percent}%`;
}
```
`We calculate the percent of the video, and set the flexBasis(CSS) value to the calculated percent.`

Add a listener
```javascript
video.addEventListener("timeupdate", handleProgress);
```
`Listens for updates on the time of the video(automatically), and runs the function.`

And that's it. Now the progressbar's css will update according to the video's time.

## 7. Set time manually in progressbar.

To achieve this, we'll use the positioning of the mouseclick comparative to the width of the Progress to get a value.

```javascript
function time(e) {
  const setTime = (e.offsetX / progress.offsetWidth) * video.duration;
  video.currentTime = setTime;
}
```
`Take the position where I clicked, divided by the width of the progressbar and multiply with duration to get a value.`

And then the listener
```javascript
progress.addEventListener("click", scrub);
```

Now, to take this functionality up a notch, I also added the option to drag the progressbar up/down - like you usually can do on videoplayers.

```javascript
let mousedown = false;
progress.addEventListener("mousemove", (e) => mousedown && time(e));
progress.addEventListener("mousedown", () => (mousedown = true));
progress.addEventListener("mouseup", () => (mousedown = false));
```
`Check if mousedown is true and then update the time according to the event(where your mouse is)`
___
## Results

![Result Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofqfyli96buamk3ej8az.png)

## Thoughts

I have to say it was way less complicated than I thought it would've been. The key points that I felt were either new or interesting were:

- The various types of listeners you can use.
- Using HTML5's media element.


Definitely a fun exercise and I'm excited to see what's next in the JS30 challenges.