<!-- https://youtu.be/1-CvPn4AbT4?feature=shared -->
<div id="audioPlayerWrapper" class="card shadow-lg border-0">
	
	<img src="..." class="card-img-top track-art" alt="Track Art">
	
	<div class="card-body text-center text-bg-dark bg-gradient">
		<div class="progress" role="progressbar" aria-label="Basic example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
			<div class="progress-bar" style="width: 0%"></div>
		</div>
		
		<div class="d-flex flex-row justify-content-between">
			<p class="small m-0 current-time">0:00</p>
			<p class="small m-0 duration">0:00</p>
		</div>
		
		<audio id="audio-player">
      <source src="" type="audio/mpeg">
      Your browser does not support the audio element.
    </audio>

    <h4 class="card-title display-6 mb-3 title"></h4>
    <h6 class="artist"></h6>
    <p class="small album"></p>
    
    <div class="btn-group d-flex my-2" role="group" aria-label="Player Controls">
			<button type="button" class="btn text-white repeat"><i id="repeat" class="fa-solid fa-repeat"></i></button>
      <button type="button" class="btn text-white prev-track"><i class="fa-solid fa-backward-step"></i></button>
      <button type="button" class="btn btn-lg text-white play-pause"><i class="fa-solid fa-play"></i></button>
      <button type="button" class="btn text-white next-track"><i class="fa-solid fa-forward-step"></i></button>
      <button type="button" class="btn text-white"><i class="fa-solid fa-list"></i></button>
    </div>
    
    <div class="btn-group d-flex justify-content-start volume-container" role="group" aria-label="Player Volume">
      <button type="button" id="toggleVolumeMute" class="btn btn-sm flex-shrink-1 text-white"><i class="fa-solid fa-volume-off"></i></button>
      <input type="range" class="flex-grow-1 volume-slider" />
			<button type="button" id="toggleVolumeMax" class="btn btn-sm flex-shrink-1 text-white"><i class="fa-solid fa-volume-high"></i></button>
    </div>

  </div><!-- Card Body -->
	
	<!-- The Playlist	 -->
			<ul id="audio-playlist" class="list-group list-group-flush border-top">
			</ul><!-- The Playlist	 -->
