Home > Software engineering >  ended event not firing in a playlist
ended event not firing in a playlist

Time:10-23

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>

  • Related