MediaWiki:AudioPlayer.js

From Blue Archive Wiki
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
(function() {
  function addScript( src, callback ) {
    var s = document.createElement( 'script' );
    s.setAttribute( 'src', src );
    s.onload=callback;
    document.body.appendChild( s );
  }

  function getTimeCodeFromNum(num) {
    let seconds = parseInt(num);
    let minutes = parseInt(seconds / 60);
    seconds -= minutes * 60;
    const hours = parseInt(minutes / 60);
    minutes -= hours * 60;
  
    if (hours === 0) return `${minutes}:${String(seconds % 60).padStart(2, 0)}`;
    return `${String(hours).padStart(2, 0)}:${minutes}:${String(
      seconds % 60
    ).padStart(2, 0)}`;
  }

  function audioInit() {
    groups = {};

    $(".audio-player").each(function(index, audioPlayer) {
      const dataSet = audioPlayer.dataset;
      const audioGroup = dataSet.group;
      const shouldLoop = dataSet.loop === "true";
      const loopStart = parseFloat(dataSet.loopStart);
      const loopEnd = parseFloat(dataSet.loopEnd);
      const isPauseButton = dataSet.pauseButton;
      
      const playerId = "audio" + index;
      const playButton = audioPlayer.querySelector(".toggle-play");

      const progressBar = audioPlayer.querySelector(".progress");
      const timeline = audioPlayer.querySelector(".timeline");

      const volumeButton = audioPlayer.querySelector(".volume-button");
      const volumeButtonIcon = audioPlayer.querySelector(".volume");
      const volumeSlider = audioPlayer.querySelector(".controls .volume-slider");
      const volumePercentage = audioPlayer.querySelector(".controls .volume-percentage");

      const audioTime = audioPlayer.querySelector(".time");
      const audioCurrentTime = audioPlayer.querySelector(".current");
      const audioDivider = audioPlayer.querySelector(".divider");
      const audioLength = audioPlayer.querySelector(".length");
      
      if (isPauseButton && isPauseButton === "true") {
      	playButton.addEventListener("click", function() {
      		groups[audioGroup].pause();
      	});
      	return;
      }

      let muted = false;

      function pauseAudioIcon() {
        playButton.classList.remove("pause");
        playButton.classList.add("play");
      }

      const howler = new Howl({
        src: [dataSet.src],
        onpause: pauseAudioIcon,
        onplay: function() {
          playButton.classList.remove("play");
          playButton.classList.add("pause");
        },
        onend: function() {
          if (shouldLoop) {
            howler.seek(0);
            howler.play();
          } else {
            pauseAudioIcon();
          }
        },
        onload: function() {
          if (audioTime) {
            audioCurrentTime.innerText = "0:00";
            audioDivider.innerText = "/";
            audioLength.innerText = getTimeCodeFromNum(howler.duration());
          }
        },
        onvolume: function() {
          if (volumePercentage) {
            volumePercentage.style.width = howler.volume() * 100 + '%';
          }
        },
      });

      howler.volume(parseFloat(dataSet.volume));

      function checkBGMLoop() {
      	const seek = howler.seek();
        if (seek >= loopEnd && seek - loopEnd < 0.5) {
          howler.seek(loopStart);
          // seek will trigger update progress, so exit immediately for progress to be updated by next call
          return;
        }
      }

      if (shouldLoop && loopEnd !== 0) {
        setInterval(checkBGMLoop, 20);
      }
      
      let lastSeek = 0;
      updateProgress = function() {
        const seek = howler.seek();
        if (seek === lastSeek) {
        	return;
        }
        lastSeek = seek;
        
        if (progressBar) {
          progressBar.style.width = (seek / howler.duration() * 100) + "%";
        }
        if (audioCurrentTime) {
          audioCurrentTime.innerText = getTimeCodeFromNum(seek);
        }
      };
      howler.on("seek", updateProgress);

      // update progress in every set interval
      if ((shouldLoop && loopEnd !== 0) || progressBar || audioCurrentTime) {
        setInterval(updateProgress, 100);
      }

      // controls playing and pausing
      playButton.addEventListener("click", function() {
        if (howler.playing()) {
          howler.pause();
        } else {
          if (audioGroup && audioGroup !== "concurrent") {
            const previousPlaying = groups[audioGroup];
            if (previousPlaying) {
              previousPlaying.pause();
            }
            groups[audioGroup] = howler;
          }
          howler.play();
        }
      });

      // seek whenever the timeline is clicked
      if (timeline) {
        timeline.addEventListener("click", e => {
          const timelineWidth = window.getComputedStyle(timeline).width;
          const timeToSeek = e.offsetX / parseInt(timelineWidth) * howler.duration();
          howler.seek(timeToSeek);
        });
      }

      // controls volume button: either mute or unmute
      if (volumeButton) {
        volumeButton.addEventListener("click", function() {
          if (muted) {
            howler.mute(false);
            volumeButtonIcon.classList.remove("icon-muted");
            volumeButtonIcon.classList.add("icon-volume-medium");
          } else {
            howler.mute(true);
            volumeButtonIcon.classList.add("icon-muted");
            volumeButtonIcon.classList.remove("icon-volume-medium");
          }
          muted = !muted;
        });
      }

      // controls volume slider
      if (volumeSlider) {
        volumeSlider.addEventListener('click', e => {
          const sliderWidth = window.getComputedStyle(volumeSlider).width;
          const newVolume = e.offsetX / parseInt(sliderWidth);
          howler.volume(newVolume);
        });
      }
    });
  }

  addScript("https://cdn.jsdelivr.net/npm/howler@2.2.4/dist/howler.min.js", audioInit);
})();