-
-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: refactor music player project (#669)
* reduce functionalities and fix bugs * move playlist to html
- Loading branch information
Showing
3 changed files
with
732 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap" rel="stylesheet" /> | ||
<link href="https://fonts.googleapis.com/css2?family=Lato&family=Roboto+Mono&display=swap" rel="stylesheet" /> | ||
<link rel="stylesheet" href="styles.css" /> | ||
<title> | ||
Build a Music Player App | ||
</title> | ||
</head> | ||
|
||
<body> | ||
<div class="container"> | ||
<div class="player"> | ||
<div class="player-bar"> | ||
<div class="parallel-lines"> | ||
<div></div> | ||
<div></div> | ||
</div> | ||
<h1 class="fcc-title">freeCodeCamp</h1> | ||
<div class="parallel-lines"> | ||
<div></div> | ||
<div></div> | ||
</div> | ||
</div> | ||
<div class="player-content"> | ||
<div id="player-album-art"> | ||
<img src="https://cdn.freecodecamp.org/curriculum/js-music-player/quincy-larson-album-art.jpg" | ||
alt="song cover art" /> | ||
</div> | ||
<div class="player-display"> | ||
<div class="player-display-song-artist"> | ||
<p id="player-song-title"></p> | ||
<p id="player-song-artist"></p> | ||
</div> | ||
<div class="player-buttons"> | ||
<button id="previous" class="previous" aria-label="Previous"> | ||
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M23.2248 0L7.03964 9.5L23.2248 19L23.2248 0Z" /> | ||
<rect width="4.63633" height="18.5453" transform="matrix(-1 0 0 1 4.63633 0)" /> | ||
</svg> | ||
</button> | ||
<button id="play" class="play" aria-label="Play"> | ||
<svg width="17" height="19" viewBox="0 0 17 19" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M0 0L16.1852 9.5L1.88952e-07 19L0 0Z" /> | ||
</svg> | ||
</button> | ||
<button id="pause" class="pause" aria-label="Pause"> | ||
<svg width="17" height="19" viewBox="0 0 17 19" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M0 6.54013e-07H4.75V19H0V6.54013e-07Z" /> | ||
<path d="M11.4 0H16.15V19H11.4V0Z" /> | ||
</svg> | ||
</button> | ||
<button id="next" class="next" aria-label="Next"> | ||
<svg width="24" height="19" viewBox="0 0 24 19" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M0 0L16.1852 9.5L1.88952e-07 19L0 0Z" /> | ||
<rect x="18.5885" width="4.63633" height="18.5453" /> | ||
</svg> | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="playlist"> | ||
<div class="playlist-bar"> | ||
<div class="parallel-lines"> | ||
<div></div> | ||
<div></div> | ||
</div> | ||
<h2 class="playlist-title" id="playlist">Playlist</h2> | ||
<div class="parallel-lines"> | ||
<div></div> | ||
<div></div> | ||
</div> | ||
</div> | ||
<ul id="playlist-songs"> | ||
<li id="song-0" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(0)"> | ||
<span class="playlist-song-title">Scratching The Surface</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">4:25</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-1" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(1)"> | ||
<span class="playlist-song-title">Can't Stay Down</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">4:15</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-2" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(2)"> | ||
<span class="playlist-song-title">Still Learning</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:51</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-3" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(3)"> | ||
<span class="playlist-song-title">Cruising for a Musing</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:34</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-4" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(4)"> | ||
<span class="playlist-song-title">Never Not Favored</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:35</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-5" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(5)"> | ||
<span class="playlist-song-title">From the Ground Up</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:12</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-6" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(6)"> | ||
<span class="playlist-song-title">Walking on Air</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:25</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-7" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(7)"> | ||
<span class="playlist-song-title">Can't Stop Me. Can't Even Slow Me Down.</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:52</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-8" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(8)"> | ||
<span class="playlist-song-title">The Surest Way Out is Through</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">3:10</span> | ||
</button> | ||
</li> | ||
|
||
<li id="song-9" class="playlist-song"> | ||
<button class="playlist-song-info" onclick="playSong(9)"> | ||
<span class="playlist-song-title">Chasing That Feeling</span> | ||
<span class="playlist-song-artist">Quincy Larson</span> | ||
<span class="playlist-song-duration">2:43</span> | ||
</button> | ||
</li> | ||
</ul> | ||
</div> | ||
</div> | ||
<script src="script.js"></script> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
const playlistSongs = document.getElementById("playlist-songs"); | ||
const playButton = document.getElementById("play"); | ||
const pauseButton = document.getElementById("pause"); | ||
const nextButton = document.getElementById("next"); | ||
const previousButton = document.getElementById("previous"); | ||
|
||
const allSongs = [ | ||
{ | ||
id: 0, | ||
title: "Scratching The Surface", | ||
artist: "Quincy Larson", | ||
duration: "4:25", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/scratching-the-surface.mp3", | ||
}, | ||
{ | ||
id: 1, | ||
title: "Can't Stay Down", | ||
artist: "Quincy Larson", | ||
duration: "4:15", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/can't-stay-down.mp3", | ||
}, | ||
{ | ||
id: 2, | ||
title: "Still Learning", | ||
artist: "Quincy Larson", | ||
duration: "3:51", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/still-learning.mp3", | ||
}, | ||
{ | ||
id: 3, | ||
title: "Cruising for a Musing", | ||
artist: "Quincy Larson", | ||
duration: "3:34", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/cruising-for-a-musing.mp3", | ||
}, | ||
{ | ||
id: 4, | ||
title: "Never Not Favored", | ||
artist: "Quincy Larson", | ||
duration: "3:35", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/never-not-favored.mp3", | ||
}, | ||
{ | ||
id: 5, | ||
title: "From the Ground Up", | ||
artist: "Quincy Larson", | ||
duration: "3:12", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/from-the-ground-up.mp3", | ||
}, | ||
{ | ||
id: 6, | ||
title: "Walking on Air", | ||
artist: "Quincy Larson", | ||
duration: "3:25", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/walking-on-air.mp3", | ||
}, | ||
{ | ||
id: 7, | ||
title: "Can't Stop Me. Can't Even Slow Me Down.", | ||
artist: "Quincy Larson", | ||
duration: "3:52", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/cant-stop-me-cant-even-slow-me-down.mp3", | ||
}, | ||
{ | ||
id: 8, | ||
title: "The Surest Way Out is Through", | ||
artist: "Quincy Larson", | ||
duration: "3:10", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/the-surest-way-out-is-through.mp3", | ||
}, | ||
{ | ||
id: 9, | ||
title: "Chasing That Feeling", | ||
artist: "Quincy Larson", | ||
duration: "2:43", | ||
src: "https://cdn.freecodecamp.org/curriculum/js-music-player/chasing-that-feeling.mp3", | ||
} | ||
]; | ||
|
||
const audio = new Audio(); | ||
let userData = { | ||
songs: allSongs, | ||
currentSong: null, | ||
songCurrentTime: 0, | ||
}; | ||
|
||
const playSong = (id, start = true) => { | ||
const song = userData.songs.find((song) => song.id === id); | ||
audio.src = song.src; | ||
audio.title = song.title; | ||
|
||
if ( | ||
userData.currentSong === null || | ||
playButton.classList.contains("playing") || | ||
start | ||
) { | ||
audio.currentTime = 0; | ||
} else { | ||
audio.currentTime = userData.songCurrentTime; | ||
} | ||
userData.currentSong = song; | ||
playButton.classList.add("playing"); | ||
|
||
highlightCurrentSong(); | ||
setPlayerDisplay(); | ||
setPlayButtonAccessibleText(); | ||
audio.play(); | ||
}; | ||
|
||
const pauseSong = () => { | ||
userData.songCurrentTime = audio.currentTime; | ||
playButton.classList.remove("playing"); | ||
audio.pause(); | ||
}; | ||
|
||
const getCurrentSongIndex = () => userData.songs.indexOf(userData.currentSong); | ||
|
||
const getNextSong = () => userData.songs[getCurrentSongIndex() + 1]; | ||
|
||
const getPreviousSong = () => userData.songs[getCurrentSongIndex() - 1]; | ||
|
||
const playNextSong = () => { | ||
if (userData.currentSong === null) { | ||
playSong(userData.songs[0].id); | ||
return | ||
} | ||
const nextSong = getNextSong(); | ||
if (nextSong) { | ||
playSong(nextSong.id); | ||
} else { | ||
userData.currentSong = null; | ||
userData.songCurrentTime = 0; | ||
pauseSong(); | ||
setPlayerDisplay(); | ||
highlightCurrentSong(); | ||
setPlayButtonAccessibleText(); | ||
} | ||
}; | ||
|
||
const playPreviousSong = () => { | ||
if (userData.currentSong === null) return; | ||
const previousSong = getPreviousSong(); | ||
if (previousSong) { | ||
playSong(previousSong.id); | ||
} else { | ||
playSong(userData.songs[0].id); | ||
} | ||
}; | ||
|
||
const setPlayerDisplay = () => { | ||
const playingSong = document.getElementById("player-song-title"); | ||
const songArtist = document.getElementById("player-song-artist"); | ||
const currentTitle = userData.currentSong?.title; | ||
const currentArtist = userData.currentSong?.artist; | ||
|
||
playingSong.textContent = currentTitle ? currentTitle : ""; | ||
songArtist.textContent = currentArtist ? currentArtist : ""; | ||
}; | ||
|
||
const highlightCurrentSong = () => { | ||
const playlistSongElements = document.querySelectorAll(".playlist-song"); | ||
const songToHighlight = document.getElementById( | ||
`song-${userData.currentSong?.id}` | ||
); | ||
|
||
playlistSongElements.forEach((songEl) => { | ||
songEl.removeAttribute("aria-current"); | ||
}); | ||
|
||
if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); | ||
}; | ||
|
||
const setPlayButtonAccessibleText = () => { | ||
const song = userData.currentSong || userData.songs[0]; | ||
|
||
playButton.setAttribute( | ||
"aria-label", | ||
song.title ? `Play ${song.title}` : "Play" | ||
); | ||
}; | ||
|
||
playButton.addEventListener("click", () => { | ||
if (userData.currentSong === null) { | ||
playSong(userData.songs[0].id); | ||
} else { | ||
playSong(userData.currentSong.id, false); | ||
} | ||
}); | ||
|
||
pauseButton.addEventListener("click", pauseSong); | ||
|
||
nextButton.addEventListener("click", playNextSong); | ||
|
||
previousButton.addEventListener("click", playPreviousSong); | ||
|
||
audio.addEventListener("ended", playNextSong); | ||
|
||
setPlayButtonAccessibleText(); |
Oops, something went wrong.