0

I'm writing a simple website with an audio player. I want all the code to be in separate html/css file to reference it quickly on multiple pages. The player is inside a navigation element. Newsletter form also suffers from the same problem, it works locally, but not when hosted.

Firstly, here is a codepen containing a properly working player - https://codepen.io/terramsc/pen/YzerzYw

And here is how I implemented in on my page. It's hosted on github - https://terramsc.github.io/stash/

index.html (main page)

<div id="navigation-wrap"></div>
<script src="JS/navigation.js" type="text/javascript"></script>

navigation.js

$(function(){
  $("#navigation-wrap").load("navigation.html");
});

navigation.html

<link rel="stylesheet" href="CSS/player.css">

<!-- NAVIGATION POPUPS -->

<div class="pops">
  <div class="logotype-small"><img src="https://i.imgur.com/vhVfgRN.png"></div>
  <div class="content">
    <div class="content-wrap">
      <div class="post">
        <h3></h3>
        <h2></h2>
        <p>No content.</p>
      </div>
    </div>
  </div>
  <button class="cls-pop"></button>
</div>

<div class="nwsletter-content">
  <div class="logotype-small"><img src="https://i.imgur.com/vhVfgRN.png"></div>
  <button class="cls-pop"></button>
  <div class="ml-embedded" data-form="Zm6WMb"></div>
</div>

<!-- NAVIGATION BUTTONS -->

<div id="navigation">

  <button class="navigation-button-info"></button>

<!-- AUDIO PLAYER -->

  <div id="player">

    <div id="color-switch"><img src="https://i.imgur.com/SYyiJUa.png">

      <div id="volume-slider-container">
        <output id="volume-output">100</output>
        <div id="volume-slider-squish">
          <input type="range" id="volume-slider" max="100" value="70">
        </div>
        <button id="mute-icon"></button>
      </div>

      <div id="audio-player-container">
        <audio src="https://assets.codepen.io/4358584/Anitek_-_Komorebi.mp3" preload="metadata" loop></audio>

        <button id="play-icon"></button>
        <span id="current-time" class="time">0:00</span>
        <input type="range" id="seek-slider" max="100" value="0">
        <span id="duration" class="time">0:00</span>

      </div>
    </div>
  </div>

  <button class="navigation-button-nwsletter"></button>

</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

<script>
  $(document).ready(function() {
    $('.navigation-button-info').click(function() {
      $('.pops').fadeIn();
    });
    $('.cls-pop').click(function() {
      $('.pops').fadeOut();
    });
  });
</script>

<script>
  $(document).ready(function() {
    $('.navigation-button-nwsletter').click(function() {
      $('.nwsletter-content').fadeIn();
    });
    $('.cls-pop').click(function() {
      $('.nwsletter-content').fadeOut();
    });
  });
</script>

