<div class="c-containter">
        <div class="music-container">
            <section class="album-cover">
                
                <button class="arrow left" id="prev">
                    <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/arrow_left.svg" alt="Next Music">
                </button>
                <img src="//cdn.atrera.com/images/cover_yz2mak.jpg" class="cover" alt="From One To Nine by Marcel Pequel">
                
                <button class="arrow right" id="next">
                    <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/arrow_right.svg" alt="Next Music">
                </button>
            </section>
            <section class="music-player">
                <h1 class="music-player__title"></h1>
                <h2 class="music-player__author"></h2>
                <div class="music-time">
                    <p class="music-time__current"></p>
                    <p class="music-time__last"></p>
                </div>
                <div class="music-bar" id="progress">
                    <div id="length"></div>
                </div>
                <div class="music-order">
                    <div class="music-order__loop is-loop" id="loop">
                        <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg" alt="Loop music">
                    </div>
                    <div class="music-order__shuffle" id="shuffle">
                        <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/shuffle.svg" alt="Shuffle music">
                    </div>
                </div>
                <div class="music-control">
                    <div class="music-control__backward" id="backward">
                        <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/backward.svg" alt="Backward">
                    </div>
                    <div class="music-control__play" id="play">
                        <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg" alt="Play" class="play">
                    </div>
                    <div class="music-control__forward" id="forward">
                        <img src="https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/forward.svg" alt="Forward">
                    </div>
                </div>
            </section>
        </div>
        <p class="disclaimer">Music by Marcel Pequel and audio from <a href="http://freemusicarchive.org/music/Marcel_Pequel/From_One_To_Nine/" target="_blank" rel="noopener">Free Music Archive</a>. Design idea from <a href="https://dribbble.com/shots/2315906-Music-player-PSD-freebie-dailyui-Day-009" target="_blank" rel="noopener">Dima Blover</a></p>
    </div>
$bg-1: #FFCDD2
$bg-2: #B2EBF2
$music-bar: #2196F3
$music-bar-bg: #efefef
  
%player-action
  transition: 300ms
  &:hover
    opacity: 0.7
    cursor: pointer

div
  box-sizing: border-box

img
  width: 100%
  height: 100%

p 
  margin-top: 0
  margin-bottom: 0.3em

body
  font-family: 'Mukta', sans-serif
  width: 100%
  height: 100%
  margin: 0
  padding: 0
  min-width: 100vw
  min-height: 100vh
  background: linear-gradient(-45deg, $bg-1 50%, $bg-2 50%)

//for all buttons
div > img
  @extend %player-action

div,
section
  box-sizing: border-box

.c-containter
  display: flex
  flex-flow: column nowrap
  justify-content: center
  align-items: center
  width: 100%
  height: 100vh
  padding: 1em

.music-container
  position: relative
  display: flex
  box-shadow: 1px 1px 5px 0 rgba(0,0,0,0.3)
  max-height: 290px

.album-cover
  flex: 1 0 30%
  img
    width: 100%
    height: 100%

.arrow
  position: absolute
  top: calc(50% - 2.5em)
  background: rgba(255,255,255,0.3)
  border: 0
  width: 5em
  height: 5em
  cursor: pointer
  &:hover
    background: rgba(255,255,255,0.5)
  img
    display: block
    width: 20px
    margin: 0 auto
  &.left
    left: -5em
  &.right
    right: -5em

.music-player
  display: flex
  flex-flow: column wrap
  justify-content: center
  background: white
  padding: 1em
  text-align: center
  width: 500px
  max-width: 500px
  &__title
    margin: 0 0 0.1em 0
  &__author
    margin: 0 0 0.5em 0

.music-bar 
  background: $music-bar-bg
  stroke-width: 1
  height: 8px
  width: 100%
  &:hover
    cursor: pointer
  #length
    width: 0%
    background: $music-bar
    height: 100%
    transition: width linear 200ms

.music-time
  display: flex
  flex-flow: row wrap
  &__last
    margin-left: auto

.music-order
  display: flex
  flex-flow: row wrap
  &__shuffle,
  &__loop
    width: 1.2em
    height: 1.2em
    opacity: 0.2
    margin: 0.3em 0
    &.is-loop
      opacity: 1 !important
    &.is-loop-one
      opacity: 1 !important
  &__shuffle
    margin-left: auto

.music-control
  display: flex
  flex-flow: row wrap
  justify-content: center
  align-items: center
  height: 2em
  &__play
    width: 3em
    height: 3em
    margin: 0 1em
  &__backward,
  &__forward
    width: 1.5em
    height: 1.5em

