|
| 1 | +/* |
| 2 | +_____________________________________ |
| 3 | +https://github.com/kenysdev |
| 4 | +2024 - JavaScript |
| 5 | +_______________________________________________________ |
| 6 | +#37 OASIS VS LINKIN PARK |
| 7 | +------------------------------------------------------- |
| 8 | +* ¡Dos de las bandas más grandes de la historia están de vuelta! |
| 9 | +* Oasis y Linkin Park han anunciado nueva gira, pero, ¿quién es más popular? |
| 10 | +* Desarrolla un programa que se conecte al API de Spotify y los compare. |
| 11 | +* Requisitos: |
| 12 | +* 1. Crea una cuenta de desarrollo en https://developer.spotify.com. |
| 13 | +* 2. Conéctate al API utilizando tu lenguaje de programación. |
| 14 | +* 3. Recupera datos de los endpoint que tú quieras. |
| 15 | +* Acciones: |
| 16 | +* 1. Accede a las estadísticas de las dos bandas. |
| 17 | +* Por ejemplo: número total de seguidores, escuchas mensuales, |
| 18 | +* canción con más reproducciones... |
| 19 | +* 2. Compara los resultados de, por lo menos, 3 endpoint. |
| 20 | +* 3. Muestra todos los resultados por consola para notificar al usuario. |
| 21 | +* 4. Desarrolla un criterio para seleccionar qué banda es más popular. |
| 22 | +*/ |
| 23 | +// ________________________________________________________ |
| 24 | +require('dotenv').config(); |
| 25 | +const https = require('https'); |
| 26 | + |
| 27 | +const SPOTIFY_CLIENT_ID = process.env.SPOTIFY_CLIENT_ID; |
| 28 | +const SPOTIFY_CLIENT_SECRET = process.env.SPOTIFY_CLIENT_SECRET; |
| 29 | + |
| 30 | +const getSpotifyAccessToken = async () => { |
| 31 | + const options = { |
| 32 | + hostname: "accounts.spotify.com", |
| 33 | + path: "/api/token", |
| 34 | + method: "POST", |
| 35 | + headers: { |
| 36 | + "Content-Type": "application/x-www-form-urlencoded", |
| 37 | + Authorization: `Basic ${Buffer.from( |
| 38 | + `${SPOTIFY_CLIENT_ID}:${SPOTIFY_CLIENT_SECRET}` |
| 39 | + ).toString("base64")}`, |
| 40 | + }, |
| 41 | + }; |
| 42 | + |
| 43 | + return new Promise((resolve, reject) => { |
| 44 | + const req = https.request(options, (res) => { |
| 45 | + let data = ""; |
| 46 | + |
| 47 | + res.on("data", (chunk) => { |
| 48 | + data += chunk; |
| 49 | + }); |
| 50 | + |
| 51 | + res.on("end", () => { |
| 52 | + const response = JSON.parse(data); |
| 53 | + resolve(response.access_token); |
| 54 | + }); |
| 55 | + }); |
| 56 | + |
| 57 | + req.on("error", (e) => { |
| 58 | + reject(e); |
| 59 | + }); |
| 60 | + |
| 61 | + req.write("grant_type=client_credentials"); |
| 62 | + req.end(); |
| 63 | + }); |
| 64 | +}; |
| 65 | + |
| 66 | +const spotifyAPIRequest = async (endpoint, accessToken) => { |
| 67 | + const options = { |
| 68 | + hostname: "api.spotify.com", |
| 69 | + path: endpoint, |
| 70 | + method: "GET", |
| 71 | + headers: { |
| 72 | + Authorization: `Bearer ${accessToken}`, |
| 73 | + }, |
| 74 | + }; |
| 75 | + |
| 76 | + return new Promise((resolve, reject) => { |
| 77 | + const req = https.request(options, (res) => { |
| 78 | + let data = ""; |
| 79 | + |
| 80 | + res.on("data", (chunk) => { |
| 81 | + data += chunk; |
| 82 | + }); |
| 83 | + |
| 84 | + res.on("end", () => { |
| 85 | + resolve(JSON.parse(data)); |
| 86 | + }); |
| 87 | + }); |
| 88 | + |
| 89 | + req.on("error", (e) => { |
| 90 | + reject(e); |
| 91 | + }); |
| 92 | + |
| 93 | + req.end(); |
| 94 | + }); |
| 95 | +}; |
| 96 | + |
| 97 | +class Spotify { |
| 98 | + constructor() { |
| 99 | + this.accessToken = null; |
| 100 | + } |
| 101 | + |
| 102 | + async authenticate() { |
| 103 | + this.accessToken = await getSpotifyAccessToken(); |
| 104 | + } |
| 105 | + |
| 106 | + async getArtists(name) { |
| 107 | + const results = await spotifyAPIRequest( |
| 108 | + `/v1/search?q=artist:${encodeURIComponent(name)}&type=artist&limit=3`, |
| 109 | + this.accessToken |
| 110 | + ); |
| 111 | + return results.artists ? results.artists.items : []; |
| 112 | + } |
| 113 | + |
| 114 | + async getMostPopularArtist(name) { |
| 115 | + const artists = await this.getArtists(name); |
| 116 | + if (artists.length === 0) return null; |
| 117 | + |
| 118 | + return artists.sort((a, b) => b.popularity - a.popularity)[0]; |
| 119 | + } |
| 120 | + |
| 121 | + async artistTopTracks(artistId) { |
| 122 | + const results = await spotifyAPIRequest( |
| 123 | + `/v1/artists/${artistId}/top-tracks?market=US`, |
| 124 | + this.accessToken |
| 125 | + ); |
| 126 | + return results.tracks || []; |
| 127 | + } |
| 128 | + |
| 129 | + async artistAlbums(artistId) { |
| 130 | + const results = await spotifyAPIRequest( |
| 131 | + `/v1/artists/${artistId}/albums?album_type=album`, |
| 132 | + this.accessToken |
| 133 | + ); |
| 134 | + return results.items || []; |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +// Clase Versus |
| 139 | +class Versus { |
| 140 | + constructor(artist1, artist2, spotifyInstance) { |
| 141 | + this.a1 = artist1; |
| 142 | + this.a2 = artist2; |
| 143 | + this.sp = spotifyInstance; |
| 144 | + this.a1Score = 0; |
| 145 | + this.a2Score = 0; |
| 146 | + } |
| 147 | + |
| 148 | + popularity() { |
| 149 | + console.log(`Popularidad: ${this.a1.popularity} vs ${this.a2.popularity}`); |
| 150 | + if (this.a1.popularity > this.a2.popularity) this.a1Score++; |
| 151 | + else if (this.a2.popularity > this.a1.popularity) this.a2Score++; |
| 152 | + } |
| 153 | + |
| 154 | + followers() { |
| 155 | + console.log( |
| 156 | + `Seguidores: ${this.a1.followers.total} vs ${this.a2.followers.total}` |
| 157 | + ); |
| 158 | + if (this.a1.followers.total > this.a2.followers.total) this.a1Score++; |
| 159 | + else if (this.a2.followers.total > this.a1.followers.total) this.a2Score++; |
| 160 | + } |
| 161 | + |
| 162 | + async top3Tracks() { |
| 163 | + const a1Tracks = await this.sp.artistTopTracks(this.a1.id); |
| 164 | + const a2Tracks = await this.sp.artistTopTracks(this.a2.id); |
| 165 | + |
| 166 | + const a1Popularity = a1Tracks.slice(0, 3).reduce((sum, track) => sum + track.popularity, 0); |
| 167 | + const a2Popularity = a2Tracks.slice(0, 3).reduce((sum, track) => sum + track.popularity, 0); |
| 168 | + |
| 169 | + console.log(`Popularidad Top 3 canciones: ${a1Popularity} vs ${a2Popularity}`); |
| 170 | + if (a1Popularity > a2Popularity) this.a1Score++; |
| 171 | + else if (a2Popularity > a1Popularity) this.a2Score++; |
| 172 | + } |
| 173 | + |
| 174 | + async albumsAndActiveYears() { |
| 175 | + const a1Albums = await this.sp.artistAlbums(this.a1.id); |
| 176 | + const a2Albums = await this.sp.artistAlbums(this.a2.id); |
| 177 | + |
| 178 | + console.log(`Número de álbumes: ${a1Albums.length} vs ${a2Albums.length}`); |
| 179 | + if (a1Albums.length > a2Albums.length) this.a1Score++; |
| 180 | + else if (a2Albums.length > a1Albums.length) this.a2Score++; |
| 181 | + |
| 182 | + const a1Years = new Set(a1Albums.map((album) => album.release_date.slice(0, 4))); |
| 183 | + const a2Years = new Set(a2Albums.map((album) => album.release_date.slice(0, 4))); |
| 184 | + |
| 185 | + console.log(`Años activos: ${a1Years.size} vs ${a2Years.size}`); |
| 186 | + if (a1Years.size > a2Years.size) this.a1Score++; |
| 187 | + else if (a2Years.size > a1Years.size) this.a2Score++; |
| 188 | + } |
| 189 | + |
| 190 | + finalResult() { |
| 191 | + console.log("\nRESULTADO FINAL:"); |
| 192 | + console.log(`${this.a1.name}: ${this.a1Score} puntos`); |
| 193 | + console.log(`${this.a2.name}: ${this.a2Score} puntos`); |
| 194 | + |
| 195 | + if (this.a1Score > this.a2Score) { |
| 196 | + console.log(`\n¡'${this.a1.name}' gana el versus!`); |
| 197 | + } else if (this.a2Score > this.a1Score) { |
| 198 | + console.log(`\n¡'${this.a2.name}' gana el versus!`); |
| 199 | + } else { |
| 200 | + console.log("\n¡Es un empate!"); |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + async start() { |
| 205 | + console.log(`${this.a1.name} vs ${this.a2.name}`); |
| 206 | + this.popularity(); |
| 207 | + this.followers(); |
| 208 | + await this.top3Tracks(); |
| 209 | + await this.albumsAndActiveYears(); |
| 210 | + this.finalResult(); |
| 211 | + } |
| 212 | +} |
| 213 | + |
| 214 | +const main = async () => { |
| 215 | + const spotify = new Spotify(); |
| 216 | + await spotify.authenticate(); |
| 217 | + |
| 218 | + const artist1 = await spotify.getMostPopularArtist("Oasis"); |
| 219 | + const artist2 = await spotify.getMostPopularArtist("Linkin Park"); |
| 220 | + |
| 221 | + if (!artist1 || !artist2) { |
| 222 | + console.log("Artistas no encontrados"); |
| 223 | + return; |
| 224 | + } |
| 225 | + |
| 226 | + const versus = new Versus(artist1, artist2, spotify); |
| 227 | + await versus.start(); |
| 228 | +}; |
| 229 | + |
| 230 | +main(); |
0 commit comments