Skip to content
Open

Solved #2522

Show file tree
Hide file tree
Changes from all commits
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
71 changes: 63 additions & 8 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,73 @@
require('dotenv').config();
require("dotenv").config();

const express = require('express');
const hbs = require('hbs');
const express = require("express");
const hbs = require("hbs");

// require spotify-web-api-node package here:

const SpotifyWebApi = require("spotify-web-api-node");
const app = express();

app.set('view engine', 'hbs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
app.set("view engine", "hbs");
app.set("views", __dirname + "/views");
app.use(express.static(__dirname + "/public"));

// setting the spotify-api goes here:
const spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});

// Retrieve an access token
spotifyApi
.clientCredentialsGrant()
.then((data) => spotifyApi.setAccessToken(data.body["access_token"]))
.catch((error) => console.log("Something went wrong when retrieving an access token", error));

// Our routes go here:
app.get("/", (req, res) => {
res.render("home");
});

app.get("/artist-search", (req, res) => {
spotifyApi
.searchArtists(req.query.artist)
.then((data) => {
const artists = data.body.artists.items;
res.status(200).render("artist-search-results", { artists });
})
.catch((err) => console.log("The error while searching artists occurred: ", err));
});

app.get("/albums/:artistId", (req, res, next) => {
spotifyApi.getArtistAlbums(req.params.artistId).then((data) => {
console.log("Artist albums", data.body.items);
const albums = data.body.items;
res.render("albums", { albums });
});
});

app.get("/tracks/:albumId", (req, res, next) => {
spotifyApi
.getAlbumTracks(req.params.albumId)
.then((data) => {
const tracks = data.body.items;
// Get album info to display album name and image
spotifyApi
.getAlbum(req.params.albumId)
.then((albumData) => {
const albumInfo = albumData.body;
res.render("tracks", { tracks, album: albumInfo });
})
.catch((error) => {
console.error("Error getting album info:", error);
next(error);
});
})
.catch((error) => {
console.error("Error getting album tracks:", error);
next(error);
});
});

app.listen(3000, () => console.log('My Spotify project running on port 3000 🎧 🥁 🎸 🔊'));
// Start listening the server
app.listen(3000, () => console.log("My Spotify project running on port 3000 🎧 🥁 🎸 🔊"));
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,11 @@
"license": "ISC",
"devDependencies": {
"nodemon": "^2.0.2"
},
"dependencies": {
"dotenv": "^16.4.7",
"express": "^4.21.2",
"hbs": "^4.2.0",
"spotify-web-api-node": "^5.0.2"
}
}
33 changes: 33 additions & 0 deletions views/albums.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="container mt-4">
<h1 class="text-center mb-4">Albums for: {{albums.[0].artists.[0].name}}</h1>

<div class="row row-cols-1 row-cols-md-3 g-4">
{{#each albums}}
<div class="col">
<div class="card h-100 bg-dark text-white">
{{#if images.[0].url}}
<img src="{{images.[0].url}}" class="card-img-top" alt="{{name}}" style="height: 300px; object-fit: cover;">
{{/if}}
<div class="card-body text-center">
<h5 class="card-title">{{name}}</h5>
<div class="mt-3">
<a href="/tracks/{{id}}" class="btn btn-danger">
View Tracks
</a>
</div>
</div>
</div>
</div>
{{/each}}
</div>
</div>

<style>
.card {
transition: transform 0.2s;
border: none;
}
.card:hover {
transform: translateY(-5px);
}
</style>
18 changes: 18 additions & 0 deletions views/artist-search-results.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<div class="container">
<h1>Artist Search Results</h1>
<div class="row">
{{#each artists}}
<div class="col-md-4 mb-4">
<div class="card bg-secondary text-white">
<img src="{{this.images.[0].url}}" class="card-img-top" alt="{{this.name}}" style="height: 200px; object-fit: cover;">
<div class="card-body">
<h5 class="card-title text-center">{{this.name}}</h5>
<div class='button-container d-flex justify-content-center'>
<a href="/albums/{{this.id}}" class="btn btn-danger">View Albums</a>
</div>
</div>
</div>
</div>
{{/each}}
</div>
</div>
22 changes: 22 additions & 0 deletions views/home.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<style>
body {
background: url('/images/spotify-background.jpeg') no-repeat center center fixed;
background-size: cover;
}
.search-container {
max-width: 500px;
width: 100%;
opacity: 0.9;
}
</style>

<div class="container d-flex justify-content-center align-items-center vh-100">
<div class="bg-light p-5 rounded shadow search-container">
<form action="/artist-search" method="GET">
<div class="mb-3">
<input type="text" class="form-control" placeholder="Search for an artist" name="artist" required />
</div>
<button type="submit" class="btn btn-danger w-100">Search</button>
</form>
</div>
</div>
36 changes: 36 additions & 0 deletions views/layout.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Artist Search Results</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<nav class="navbar navbar-expand-sm navbar-dark bg-dark mb-4">
<div class="container">
<a class="navbar-brand" href="/">Spotify Search</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/artist-search">Artists</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/albums">Albums</a>
</li>
</ul>
</div>
</div>
</nav>

{{{body}}}
<!-- Bootstrap JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
36 changes: 36 additions & 0 deletions views/tracks.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div class="container mt-4">
<div class="row">
<div class="col-md-4">
{{#if album.images.[0].url}}
<img src="{{album.images.[0].url}}" class="img-fluid rounded shadow" alt="{{album.name}}">
{{/if}}
</div>
<div class="col-md-8">
<h1>{{album.name}}</h1>
<p class="text-muted">By {{album.artists.[0].name}}</p>

<div class="list-group mt-4">
{{#each tracks}}
<div class="list-group-item list-group-item-dark d-flex justify-content-between align-items-center">
<div>
<h5 class="mb-1">{{name}}</h5>
<small class="text-muted">Duration: {{duration_ms}} ms</small>
</div>
{{#if preview_url}}
<audio controls>
<source src="{{preview_url}}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
{{else}}
<span class="badge bg-secondary">No preview available</span>
{{/if}}
</div>
{{/each}}
</div>

<a href="/albums/{{album.artists.[0].id}}" class="btn btn-secondary mt-4">
Back to Albums
</a>
</div>
</div>
</div>