<script>
  /* Implementation of the presentation of the audio player */
  import lottieWeb from 'https://cdn.skypack.dev/lottie-web';

  const player = document.querySelector('#player')
  const playIconContainer = document.getElementById('play-icon');
  const audioPlayerContainer = document.getElementById('audio-player-container');
  const seekSlider = document.getElementById('seek-slider');
  const volumeSlider = document.getElementById('volume-slider');
  const muteIconContainer = document.getElementById('mute-icon');
  let playState = 'play';
  let muteState = 'unmute';

  const playAnimation = lottieWeb.loadAnimation({
    container: playIconContainer,
    path: 'https://assets7.lottiefiles.com/packages/lf20_vbkmvxki.json',
    renderer: 'svg',
    loop: false,
    autoplay: false,
    name: "Play Animation",
  });

  const muteAnimation = lottieWeb.loadAnimation({
      container: muteIconContainer,
      path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/mute/mute.json',
      renderer: 'svg',
      loop: false,
      autoplay: false,
      name: "Mute Animation",
  });

  playAnimation.goToAndStop(10, true);

  playIconContainer.addEventListener('click', () => {
      if(playState === 'play') {
          audio.play();
          playAnimation.playSegments([40, 42], true);
          requestAnimationFrame(whilePlaying);
          playState = 'pause';
      } else {
          audio.pause();
          playAnimation.playSegments([10, 12], true);
          cancelAnimationFrame(raf);
          playState = 'play';
      }
  });

  muteIconContainer.addEventListener('click', () => {
      if(muteState === 'unmute') {
          muteAnimation.playSegments([0, 15], true);
          audio.muted = true;
          muteState = 'mute';
      } else {
          muteAnimation.playSegments([15, 25], true);
          audio.muted = false;
          muteState = 'unmute';
      }
  });

  const showRangeProgress = (rangeInput) => {
      if(rangeInput === seekSlider) player.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%');
      else player.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%');
  }

  seekSlider.addEventListener('input', (e) => {
      showRangeProgress(e.target);
  });
  volumeSlider.addEventListener('input', (e) => {
      showRangeProgress(e.target);
  });





  /* Implementation of the functionality of the audio player */

  const audio = document.querySelector('audio');
  const durationContainer = document.getElementById('duration');
  const currentTimeContainer = document.getElementById('current-time');
  const outputContainer = document.getElementById('volume-output');
  let raf = null;

  const calculateTime = (secs) => {
      const minutes = Math.floor(secs / 60);
      const seconds = Math.floor(secs % 60);
      const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
      return `${minutes}:${returnedSeconds}`;
  }

  const displayDuration = () => {
      durationContainer.textContent = calculateTime(audio.duration);
  }

  const setSliderMax = () => {
      seekSlider.max = Math.floor(audio.duration);
  }

  const displayBufferedAmount = () => {
      const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1));
      player.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`);
  }

  const whilePlaying = () => {
      seekSlider.value = Math.floor(audio.currentTime);
      currentTimeContainer.textContent = calculateTime(seekSlider.value);
      player.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`);
      raf = requestAnimationFrame(whilePlaying);
  }

  if (audio.readyState > 0) {
      displayDuration();
      setSliderMax();
      displayBufferedAmount();
  } else {
      audio.addEventListener('loadedmetadata', () => {
          displayDuration();
          setSliderMax();
          displayBufferedAmount();
      });
  }

  audio.addEventListener('progress', displayBufferedAmount);

  seekSlider.addEventListener('input', () => {
      currentTimeContainer.textContent = calculateTime(seekSlider.value);
      if(!audio.paused) {
          cancelAnimationFrame(raf);
      }
  });

  seekSlider.addEventListener('change', () => {
      audio.currentTime = seekSlider.value;
      if(!audio.paused) {
          requestAnimationFrame(whilePlaying);
      }
  });

  volumeSlider.addEventListener('input', (e) => {
      const value = e.target.value;

      outputContainer.textContent = value;
      audio.volume = value / 100;
  });




  /* Implementation of the Media Session API */
  if('mediaSession' in navigator) {
      navigator.mediaSession.metadata = new MediaMetadata({
          title: 'Komorebi',
          artist: 'Anitek',
          album: 'MainStay',
          artwork: [
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '96x96', type: 'image/png' },
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '128x128', type: 'image/png' },
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '192x192', type: 'image/png' },
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '256x256', type: 'image/png' },
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '384x384', type: 'image/png' },
              { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '512x512', type: 'image/png' }
          ]
      });
      navigator.mediaSession.setActionHandler('play', () => {
          if(playState === 'play') {
              audio.play();
              playAnimation.playSegments([14, 27], true);
              requestAnimationFrame(whilePlaying);
              playState = 'pause';
          } else {
              audio.pause();
              playAnimation.playSegments([0, 14], true);
              cancelAnimationFrame(raf);
              playState = 'play';
          }
      });
      navigator.mediaSession.setActionHandler('pause', () => {
          if(playState === 'play') {
              audio.play();
              playAnimation.playSegments([14, 27], true);
              requestAnimationFrame(whilePlaying);
              playState = 'pause';
          } else {
              audio.pause();
              playAnimation.playSegments([0, 14], true);
              cancelAnimationFrame(raf);
              playState = 'play';
          }
      });
      navigator.mediaSession.setActionHandler('seekbackward', (details) => {
          audio.currentTime = audio.currentTime - (details.seekOffset || 10);
      });
      navigator.mediaSession.setActionHandler('seekforward', (details) => {
          audio.currentTime = audio.currentTime + (details.seekOffset || 10);
      });
      navigator.mediaSession.setActionHandler('seekto', (details) => {
          if (details.fastSeek && 'fastSeek' in audio) {
            audio.fastSeek(details.seekTime);
            return;
          }
          audio.currentTime = details.seekTime;
      });
      navigator.mediaSession.setActionHandler('stop', () => {
          audio.currentTime = 0;
          seekSlider.value = 0;
          audioPlayerContainer.style.setProperty('--seek-before-width', '0%');
          currentTimeContainer.textContent = '0:00';
          if(playState === 'pause') {
              playAnimation.playSegments([0, 14], true);
              cancelAnimationFrame(raf);
              playState = 'play';
          }
      });
  }