.disclaimer
  font-size: 0.9em
  margin-top: 1em
  text-align: center
  a 
    color: $music-bar

@media all and (max-width: 960px)
  .c-containter
    display: block
    overflow: auto

  .music-container
    flex-flow: column wrap
    max-height: inherit
    max-width: 270px
    margin: 0 auto
    overflow: auto

  .music-player
    width: 100%
    max-width: 100%
    &__title
      font-size: 1.5em
    &__author
      font-size: 1em

  .album-cover
    position: relative
    flex: 1 1 100%
    max-width: 270px
    max-height: 270px

  .arrow
    position: absolute
    top: calc(50% - 1.5em)
    width: 3em
    height: 3em
    &.left
      left: 0
    &.right
      right: 0

  .music-control
    &__play
      width: 2.2em
      height: 2.2em
View Compiled
(function IIFE() {
  const list = [
    {
      id: 1,
      url:
        "//cdn.atrera.com/audio/Marcel_Pequel_-_01_-_One.mp3",
      author: "Marcel Pequel",
      title: "One",
      cover:
        "//cdn.atrera.com/images/cover_yz2mak.jpg"
    },
    {
      id: 2,
      url:
        "//cdn.atrera.com/audio/Marcel_Pequel_-_02_-_Two.mp3",
      author: "Marcel Pequel",
      title: "Two",
      cover:
        "//cdn.atrera.com/images/cover_yz2mak.jpg"
    },
    {
      id: 3,
      url:
        "//cdn.atrera.com/audio/Marcel_Pequel_-_03_-_Three.mp3",
      author: "Marcel Pequel",
      title: "Three",
      cover:
        "//cdn.atrera.com/images/cover_yz2mak.jpg"
    }
  ];

  let currentId = 0;
  let isPlaying = false;
  let isLoop = true;
  let isShuffle = false;
  let currentAudio = "music1";
  let timer = null;
  let loopOne = false;

  const currentTimeIndicator = document.querySelector(".music-time__current");
  const leftTimeIndicator = document.querySelector(".music-time__last");
  const progressBar = document.getElementById("length");
  const playBtn = document.querySelector(".play");
  const cover = document.querySelector(".cover");
  const title = document.querySelector(".music-player__title");
  const author = document.querySelector(".music-player__author");

  const loopBtn = document.getElementById("loop");
  const shuffleBtn = document.getElementById("shuffle");
  const forwardBtn = document.getElementById("forward");
  const backwardBtn = document.getElementById("backward");
  const prevBtn = document.getElementById("prev");
  const nextBtn = document.getElementById("next");
  const progressDiv = document.getElementById("progress");

  function play(e) {
    if (!isPlaying) {
      // console.log('play');
      e.target.src =
        "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/pause.svg";
      e.target.alt = "Pause";
      isPlaying = true;
      document.getElementById(currentAudio).play();
      showTime();
    } else {
      // console.log('pause');
      e.target.src =
        "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
      e.target.alt = "Play";
      document.getElementById(currentAudio).pause();
      isPlaying = false;
      clearInterval(timer);
    }
  }

  function changeBar() {
    const audio = document.getElementById(currentAudio);
    const percentage = (audio.currentTime / audio.duration).toFixed(3);
    progressBar.style.transition = "";
    // console.log(audio.currentTime);

    //set current time
    const minute = Math.floor(audio.currentTime / 60);
    const second = Math.floor(audio.currentTime % 60);
    const leftTime = audio.duration - audio.currentTime;
    currentTimeIndicator.innerHTML =
      ("0" + minute).substr(-2) + ":" + ("0" + second).substr(-2);

    //set left time
    const leftMinute = Math.floor(leftTime / 60);
    const leftSecond = Math.floor(leftTime % 60);

    leftTimeIndicator.innerHTML =
      ("0" + leftMinute).substr(-2) + ":" + ("0" + leftSecond).substr(-2);

    //set time bar
    progressBar.style.width = percentage * 100 + "%";
  }

  function showTime() {
    timer = setInterval(() => changeBar(), 500);
  }

  function nextMusic(mode) {
    playBtn.src =
      "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
    playBtn.alt = "Play";
    document.getElementById(currentAudio).pause();
    isPlaying = false;
    clearInterval(timer);

    if (mode === "next") {
      currentId = currentId + 1 > list.length - 1 ? 0 : currentId + 1;
      init();
    } else {
      currentId = currentId - 1 < 0 ? list.length - 1 : currentId - 1;
      init();
    }
  }

  function shuffle(e) {
    isShuffle = !isShuffle;
    if (isShuffle) {
      e.target.parentNode.classList.add("is-loop");
    } else {
      e.target.parentNode.classList.remove("is-loop");
    }
  }

  function backward() {
    const audio = document.getElementById(currentAudio);
    audio.currentTime -= 5;
    if (!isPlaying) {
      changeBar();
    }
  }

  function forward() {
    const audio = document.getElementById(currentAudio);
    audio.currentTime += 5;
    if (!isPlaying) {
      changeBar();
    }
  }

  function stopMusic() {
    playBtn.src =
      "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/play.svg";
    playBtn.alt = "Play";
    isPlaying = false;
  }

  function goToNextMusic() {
    let newId = currentId;
    while (isShuffle && !loopOne && newId === currentId) {
      newId = Math.floor(Math.random() * Math.floor(list.length - 1));
    }

    if (!isShuffle && !loopOne) {
      currentId = currentId + 1 > list.length - 1 ? 0 : currentId + 1;
    }
    if (!isShuffle && loopOne) {
      currentId = currentId;
    }

    if (isShuffle) {
      currentId = newId;
    }
    init();
    document.getElementById(currentAudio).play();
  }

  function loop(e) {
    const audio = document.getElementById(currentAudio);

    if (!isLoop && !loopOne) {
      isLoop = true;
      loopOne = false;
      // console.log('is loop');
      e.target.parentNode.classList.add("is-loop");
      e.target.src =
        "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg";
      audio.loop = false;
      audio.onended = e => goToNextMusic();
      console.log(isLoop, loopOne);
    } else if (isLoop && !loopOne) {
      // console.log('is loop one');
      isLoop = true;
      loopOne = true;
      e.target.parentNode.classList.add("is-loop");
      e.target.src =
        "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loopone.svg";
      audio.loop = true;
      audio.onended = e => goToNextMusic();
      console.log(isLoop, loopOne);
    } else {
      // console.log('not loop');
      isLoop = false;
      loopOne = false;
      e.target.parentNode.classList.remove("is-loop");
      e.target.src =
        "https://snowleo208.github.io/100-Days-of-Code/7.%20Music%20Player/img/loop.svg";
      audio.loop = false;
      audio.onended = e => stopMusic();
      console.log(isLoop, loopOne);
    }
  }

  function progress(e) {
    const audio = document.getElementById(currentAudio);
    //get current position and minus progress bar's x position to get current position in progress bar
    const pos =
      (e.pageX - progressDiv.getClientRects()[0].x) /
      progressDiv.getClientRects()[0].width;
    audio.currentTime = pos * audio.duration;
    changeBar();
  }

  function init() {
    //reset music duration and setup audio
    const audio =
      document.getElementById(currentAudio) === null
        ? new Audio()
        : document.getElementById(currentAudio);
    audio.src = list[currentId].url;
    audio.id = currentAudio;
    document.getElementById(currentAudio) === null
      ? document.body.appendChild(audio)
      : "";

    progressBar.style.transition = "none";
    progressBar.style.width = "0%";
    document.getElementById(currentAudio).currentTime = 0;

    title.innerHTML = list[currentId].title;
    author.innerHTML = list[currentId].author;
    cover.src = list[currentId].cover;

    //set current time
    audio.addEventListener("loadedmetadata", function() {
      const leftMinute = Math.floor(audio.duration / 60);
      const leftSecond = Math.floor(audio.duration % 60);
      currentTimeIndicator.innerHTML = "00:00";
      leftTimeIndicator.innerHTML =
        ("0" + leftMinute).substr(-2) + ":" + ("0" + leftSecond).substr(-2);
      progressBar.style.transition = "";
    });

    //set loop
    document.getElementById(currentAudio).onended = e => goToNextMusic(e);
  }

  playBtn.addEventListener("click", play);
  loopBtn.addEventListener("click", loop);

  shuffleBtn.addEventListener("click", shuffle);
  forwardBtn.addEventListener("click", forward);
  backwardBtn.addEventListener("click", backward);

  prevBtn.addEventListener("click", e => nextMusic("prev"));
  nextBtn.addEventListener("click", e => nextMusic("next"));
  progressDiv.addEventListener("click", e => {
    progress(e);
  });

  init();
})();
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.