0

I have two tracks that get loaded on a single <audio> when you hit play on either of these tracks. That seems to work perfectly fine. Each of these tracks has a separate <progress> field but no matter what track you play you only see the progress bar moving on the first <progress> field.

Is there a way to fix this?

There's also an error when you pause a song and resume it. The total and current time text fields display a "Na" message for a split second before showing the correct total/current time back again.

How can I stop that from happening?

HTML

<audio id="globalAudio"></audio>

<div class="mp3Player" data-src="https://www.freesound.org/data/previews/338/338825_1648170-lq.mp3" data-pos="0">
    <button class="btnPlayPause button">Play</button>
    <span class="infoLabel">
        <span id="seekObjContainer">
            <progress id="seekbar" value="0" max="1"></progress>
        </span>
        <span class="start-time"></span>
        <span class="end-time"></span>
    </span>
</div>

<div class="mp3Player" data-src="http://www.lukeduncan.me/oslo.mp3" data-pos="0">
    <button class="btnPlayPause button">Play</button>
    <span class="infoLabel">
        <span id="seekObjContainer">
            <progress class="seekbar1" value="0" max="1"></progress>
        </span>
        <span class="start-time"></span>
        <span class="end-time"></span>
    </span>
</div>

JS

var globalAudio = document.getElementById("globalAudio");
var current = null;
var playingString = "<span>Pause</span>";
var pausedString = "<span>Play</span>";
$(document.body).on('click', '.btnPlayPause', function(e) {
  var target = this;

function calculateTotalValue(length) {
  var minutes = Math.floor(length / 60),
    seconds_int = length - minutes * 60,
    seconds_str = seconds_int.toString(),
    seconds = seconds_str.substr(0, 2),
    time = minutes + ':' + seconds;

  return time;
}

function calculateCurrentValue(currentTime) {
  var current_hour = parseInt(currentTime / 3600) % 24,
    current_minute = parseInt(currentTime / 60) % 60,
    current_seconds_long = currentTime % 60,
    current_seconds = current_seconds_long.toFixed(),
    current_time = (current_minute < 10 ? "0" + current_minute : current_minute) + ":" + (current_seconds < 10 ? "0" + current_seconds : current_seconds);

  return current_time;
}

function initProgressBar() {
  var length = globalAudio.duration;
  var current_time = globalAudio.currentTime;

  var totalLength = calculateTotalValue(length);
  jQuery(".end-time").html(totalLength);
  var currentTime = calculateCurrentValue(current_time);
  jQuery(".start-time").html(currentTime);

  var progressbar = document.getElementById('seekbar');
  progressbar.value = globalAudio.currentTime / globalAudio.duration;
  console.log(target);
}

if (current == target) {
  target.innerHTML = pausedString;
  target.parentNode.setAttribute('data-pos', globalAudio.currentTime); //start from paused
  globalAudio.pause();
  current = null;
} else {
  if (current != null) {
    current.innerHTML = pausedString;
    current.parentNode.setAttribute('data-pos', '0'); //reset position
    target.parentNode.setAttribute('data-pos', globalAudio.currentTime); //start from paused
  }
  current = target;
  target.innerHTML = playingString;
  globalAudio.src = target.parentNode.getAttribute('data-src');
  globalAudio.play();
  globalAudio.onloadeddata = function() {
    globalAudio.currentTime = parseFloat(target.parentNode.getAttribute('data-pos'));
    globalAudio.addEventListener("timeupdate",function(){ initProgressBar(); });
  };
}
});

Here's is a working example in this fiddle

Thank you

Rocha
  • 1
  • 1

1 Answers1

0

That's because only the first <progress> tag have an id:

<progress id="seekbar" value="0" max="1"></progress>
<progress class="seekbar1" value="0" max="1"></progress>

Then:

var progressbar = document.getElementById('seekbar'); // <-- always getting the first progress tag
progressbar.value = globalAudio.currentTime / globalAudio.duration;

For the NaN issue appearing for a split second, that's because when loading a source in an <audio> tag the duration is unknown until the browser has retrieved the file's metadata. While this duration is unknown its value is NaN (Not A Number).

You may add a check:

if (Number.isNaN(element.duration)) {
  // display 00:00 or whatever you want
}
Neovov
  • 349
  • 2
  • 14
  • The second `` also has an ID but it would have to be different to the fist one otherwise none of the progress bars would work. Is there a way to automate it so I don't have to duplicate this code for each audio track? `var progressbar = document.getElementById('seekbar'); progressbar.value = globalAudio.currentTime / globalAudio.duration; ` – Rocha May 19 '20 at 16:18
  • I understand why it would display `NaN` the first time you hit play but if I pause the audio and press play again it shouldn't need to make that call again. [This example](https://codepen.io/luke__duncan/pen/dpZVOr/) seems to be working fine without displaying any `NaN` – Rocha May 19 '20 at 16:30