I've been following and personalizing this youtube video to create a playlist. My problem is that when an audio ends, the event listener does not detect it, so the following audio is not automatically played. I think this may be because my audios are played on clic (with "onclick" in the html), and not loaded in the player.
Here is the html :
<body>
<audio controls id="audioPlayer" autoplay="false">
Sorry, your browser doesn't support html5!
</audio>
<ul id="playlist">
<li >
<a
src="test.wav"
onclick="playAudio('test.wav')">
test
</a></li>
<li><a src="algebrasuicide_fathersbythedoor.wav" onclick=
"playAudio('algebrasuicide_fathersbythedoor.wav')">algebra suicide <i>father by the door</i>
</a></li>
<li><a src="algebrasuicide_inbedwithboys.wav" onclick=
"playAudio('algebrasuicide_inbedwithboys.wav')">
algebra suicide <i>in bed with boys</i>
</a></li>
<li><a
src="aprilmagazine_parade.wav"
onclick="playAudio('aprilmagazine_parade.wav')">
april magazine <i>parade</i>
</a></li>
<ul>
<button id="button">PAUSE</button>
<script src="https://code.jquery.com/jquery-2.2.0.js"></script>
<script src="js/script.js"></script>
<script>
// loads the audio player
audioPlayer();
</script>
</body>
and here is the js :
let audio;
function stopAudio() {
// If audio in not undefined and if is playing, pause it
if (audio && !audio.paused) {
audio.pause();
audio.currentTime = 0; // Rewind track to beginning (is you need this)
}
}
function playAudio(src) {
stopAudio(); // Pause any currently playing
audio = new Audio(); // Save a reference
audio.src = src;
audio.play();
}
function pauseAudio(){
audio.pause();
}
var button = document.getElementById("button");
button.addEventListener("click", function(){
if(audio.paused){
audio.play();
button.innerHTML = "Pause";
} else {
pauseAudio();
button.innerHTML = "Play";
}
});
function audioPlayer(){
var currentSong = 0;
$("#audioPlayer")[0].src = $("#playlist li a")[0];
$("#playlist li a").click(function(e){
e.preventDefault();
$("#audioPlayer")[0].src = this;
$("#playlist li").removeClass("current-song");
currentSong = $(this).parent().index();
$(this).parent().addClass("current-song");
});
}
$("#audioPlayer")[0].addEventListener("ended", function(){
alert("hi");
currentSong ;
if(currentSong == $("#playlist li a").length)
currentSong = 0;
$("#playlist li").removeClass("current-song");
$("#playlist li:eq(" currentSong ")").addClass("current-song");
$("#audioPlayer")[0].src = $("#playlist li a")[currentSong].href;
$("#audioPlayer")[0].play();
});
$(document).ready(function() {
audioPlayer();
});
If someone knows how I could do to automatically play the next audio of the list I'm very interested, I'd love to understand where is the error of logic in this code :) I'm very new to coding so maybe the answer to this in simple.
Thank you !
CodePudding user response:
The main issue in your code is that you were using two Audio elements. One in the DOM in your <audio>
element, the other in-memory in the audio
variable. As such, you weren't hooking the ended
event handler to the Audio which was actually playing.
I've fixed this in the example below by only using the in-memory version of Audio. I've also tidied some of your other logic as there were parts which were unnecessary, and other which can be improved.
For example, don't use inline onclick
attributes. Add your event handlers unobtrusively in JS. If you need to pass data to functions, place the argument in a data
attribute in the HTML and read it from the DOM when the event fires.
Also note that it's better to stick to one library, so I removed jQuery, as you only used it in a couple of places, and replaced that logic with plain JS instead.
Here's a working example. You can see the file changes after the first file, which is around 45 seconds, ends. Unfortunately the first file was the shortest one which I could find which was freely available for the demo!
const button = document.querySelector("#button");
const li = document.querySelectorAll('#playlist li');
let audio = new Audio();
audio.volume = 0.15; // so we don't deafen people for this demo
const stopAudio = () => {
if (!audio.paused) {
audio.pause();
audio.currentTime = 0;
}
}
const playAudio = src => {
stopAudio();
audio.src = src;
audio.play();
}
const togglePause = () => {
if (audio.paused) {
audio.play();
button.innerHTML = "Pause";
} else {
audio.pause();
button.innerHTML = "Play";
}
}
button.addEventListener("click", togglePause);
// add the click event handler to the li elements so they play audio when clicked.
document.querySelectorAll('#playlist li a').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();
li.forEach(li => li.classList.remove("current-song"));
const a = e.currentTarget;
playAudio(a.dataset.fileurl);
a.closest('li').classList.add("current-song");
});
});
// move to the next file when one ends
audio.addEventListener("ended", function() {
const playingLi = document.querySelector('li.current-song');
playingLi.classList.remove('current-song');
const nextLi = playingLi.nextElementSibling;
nextLi.classList.add('current-song');
playAudio(nextLi.querySelector('a').dataset.fileurl);
});
.current-song {
color: #FFF;
background-color: #C00;
}
<ul id="playlist">
<li>
<a src="algebrasuicide_fathersbythedoor.wav" data-fileurl="http://www.sousound.com/music/healing/healing_01.mp3">
algebra suicide <i>father by the door</i>
</a>
</li>
<li>
<a src="algebrasuicide_inbedwithboys.wav" data-fileurl="http://grochtdreis.de/fuer-jsfiddle/audio/TalkNerdyToMe.mp3">
algebra suicide <i>in bed with boys</i>
</a>
</li>
</ul>
<button id="button">Pause</button>