Welcome to a tutorial and example on how to create a custom audio player with a playlist. Looking to build your own audio player and add a playlist to it? Sadly, there are no native implementations of a playlist at the time of writing. So the only way to build a playlist is to create an array of songs, and feed it into the player – Read on for an example!
TABLE OF CONTENTS
CUSTOM AUDIO PLAYER WITH PLAYLIST
All right, let us now get into the example of creating a custom audio player with a playlist.
STEP 1) THE HTML
<div id="aWrap">
<!-- (A) PLAY/PAUSE BUTTON -->
<button id="aPlay" disabled><span id="aPlayIco" class="material-icons">
play_arrow
</span></button>
<!-- (B) TIME -->
<div id="aCron">
<span id="aNow"></span> / <span id="aTime"></span>
</div>
<!-- (C) SEEK BAR -->
<input id="aSeek" type="range" min="0" value="0" step="1" disabled>
<!-- (D) VOLUME SLIDE -->
<span id="aVolIco" class="material-icons">volume_up</span>
<input id="aVolume" type="range" min="0" max="1" value="1" step="0.1" disabled>
<!-- (E) PLAYLIST -->
<div id="aList"></div>
</div>
There are only 5 components for this custom audio player.
<button id="aPlay">
– Play/pause button.<span id="aNow"></span>
– The current playtime.<span id="aTime"></span>
– Total time of the current track.<input id="aSeek">
Time seek slider bar, this is in seconds.<input id="aVolume">
Volume slider bar, this is a value from 0.0 (mute) to 1.0 (loudest).<div id="aList">
The playlist, generated with Javascript in the next step.
STEP 2) INITIALIZE PLAYER
window.addEventListener("DOMContentLoaded", () => {
// (A) PLAYER INIT
// (A1) PLAYLIST - CHANGE TO YOUR OWN!
let playlist = [
{name: "Sugar Plum Fairy", src: "S1.mp3"},
{name: "If I Had A Chicken", src: "S2.mp3"},
{name: "Run Little Chicken", src: "S3.mp3"}
];
// (A2) AUDIO PLAYER & GET HTML CONTROLS
const audio = new Audio(),
aPlay = document.getElementById("aPlay"),
aPlayIco = document.getElementById("aPlayIco"),
aNow = document.getElementById("aNow"),
aTime = document.getElementById("aTime"),
aSeek = document.getElementById("aSeek"),
aVolume = document.getElementById("aVolume"),
aVolIco = document.getElementById("aVolIco"),
aList = document.getElementById("aList");
// (A3) BUILD PLAYLIST
for (let i in playlist) {
let row = document.createElement("div");
row.className = "aRow";
row.innerHTML = playlist[i]["name"];
row.addEventListener("click", () => audPlay(i));
playlist[i]["row"] = row;
aList.appendChild(row);
}
});
- Captain Obvious to the rescue. We wait until
DOMContentLoaded
before proceeding, to prevent things from screwing up. - (A1) The
playlist
, this is an array of objects. Each entry should have the track namename
and sourcesrc
. Quick advice – It is more reliable to use an absolute URL here. I.E.http://site.com/songs/mysong.mp3
instead ofmysong.mp3
. - (A2) Create a new audio object, get all the HTML controls.
- (A3) Loop through
playlist
to generate the HTML. Just take note that clicking on a track will triggeraudPlay()
.
STEP 3) PLAY MECHANISM
// (B) PLAY MECHANISM
// (B1) FLAGS
var audNow = 0, // current song
audStart = false, // auto start next song
// (B2) PLAY SELECTED SONG
audPlay = (idx, nostart) => {
audNow = idx;
audStart = nostart ? false : true;
audio.src = encodeURI(playlist[idx]["src"]);
for (let i in playlist) {
if (i == idx) { playlist[i]["row"].classList.add("now"); }
else { playlist[i]["row"].classList.remove("now"); }
}
};
// (B3) AUTO START WHEN SUFFICIENTLY BUFFERED
audio.addEventListener("canplay", () => { if (audStart) {
audio.play();
audStart = false;
}});
// (B4) AUTOPLAY NEXT SONG IN THE PLAYLIST
audio.addEventListener("ended", () => {
audNow++;
if (audNow >= playlist.length) { audNow = 0; }
audPlay(audNow);
});
// (B5) INIT SET FIRST SONG
audPlay(0, true);
- (B1) 2 flags are used to control the player.
- Remember that
playlist
is an array?audNow
keeps track of which song is currently playing. audStart
is used to control autoplay in (B3).
- Remember that
- (B2)
audPlay()
will play the selected song. For example,audPlay(2)
will play the third song inplaylist
. This works very simply by settingaudio.src = playlist[N]["src"]
. Also, take note of settingaudStart
here. - (B3) Automatically start playing when the current track is sufficiently buffered, but only if
audStart
is set.- Basically,
canplay
can be triggered via 2 possible means. When we changeaudio.src = NEW SONG
, or upon recovering from a bad connection. - We don’t want to piss the users by forcing a patchy playback when they have a bad connection.
- Thus the use of the
audStart
flag, to make sure autoplay is only triggered after clicking on a playlist item (or when auto-starting the next song in the list).
- Basically,
- (B4) When the current song ends, we do a
audNow++
and play the next song.
STEP 4) PLAY/PAUSE BUTTON
// (C) PLAY/PAUSE BUTTON
// (C1) AUTO SET PLAY/PAUSE TEXT
audio.addEventListener("play", () => aPlayIco.innerHTML = "pause");
audio.addEventListener("pause", () => aPlayIco.innerHTML = "play_arrow");
// (C2) CLICK TO PLAY/PAUSE
aPlay.addEventListener("click", () => {
if (audio.paused) { audio.play(); }
else { audio.pause(); }
});
- (C1) Automatically set the play/pause icon. This is Google’s Material Icon by the way. Links below.
- (C2) Self-explanatory? If the audio is paused, we click to play. If the audio is playing, we click to pause.
STEP 5) TRACK TIME
// (D) TRACK PROGRESS
// (D1) SUPPORT FUNCTION - FORMAT HH:MM:SS
var timeString = secs => {
// (D1-1) HOURS, MINUTES, SECONDS
let ss = Math.floor(secs),
hh = Math.floor(ss / 3600),
mm = Math.floor((ss - (hh * 3600)) / 60);
ss = ss - (hh * 3600) - (mm * 60);
// (D1-2) RETURN FORMATTED TIME
if (hh>0) { mm = mm<10 ? "0"+mm : mm; }
ss = ss<10 ? "0"+ss : ss;
return hh>0 ? `${hh}:${mm}:${ss}` : `${mm}:${ss}` ;
};
// (D2) INIT SET TRACK TIME
audio.addEventListener("loadedmetadata", () => {
aNow.innerHTML = timeString(0);
aTime.innerHTML = timeString(audio.duration);
});
// (D3) UPDATE TIME ON PLAYING
audio.addEventListener("timeupdate", () => aNow.innerHTML = timeString(audio.currentTime));
- (D1) Both
audio.duration
andaudio.currentTime
are in seconds. Thus the need for this support function to create a “nice-looking time string”. - (D2) Update the HTML total track time on receiving the metadata.
- (D3) Update the HTML time while the track is playing.
STEP 6) TIME SEEK BAR
// (E) SEEK BAR
audio.addEventListener("loadedmetadata", () => {
// (E1) SET SEEK BAR MAX TIME
aSeek.max = Math.floor(audio.duration);
// (E2) USER CHANGE SEEK BAR TIME
var aSeeking = false; // user is now changing time
aSeek.addEventListener("input", () => aSeeking = true); // prevents clash with (e3)
aSeek.addEventListener("change", () => {
audio.currentTime = aSeek.value;
if (!audio.paused) { audio.play(); }
aSeeking = false;
});
// (E3) UPDATE SEEK BAR ON PLAYING
audio.addEventListener("timeupdate", () => {
if (!aSeeking) { aSeek.value = Math.floor(audio.currentTime); }
});
});
- (E1) Set the
max
of the seek bar on receiving the metadata. - (E2) When the user drags the seek bar, we update
audio.currentTime
accordingly. - (E3) Update the seek bar as the track plays.
- (E2 & E3) Take note of the
aSeeking
flag here. Basically, we don’t want (E3) to update while the user is manually dragging the bar.
STEP 7) VOLUME
// (F) VOLUME
aVolIco.addEventListener("click", () => {
audio.volume = audio.volume==0 ? 1 : 0 ;
aVolume.value = audio.volume;
aVolIco.innerHTML = (aVolume.value==0 ? "volume_mute" : "volume_up");
});
aVolume.addEventListener("change", () => {
audio.volume = aVolume.value;
aVolIco.innerHTML = (aVolume.value==0 ? "volume_mute" : "volume_up");
});
Don’t think this needs any explanation…
STEP 8) ENABLE/DISABLE ALL CONTROLS
// (G) ENABLE/DISABLE CONTROLS
audio.addEventListener("canplay", () => {
aPlay.disabled = false;
aVolume.disabled = false;
aSeek.disabled = false;
});
audio.addEventListener("waiting", () => {
aPlay.disabled = true;
aVolume.disabled = true;
aSeek.disabled = true;
});
Enable all controls when the player can play, and disable all controls while the player is still loading. We can use canplaythrough
to prevent “halfway breaks”, but the initial loading will take longer.
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
EXAMPLE CODE DOWNLOAD
Click here to download. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
EXTRA BITS & LINKS
That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.
BACK/NEXT BUTTONS
I don’t see these buttons as “necessary”, since there is already a playlist. But if you want to add them, here’s a simple Javascript snippet:
function backnext (n) {
if (n) { audNow++; } else { audNow--; }
if (audNow >= playlist.length) { audNow = 0; }
if (audNow < 0) { audNow = playlist.length - 1; }
audPlay(audNow);
}
MULTIPLE INSTANCES
It is a design issue and also a technical one.
- Is it really necessary to have multiple playlist players on a single page?
- A single playlist is easier to manage than multiple playlists.
- How do you deal with multiple instances playing at the same time? Allow all of them to play together? Does this make sense?
- Or track all the instances, and allow only one to play at a time? Isn’t this the same as a single instance?
- Is playing multiple audio on the same page a good idea for mobile devices and slow connections?
- How are you going to squeeze multiple players onto small screens? Good idea?
- Wouldn’t a “single player with multiple playlists” be a better idea?
So yep, feel free to challenge yourself if you really need “multiple instances”.
COMPATIBILITY CHECKS
This audio player will obviously not work with ancient browsers. But it should work well across all “Grade A” modern browsers.
LINKS & REFERENCES
- HTML Media Element– MDN
- HTML Audio – WhatWG
- PHP Audio Player With Playlist – Code Boxx
- Simple HTML Audio Player – Code Boxx
THE END
Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
Excellent tutorial! I had a really hard time finding working playlists that were easy to customize, but this fit the bill perfectly and was so clearly worded. Thank you!
Love the code, wondering how I can center the playlist on a page?
Just do a search for “center div on page”?
https://code-boxx.com/faq/#help “Answers can be found all over the Internet”
This was a great article – thanks! My question: The player advances to the next song on the list after the previous one ends but will not autostart the song on iPhone with IOS 15 – the play button has to be clicked each time. It runs just fine on MacBook Pro running MacOSMonterey. Any simple way to fix this in the code?
I don’t have half-eaten Apples, cannot afford to buy one. But my guesses:
1) It’s a default browser behavior or security feature, the user MUST click to play (to prevent annoying background music and sounds).
2) Slow connection, buffering issues – No quick fixes, will need to work with buffering.
I love this, I know nothing about Javascript so have been looking for ages for an audio player with simple enough layout that I can easily see what is happening to easily customise the CSS myself and this is near exactly what I wanted!
Was just wondering if it would be possible to add mute and skip buttons to the interface?
Mute – Set volume = 0
Previous/Next – Work with the
audNow
flag andplaylist
.Good luck.
I’ve been playing around with your mp3 player and like it very much.
It works great when I load and play the first playlist. However, when I try to load
a second playlist some very strange things can occur. The second playlist will play just fine
but if I click the Pause / Play button then two songs begin playing at the same time.
Apparently the second playlist is appended to the end of the first playlist, or so it appears. Is there a way
to remove all previous playlist records from the playlist array before launching the second playlist.
If so, how would I code that initialization routine. I figured out how to initialize the content of the aList Div
but I don’t know how to remove the previous playlist songs. Any help would be very much appreciated.
Just so that you know, you’re dealing with an eighty something. I took an interest in things like this in the last few years.
I’ve always liked music and this allows me to play a lot of my old songs from my youth.
Thanks for listening.
Paul Chester
Crofton, MD.
Long story short – This audio player is not made to run multiple instances on the same page. Will consider this as a possible upgrade in the next update. Good luck.
https://code-boxx.com/faq/#help