Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: refactor music player project #669

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions frontend-cert/js-projects/music-player-lab/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!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"></ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
217 changes: 217 additions & 0 deletions frontend-cert/js-projects/music-player-lab/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
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 renderSongs = (array) => {
const songsHTML = array
.map((song) => {
return `
<li id="song-${song.id}" class="playlist-song">
<button class="playlist-song-info" onclick="playSong(${song.id})">
<span class="playlist-song-title">${song.title}</span>
<span class="playlist-song-artist">${song.artist}</span>
<span class="playlist-song-duration">${song.duration}</span>
</button>
</li>
`;
})
.join("");

playlistSongs.innerHTML = songsHTML;
};
jdwilkin4 marked this conversation as resolved.
Show resolved Hide resolved

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);

renderSongs(userData.songs);
setPlayButtonAccessibleText();
Loading