Audio Player In HTML Javascript (With Playlist)

So, you want to create a custom audio player? Only to find out that there is literally no way to style the native HTML audio (at the time of writing). What’s worst, it does not even support a playlist. Well, it’s not really easy. But let Master Coffee walk you through a “rather capable custom audio player with a playlist”, let’s go.

 

CODE DOWNLOAD

I have released this under the MIT license, feel free to use it in your own project – Personal or commercial. Some form of credits will be nice though. 🙂

 

 

VIDEO TUTORIAL

 

PART 1) THE HTML

player.html
<div id="player">
  <!-- (PART A) CURRENT SONG IMAGE -->
  <img id="playImg" src="songs/loading.webp">

  <!-- (PART B) CONTROLS -->
  <div id="playControls">
    <!-- (B1) SONG NAME -->
    <div id="playName">Select A Song</div>

    <!-- (B2) SONG TIME -->
    <input id="playTimeR" type="range" value="0" min="0" disabled>
    <div id="playTimeD">
      <div id="playTimeN">0:00</div>
      <div id="playTimeT">0:00</div>
    </div>

    <!-- (B3) LAST, PLAY/PAUSE, NEXT, VOLUME -->
    <div id="playButtons">
      <i id="playLast" class="icon-previous2"></i>
      <i id="playTog" class="icon-pause2"></i>
      <i id="playNext" class="icon-next2"></i>
      <i id="playVolI" class="icon-volume-high"></i>
      <input id="playVolR" type="range" min="0" max="1" step="0.1" value="1" disabled>
    </div>
  </div>

  <!-- (PART C) PLAYLIST -->
  <div id="playList">
    <div data-src="guitar.mp3" data-img="guitar.webp">Guitar</div>
    <div data-src="piano.mp3" data-img="piano.webp">Piano</div>
    <div data-src="trombone.mp3" data-img="trombone.webp">Trombone</div>
  </div>
</div>

There are quite a lot of components to the audio player. But look at the screenshot above and you will be able to figure out which is which.

  1. <img id="playImg"> The current song image/cover.
  2. Audio player controls.
    • (B1) <div id="playName"> the current song name.
    • (B2) <input id="playTimeR"> time select slider, <div id="playTimeN"> current time, <div id="playTimeT"> total time.
    • (B3) <i id="playLast"> last song, <i id="playTog"> play/pause, <i id="playNext"> next song.
    • (B3) <i id="playVolI"> volume icon/mute toggle, <input id="playVolR"> volume slider.
  3. <div id="playList"> The playlist. Each song in the format of <div data-src="SONG.FILE" data-img="IMAGE.FILE">NAME</div>

P.S. Keep all your songs and images in the songs folder.

 

 

PART 2) THE JAVASCRIPT – PROPERTIES & HELPER

player.js
var player = {
  // (PART A) PROPERTIES
  // (A1) HTML ELEMENTS
  hImg : null, // song image
  hName : null, // song name
  hTimeR : null, // song time slider
  hTimeN : null, // song current time
  hTimeT : null, // song time
  hLast : null, // last song
  hTog : null, // toggle play/pause
  hNext : null, // next song
  hVolI : null, // volume icon/toggle
  hVolR : null, // volume slider

  // (A2) AUDIO & PLAYLIST
  pAud : null, // audio player
  pList : null, // playlist
  pSeek : false, // user seeking time slider
  pNow : 0, // currently playing

  // (PART B) HELPER - FORMAT "NICE TIME"
  nicetime : secs => {
    let m = Math.floor(secs/60),
    s = secs - (m * 60);
    if (s<10) { s = "0" + s; }
    return `${m}:${s}`;
  },
  ...
};

The Javascript can be intimidating, let’s break it down section-by-section.

  • All the mechanics are contained within the var player = {} object.
  • (A1) Seemingly a lot of properties, but these are all just references to the HTML buttons and sections.
  • (A2) The audio player itself, the playlist, current song, and “currently seeking time” flag – Will explain these later.
  • (B) A helper function to turn seconds into a “nice format” of MM:SS.

 

 

PART 3) THE JAVASCRIPT – INITIALIZE

player.js
// (PART C) INITIALIZE
init : () => {
  // (C1) GET HTML ELEMENTS
  player.hImg = document.getElementById("playImg");
  player.hName = document.getElementById("playName");
  player.hTimeR = document.getElementById("playTimeR");
  player.hTimeN = document.getElementById("playTimeN");
  player.hTimeT = document.getElementById("playTimeT");
  player.hLast = document.getElementById("playLast");
  player.hNext = document.getElementById("playNext");
  player.hTog = document.getElementById("playTog");
  player.hVolI = document.getElementById("playVolI");
  player.hVolR = document.getElementById("playVolR");

  // (C2) AUDIO OBJECT & PLAYLIST
  player.pAud = new Audio();
  player.pList = document.querySelectorAll("#playList div");

  // (C3) AUTO SWITCH PLAY/PAUSE ICON
  let pp = () => player.hTog.className = player.pAud.paused ? "icon-pause2" : "icon-play3" ;
  player.pAud.onplay = pp;
  player.pAud.onpause = pp;

  // (C4) AUTO PLAY NEXT SONG
  player.pAud.onended = () => player.load(true);

  // (C5) AUTO UPDATE CURRENT TIME
  player.pAud.ontimeupdate = () => {
    if (!player.pSeek) { player.hTimeR.value = Math.floor(player.pAud.currentTime); }
    player.hTimeN.innerHTML = player.nicetime(Math.floor(player.pAud.currentTime));
  };

  // (C6) TIME SLIDER
  player.hTimeR.oninput = () => player.pSeek = true;
  player.hTimeR.onchange = () => {
    player.pAud.currentTime = player.hTimeR.value;
    player.pSeek = false;
    if (player.pAud.paused) { player.pAud.play(); }
  }

  // (C7) CLICK TO PLAY SONG
  for (let [i, song] of Object.entries(player.pList)) {
    song.onclick = () => player.load(i);
  }

  // (C8) INIT - PRELOAD FIRST SONG
  player.load(0, true);
},
...
// (PART E) START
window.addEventListener("load", player.init);

