본문 바로가기

프론트엔드/자바스크립트

프로젝트 - 뮤직 플레이어

반응형

뮤직 플레이어 애플리케이션입니다.

 

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Music</title>

  <script src="https://kit.fontawesome.com/833be080c6.js" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="./main.css">
  <script defer src="./index.js"></script>
</head>

<body>
  <!-- Container -->
  <div class="player-container">
    
    <!-- Player -->
    <div class="img-container">
      <img id="image" src="https://lastfm.freetls.fastly.net/i/u/500x500/30ef0d3d35720910529fe026a2d2fe7c.jpg" alt="">
      <h2 id="title">Takyon (Death Yon)</h2>
      <h3 id="artist">Death Grips</h3>
      <div class="control">
        <i class="fas fa-arrow-left" id="left"></i>
        <i class="fas fa-pause" id="pause"></i>
        <i class="fas fa-play" id="play"></i>
        <i class="fas fa-stop" id="stop"></i>
        <i class="fas fa-arrow-right" id="right"></i>
      </div>
      <div class="gauge-box">
        <div class="time-box">
          <small class="current" id="current">00:00</small>
          <small class="duration" id="duration">00:00</small>
        </div>
        <input class="progress" type="range" value="0">
      </div>
    </div>
    
    <!-- Audio object -->
    <audio id="audio" src="./assets/music/Death Grips - Takyon (Death Yon).mp3"></audio>    
  </div>
</body>

</html>

 

main.css

@import url('https://fonts.googleapis.com/css2?family=Spartan:wght@400;700&display=swap');

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  background: #c9cde3;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-family: 'Spartan';
}

/* image styles */
.img-container {
  height: 400px;  
  width: 280px;
  background-color: #383636;
  position: relative; 
  border-radius: 5px; 
  box-shadow: 0 0 5px 1px rgba(0, 0, 0, .3);
  color: #c9cde3;
}

.img-container h2 {
  width: 100%;
  text-align: center;
  position: absolute;
  bottom:80px;  
}

.img-container h3 {
  width: 100%;
  text-align: center;
  position: absolute;
  bottom: 60px;
}

/* control styles */
.control {
  width: 100%;
  position: absolute;
  bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.control i {
  margin: 0 15px;
  cursor: pointer;
  transition: .4s ease-in-out;  
}

.control i:hover {
  color: #f1851a;
}

.control i:active {
  transform: scale(.85);
}

img {
  height: 250px;
  width: 250px;
  position: absolute;
  left: 50%;
  top: 15px;
  transform: translate(-50%, 0%);
  object-fit: cover;
  box-shadow: 0 0 5px 1px rgba(255, 255, 255, .3);
}

/* player guage styles */
.gauge-box {
  width: 100%;
  padding: 0 15px;
  position: absolute;  
  bottom: 45px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
}

.time-box {
  width: 100%;
  padding: 0 5px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.progress {
  height: 4px;
  width: 100%;
  -webkit-appearance: none;
  margin: 5px;
}

.progress::-webkit-slider-thumb {
  box-shadow: 0px 0px 0px #000000;
  border: 0px solid #000000;
  height: 12px;
  width: 12px;
  border-radius: 50%;
  background: #f1851a;
  cursor: pointer;
  -webkit-appearance: none;  
}

.gauge-box small {
 color: #c9cde3; 
}

 

index.js

const title = document.getElementById('title')
const artist = document.getElementById('artist')
const image = document.getElementById('image')
const audio = document.getElementById('audio')
const left = document.getElementById('left')
const play = document.getElementById('play')
const pause = document.getElementById('pause')
const stop = document.getElementById('stop')
const right = document.getElementById('right')
const current = document.querySelector('.current')
const duration = document.querySelector('.duration')
const progress = document.querySelector('.progress')

const photos = [
  'https://lastfm.freetls.fastly.net/i/u/500x500/30ef0d3d35720910529fe026a2d2fe7c.jpg',
  'https://lastfm.freetls.fastly.net/i/u/500x500/831e96df3afd4777c7ac562537bdb356.jpg',
  'https://lastfm.freetls.fastly.net/i/u/500x500/bb528670782ee23cfebc8232070f86a5.jpg',
  'https://lastfm.freetls.fastly.net/i/u/500x500/008082c0cae3371b6ed6a85ea3bb15fb.jpg',
]

const audios = [
  './assets/music/Death Grips - Takyon (Death Yon).mp3',
  './assets/music/Death Grips - Get Got.mp3',
  './assets/music/Death Grips - No Love.mp3',
  "./assets/music/Sleepmakeswaves - It's Dark, It's Cold, It's Winter.mp3",
]

let idx = 0

left.addEventListener('click', () => {
  idx++
  if (idx > photos.length - 1) idx = 0
  changeImage()
  changeTitleAndArtist()
  changeMusic()
})

right.addEventListener('click', () => {
  idx--
  if (idx < 0) idx = photos.length - 1
  changeImage()
  changeTitleAndArtist()
  changeMusic()
})

function changeImage() {
  image.src = photos[idx]
}

function changeMusic() {
  audio.src = audios[idx]
  setTimeout(() => {
    getTrackTime()
  }, 200)
}

function changeTitleAndArtist() {
  const song = audios[idx].replace('.mp3', '').replace('./assets/music/', '')
  title.innerText = song.split(' - ')[1]
  artist.innerText = song.split(' - ')[0]
}

play.addEventListener('click', () => {
  audio.play()
})

pause.addEventListener('click', () => {
  audio.pause()
})

stop.addEventListener('click', () => {
  audio.pause()
  audio.currentTime = 0
  current.textContent = '00:00'
  progress.value = 0
})

audio.addEventListener('ended', () => {
  right.click()
  audio.play()
})

audio.addEventListener('loadeddata', () => {
  setTimeout(() => {
    getTrackTime()
  }, 200)
})

audio.addEventListener('timeupdate', (e) => {
  if (!audio.paused) {
    const { duration, currentTime } = e.srcElement

    let min = Math.round(currentTime / 60)
    let sec = Math.round(currentTime % 60)

    current.textContent = `${min.toString().length < 2 ? '0' + min : min}: ${
      sec.toString().length < 2 ? '0' + sec : sec
    }`

    progress.value = (currentTime / duration) * 100
  }
})

function getTrackTime() {
  const total = audio.duration
  const min = Math.floor(total / 60).toString()
  const sec = Math.floor(total % 60).toString()
  duration.textContent = `${min.length < 2 ? '0' + min : min}: ${
    sec.length < 2 ? '0' + sec : sec
  }`
}

getTrackTime()

progress.addEventListener('change', (e) => {
  audio.currentTime = (+e.target.value / 100) * audio.duration
})

 

데모

 

Music

 

jin-co-jcg.vercel.app

 

728x90
반응형