Seminar -II
Mini Project Report On
Music Album Page
Submitted to the
Dr. Babasaheb Ambedkar Technological University, Lonere.
For the Degree of
Bachelor of Technology in Computer Science & Engineering
By
Sr. No. PRN No. Name
1 24063211242510 Ankita Parshuram Indikar
Under the Guidance of
Prof. K. A. Mangalaram
Department of Computer Science and Engineering
V. V. P. Institute of Engineering and Technology, Solapur
A.Y. – 2024-25
V. V. P. Institute of Engineering and Technology, Solapur
Department of Computer Science and Engineering
Page 1
Certificate
This is to certify that the Mini-Project entitled “ Music Album Page ” has been submitted
by
Sr. No. PRN No. Name
1 24063211242505 Ankita Parshuram Indikar
of S. Y. (Computer) class in the partial fulfillment for the award of Degree of
Bachelor of Technology.
Course Coordinator H. O. D (Prof.
K. A. Mangalaram) (Prof. M. Katkar)
Dr. Arun Gaikwad
(PRINCIPAL)
External Examiner
Page 2
ACKNOLEDGEMENT
The compilation of dissertation report on “Music Album Page” is the
result of the endless help received from number of people. So, it gives me
immense pleasure to acknowledge and express my sincere gratitude to those
who helped us along my dissertation work.
We would like to express my deep sense of gratitude to our guide
Prof. K. A.Mangalaram for giving his valuable time, precious guidance which
helped us in completion of report successfully. We are very much thankful for
his moral support and kind cooperation, which he gave us from time to time.
We are also thankful to our Principal Dr. Arun Gaikwad and Head of
Department Prof. Manish Katkar for providing all the necessary facilities. Last
but not the least we would like to thank other faculty staff for their direct and
indirect contribution and support in completion of this report.
Miss. Indikar Ankita
Page 3
Contents
Sr. Page
Title
No. No.
1 Abstract 5
2 Introduction 6
3 Introduction to problem Statement 7
4 Aim of the problem 7
5 What is the purpose of this project? 8
6 Features of Music Album 8
7 Entity Realtionship Diagram 9
8 Project frontend 10
9 Code 11-34
10 Result 35
11 Conclusion 36
12 References 36
Page 4
Abstract
This abstract outlines a project focused on the creation of a music album
page, encompassing both its visual design and user experience. The project
aims to enhance the overall experience of browsing and interacting with music
albums online, going beyond simple album listing to provide a more immersive
and engaging platform.
The project will explore various design elements, including:
Visual aesthetics:Creating visually appealing album pages that reflect the artist's
style and the music's genre.
User interface:Developing an intuitive and user-friendly interface for
navigation, exploration, and interaction.
Multimedia integration:Incorporating high-quality visuals, audio, and
potentially video elements to enhance the album's presentation.
Page 5
Introduction
This project dives into the world of music albums, exploring their
history, format, and the role they play in shaping music culture. We'll examine
how albums have evolved, from the vinyl era to digital releases, and how they
continue to serve as platforms for artistic expression and community. This
project will analyze album packaging, track lists, and the overall concept behind
each album, showcasing the artistry and narrative behind each release. It will
also explore the impact of albums on music trends, artist branding, and fan
engagement.
This project will be a comprehensive exploration of music albums as a
medium, offering insights into their significance in the music industry. This
project will provide a platform for creative interpretation and showcase the
diversity of music album aesthetics and narratives. We will examine how
different genres utilize album formats to create unique listening experiences.
We'll delve into the evolution of album art and its role in capturing the
essence of an album's theme. This project aims to appreciate the album as a
complete art form, from the music to the visual presentation. We will explore
how albums have been influential in shaping musical trends and trends within
the music industry.
❖ Introduction to problem domain
Page 6
A music album page presents information about a particular album, including
tracklist, cover art, and potentially additional details like release date, producer,
and lyrics. It's a crucial part of a music website or app, allowing users to explore
and engage with specific albums. The domain problem with a music album page
involves managing and presenting information accurately, ensuring a seamless
user experience, and potentially addressing copyright and licensing issues.
❖ Aim of the problem
The primary aim of a music album page, whether a physical release or a
digital one, is to provide listeners with a cohesive and curated listening
experience. It goes beyond just a collection of songs; it's a carefully designed
artistic work intended to tell a story, explore a theme, or convey a specific
emotional or artistic vision.
Page 7
❖ What is the purpose of this project?
The purpose of an album goes beyond just gathering a bunch of songs
together. It's a way for an artist to tell a story or express a specific theme
or emotion through music. Think of an album like a journey, where each
song is a step along the way, showing a different part of the artist's world.
❖ Features of the Music Album Page
A music album page project involves creating a digital page that
showcases a specific album, its artwork, tracklist, and potentially other
related content like lyrics, behind-the-scenes photos, or artist
information. These pages can be used for online stores, streaming
services, or artist websites, allowing users to explore and engage with
the album.
Here's a breakdown of features and aspects of a music album page
project:
Core Features:
Album Artwork: The primary visual element, showcasing the album's
cover art.
Tracklist: A list of songs included on the album, often with track
durations or other relevant information.
Audio Playback/Links: Integration with streaming services or a direct
link to purchase or download the album.
Artist Information: Brief details about the artist(s) involved.
Release Date: Information about when the album was released.
Genre and Subgenre: Categorization of the album for easier browsing.
Page 8
❖ Entity Relationship Diagram
Page 9
Project Front-End
❖ System Testing and results analysis
The completion of a system will be achieved only after it has been
thoroughly tested. Though this gives a feel the project is completed, there
cannot be any project without going through this stage. Hence in this stage it is
decided whether the project can undergo the real time environment execution
without any break downs, therefore a package can be rejected even at this
stage.
Page 10
❖ Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Spotify-Inspired Album View</title>
<!-- Google Fonts: Poppins -->
<link href="https://fonts.googleapis.com/css2?
family=Poppins:wght@300;500;700&display=swap" rel="stylesheet" />
<!-- Google Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet" />
<style>
/* CSS Reset */
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
background-color: #121212;
color: #FFFFFF;
font-family: 'Poppins', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
a{
color: inherit;
text-decoration: none;
}
button {
font-family: inherit;
cursor: pointer;
border: none;
background: none;
color: inherit;
Page 11
}
/* Root Variables */
:root {
--spotify-green: #1db954;
--spotify-green-dark: #1aa34a;
--gray-900: #121212;
--gray-800: #181818;
--gray-700: #282828;
--gray-600: #3e3e3e;
--gray-500: #535353;
--gray-400: #b3b3b3;
--gray-300: #a0a0a0;
--gray-200: #cfcfcf;
--gray-100: #e1e1e1;
--accent-gradient: linear-gradient(135deg, #1db954, #1aa34a);
--transition-fast: 0.22s ease-in-out;
}
/* Layout containers */
.app-container {
display: grid;
grid-template-columns: 1fr;
min-height: 100vh;
max-width: 1440px;
margin: 0 auto;
padding: 0 24px 48px;
gap: 24px;
}
/* Responsive layout changes */
@media (min-width: 768px) {
/* tablet */
.app-container {
grid-template-columns: 280px 1fr;
padding: 32px 40px 56px;
}
}
@media (min-width: 1024px) {
/* desktop: three columns: sidebar, content, queue */
.app-container {
Page 12
grid-template-columns: 300px 1fr 300px;
padding: 48px 64px 64px;
gap: 32px;
}
}
/* Sidebar */
.sidebar {
background-color: var(--gray-900);
padding: 24px;
border-radius: 16px;
display: flex;
flex-direction: column;
gap: 20px;
position: sticky;
top: 48px;
height: fit-content;
}
.sidebar h2 {
font-weight: 700;
font-size: 1.3rem;
margin-bottom: 12px;
letter-spacing: 0.03em;
color: var(--spotify-green);
}
.sidebar nav a {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 12px;
font-weight: 500;
color: var(--gray-400);
transition: background var(--transition-fast), color var(--transition-fast);
user-select: none;
}
.sidebar nav a:hover,
.sidebar nav a.active {
background: var(--gray-700);
color: var(--spotify-green);
}
Page 13
.sidebar nav a .material-icons {
font-size: 20px;
color: inherit;
}
/* Main content area */
main {
display: flex;
flex-direction: column;
gap: 32px;
overflow-x: hidden;
}
/* Album Header */
.album-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
text-align: center;
padding: 16px;
background: var(--gray-900);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.6);
position: relative;
}
@media(min-width: 768px) {
.album-header {
flex-direction: row;
align-items: flex-end;
text-align: left;
gap: 36px;
padding: 32px;
}
}
.album-cover {
min-width: 220px;
min-height: 220px;
max-width: 220px;
max-height: 220px;
border-radius: 14px;
Page 14
overflow: hidden;
box-shadow:
0 0 15px var(--spotify-green),
inset 0 0 30px var(--spotify-green-dark);
flex-shrink: 0;
}
.album-cover img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
user-select: none;
}
.album-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.album-type {
text-transform: uppercase;
font-weight: 600;
font-size: 0.8rem;
letter-spacing: 0.15em;
color: var(--spotify-green);
margin-bottom: 6px;
}
.album-title {
font-size: 2.4rem;
font-weight: 700;
line-height: 1.1;
margin-bottom: 12px;
}
.album-artist {
font-size: 1.1rem;
color: var(--gray-400);
margin-bottom: 6px;
}
.album-meta {
font-size: 0.9rem;
color: var(--gray-600);
Page 15
}
/* Controls */
.album-controls {
margin-top: 24px;
display: flex;
gap: 16px;
justify-content: center;
}
@media(min-width: 768px) {
.album-controls {
justify-content: flex-start;
}
}
.btn-play {
background: var(--spotify-green);
padding: 18px 48px;
border-radius: 50px;
box-shadow: 0 5px 20px rgba(29, 185, 84, 0.6);
font-weight: 700;
font-size: 1.2rem;
color: #121212;
display: flex;
align-items: center;
gap: 14px;
user-select: none;
transition: background 0.3s ease;
border: none;
}
.btn-play:hover,
.btn-play:focus {
background: var(--spotify-green-dark);
outline: none;
box-shadow: 0 8px 30px rgba(29, 185, 84, 0.9);
}
.btn-icon {
font-size: 28px;
vertical-align: middle;
}
/* Tracks List */
Page 16
.tracks-list {
background-color: var(--gray-900);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
padding: 24px;
max-height: 520px;
overflow-y: auto;
scroll-behavior: smooth;
user-select: none;
}
.tracks-header {
display: grid;
grid-template-columns: 48px 1fr 80px 64px;
padding-bottom: 16px;
border-bottom: 1px solid var(--gray-700);
font-weight: 600;
font-size: 0.85rem;
color: var(--gray-400);
letter-spacing: 0.06em;
}
.track-row {
display: grid;
grid-template-columns: 48px 1fr 80px 64px;
align-items: center;
padding: 14px 0;
border-bottom: 1px solid var(--gray-800);
color: var(--gray-300);
font-weight: 500;
font-size: 1rem;
transition: background var(--transition-fast);
cursor: pointer;
}
.track-row:last-child {
border-bottom: none;
}
.track-row:hover,
.track-row.playing {
background-color: var(--gray-800);
color: white;
}
.track-row.playing {
Page 17
font-weight: 700;
box-shadow: inset 4px 0 0 var(--spotify-green);
}
.track-number,
.track-length {
text-align: center;
user-select: none;
}
.track-title {
user-select: text;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-right: 8px;
}
.track-artist {
color: var(--gray-500);
font-size: 0.9rem;
}
/* Player Controls Bar */
.player-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: var(--gray-900);
border-top: 1px solid var(--gray-700);
padding: 12px 32px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
z-index: 101;
}
@media(min-width: 768px) {
.player-bar {
padding: 16px 64px;
}
}
Page 18
.player-left,
.player-center,
.player-right {
display: flex;
align-items: center;
gap: 20px;
min-width: 0;
}
.player-left {
min-width: 180px;
gap: 12px;
}
.player-left img {
width: 48px;
height: 48px;
border-radius: 8px;
user-select: none;
object-fit: cover;
}
.player-track-info {
display: flex;
flex-direction: column;
overflow: hidden;
}
.player-track-title {
font-weight: 600;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: white;
user-select: text;
}
.player-track-artist {
font-weight: 400;
font-size: 0.85rem;
color: var(--gray-400);
}
/* Controls center */
.player-center button {
Page 19
color: var(--gray-400);
font-size: 28px;
transition: color 0.2s ease;
background: none;
border: none;
border-radius: 50%;
padding: 12px;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
.player-center button:hover,
.player-center button:focus {
color: var(--spotify-green);
outline: none;
background-color: var(--gray-700);
}
.player-center button.play-pause {
font-size: 36px;
color: var(--spotify-green);
background-color: white;
border-radius: 50%;
width: 56px;
height: 56px;
display: flex;
justify-content: center;
align-items: center;
transition: background-color 0.3s ease, color 0.3s ease;
}
.player-center button.play-pause:hover {
background-color: var(--spotify-green-dark);
color: white;
}
/* Progress bar */
.progress-container {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
Page 20
min-width: 150px;
}
.time {
font-size: 0.75rem;
color: var(--gray-400);
width: 40px;
user-select: none;
text-align: center;
}
.progress-bar {
flex: 1;
height: 4px;
border-radius: 2px;
background-color: var(--gray-700);
cursor: pointer;
position: relative;
}
.progress-filled {
height: 100%;
background: var(--spotify-green);
width: 0%;
border-radius: 2px 0 0 2px;
transition: width 0.3s linear;
}
/* Right player controls */
.player-right button {
font-size: 28px;
color: var(--gray-400);
transition: color 0.2s ease;
background: none;
border: none;
border-radius: 8px;
padding: 6px;
user-select: none;
}
.player-right button:hover,
.player-right button:focus {
color: var(--spotify-green);
outline: none;
background-color: var(--gray-700);
Page 21
}
/* Scrollbar styling */
.tracks-list::-webkit-scrollbar {
width: 8px;
}
.tracks-list::-webkit-scrollbar-track {
background: var(--gray-900);
}
.tracks-list::-webkit-scrollbar-thumb {
background: var(--spotify-green);
border-radius: 8px;
}
/* Accessibility focus */
a:focus,
button:focus,
.track-row:focus-visible {
outline: 2px solid var(--spotify-green);
outline-offset: 2px;
}
</style>
</head>
<body>
<div class="app-container" role="main">
<!-- Sidebar for navigation (simplified) -->
<aside class="sidebar" aria-label="Primary Navigation">
<h2>Spotify</h2>
<nav>
<a href="#" class="active" aria-current="page">
<span class="material-icons" aria-hidden="true">home</span> Home
</a>
<a href="#">
<span class="material-icons" aria-hidden="true">search</span> Search
</a>
<a href="#">
<span class="material-icons" aria-hidden="true">library_music</span>
Your Library
</a>
</nav>
</aside>
Page 22
<!-- Main content -->
<main>
<section class="album-header" aria-label="Album Information">
<div class="album-cover">
<img src="https://storage.googleapis.com/workspace-0f70711f-8b4e-
4d94-86f1-2a93ccde5887/image/19bbfa1b-76f8-4a60-a0cd-dfd6960c7ee9.png"
alt="Abstract green and black modern album cover art with geometric
patterns" />
</div>
<div class="album-info">
<div class="album-type" id="album-type">Album</div>
<h1 class="album-title" id="album-title">Discovery of Sound</h1>
<a href="#" class="album-artist" id="album-artist" tabindex="0">The
Echoes</a>
<div class="album-meta" id="album-meta">
Released 2024 · 12 Tracks · 45 min
</div>
<div class="album-controls">
<button class="btn-play" id="btnPlayAlbum" aria-label="Play Album">
<span class="material-icons btn-icon" aria-hidden="true"
id="playIcon">play_arrow</span> Play
</button>
<button class="btn-icon-btn" id="btnShuffle" aria-label="Shuffle">
<span class="material-icons">shuffle</span>
</button>
<button class="btn-icon-btn" id="btnRepeat" aria-label="Repeat">
<span class="material-icons">repeat</span>
</button>
</div>
</div>
</section>
<section class="tracks-list" aria-label="Tracks List" tabindex="0">
<div class="tracks-header" aria-hidden="true">
<div>#</div><div>Title</div><div>Length</div><div></div>
</div>
<div id="trackList" role="list" tabindex="-1"></div>
</section>
</main>
<!-- Player Controls Bar -->
Page 23
<footer class="player-bar" role="region" aria-label="Music Player Controls">
<div class="player-left">
<img src="https://storage.googleapis.com/workspace-0f70711f-8b4e-4d94-
86f1-2a93ccde5887/image/387e9d2e-c8e6-4359-b0a9-998ff259ffaa.png"
alt="Currently playing album cover" id="playerCover" />
<div class="player-track-info">
<div id="playerTitle" class="player-track-title" aria-live="polite" aria-
atomic="true">Not Playing</div>
<div id="playerArtist" class="player-track-artist"></div>
</div>
</div>
<div class="player-center">
<button id="btnShufflePlayer" aria-label="Toggle Shuffle">
<span class="material-icons">shuffle</span>
</button>
<button id="btnPrev" aria-label="Previous Track">
<span class="material-icons">skip_previous</span>
</button>
<button id="btnPlayPause" class="play-pause" aria-label="Play" aria-
pressed="false">
<span class="material-icons" id="playPauseIcon">play_arrow</span>
</button>
<button id="btnNext" aria-label="Next Track">
<span class="material-icons">skip_next</span>
</button>
<button id="btnRepeatPlayer" aria-label="Toggle Repeat">
<span class="material-icons">repeat</span>
</button>
</div>
<div class="progress-container" aria-label="Seek controls">
<div id="currentTime" class="time" aria-live="polite" aria-
atomic="true">0:00</div>
<div class="progress-bar" id="progressBar" role="slider" aria-
valuemin="0" aria-valuemax="100" aria-valuenow="0" tabindex="0">
<div class="progress-filled" id="progressFilled"></div>
</div>
<div id="totalTime" class="time">0:00</div>
</div>
<div class="player-right">
<button id="btnVolume" aria-label="Adjust Volume">
<span class="material-icons">volume_up</span>
Page 24
</button>
</div>
</footer>
</div>
<script>
// Sample album tracks data
const albumData = {
cover: 'https://storage.googleapis.com/workspace-0f70711f-8b4e-4d94-86f1-
2a93ccde5887/image/c371bab0-b4ef-4a88-9bf4-cff46edfd34a.png',
title: 'Discovery of Sound',
artist: 'The Echoes',
released: 2024,
tracks: [
{ title: "Awakening", length: "3:12" },
{ title: "Midnight Wanderer", length: "4:05" },
{ title: "Electric Dreams", length: "5:08" },
{ title: "Echoes in Time", length: "3:56" },
{ title: "Lost in the Light", length: "4:22" },
{ title: "Neon Horizon", length: "3:40" },
{ title: "Infinite Loop", length: "4:01" },
{ title: "Pulse of the City", length: "3:30" },
{ title: "Silent Signals", length: "4:13" },
{ title: "Midnight Mirage", length: "3:55" },
{ title: "Gravity Falls", length: "4:18" },
{ title: "Final Silence", length: "5:06" },
],
};
// Elements references
const trackListEl = document.getElementById('trackList');
const playPauseBtn = document.getElementById('btnPlayPause');
const playPauseIcon = document.getElementById('playPauseIcon');
const btnPlayAlbum = document.getElementById('btnPlayAlbum');
const playerTitle = document.getElementById('playerTitle');
const playerArtist = document.getElementById('playerArtist');
const playerCover = document.getElementById('playerCover');
const progressBar = document.getElementById('progressBar');
const progressFilled = document.getElementById('progressFilled');
const currentTimeEl = document.getElementById('currentTime');
const totalTimeEl = document.getElementById('totalTime');
Page 25
const btnNext = document.getElementById('btnNext');
const btnPrev = document.getElementById('btnPrev');
const btnShuffle = document.getElementById('btnShuffle');
const btnShufflePlayer = document.getElementById('btnShufflePlayer');
const btnRepeat = document.getElementById('btnRepeat');
const btnRepeatPlayer = document.getElementById('btnRepeatPlayer');
// Playback state
let currentTrackIndex = null;
let isPlaying = false;
let isShuffle = false;
let isRepeat = false;
let trackProgress = 0;
let trackDuration = 240; // placeholder 4 minutes default
let progressInterval = null;
// Render track list
function renderTrackList() {
trackListEl.innerHTML = '';
albumData.tracks.forEach((track, index) => {
const trackEl = document.createElement('div');
trackEl.setAttribute('role', 'listitem');
trackEl.classList.add('track-row');
trackEl.tabIndex = 0;
trackEl.innerHTML = `
<div class="track-number">${index + 1}</div>
<div class="track-title" title="${track.title}">${track.title}</div>
<div class="track-length" aria-label="Track
length">${track.length}</div>
<button class="btn-track-play" aria-label="Play ${track.title}" data-
index="${index}">
<span class="material-icons">play_arrow</span>
</button>
`;
// Highlight playing track
if (currentTrackIndex === index && isPlaying) {
trackEl.classList.add('playing');
trackEl.querySelector('.btn-track-play span').textContent = 'pause';
trackEl.setAttribute('aria-current', 'true');
Page 26
}
trackListEl.appendChild(trackEl);
});
}
// Format seconds to m:ss
function formatTime(seconds) {
const m = Math.floor(seconds / 60);
const s = Math.floor(seconds % 60);
return `${m}:${s < 10 ? '0' + s : s}`;
}
// Update player UI
function updatePlayerUI() {
if (currentTrackIndex !== null) {
const track = albumData.tracks[currentTrackIndex];
playerTitle.textContent = track.title;
playerArtist.textContent = albumData.artist;
playerCover.src = albumData.cover;
totalTimeEl.textContent = track.length;
} else {
playerTitle.textContent = 'Not Playing';
playerArtist.textContent = '';
playerCover.src = 'https://storage.googleapis.com/workspace-0f70711f-
8b4e-4d94-86f1-2a93ccde5887/image/8f8118c2-e1e6-44cf-999a-
83b0e06fe64b.png';
totalTimeEl.textContent = '0:00';
}
playPauseIcon.textContent = isPlaying ? 'pause' : 'play_arrow';
playPauseBtn.setAttribute('aria-label', isPlaying ? 'Pause' : 'Play');
playPauseBtn.setAttribute('aria-pressed', isPlaying.toString());
btnPlayAlbum.querySelector('#playIcon').textContent = isPlaying ? 'pause' :
'play_arrow';
if (isShuffle) {
btnShuffle.classList.add('active');
btnShufflePlayer.classList.add('active');
} else {
btnShuffle.classList.remove('active');
btnShufflePlayer.classList.remove('active');
Page 27
}
if (isRepeat) {
btnRepeat.classList.add('active');
btnRepeatPlayer.classList.add('active');
} else {
btnRepeat.classList.remove('active');
btnRepeatPlayer.classList.remove('active');
}
// update track list highlight
renderTrackList();
}
// Play a track by index
function playTrack(index) {
if (index < 0 || index >= albumData.tracks.length) return;
currentTrackIndex = index;
isPlaying = true;
trackProgress = 0;
trackDuration = trackLengthToSeconds(albumData.tracks[index].length);
updatePlayerUI();
startProgress();
}
// Convert track length string "m:ss" to seconds
function trackLengthToSeconds(str) {
const parts = str.split(':');
if(parts.length !== 2) return 240; // default
const m = Number(parts[0]);
const s = Number(parts[1]);
return m * 60 + s;
}
// Toggle play/pause
function togglePlayPause() {
if (currentTrackIndex === null) {
playTrack(0);
} else {
isPlaying = !isPlaying;
if (isPlaying) {
startProgress();
Page 28
} else {
stopProgress();
}
updatePlayerUI();
}
}
// Progress bar animation simulation
function startProgress() {
stopProgress();
progressInterval = setInterval(() => {
if (!isPlaying) return;
trackProgress++;
if (trackProgress >= trackDuration) {
if (isRepeat) {
playTrack(currentTrackIndex);
} else {
playNext();
}
return;
}
updateProgressUI();
}, 1000);
}
function stopProgress() {
if (progressInterval) clearInterval(progressInterval);
progressInterval = null;
}
// Update progress bar UI
function updateProgressUI() {
const percent = (trackProgress / trackDuration) * 100;
progressFilled.style.width = percent + '%';
currentTimeEl.textContent = formatTime(trackProgress);
progressBar.setAttribute('aria-valuenow', percent.toFixed(0));
}
// Play next track
function playNext() {
if (isShuffle) {
let nextIndex = Math.floor(Math.random() * albumData.tracks.length);
Page 29
if(albumData.tracks.length>1){
while(nextIndex === currentTrackIndex){
nextIndex = Math.floor(Math.random() * albumData.tracks.length);
}
}
playTrack(nextIndex);
} else {
let nextIndex = currentTrackIndex + 1;
if (nextIndex >= albumData.tracks.length) {
if (isRepeat) {
nextIndex = 0;
} else {
stopPlayback();
return;
}
}
playTrack(nextIndex);
}
}
// Play previous track
function playPrev() {
let prevIndex = currentTrackIndex - 1;
if (prevIndex < 0) {
if (isRepeat) {
prevIndex = albumData.tracks.length - 1;
} else {
prevIndex = 0;
}
}
playTrack(prevIndex);
}
// Stop playback
function stopPlayback() {
isPlaying = false;
currentTrackIndex = null;
stopProgress();
updatePlayerUI();
progressFilled.style.width = '0%';
currentTimeEl.textContent = '0:00';
}
Page 30
// Event Listeners
playPauseBtn.addEventListener('click', togglePlayPause);
btnPlayAlbum.addEventListener('click', () => {
if (currentTrackIndex === null) {
playTrack(0);
} else {
togglePlayPause();
}
});
btnNext.addEventListener('click', () => {
if (currentTrackIndex === null) {
playTrack(0);
} else {
playNext();
}
});
btnPrev.addEventListener('click', () => {
if (currentTrackIndex === null) {
playTrack(0);
} else {
playPrev();
}
});
btnShuffle.addEventListener('click', () => {
isShuffle = !isShuffle;
updatePlayerUI();
});
btnShufflePlayer.addEventListener('click', () => {
isShuffle = !isShuffle;
updatePlayerUI();
});
btnRepeat.addEventListener('click', () => {
isRepeat = !isRepeat;
updatePlayerUI();
});
btnRepeatPlayer.addEventListener('click', () => {
isRepeat = !isRepeat;
updatePlayerUI();
});
Page 31
// Play track from track list
trackListEl.addEventListener('click', e => {
const target = e.target.closest('button.btn-track-play');
if (!target) return;
const index = parseInt(target.dataset.index, 10);
if (index === currentTrackIndex) {
togglePlayPause();
} else {
playTrack(index);
}
});
// Keyboard support for track rows
trackListEl.addEventListener('keydown', e => {
if ((e.key === 'Enter' || e.key === ' ') && e.target.classList.contains('track-
row')) {
e.preventDefault();
const index = Array.from(trackListEl.children).indexOf(e.target);
if(index === currentTrackIndex){
togglePlayPause();
} else {
playTrack(index);
}
}
});
// Click to seek progress bar
progressBar.addEventListener('click', e => {
const rect = progressBar.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const percentage = clickX / rect.width;
if(currentTrackIndex === null) return;
trackProgress = Math.floor(percentage * trackDuration);
updateProgressUI();
});
// Keyboard control for progress bar
progressBar.addEventListener('keydown', e => {
if(currentTrackIndex === null) return;
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
e.preventDefault();
Page 32
trackProgress = Math.min(trackProgress + 5, trackDuration);
updateProgressUI();
}
if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
e.preventDefault();
trackProgress = Math.max(trackProgress - 5, 0);
updateProgressUI();
}
});
// Initialization
document.getElementById('album-title').textContent = albumData.title;
document.getElementById('album-artist').textContent = albumData.artist;
document.getElementById('album-meta').textContent = `Released $
{albumData.released} · ${albumData.tracks.length} Tracks · $
{albumData.tracks.reduce((acc, t) => acc +
trackLengthToSeconds(t.length),0)/60 | 0} min`;
document.querySelector('.album-cover img').src = albumData.cover;
playerCover.src = albumData.cover;
renderTrackList();
</script>
</body>
</html>
Page 33
❖ Results
Page 34
Conclusion
In music, "conclusion" can refer to the ending of a song or album, often
signaling the close of a composition. It can also be used to describe the final
track on an album. Additionally, "conclusion" might refer to an outro-solo, an
instrumental section played as the song fades out. The term is commonly used
in popular music and can be used for both the concluding track on an album
and the instrumental section at the end of a song.
References
1. https://www.Google.com/
2. https:// Deepseek.com/
3. https://www.tutorialspoint.com/
4. https://www.geeksforgeeks.com/
Page 35