On window load, we call player.init(). Pretty much get the HTML elements and deal with the “basic player mechanics”.

  • (C1) Get the HTML buttons, controls, sections.
  • (C2) Create a new Audio() object, and get the playlist.
  • (C3) Automatically switch between the play and pause icons when the song is playing/paused.
  • (C4) Automatically play the next song when the current song has ended.
  • (C5) Update the current time and time slider as the song plays.
  • (C6) Update the song’s current time as the user changes the time slider. Take note of the player.pSeek flag here. As the song plays, (C5) will continue to update. This flag is to “temporarily disable” (C5), so the time slider does not “suddenly move” as the user changes the slider.
  • (C7) Loop through the playlist, click on a song to play it.
  • (C8) Preload the first song in the playlist.

 

 

PART 4) THE JAVASCRIPT – LOAD SONG

player.js
// (PART D) LOAD SELECTED SONG
load : (song, preload) => {
  // (D1) STOP PLAYING CURRENT SONG
  if (!player.pAud.paused) { player.pAud.pause(); }

  // (D2) LOCK INTERFACE
  player.hImg.src = "songs/loading.webp";
  player.hName.innerHTML = "Loading";
  player.hTimeR.disabled = true;
  player.pSeek = false;
  player.hLast.onclick = "";
  player.hNext.onclick = "";
  player.hTog.onclick = "";
  player.hVolI.onclick = "";
  player.hVolR.disabled = true;

  // (D3) NEXT SONG TO PLAY
  if (song === true) { player.pNow++; }
  else if (song === false) { player.pNow--; }
  else { player.pNow = song; }
  if (player.pNow >= player.pList.length) { player.pNow = 0; }
  if (player.pNow < 0) { player.pNow = player.pList.length - 1; }

  // (D4) SET SELECTED SONG
  for (let song of player.pList) { song.classList.remove("current"); }
  let selected = player.pList[player.pNow];
  selected.classList.add("current");

  // (D5) LOAD SELECTED SONG
  player.pAud.src = "songs/" + selected.dataset.src;
  player.pAud.oncanplaythrough = () => {
    // (D5-1) SET SONG IMAGE & NAME
    player.hImg.src = "songs/" + selected.dataset.img;
    player.hName.innerHTML = selected.innerHTML;

    // (D5-2) SET SONG TIME
    player.hTimeN.innerHTML = "0:00";
    player.hTimeT.innerHTML = player.nicetime(Math.floor(player.pAud.duration));
    player.hTimeR.value = 0;
    player.hTimeR.max = Math.floor(player.pAud.duration);

    // (D5-3) ENABLE CONTROLS
    player.hTimeR.disabled = false;
    player.hVolR.disabled = false;
    player.hLast.onclick = () => player.load(false);
    player.hNext.onclick = () => player.load(true);
    player.hTog.onclick = () => {
      if (player.pAud.paused) { player.pAud.play(); }
      else { player.pAud.pause(); }
    };
    player.hVolI.onclick = () => {
      player.pAud.volume = player.pAud.volume==0 ? 1 : 0 ;
      player.hVolR.value = player.pAud.volume;
      player.hVolI.className = player.pAud.volume==0 ? "icon-volume-mute2" : "icon-volume-high" ;
    };
    player.hVolR.onchange = () => {
      player.pAud.volume = player.hVolR.value;
      player.hVolI.className = player.pAud.volume==0 ? "icon-volume-mute2" : "icon-volume-high" ;
    };

    // (D5-4) START PLAYING SONG
    if (!preload) { player.pAud.play(); }
  };
}

Lastly, player.load() is called “whenever a song is being played” – Preload from init, click on a playlist song, next song, last song.

  • (D1) Pause the current song if the player is playing.
  • (D2) Lock the controls while the next song loads.
  • (D3) “Calculate” the next song to play, remember the player.pNow “current song flag”? Increment by 1 if it is “next song”, decrement by 1 if it is “last song”, or set the exact song number in the playlist.
  • (D4) Update the HTML, set the current song.
  • (D5) Load the selected song.
    • (D5-1) On load, set the song image and name.
    • (D5-2) Update the song time.
    • (D5-3) Enable the controls.
    • (D5-4) Play it.

 

 

THE END – MULTIPLE PLAYERS ON THE SAME PAGE?!

That’s all for this tutorial and sharing. For those who are thinking of “adding multiple players to a single page” – Yes, it is possible with some modifications. But things will get very messy with multiple instances, and you need to check and only allow one player to play at a time.

So yes, Master Coffee will recommend you to think in a different manner instead. There is only one audio player, but multiple playlists. The user can choose which playlist, or even add/remove songs by themselves.