</script>
DXK183
  • 13
  • 4
  • ` – ggorlen May 31 '22 at 14:06
  • In the future, I strongly recommend making a [mcve]. 99% of this code isn't actually relevant to the problem, and if you stripped it out piece by piece until you got the error, you'd wind up with 2-3 lines of code that are easy to search, debug and ask about (if the answer still wasn't obvious at that time). – ggorlen May 31 '22 at 14:16
  • @ggorlen To be sure, that should be added for the player script? On the tag just before `import lottieWeb from 'https://cdn.skypack.dev/lottie-web';`? – DXK183 May 31 '22 at 14:18
  • Does this answer your question? [ES2015 import doesn't work (even at top-level) in Firefox](https://stackoverflow.com/questions/37624819/es2015-import-doesnt-work-even-at-top-level-in-firefox) – ggorlen May 31 '22 at 14:19
  • Sorry, I was able to modify and customize the player, but some code is still difficult for me to understand. That's why I provided most of it. I stripped a lot from index.html and navigation.js. I try to respect the rules. – DXK183 May 31 '22 at 14:20
  • That's fine, but at the very least please check the console and post the exact errors you see there. Ultimately, others are going to minimize the problem down--that's just how debugging works. Notice how the suggested dupe stripped the problem down to the bare essence so it's totally unambiguous and maximally useful as a canonical reference for others with the same problem. Yes, add `type="module"` to the script tag that uses `import` syntax, as shown in the dupe suggestion. – ggorlen May 31 '22 at 14:21
  • @ggorlen Thank you for learning me about this, but unfortunately it didn't resolve the problem. My code now starts with ` – DXK183 May 31 '22 at 14:24
  • Please be specific. What error(s) are you getting? I assume you're not using a build, just plain files, correct? I also see `Uncaught ReferenceError: switchSlide is not defined` in your github, in `fade-in-body-wrapper.js`. Did you define it? – ggorlen May 31 '22 at 14:25
  • @ggorlen I don't know what you mean by build, but I mostly create files in Atom editor. The only error I have right now is `Uncaught ReferenceError: switchSlide is not defined`. However, what doesn't work is the player and mailing form. Some JS just doesn't seem to run properly. I didn't define it, how should I do so? – DXK183 May 31 '22 at 14:54
  • Well, that variable isn't anywhere in your codepen or the code posted here, so I don't know why you've added it to your github code. When you throw an error like this, the whole script stops, so it's expected that the player and mailing form don't work. – ggorlen May 31 '22 at 14:57
  • @ggorlen ok, My bad. I removed that script and repleced it with CSS animation. Right now my error log in console is empty, but still - neither player nor mailing form do not work. – DXK183 May 31 '22 at 15:14
  • I see you updated that on the live deploy, but I don't see that there's any of your codepen JS code in the github.io page. Try adding the script in from the codepen, being sure to use the ` – ggorlen May 31 '22 at 15:15
  • @ggorlen the code is inside player.html – DXK183 May 31 '22 at 15:23
  • That seems to work. Did you want that code in index.html? If so, put it in index.html rather than player.html. – ggorlen May 31 '22 at 15:26
  • The problem is it doesn't :( The audio player on codepen is fully functional. On my website, it's broken. It doesn't seem to load the audio, as it shows 0:00 out of 0:00, play and mute buttons are not visible and sliders do not work. Also, the mailing form on my website is not displayed. Everything works properly on codepen. – DXK183 May 31 '22 at 15:28
  • player.html plays audio for me. There seems to be some fundamental misunderstandings here. Your codepen code and your github.io code are different, and index.html has none of the code from player.html, so naturally it won't work, which is expected (websites only run their code, not other sites' code). The mailer and other scripts on index.html seem like unrelated things you're attempting to graft on without really understanding how to do so, so I'd take a step back from that and just get the player working first before trying to add complexity. – ggorlen May 31 '22 at 15:30
  • Are you aware that index.html and player.html are two totally separate websites that have no interaction whatsoever? Right now, index.html has your CSS and player.html has your JS, so the CSS appears broken (nonexistent) in player.html and the JS (audio player) is broken (nonexistent) in index.html. The task should be to move the script from player.html over to index.html so you have one web page with both CSS and JS, just like your codepen. Codepen merges HTML, CSS and JS into one page when you run the pen. – ggorlen May 31 '22 at 15:33
  • @ggorlen yeah I think I put too much on myself. I just condensed everything into separate css/js files, but dropped linking html so often. Now it works, thank you. – DXK183 May 31 '22 at 16:01

0 Answers0