</div><!-- card -->
body {
	//background: #FFF; 
	background: #F7971E;  /* fallback for old browsers */
background: -webkit-linear-gradient(to bottom, #FFD200, #F7971E);  /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to bottom, #FFD200, #F7971E); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */

}//body

.card {
	margin:0 auto 3rem;
	width:100%;
	
	@media (min-width: 600px) {
		margin:3rem auto;
		width:80%;
	}
	
	@media (min-width: 900px) {
		width:30rem;
	}
}

.play-pause {
	//background-color:pink;
	//height:5rem;
	padding: 1rem 0.5rem;
   font-size: 2.5rem;
    --bs-btn-border-radius: var(--bs-border-radius-lg);
}


.progress {
	overflow:visible;
	cursor:pointer;
	height:10px;
	
	.progress-bar {
		background: #F7971E;  /* fallback for old browsers */
		background: -webkit-linear-gradient(to left, #FFD200, #F7971E);  /* Chrome 10-25, Safari 5.1-6 */
		background: linear-gradient(to left, #FFD200, #F7971E); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */


		border-radius:10px;

		overflow:visible!important;
		position:relative;
		animation-timing-function: linear;
		animation-duration: .01s;
		animation-iteration-count: infinite;
		transition: width .01s ease;
		
		&::before {
			border:2px solid #F7971E;
			border-radius:50%;
			height:20px;
			width:20px;
			content:" ";
			
			position:absolute;
			background: linear-gradient(to bottom,  #FFFFFF 0%,#DDD 100%); 

			top:-5px;
			right:-5px;
			transform: translatY(-50%);
			opacity:0;
			transition:opacity 0.3s ease;
		}//before
		
		
	}//progress-bar
	
	&:hover {
		.progress-bar {
			&::before {
				opacity:1;
			}//before
		}//progress-bar
	}//hovwer
}//audioProgress


.volume-container {
	margin:0 auto;
	width:50%;
}//volume-container
.volume-slider {
	-webkit-appearance:none;
		width:100%;
		height:3px;
		border-radius:4px;
		cursor:pointer;
		margin: 1rem;
	
		background: #F7971E;  /* fallback for old browsers */
		background: -webkit-linear-gradient(to left, #FFD200, #F7971E);  /* Chrome 10-25, Safari 5.1-6 */
		background: linear-gradient(to left, #FFD200, #F7971E); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */


		
		&::-webkit-slider-thumb {
			-webkit-appearance:none;
			//background-color:#FFF;
			border:1px solid #CCC;
			border-radius:50%;
			height:15px;
			width:15px;
			background: linear-gradient(to bottom,  #FFFFFF 0%,#DDD 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */

			
			//-webkit-box-shadow: 0 5px 5px px rgba(0,0,0,.25);
			box-shadow: 0 1px 1px 1px rgba(0,0,0,.20);
		}//knob
}//volume-slider


// Display Track Info under the AUDIO tag -------------------- \\
.list-group-item {
	overflow: hidden;
	cursor:pointer;
	
	.playlist-thumb {
		float: left; 
		height:6rem;
		overflow:hidden;
		position:relative;
		width:6rem;
		
		img {
			position:absolute;
			top:0;
			left:0;
			
			height:100%;
			width:100%;
			
			transition: all 1s linear;
		}//img
	}//playlist-thumb
	
	.display-track-info {
		padding: 0 1em; 
		overflow: hidden;
	}//div
	
	&.playing {
		color:#FFD200!important;
	}//playing
	
	
	&:hover {
		.playlist-thumb {
			img {
				transform: scale(1.2);
			}//img
		}//playlist-thumb
		
	}//hover
}//LI
// END || Display Track Info under the AUDIO tag -------------------- \\
View Compiled
let allMusic = [
	{
		title: "Casual Observer",
		artist: "Hamiltopia feat. Frawls",
		album: "Cardboard Ferrari",
		src: "Casual-Observer",
		img: "https://hamiltopia.com/wp-content/uploads/2022/11/ham-music-32-featured.png"
	},
	{
		title: "Figured As Much",
		artist: "Hamiltopia",
		album: "Cardboard Ferrari",
		src: "Figured-As-Much",
		img: "https://hamiltopia.com/wp-content/uploads/2022/11/ham-music-29-featured.png"
	},
	{
		title: "Chalupacabra",
		artist: "Hamiltopia feat. Frawls",
		album: "Cardboard Ferrari",
		src: "Chalupacabra",
		img: "https://hamiltopia.com/wp-content/uploads/2022/11/ham-music-1-featured.png"
	},
	{
		title: "Menu Bar",
		artist: "Hamiltopia feat. Frawls",
		album: "Cardboard Ferrari",
		src: "Menu-Bar-V2",
		img: "https://hamiltopia.com/wp-content/uploads/2022/11/ham-music-3-featured.png"
	},
	{
		title: "Spiked Mai Tai",
		artist: "Hamiltopia",
		album: "Cardboard Ferrari",
		src: "Spiked-Mai-Tai",
		img: "https://hamiltopia.com/wp-content/uploads/2022/11/ham-music-8-featured.png"
	}
]


const audioWrapper = document.getElementById('audioPlayerWrapper'),
			audioPlayer = audioWrapper.querySelector('#audio-player'),
			audioTitle = audioWrapper.querySelector('.title'),
			audioArtist = audioWrapper.querySelector('.artist'),
			audioAlbum = audioWrapper.querySelector('.album'),
			audioArt = audioWrapper.querySelector('.track-art'),
			playPauseBtn = audioWrapper.querySelector(".play-pause"),
			playPauseIcon = audioWrapper.querySelector(".play-pause i"),
			nextBtn = audioWrapper.querySelector(".next-track"),
			prevBtn = audioWrapper.querySelector(".prev-track"),
			progressBarContainer = audioWrapper.querySelector(".progress"),
			progressBar = audioWrapper.querySelector(".progress-bar"),
			volumeSlider = audioWrapper.querySelector(".volume-slider"),
			volumeMuteBtn = document.getElementById("toggleVolumeMute"),
			volumeMaxBtn = document.getElementById("toggleVolumeMax"),
			audioPlaylist = document.querySelector('#audio-playlist');


//Play random track whje page loads
let musicIndex = Math.floor((Math.random() * allMusic.length) + 1);

window.addEventListener("load", ()=>{
	loadMusic(musicIndex);
	playingNow();
});

//Load Music
function loadMusic(indexNumb){
	audioTitle.innerText = allMusic[indexNumb - 1].title;
	audioArtist.innerText = allMusic[indexNumb - 1].artist;
	audioAlbum.innerText = allMusic[indexNumb - 1].album;
	audioArt.src = allMusic[indexNumb - 1].img;
	audioPlayer.src = `https://hamiltopia.com/wp-content/uploads/2023/09/${allMusic[indexNumb - 1].src}.mp3`;
}

//Play Music
function playMusic(){
	audioWrapper.classList.add("paused");
	playPauseIcon.classList.remove("fa-play");
	playPauseIcon.classList.add("fa-pause");
	playPauseBtn.classList.add("text-warning");
	playPauseBtn.classList.remove("text-white");
	audioPlayer.play();
}

//Pause Music
function pauseMusic(){
	audioWrapper.classList.remove("paused");
	playPauseIcon.classList.remove("fa-pause");
	playPauseIcon.classList.add("fa-play");
	playPauseBtn.classList.remove("text-warning");
	playPauseBtn.classList.add("text-white");
	audioPlayer.pause();
}

//Next Music
function nextMusic(){
	//Increment index by 1
	musicIndex++;
	//If musicIndex is greater then the array length then musicIndex will be 1
	musicIndex > allMusic.length ? musicIndex = 1 : musicIndex = musicIndex;
	loadMusic(musicIndex);
	playMusic();
	playingNow();
}

//Previous Music
function prevMusic(){
	//Decrement index by 1
	musicIndex--;
	//If musicIndex is less then 1 musicIndex will be array length so last song will play
	musicIndex < 1 ? musicIndex = allMusic.length : musicIndex = musicIndex;
	loadMusic(musicIndex);
	playMusic();
	playingNow();
}

//PlayPause Music
playPauseBtn.addEventListener("click", ()=>{
	const isMusicPaused = audioWrapper.classList.contains("paused");
	isMusicPaused ? pauseMusic() : playMusic();
	playingNow();
});

//Next Track 
nextBtn.addEventListener("click", ()=>{
	nextMusic();
});

//Previous Track 
prevBtn.addEventListener("click", ()=>{
	prevMusic();
});


//Progressbar
audioPlayer.addEventListener("timeupdate", (e)=>{
	const currentTime = e.target.currentTime; //current time of song
	const duration = e.target.duration;//duration of song
	
	//Progressbar
	let progressWidth = (currentTime / duration) * 100;
	progressBar.style.width = `${progressWidth}%`;
	
	
	//Current Time and Duration
	let musicCurrentTime = document.querySelector(".current-time"),
		musicDuration = document.querySelector(".duration");
	
	audioPlayer.addEventListener("loadeddata", ()=>{
		//Update Duration
		let audioDuration = audioPlayer.duration;
		let totalMin = Math.floor(audioDuration / 60);
		let totalSec = Math.floor(audioDuration % 60);
		if (totalSec < 10){
			totalSec = `0${totalSec}`;
		}
		musicDuration.innerText = `${totalMin}:${totalSec}`;
	});
	
	//Current TIme
		let currentMin = Math.floor(currentTime / 60);
		let currentSec = Math.floor(currentTime % 60);
		if (currentSec < 10) {
			currentSec = `0${currentSec}`;
		}
		musicCurrentTime.innerText = `${currentMin}:${currentSec}`;
	
});

//Progressbar click 
progressBarContainer.addEventListener("click", (e)=>{
	let progressWidthVal = progressBarContainer.clientWidth;
	let clickedOffSetX = e.offsetX;
	let songDuration = audioPlayer.duration
	
	audioPlayer.currentTime = (clickedOffSetX / progressWidthVal) * songDuration;
	playMusic();
});


//Control Volume
let volume = document.querySelector(".volume-slider");
volume.value = 80;
volume.addEventListener("change", function(e) {
	audioPlayer.volume = e.currentTarget.value / 100;
})

//Mute Track 
volumeMuteBtn.addEventListener("click", ()=>{
	volume.value = 0;
	audioPlayer.volume = 0;
});

//Max Track 
volumeMaxBtn.addEventListener("click", ()=>{
	volume.value = 100;
	audioPlayer.volume = 1;
});



//Repeat shuffle
const repeatBtn = document.querySelector(".repeat");
const repeatBtnIcon = document.querySelector(".repeat i");

repeatBtn.addEventListener("click", ()=>{
	//Get InnerText of icon
	let myClass = document.getElementById("repeat").className;
	
	//change Icoin
	switch (myClass){
		case "fa-solid fa-repeat":
			repeatBtnIcon.classList.remove("fa-repeat");
			repeatBtnIcon.classList.add("fa-bone");
			break;
		case "fa-solid fa-bone":
			repeatBtnIcon.classList.remove("fa-bone");
			repeatBtnIcon.classList.add("fa-shuffle");
			break;
		case "fa-solid fa-shuffle":
			repeatBtnIcon.classList.remove("fa-shuffle");
			repeatBtnIcon.classList.add("fa-repeat");
			break;
	}
});


//When it Ends
//Next Track 
audioPlayer.addEventListener("ended", (e)=>{
	let myClass = document.getElementById("repeat").className;
	
	//change Icoin
	switch (myClass){
		case "fa-solid fa-repeat":
			nextMusic();
			break;
		case "fa-solid fa-bone":
			audioPlayer.currentTime = 0;
			loadMusic(musicIndex);
			playMusic();
			break;
		case "fa-solid fa-shuffle":
			//Generating random index between the max range of the array length
			let randIndex = Math.floor((Math.random() * allMusic.length) + 1);
			do{
				randIndex = Math.floor((Math.random() * allMusic.length) + 1);
			}while(musicIndex == randIndex);//this loop runs until the next random number won't be the same of currenmt musicIndex
			musicIndex = randIndex;//Pasing randIndex to musicIndex so random song will play
			loadMusic(musicIndex);
			playMusic();
			playingNow();
			break;
	}
});


//Create the playlist
for(let i = 0; i < allMusic.length; i++) {
	let liTag =`<li class="list-group-item text-bg-dark playlist-item" li-index="${i + 1}">
								<div class="d-flex flex-row justify-content-start">
								<div class="flex-grow-1">
									<div class="playlist-thumb"><img src="${allMusic[i].img}" class="img-fluid rounded-1" alt="${allMusic[i].title} by ${allMusic[i].artist} from ${allMusic[i].album}"></div>
									<div class="display-track-info">
									<audio class="${allMusic[i].src}"><source src="https://hamiltopia.com/wp-content/uploads/2023/09/${allMusic[i].src}.mp3" type="audio/mpeg"></audio>
										<h5 class="my-0">${allMusic[i].title}</h5>
										<p class="my-0">${allMusic[i].artist}</p>
										<p class="small">${allMusic[i].album}</p>
									</div>
								</div>
								<div class="flex-shrink-0"><p id="${allMusic[i].src}" class="small duration">0:00</p></div>
							</div>
							</li>`;
	audioPlaylist.insertAdjacentHTML("beforeend", liTag);
	
	let liAudioDuration = audioPlaylist.querySelector(`#${allMusic[i].src}`);
	let liAudioTag = audioPlaylist.querySelector(`.${allMusic[i].src}`);
	
	liAudioTag.addEventListener("loadeddata", ()=>{
		let audioDuration = liAudioTag.duration;
		let totalMin = Math.floor(audioDuration / 60);
		let totalSec = Math.floor(audioDuration % 60);
		if (totalSec < 10){
			totalSec = `0${totalSec}`;
		}
		liAudioDuration.innerText = `${totalMin}:${totalSec}`;
		liAudioDuration.setAttribute("t-duration", `${totalMin}:${totalSec}`);
	});
}




///Play song on click
let allLiTags = audioPlaylist.querySelectorAll("li");

function playingNow(){
	
	for(let j = 0; j < allLiTags.length; j++){
		
		let audioTag = allLiTags[j].querySelector(".duration");
		
		//Remove Played class to active playlist track item
		if(allLiTags[j].classList.contains("playing")){
			allLiTags[j].classList.remove("playing");
			
			let adDuration = audioTag.getAttribute("t-duration");
			audioTag.innerText = adDuration;
		};

		//Add Played class to active playlist track item
		if(allLiTags[j].getAttribute("li-index") == (musicIndex)){
			allLiTags[j].classList.add("playing");
			audioTag.innerText = "Playing";
		};

		allLiTags[j].setAttribute("onclick", "clicked(this)");
	}
	
}


function clicked(element){
	let getLiIndex = element.getAttribute("li-index");
	musicIndex = getLiIndex;
	loadMusic(musicIndex);
	playMusic();
	playingNow();
}

External CSS

  1. https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css
  2. https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200

External JavaScript

  1. https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js
  2. https://kit.fontawesome.com/cda9642281.js