From a9bb6c317b94ab7b98853fb7b3f9d5273850aa90 Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Thu, 11 Mar 2021 18:44:57 +0000 Subject: [PATCH 01/46] updated readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 36a92f1..db8d547 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# listspotter \ No newline at end of file +# listspotter +hello! \ No newline at end of file From 28a67995c9094ed4856f0f32eec2e3db31cc50e7 Mon Sep 17 00:00:00 2001 From: Gero Date: Thu, 11 Mar 2021 19:36:31 +0000 Subject: [PATCH 02/46] build(readme): test git workflow n --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db8d547..7f90110 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # listspotter -hello! \ No newline at end of file + +hello! +hello back From 8656630857a7d49e03c7a5891f8b8f9992bc321d Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Thu, 11 Mar 2021 19:37:52 +0000 Subject: [PATCH 03/46] added branch test readme --- BRANCHTEST.MD | 1 + 1 file changed, 1 insertion(+) create mode 100644 BRANCHTEST.MD diff --git a/BRANCHTEST.MD b/BRANCHTEST.MD new file mode 100644 index 0000000..3cbbc67 --- /dev/null +++ b/BRANCHTEST.MD @@ -0,0 +1 @@ +Wassup my homie \ No newline at end of file From 65522d4892425a812c82ee73193f6ee5eb280ba2 Mon Sep 17 00:00:00 2001 From: Gero Date: Thu, 11 Mar 2021 19:39:47 +0000 Subject: [PATCH 04/46] chore(gerotest): n --- GEROTEST.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 GEROTEST.md diff --git a/GEROTEST.md b/GEROTEST.md new file mode 100644 index 0000000..d12b566 --- /dev/null +++ b/GEROTEST.md @@ -0,0 +1 @@ +hihihih From fc76d1e7bde3358e4e20157e3a58141071cd028b Mon Sep 17 00:00:00 2001 From: Pamela Date: Thu, 11 Mar 2021 20:20:14 +0000 Subject: [PATCH 05/46] updated readme w todos --- BRANCHTEST.MD | 1 - GEROTEST.md | 1 - README.md | 6 ++++-- 3 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 BRANCHTEST.MD delete mode 100644 GEROTEST.md diff --git a/BRANCHTEST.MD b/BRANCHTEST.MD deleted file mode 100644 index 3cbbc67..0000000 --- a/BRANCHTEST.MD +++ /dev/null @@ -1 +0,0 @@ -Wassup my homie \ No newline at end of file diff --git a/GEROTEST.md b/GEROTEST.md deleted file mode 100644 index d12b566..0000000 --- a/GEROTEST.md +++ /dev/null @@ -1 +0,0 @@ -hihihih diff --git a/README.md b/README.md index 7f90110..e40a344 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # listspotter -hello! -hello back +1. Implement testing +2. Implement TS on backend +3. Set up JWT for multiple users + From 8b393e9c9947a5cc211e2a35ed431fcbd647d79d Mon Sep 17 00:00:00 2001 From: Pamela Date: Thu, 11 Mar 2021 20:27:45 +0000 Subject: [PATCH 06/46] added git workflow --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e40a344..2ea58cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ -# listspotter +# Listspotter + +## TODO 1. Implement testing 2. Implement TS on backend 3. Set up JWT for multiple users +## GIT WORKFLOW +- CREATING NEW BRANCH: git checkout -b branch_name branched_off_name +- PUSHING TO NEW BRANCH UPSTREAM: git push -u origin branch_name +- NAVIGATING TO EXISTING BRANCH: git checkout branch_name +- BEFORE YOU PUSH, PULL FROM: git pull origin branch_name. THEN: git push origin branch_name From 8283bf1198334ef3a3ff4b50b7e9b6e0d031e94d Mon Sep 17 00:00:00 2001 From: Gero Date: Fri, 12 Mar 2021 11:04:43 +0000 Subject: [PATCH 07/46] set-up complete --- client/src/components/Login/login-index.tsx | 28 ++++++++------- .../components/Login/login-queryParams.tsx | 35 +++++++++++-------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/client/src/components/Login/login-index.tsx b/client/src/components/Login/login-index.tsx index 9d6b926..865203a 100644 --- a/client/src/components/Login/login-index.tsx +++ b/client/src/components/Login/login-index.tsx @@ -1,24 +1,28 @@ -import * as React from 'react'; -import { queryUrl } from './login-queryParams'; -import './login-style.scss'; -import logo from './Spotify_Logo_RGB_Green.png'; +import * as React from "react"; +import { queryUrl } from "./login-queryParams"; +import "./login-style.scss"; +import logo from "./Spotify_Logo_RGB_Green.png"; // import { useState, useEffect } from 'react'; - -export interface Props { -} +export interface Props {} const Login: React.FC = () => { return (

Listspotter.

-

Create playlists from your saved songs in using intuitive genre filters.

- LOGIN +

+ Create playlists from your saved songs in{" "} + using intuitive + genre filters. +

+ + LOGIN +
- ); -} + ); +}; -export default Login; \ No newline at end of file +export default Login; diff --git a/client/src/components/Login/login-queryParams.tsx b/client/src/components/Login/login-queryParams.tsx index f04bc8c..499c1ba 100644 --- a/client/src/components/Login/login-queryParams.tsx +++ b/client/src/components/Login/login-queryParams.tsx @@ -1,26 +1,31 @@ -const baseUrl = 'https://accounts.spotify.com/authorize'; +const baseUrl = "https://accounts.spotify.com/authorize"; interface QueryParams { - client_id: string, - response_type: string, - redirect_uri: string, - state: string, - scope: string + client_id: string; + response_type: string; + redirect_uri: string; + state: string; + scope: string; } const queryParams: QueryParams = { - client_id: 'decae5e905644494a2de08b59116f140', - response_type: 'code', - redirect_uri: 'http://localhost:3000/main', - state: 'bayburt', + client_id: "8bc6f1323c3a4081bc3416b632218513", + response_type: "code", + redirect_uri: "http://localhost:3000/main", + state: "bayburt", // scope: 'user-library-read user-follow-modify' - scope: 'user-library-read user-follow-read user-follow-modify playlist-modify-public' -} + scope: + "user-library-read user-follow-read user-follow-modify playlist-modify-public", +}; -function buildQueryUrl (url: string, params: QueryParams) : string { - return `${baseUrl}?client_id=${params.client_id}&response_type=${params.response_type}&redirect_uri=${params.redirect_uri}&scope=${encodeURIComponent(queryParams.scope)}&state=${params.state}`; +function buildQueryUrl(url: string, params: QueryParams): string { + return `${baseUrl}?client_id=${params.client_id}&response_type=${ + params.response_type + }&redirect_uri=${params.redirect_uri}&scope=${encodeURIComponent( + queryParams.scope + )}&state=${params.state}`; } const queryUrl = buildQueryUrl(baseUrl, queryParams); -export {queryUrl}; \ No newline at end of file +export { queryUrl }; From f432339d8e595b8493a1d1e6d63d187ce2e2c842 Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 11:05:10 +0000 Subject: [PATCH 08/46] added prettier --- server/.prettierrc.js | 5 +++ server/controller/controller.js | 67 +++++++++++++++++++++------------ server/modeller/modeller.js | 64 ++++++++++++++++++------------- 3 files changed, 84 insertions(+), 52 deletions(-) create mode 100644 server/.prettierrc.js diff --git a/server/.prettierrc.js b/server/.prettierrc.js new file mode 100644 index 0000000..0310300 --- /dev/null +++ b/server/.prettierrc.js @@ -0,0 +1,5 @@ +module.exports = { + bracketSpacing: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/server/controller/controller.js b/server/controller/controller.js index b097557..145d491 100644 --- a/server/controller/controller.js +++ b/server/controller/controller.js @@ -14,7 +14,7 @@ const offsetIncrement = 50; // max number of tracks allowed in a single "get sav const msBetweenTrackRequests = 250; // TODO: TOKEN TO BE PER USER SESSION RATHER THAN ONE FOR THE WHOLE SERVER: GET USER ID AFTER RECEIVING AUTH TOKEN, SAVE AS ID TOKEN PAIR, SEND BACK USER ID TO CLIENT FOR USE IN SUBSEQUENT REQUESTS -let tokens =''; +let tokens = ''; // TODO: CHECK ERROR HANDLING IN CATCH METHODS // CREATE CUSTOM HANDLER MIDDLEWARE // TODO: REFACTOR AXIOS REQUESTS INTO MODELLER @@ -27,7 +27,7 @@ exports.getTokens = async (req, res, next) => { }; exports.getTracks = async (req, res, next) => { - const {code} = req.body; + const { code } = req.body; let initialOffset = 0; let trackData = []; @@ -35,21 +35,27 @@ exports.getTracks = async (req, res, next) => { tokens = await modeller.requestToken(code, next); } - function timeOutPromise () { - return new Promise((resolve) => setTimeout(() => resolve(), msBetweenTrackRequests)); - }; + function timeOutPromise() { + return new Promise((resolve) => + setTimeout(() => resolve(), msBetweenTrackRequests), + ); + } - async function fetchTracksAsync (offset) { + async function fetchTracksAsync(offset) { let trackBufferResponse; - try{ - trackBufferResponse = await modeller.requestTracks(spotifyTracksUrl, tokens, offset); + try { + trackBufferResponse = await modeller.requestTracks( + spotifyTracksUrl, + tokens, + offset, + ); } catch (err) { - console.log('inner error 😎') + console.log('inner error 😎'); console.log(err.response.status); // 404 - if(err.response.status === 404){ + if (err.response.status === 404) { await timeOutPromise(); - await fetchTracksAsync (offset); + await fetchTracksAsync(offset); return; } } @@ -59,17 +65,17 @@ exports.getTracks = async (req, res, next) => { console.log('received tracks for offset:', offset); if (trackBufferResponse.data.next) { offset += offsetIncrement; - await fetchTracksAsync (offset) + await fetchTracksAsync(offset); } - }; + } try { await fetchTracksAsync(initialOffset); - console.log('sending ' + trackData.length + ' tracks') + console.log('sending ' + trackData.length + ' tracks'); res.status = 200; res.send(trackData); } catch (err) { - console.log('outer error 😎') + console.log('outer error 😎'); console.log('something went wrong while fetching tracks'); console.log(err); res.sendStatus(500); @@ -77,13 +83,14 @@ exports.getTracks = async (req, res, next) => { }; exports.getArtists = async (req, res, next) => { - const {code, offset, nextUrl} = req.body; + const { code, offset, nextUrl } = req.body; if (!tokens) { tokens = await modeller.requestToken(code, next); } - modeller.requestArtists(spotifyArtistsUrl, nextUrl, tokens) + modeller + .requestArtists(spotifyArtistsUrl, nextUrl, tokens) .then((artistResponse) => { res.statusCode = 200; res.send(artistResponse.data); @@ -92,13 +99,14 @@ exports.getArtists = async (req, res, next) => { }; exports.getPlaylistCover = async (req, res, next) => { - const {code, playlistId} = req.body; + const { code, playlistId } = req.body; if (!tokens) { tokens = await modeller.requestToken(code, next); } - modeller.requestPlaylistCover(spotifyPlaylistUrl, playlistId, tokens) + modeller + .requestPlaylistCover(spotifyPlaylistUrl, playlistId, tokens) .then((coverResponse) => { res.statusCode = 200; console.log(coverResponse); @@ -107,9 +115,8 @@ exports.getPlaylistCover = async (req, res, next) => { .catch((err) => console.log(err.response.data)); }; - exports.createPlaylist = async (req, res, next) => { - const {code, playlistName, trackURIs} = req.body; + const { code, playlistName, trackURIs } = req.body; if (!tokens) { tokens = await modeller.requestToken(code, next); @@ -118,11 +125,21 @@ exports.createPlaylist = async (req, res, next) => { const userResponse = await modeller.requestUser(spotifyUserUrl, tokens); const userID = userResponse.data.id; - const createPlaylistResponse = await modeller.requestCreatePlaylist(spotifyCreatePlaylistUrl, playlistName, userID, tokens); + const createPlaylistResponse = await modeller.requestCreatePlaylist( + spotifyCreatePlaylistUrl, + playlistName, + userID, + tokens, + ); const playlistData = createPlaylistResponse.data; - function addTracks (trackArr) { - return modeller.requestAddTracks(spotifyPlaylistUrl, playlistData.id, trackArr, tokens); + function addTracks(trackArr) { + return modeller.requestAddTracks( + spotifyPlaylistUrl, + playlistData.id, + trackArr, + tokens, + ); } // Spotify has a track limit per request, so below we check if multiple requests are necessary (TrackQueue is all the tracks to be added in a queue form, with multiple tracks "shifting" per request.) @@ -130,4 +147,4 @@ exports.createPlaylist = async (req, res, next) => { res.status(200); res.send(JSON.stringify(playlistData)); -}; \ No newline at end of file +}; diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index cb455f0..4a02c8c 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -3,17 +3,17 @@ const { clientID, clientSecret } = require('../config'); const spotifyTokenUrl = 'https://accounts.spotify.com/api/token'; const redirectUri = 'http://localhost:3000/main'; - // TODO: REFACTOR WITH A REQUEST TEMPLATE exports.requestToken = (code, next) => { - return axios.request({ - method: 'POST', - url: spotifyTokenUrl, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${clientID}&client_secret=${clientSecret}` - }) + return axios + .request({ + method: 'POST', + url: spotifyTokenUrl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${clientID}&client_secret=${clientSecret}`, + }) .then((tokenResponse) => { return tokenResponse.data; }) @@ -25,8 +25,8 @@ exports.requestTracks = (spotifyTracksUrl, tokens, offset) => { method: 'GET', url: spotifyTracksUrl + `?offset=${offset}&limit=50`, headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/x-www-form-urlencoded' + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/x-www-form-urlencoded', }, }); }; @@ -36,9 +36,9 @@ exports.requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { method: 'GET', url: nextUrl || spotifyArtistsUrl + '?type=artist&limit=50', headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, + Authorization: `Bearer ${tokens['access_token']}`, 'Content-Type': 'application/json', - 'Accept': 'application/json' + Accept: 'application/json', }, }); }; @@ -48,8 +48,8 @@ exports.requestUser = (spotifyUserUrl, tokens) => { method: 'GET', url: spotifyUserUrl, headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/x-www-form-urlencoded' + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/x-www-form-urlencoded', }, }); }; @@ -59,35 +59,45 @@ exports.requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { method: 'GET', url: spotifyPlaylistUrl + `/${playlistId}/images`, headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, + Authorization: `Bearer ${tokens['access_token']}`, 'Content-Type': 'application/json', - Accept: 'application/json' + Accept: 'application/json', }, }); }; -exports.requestCreatePlaylist = (spotifyCreatePlaylistUrl, playlistName, userID, tokens) => { +exports.requestCreatePlaylist = ( + spotifyCreatePlaylistUrl, + playlistName, + userID, + tokens, +) => { return axios.request({ method: 'POST', url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json' + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', }, - data: {name: playlistName} + data: { name: playlistName }, }); }; -exports.requestAddTracks = (spotifySaveTracksUrl, playlistID, trackArr, tokens) => { +exports.requestAddTracks = ( + spotifySaveTracksUrl, + playlistID, + trackArr, + tokens, +) => { return axios.request({ method: 'POST', url: spotifySaveTracksUrl + `/${playlistID}/tracks`, headers: { - 'Authorization': `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json' + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', }, data: { - uris: trackArr - } + uris: trackArr, + }, }); -}; \ No newline at end of file +}; From 5ae36481ea698334e2941aff0f0002250861228e Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 12:10:37 +0000 Subject: [PATCH 09/46] added TS dependencies --- server/index.js | 2 +- server/package-lock.json | 510 +++++++++++++++++++++++++++++++++++++++ server/package.json | 21 ++ server/tsconfig.json | 10 + 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 server/package-lock.json create mode 100644 server/package.json create mode 100644 server/tsconfig.json diff --git a/server/index.js b/server/index.js index f2a4d9d..1033be2 100644 --- a/server/index.js +++ b/server/index.js @@ -18,4 +18,4 @@ app.use(router); // CONNECTION TO DB & LISTENING TO PORT app.listen(port, host, () => { console.log(`Server running at ${host}:${port}! 🐯`); -}); \ No newline at end of file +}); diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..28287b4 --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,510 @@ +{ + "name": "server", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", + "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz", + "integrity": "sha512-m4JTwx5RUBNZvky/JJ8swEJPKFd8si08pPF2PfizYjGZOKr/svUWPcoUmLow6MmPzhasphB7gSTINY67xn3JNA==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/node": { + "version": "14.14.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.34.tgz", + "integrity": "sha512-dBPaxocOK6UVyvhbnpFIj2W+S+1cBTkHQbFQfeeJhoKFbzYcVUGHvddeWPSucKATb3F0+pgDq0i6ghEaZjsugA==" + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..5585f2d --- /dev/null +++ b/server/package.json @@ -0,0 +1,21 @@ +{ + "name": "server", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@types/express": "^4.17.11", + "@types/node": "^14.14.34", + "axios": "^0.21.1", + "cors": "^2.8.5", + "express": "^4.17.1", + "moment": "^2.29.1", + "morgan": "^1.10.0", + "typescript": "^4.2.3" + } +} diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..c3cd319 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "strict": true, /* Enable all strict type-checking options. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} From dc967c39d30bfcfa55aa3a6d5e5301924f0b2550 Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 12:40:21 +0000 Subject: [PATCH 10/46] transformed imports to importfrom --- server/controller/controller.js | 8 ++--- server/index.js | 8 ++--- server/modeller/modeller.js | 4 +-- server/package-lock.json | 57 +++++++++++++++++++++++++++++++++ server/package.json | 4 ++- server/router.js | 6 ++-- server/tsconfig.json | 2 +- 7 files changed, 74 insertions(+), 15 deletions(-) diff --git a/server/controller/controller.js b/server/controller/controller.js index 145d491..3a8d3f3 100644 --- a/server/controller/controller.js +++ b/server/controller/controller.js @@ -1,7 +1,7 @@ -const axios = require('axios'); -const { renderSync } = require('node-sass'); -const modeller = require('../modeller/modeller'); -const { requestWhileQueued } = require('./controller-helpers'); +import axios from 'axios'; +import { renderSync } from 'node-sass'; +import modeller from '../modeller/modeller.js'; +import { requestWhileQueued } from './controller-helpers.js'; const baseUrl = 'https://api.spotify.com/v1'; const spotifyTracksUrl = baseUrl + '/me/tracks'; diff --git a/server/index.js b/server/index.js index 1033be2..9d14b48 100644 --- a/server/index.js +++ b/server/index.js @@ -1,8 +1,8 @@ // DEPENDENCIES -const express = require('express'); -const morgan = require('morgan'); -const cors = require('cors'); -const router = require('./router'); +import express from 'express'; +import morgan from 'morgan'; +import cors from 'cors'; +import router from './router.js'; // SERVER CONFIG const app = express(); diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index 4a02c8c..5ef41cd 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -1,5 +1,5 @@ -const axios = require('axios'); -const { clientID, clientSecret } = require('../config'); +import axios from 'axios'; +import { clientID, clientSecret } from '../config.js'; const spotifyTokenUrl = 'https://accounts.spotify.com/api/token'; const redirectUri = 'http://localhost:3000/main'; diff --git a/server/package-lock.json b/server/package-lock.json index 28287b4..e150bdb 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -80,6 +80,11 @@ "negotiator": "0.6.2" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -118,6 +123,11 @@ "type-is": "~1.6.17" } }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -155,6 +165,11 @@ "vary": "^1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -173,6 +188,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -289,6 +309,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -467,6 +492,20 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -477,6 +516,19 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -505,6 +557,11 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" } } } diff --git a/server/package.json b/server/package.json index 5585f2d..1b51a04 100644 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,8 @@ "express": "^4.17.1", "moment": "^2.29.1", "morgan": "^1.10.0", + "ts-node": "^9.1.1", "typescript": "^4.2.3" - } + }, + "type": "module" } diff --git a/server/router.js b/server/router.js index 65f69a4..55e8051 100644 --- a/server/router.js +++ b/server/router.js @@ -1,6 +1,6 @@ -const { Router } = require('express'); +import { Router } from 'express'; const router = Router(); -const controller = require('./controller/controller'); +import controller from './controller/controller.js'; router.post('/tracks', controller.getTracks); router.post('/tokens', controller.getTokens); @@ -8,4 +8,4 @@ router.post('/artists', controller.getArtists); router.post('/create', controller.createPlaylist); router.post('/cover', controller.getPlaylistCover); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/server/tsconfig.json b/server/tsconfig.json index c3cd319..fe8a141 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "strict": true, /* Enable all strict type-checking options. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ From b26455f1421139634593a86cd28efb8af73847a3 Mon Sep 17 00:00:00 2001 From: Gero Date: Fri, 12 Mar 2021 13:14:30 +0000 Subject: [PATCH 11/46] style(controller/modeller): tS implemented + imports/exports adjusted --- server/{.prettierrc.js => .prettierrc.ts} | 0 ...oller-helpers.js => controller-helpers.ts} | 0 .../{controller.js => controller.ts} | 42 +++---- server/{index.js => index.ts} | 12 +- server/modeller/modeller.js | 103 ---------------- server/modeller/modeller.ts | 113 ++++++++++++++++++ server/package-lock.json | 24 ++++ server/package.json | 7 +- server/router.js | 11 -- server/router.ts | 11 ++ 10 files changed, 181 insertions(+), 142 deletions(-) rename server/{.prettierrc.js => .prettierrc.ts} (100%) rename server/controller/{controller-helpers.js => controller-helpers.ts} (100%) rename server/controller/{controller.js => controller.ts} (81%) rename server/{index.js => index.ts} (62%) delete mode 100644 server/modeller/modeller.js create mode 100644 server/modeller/modeller.ts delete mode 100644 server/router.js create mode 100644 server/router.ts diff --git a/server/.prettierrc.js b/server/.prettierrc.ts similarity index 100% rename from server/.prettierrc.js rename to server/.prettierrc.ts diff --git a/server/controller/controller-helpers.js b/server/controller/controller-helpers.ts similarity index 100% rename from server/controller/controller-helpers.js rename to server/controller/controller-helpers.ts diff --git a/server/controller/controller.js b/server/controller/controller.ts similarity index 81% rename from server/controller/controller.js rename to server/controller/controller.ts index 3a8d3f3..7926e59 100644 --- a/server/controller/controller.js +++ b/server/controller/controller.ts @@ -1,20 +1,20 @@ -import axios from 'axios'; -import { renderSync } from 'node-sass'; -import modeller from '../modeller/modeller.js'; -import { requestWhileQueued } from './controller-helpers.js'; - -const baseUrl = 'https://api.spotify.com/v1'; -const spotifyTracksUrl = baseUrl + '/me/tracks'; -const spotifyArtistsUrl = baseUrl + '/me/following'; -const spotifyUserUrl = baseUrl + '/me'; -const spotifyCreatePlaylistUrl = baseUrl + '/users'; -const spotifyPlaylistUrl = baseUrl + '/playlists'; +import axios from "axios"; +import { renderSync } from "node-sass"; +import modeller from "../modeller/modeller"; +import { requestWhileQueued } from "./controller-helpers"; + +const baseUrl = "https://api.spotify.com/v1"; +const spotifyTracksUrl = baseUrl + "/me/tracks"; +const spotifyArtistsUrl = baseUrl + "/me/following"; +const spotifyUserUrl = baseUrl + "/me"; +const spotifyCreatePlaylistUrl = baseUrl + "/users"; +const spotifyPlaylistUrl = baseUrl + "/playlists"; const saveTrackRequestLimit = 100; // max number of tracks allowed in a single "save tracks to playlist" request in spotify const offsetIncrement = 50; // max number of tracks allowed in a single "get saved tracks" request in spotify const msBetweenTrackRequests = 250; // TODO: TOKEN TO BE PER USER SESSION RATHER THAN ONE FOR THE WHOLE SERVER: GET USER ID AFTER RECEIVING AUTH TOKEN, SAVE AS ID TOKEN PAIR, SEND BACK USER ID TO CLIENT FOR USE IN SUBSEQUENT REQUESTS -let tokens = ''; +let tokens = ""; // TODO: CHECK ERROR HANDLING IN CATCH METHODS // CREATE CUSTOM HANDLER MIDDLEWARE // TODO: REFACTOR AXIOS REQUESTS INTO MODELLER @@ -37,7 +37,7 @@ exports.getTracks = async (req, res, next) => { function timeOutPromise() { return new Promise((resolve) => - setTimeout(() => resolve(), msBetweenTrackRequests), + setTimeout(() => resolve(), msBetweenTrackRequests) ); } @@ -48,10 +48,10 @@ exports.getTracks = async (req, res, next) => { trackBufferResponse = await modeller.requestTracks( spotifyTracksUrl, tokens, - offset, + offset ); } catch (err) { - console.log('inner error 😎'); + console.log("inner error 😎"); console.log(err.response.status); // 404 if (err.response.status === 404) { await timeOutPromise(); @@ -62,7 +62,7 @@ exports.getTracks = async (req, res, next) => { trackData = [...trackData, ...trackBufferResponse.data.items]; - console.log('received tracks for offset:', offset); + console.log("received tracks for offset:", offset); if (trackBufferResponse.data.next) { offset += offsetIncrement; await fetchTracksAsync(offset); @@ -71,12 +71,12 @@ exports.getTracks = async (req, res, next) => { try { await fetchTracksAsync(initialOffset); - console.log('sending ' + trackData.length + ' tracks'); + console.log("sending " + trackData.length + " tracks"); res.status = 200; res.send(trackData); } catch (err) { - console.log('outer error 😎'); - console.log('something went wrong while fetching tracks'); + console.log("outer error 😎"); + console.log("something went wrong while fetching tracks"); console.log(err); res.sendStatus(500); } @@ -129,7 +129,7 @@ exports.createPlaylist = async (req, res, next) => { spotifyCreatePlaylistUrl, playlistName, userID, - tokens, + tokens ); const playlistData = createPlaylistResponse.data; @@ -138,7 +138,7 @@ exports.createPlaylist = async (req, res, next) => { spotifyPlaylistUrl, playlistData.id, trackArr, - tokens, + tokens ); } diff --git a/server/index.js b/server/index.ts similarity index 62% rename from server/index.js rename to server/index.ts index 9d14b48..9ecc21a 100644 --- a/server/index.js +++ b/server/index.ts @@ -1,18 +1,18 @@ // DEPENDENCIES -import express from 'express'; -import morgan from 'morgan'; -import cors from 'cors'; -import router from './router.js'; +import express from "express"; +import morgan from "morgan"; +import cors from "cors"; +import router from "./router"; // SERVER CONFIG const app = express(); const port = 3001; -const host = '127.0.0.1'; +const host = "127.0.0.1"; // MIDDLEWARES app.use(cors()); app.use(express.json()); -app.use(morgan('dev')); +app.use(morgan("dev")); app.use(router); // CONNECTION TO DB & LISTENING TO PORT diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js deleted file mode 100644 index 5ef41cd..0000000 --- a/server/modeller/modeller.js +++ /dev/null @@ -1,103 +0,0 @@ -import axios from 'axios'; -import { clientID, clientSecret } from '../config.js'; -const spotifyTokenUrl = 'https://accounts.spotify.com/api/token'; -const redirectUri = 'http://localhost:3000/main'; - -// TODO: REFACTOR WITH A REQUEST TEMPLATE -exports.requestToken = (code, next) => { - return axios - .request({ - method: 'POST', - url: spotifyTokenUrl, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${clientID}&client_secret=${clientSecret}`, - }) - .then((tokenResponse) => { - return tokenResponse.data; - }) - .catch(next); -}; - -exports.requestTracks = (spotifyTracksUrl, tokens, offset) => { - return axios.request({ - method: 'GET', - url: spotifyTracksUrl + `?offset=${offset}&limit=50`, - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }); -}; - -exports.requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { - return axios.request({ - method: 'GET', - url: nextUrl || spotifyArtistsUrl + '?type=artist&limit=50', - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }); -}; - -exports.requestUser = (spotifyUserUrl, tokens) => { - return axios.request({ - method: 'GET', - url: spotifyUserUrl, - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }); -}; - -exports.requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { - return axios.request({ - method: 'GET', - url: spotifyPlaylistUrl + `/${playlistId}/images`, - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }); -}; - -exports.requestCreatePlaylist = ( - spotifyCreatePlaylistUrl, - playlistName, - userID, - tokens, -) => { - return axios.request({ - method: 'POST', - url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json', - }, - data: { name: playlistName }, - }); -}; - -exports.requestAddTracks = ( - spotifySaveTracksUrl, - playlistID, - trackArr, - tokens, -) => { - return axios.request({ - method: 'POST', - url: spotifySaveTracksUrl + `/${playlistID}/tracks`, - headers: { - Authorization: `Bearer ${tokens['access_token']}`, - 'Content-Type': 'application/json', - }, - data: { - uris: trackArr, - }, - }); -}; diff --git a/server/modeller/modeller.ts b/server/modeller/modeller.ts new file mode 100644 index 0000000..3743378 --- /dev/null +++ b/server/modeller/modeller.ts @@ -0,0 +1,113 @@ +import axios from "axios"; +import { clientID, clientSecret } from "../config"; +const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; +const redirectUri = "http://localhost:3000/main"; + +// TODO: REFACTOR WITH A REQUEST TEMPLATE +const requestToken = (code, next) => { + return axios + .request({ + method: "POST", + url: spotifyTokenUrl, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${clientID}&client_secret=${clientSecret}`, + }) + .then((tokenResponse) => { + return tokenResponse.data; + }) + .catch(next); +}; + +const requestTracks = (spotifyTracksUrl, tokens, offset) => { + return axios.request({ + method: "GET", + url: spotifyTracksUrl + `?offset=${offset}&limit=50`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); +}; + +const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { + return axios.request({ + method: "GET", + url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); +}; + +const requestUser = (spotifyUserUrl, tokens) => { + return axios.request({ + method: "GET", + url: spotifyUserUrl, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); +}; + +const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { + return axios.request({ + method: "GET", + url: spotifyPlaylistUrl + `/${playlistId}/images`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); +}; + +const requestCreatePlaylist = ( + spotifyCreatePlaylistUrl, + playlistName, + userID, + tokens +) => { + return axios.request({ + method: "POST", + url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { name: playlistName }, + }); +}; + +const requestAddTracks = ( + spotifySaveTracksUrl, + playlistID, + trackArr, + tokens +) => { + return axios.request({ + method: "POST", + url: spotifySaveTracksUrl + `/${playlistID}/tracks`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { + uris: trackArr, + }, + }); +}; + +export default { + requestToken, + requestTracks, + requestArtists, + requestUser, + requestPlaylistCover, + requestCreatePlaylist, + requestAddTracks, +}; diff --git a/server/package-lock.json b/server/package-lock.json index e150bdb..80181f5 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -21,6 +21,12 @@ "@types/node": "*" } }, + "@types/cors": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", + "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==", + "dev": true + }, "@types/express": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", @@ -47,11 +53,29 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, + "@types/morgan": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz", + "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { "version": "14.14.34", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.34.tgz", "integrity": "sha512-dBPaxocOK6UVyvhbnpFIj2W+S+1cBTkHQbFQfeeJhoKFbzYcVUGHvddeWPSucKATb3F0+pgDq0i6ghEaZjsugA==" }, + "@types/node-sass": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@types/node-sass/-/node-sass-4.11.1.tgz", + "integrity": "sha512-wPOmOEEtbwQiPTIgzUuRSQZ3H5YHinsxRGeZzPSDefAm4ylXWnZG9C0adses8ymyplKK0gwv3JkDNO8GGxnWfg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/qs": { "version": "6.9.6", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", diff --git a/server/package.json b/server/package.json index 1b51a04..26a889c 100644 --- a/server/package.json +++ b/server/package.json @@ -19,5 +19,10 @@ "ts-node": "^9.1.1", "typescript": "^4.2.3" }, - "type": "module" + "type": "module", + "devDependencies": { + "@types/cors": "^2.8.10", + "@types/morgan": "^1.9.2", + "@types/node-sass": "^4.11.1" + } } diff --git a/server/router.js b/server/router.js deleted file mode 100644 index 55e8051..0000000 --- a/server/router.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Router } from 'express'; -const router = Router(); -import controller from './controller/controller.js'; - -router.post('/tracks', controller.getTracks); -router.post('/tokens', controller.getTokens); -router.post('/artists', controller.getArtists); -router.post('/create', controller.createPlaylist); -router.post('/cover', controller.getPlaylistCover); - -module.exports = router; diff --git a/server/router.ts b/server/router.ts new file mode 100644 index 0000000..2a49a7b --- /dev/null +++ b/server/router.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +const router = Router(); +import controller from "./controller/controller"; + +router.post("/tracks", controller.getTracks); +router.post("/tokens", controller.getTokens); +router.post("/artists", controller.getArtists); +router.post("/create", controller.createPlaylist); +router.post("/cover", controller.getPlaylistCover); + +export default router; From 1fa56b654eb908dc685b07425cc2a7d1a52c3024 Mon Sep 17 00:00:00 2001 From: Gero Date: Fri, 12 Mar 2021 13:48:31 +0000 Subject: [PATCH 12/46] style(package.json) tsc --- server/controller/controller-helpers.js | 23 +++++ server/controller/controller.js | 125 ++++++++++++++++++++++++ server/index.js | 23 +++++ server/modeller/modeller.js | 100 +++++++++++++++++++ server/package.json | 4 +- server/router.js | 14 +++ 6 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 server/controller/controller-helpers.js create mode 100644 server/controller/controller.js create mode 100644 server/index.js create mode 100644 server/modeller/modeller.js create mode 100644 server/router.js diff --git a/server/controller/controller-helpers.js b/server/controller/controller-helpers.js new file mode 100644 index 0000000..ceab268 --- /dev/null +++ b/server/controller/controller-helpers.js @@ -0,0 +1,23 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +exports.requestWhileQueued = (initialQueue, limit, handler) => __awaiter(void 0, void 0, void 0, function* () { + let queueArr = initialQueue.slice(); + while (queueArr.length > 0) { + if (queueArr.length < limit) { + yield handler(queueArr); + queueArr = []; + } + else { + let tracksToQuery = queueArr.splice(0, limit); + yield handler(tracksToQuery); + } + } +}); diff --git a/server/controller/controller.js b/server/controller/controller.js new file mode 100644 index 0000000..6922df3 --- /dev/null +++ b/server/controller/controller.js @@ -0,0 +1,125 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const modeller_1 = __importDefault(require("../modeller/modeller")); +const controller_helpers_1 = require("./controller-helpers"); +const baseUrl = "https://api.spotify.com/v1"; +const spotifyTracksUrl = baseUrl + "/me/tracks"; +const spotifyArtistsUrl = baseUrl + "/me/following"; +const spotifyUserUrl = baseUrl + "/me"; +const spotifyCreatePlaylistUrl = baseUrl + "/users"; +const spotifyPlaylistUrl = baseUrl + "/playlists"; +const saveTrackRequestLimit = 100; // max number of tracks allowed in a single "save tracks to playlist" request in spotify +const offsetIncrement = 50; // max number of tracks allowed in a single "get saved tracks" request in spotify +const msBetweenTrackRequests = 250; +// TODO: TOKEN TO BE PER USER SESSION RATHER THAN ONE FOR THE WHOLE SERVER: GET USER ID AFTER RECEIVING AUTH TOKEN, SAVE AS ID TOKEN PAIR, SEND BACK USER ID TO CLIENT FOR USE IN SUBSEQUENT REQUESTS +let tokens = ""; +// TODO: CHECK ERROR HANDLING IN CATCH METHODS // CREATE CUSTOM HANDLER MIDDLEWARE +// TODO: REFACTOR AXIOS REQUESTS INTO MODELLER +// TODO: separate gettokens/checktokens part as a middleware to be passed through in each request +exports.getTokens = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + const { code } = req.body; + tokens = yield modeller_1.default.requestToken(code, next); + res.sendStatus(200); +}); +exports.getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + const { code } = req.body; + let initialOffset = 0; + let trackData = []; + if (!tokens) { + tokens = yield modeller_1.default.requestToken(code, next); + } + function timeOutPromise() { + return new Promise((resolve) => setTimeout(() => resolve(), msBetweenTrackRequests)); + } + function fetchTracksAsync(offset) { + return __awaiter(this, void 0, void 0, function* () { + let trackBufferResponse; + try { + trackBufferResponse = yield modeller_1.default.requestTracks(spotifyTracksUrl, tokens, offset); + } + catch (err) { + console.log("inner error 😎"); + console.log(err.response.status); // 404 + if (err.response.status === 404) { + yield timeOutPromise(); + yield fetchTracksAsync(offset); + return; + } + } + trackData = [...trackData, ...trackBufferResponse.data.items]; + console.log("received tracks for offset:", offset); + if (trackBufferResponse.data.next) { + offset += offsetIncrement; + yield fetchTracksAsync(offset); + } + }); + } + try { + yield fetchTracksAsync(initialOffset); + console.log("sending " + trackData.length + " tracks"); + res.status = 200; + res.send(trackData); + } + catch (err) { + console.log("outer error 😎"); + console.log("something went wrong while fetching tracks"); + console.log(err); + res.sendStatus(500); + } +}); +exports.getArtists = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + const { code, offset, nextUrl } = req.body; + if (!tokens) { + tokens = yield modeller_1.default.requestToken(code, next); + } + modeller_1.default + .requestArtists(spotifyArtistsUrl, nextUrl, tokens) + .then((artistResponse) => { + res.statusCode = 200; + res.send(artistResponse.data); + }) + .catch((err) => console.log(err.response.data)); +}); +exports.getPlaylistCover = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + const { code, playlistId } = req.body; + if (!tokens) { + tokens = yield modeller_1.default.requestToken(code, next); + } + modeller_1.default + .requestPlaylistCover(spotifyPlaylistUrl, playlistId, tokens) + .then((coverResponse) => { + res.statusCode = 200; + console.log(coverResponse); + res.send(coverResponse.data); + }) + .catch((err) => console.log(err.response.data)); +}); +exports.createPlaylist = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + const { code, playlistName, trackURIs } = req.body; + if (!tokens) { + tokens = yield modeller_1.default.requestToken(code, next); + } + const userResponse = yield modeller_1.default.requestUser(spotifyUserUrl, tokens); + const userID = userResponse.data.id; + const createPlaylistResponse = yield modeller_1.default.requestCreatePlaylist(spotifyCreatePlaylistUrl, playlistName, userID, tokens); + const playlistData = createPlaylistResponse.data; + function addTracks(trackArr) { + return modeller_1.default.requestAddTracks(spotifyPlaylistUrl, playlistData.id, trackArr, tokens); + } + // Spotify has a track limit per request, so below we check if multiple requests are necessary (TrackQueue is all the tracks to be added in a queue form, with multiple tracks "shifting" per request.) + controller_helpers_1.requestWhileQueued(trackURIs, saveTrackRequestLimit, addTracks); + res.status(200); + res.send(JSON.stringify(playlistData)); +}); diff --git a/server/index.js b/server/index.js new file mode 100644 index 0000000..0d0866c --- /dev/null +++ b/server/index.js @@ -0,0 +1,23 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// DEPENDENCIES +const express_1 = __importDefault(require("express")); +const morgan_1 = __importDefault(require("morgan")); +const cors_1 = __importDefault(require("cors")); +const router_1 = __importDefault(require("./router")); +// SERVER CONFIG +const app = express_1.default(); +const port = 3001; +const host = "127.0.0.1"; +// MIDDLEWARES +app.use(cors_1.default()); +app.use(express_1.default.json()); +app.use(morgan_1.default("dev")); +app.use(router_1.default); +// CONNECTION TO DB & LISTENING TO PORT +app.listen(port, host, () => { + console.log(`Server running at ${host}:${port}! 🐯`); +}); diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js new file mode 100644 index 0000000..414c93b --- /dev/null +++ b/server/modeller/modeller.js @@ -0,0 +1,100 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const axios_1 = __importDefault(require("axios")); +const config_1 = require("../config"); +const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; +const redirectUri = "http://localhost:3000/main"; +// TODO: REFACTOR WITH A REQUEST TEMPLATE +const requestToken = (code, next) => { + return axios_1.default + .request({ + method: "POST", + url: spotifyTokenUrl, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.clientID}&client_secret=${config_1.clientSecret}`, + }) + .then((tokenResponse) => { + return tokenResponse.data; + }) + .catch(next); +}; +const requestTracks = (spotifyTracksUrl, tokens, offset) => { + return axios_1.default.request({ + method: "GET", + url: spotifyTracksUrl + `?offset=${offset}&limit=50`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); +}; +const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { + return axios_1.default.request({ + method: "GET", + url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); +}; +const requestUser = (spotifyUserUrl, tokens) => { + return axios_1.default.request({ + method: "GET", + url: spotifyUserUrl, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); +}; +const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { + return axios_1.default.request({ + method: "GET", + url: spotifyPlaylistUrl + `/${playlistId}/images`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); +}; +const requestCreatePlaylist = (spotifyCreatePlaylistUrl, playlistName, userID, tokens) => { + return axios_1.default.request({ + method: "POST", + url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { name: playlistName }, + }); +}; +const requestAddTracks = (spotifySaveTracksUrl, playlistID, trackArr, tokens) => { + return axios_1.default.request({ + method: "POST", + url: spotifySaveTracksUrl + `/${playlistID}/tracks`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { + uris: trackArr, + }, + }); +}; +exports.default = { + requestToken, + requestTracks, + requestArtists, + requestUser, + requestPlaylistCover, + requestCreatePlaylist, + requestAddTracks, +}; diff --git a/server/package.json b/server/package.json index 26a889c..2a3a46f 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,9 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "tsc; nodemon", + "dev": "nodemon ./index.ts" }, "author": "", "license": "ISC", diff --git a/server/router.js b/server/router.js new file mode 100644 index 0000000..1f3e5e9 --- /dev/null +++ b/server/router.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const router = express_1.Router(); +const controller_1 = __importDefault(require("./controller/controller")); +router.post("/tracks", controller_1.default.getTracks); +router.post("/tokens", controller_1.default.getTokens); +router.post("/artists", controller_1.default.getArtists); +router.post("/create", controller_1.default.createPlaylist); +router.post("/cover", controller_1.default.getPlaylistCover); +exports.default = router; From 29bb086485355f4f6e39f0ce24fef461535d64c2 Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 14:25:19 +0000 Subject: [PATCH 13/46] fix(controller): updated to ts --- server/config.ts | 4 ++++ server/controller/controller-helpers.js | 5 ++++- server/controller/controller-helpers.ts | 2 +- server/controller/controller.js | 18 ++++++++++++------ server/controller/controller.ts | 24 +++++++++++++----------- server/index.ts | 4 ++-- server/modeller/modeller.js | 4 ++-- server/modeller/modeller.ts | 4 ++-- server/router.js | 15 ++++++--------- server/router.ts | 12 ++++++------ 10 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 server/config.ts diff --git a/server/config.ts b/server/config.ts new file mode 100644 index 0000000..f0fd489 --- /dev/null +++ b/server/config.ts @@ -0,0 +1,4 @@ +export default { + clientID: '8bc6f1323c3a4081bc3416b632218513', + clientSecret: '4b9d61d555b74a24b703e09978dc5f23', +}; diff --git a/server/controller/controller-helpers.js b/server/controller/controller-helpers.js index ceab268..ceac894 100644 --- a/server/controller/controller-helpers.js +++ b/server/controller/controller-helpers.js @@ -8,7 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; -exports.requestWhileQueued = (initialQueue, limit, handler) => __awaiter(void 0, void 0, void 0, function* () { +Object.defineProperty(exports, "__esModule", { value: true }); +exports.requestWhileQueued = void 0; +const requestWhileQueued = (initialQueue, limit, handler) => __awaiter(void 0, void 0, void 0, function* () { let queueArr = initialQueue.slice(); while (queueArr.length > 0) { if (queueArr.length < limit) { @@ -21,3 +23,4 @@ exports.requestWhileQueued = (initialQueue, limit, handler) => __awaiter(void 0, } } }); +exports.requestWhileQueued = requestWhileQueued; diff --git a/server/controller/controller-helpers.ts b/server/controller/controller-helpers.ts index a827d6b..d83f570 100644 --- a/server/controller/controller-helpers.ts +++ b/server/controller/controller-helpers.ts @@ -1,4 +1,4 @@ -exports.requestWhileQueued = async (initialQueue, limit, handler) => { +export const requestWhileQueued = async (initialQueue: any[], limit: number, handler: Function) => { let queueArr = initialQueue.slice(); diff --git a/server/controller/controller.js b/server/controller/controller.js index 6922df3..6096203 100644 --- a/server/controller/controller.js +++ b/server/controller/controller.js @@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.createPlaylist = exports.getPlaylistCover = exports.getArtists = exports.getTracks = exports.getTokens = void 0; const modeller_1 = __importDefault(require("../modeller/modeller")); const controller_helpers_1 = require("./controller-helpers"); const baseUrl = "https://api.spotify.com/v1"; @@ -28,12 +29,13 @@ let tokens = ""; // TODO: CHECK ERROR HANDLING IN CATCH METHODS // CREATE CUSTOM HANDLER MIDDLEWARE // TODO: REFACTOR AXIOS REQUESTS INTO MODELLER // TODO: separate gettokens/checktokens part as a middleware to be passed through in each request -exports.getTokens = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const getTokens = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { const { code } = req.body; tokens = yield modeller_1.default.requestToken(code, next); res.sendStatus(200); }); -exports.getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +exports.getTokens = getTokens; +const getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { const { code } = req.body; let initialOffset = 0; let trackData = []; @@ -69,7 +71,7 @@ exports.getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, functi try { yield fetchTracksAsync(initialOffset); console.log("sending " + trackData.length + " tracks"); - res.status = 200; + res.status(200); res.send(trackData); } catch (err) { @@ -79,7 +81,8 @@ exports.getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, functi res.sendStatus(500); } }); -exports.getArtists = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +exports.getTracks = getTracks; +const getArtists = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { const { code, offset, nextUrl } = req.body; if (!tokens) { tokens = yield modeller_1.default.requestToken(code, next); @@ -92,7 +95,8 @@ exports.getArtists = (req, res, next) => __awaiter(void 0, void 0, void 0, funct }) .catch((err) => console.log(err.response.data)); }); -exports.getPlaylistCover = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +exports.getArtists = getArtists; +const getPlaylistCover = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { const { code, playlistId } = req.body; if (!tokens) { tokens = yield modeller_1.default.requestToken(code, next); @@ -106,7 +110,8 @@ exports.getPlaylistCover = (req, res, next) => __awaiter(void 0, void 0, void 0, }) .catch((err) => console.log(err.response.data)); }); -exports.createPlaylist = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +exports.getPlaylistCover = getPlaylistCover; +const createPlaylist = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { const { code, playlistName, trackURIs } = req.body; if (!tokens) { tokens = yield modeller_1.default.requestToken(code, next); @@ -123,3 +128,4 @@ exports.createPlaylist = (req, res, next) => __awaiter(void 0, void 0, void 0, f res.status(200); res.send(JSON.stringify(playlistData)); }); +exports.createPlaylist = createPlaylist; diff --git a/server/controller/controller.ts b/server/controller/controller.ts index 7926e59..809117b 100644 --- a/server/controller/controller.ts +++ b/server/controller/controller.ts @@ -1,8 +1,10 @@ +import { Request, Response, NextFunction } from 'express'; import axios from "axios"; import { renderSync } from "node-sass"; import modeller from "../modeller/modeller"; import { requestWhileQueued } from "./controller-helpers"; + const baseUrl = "https://api.spotify.com/v1"; const spotifyTracksUrl = baseUrl + "/me/tracks"; const spotifyArtistsUrl = baseUrl + "/me/following"; @@ -20,29 +22,29 @@ let tokens = ""; // TODO: REFACTOR AXIOS REQUESTS INTO MODELLER // TODO: separate gettokens/checktokens part as a middleware to be passed through in each request -exports.getTokens = async (req, res, next) => { +export const getTokens = async (req: Request, res: Response, next: NextFunction ) => { const { code } = req.body; tokens = await modeller.requestToken(code, next); res.sendStatus(200); }; -exports.getTracks = async (req, res, next) => { +export const getTracks = async (req: Request, res: Response, next: NextFunction) => { const { code } = req.body; let initialOffset = 0; - let trackData = []; + let trackData: any[] = []; if (!tokens) { tokens = await modeller.requestToken(code, next); } function timeOutPromise() { - return new Promise((resolve) => + return new Promise((resolve) => setTimeout(() => resolve(), msBetweenTrackRequests) ); } - async function fetchTracksAsync(offset) { - let trackBufferResponse; + async function fetchTracksAsync(offset: number) { + let trackBufferResponse: any; try { trackBufferResponse = await modeller.requestTracks( @@ -72,7 +74,7 @@ exports.getTracks = async (req, res, next) => { try { await fetchTracksAsync(initialOffset); console.log("sending " + trackData.length + " tracks"); - res.status = 200; + res.status(200); res.send(trackData); } catch (err) { console.log("outer error 😎"); @@ -82,7 +84,7 @@ exports.getTracks = async (req, res, next) => { } }; -exports.getArtists = async (req, res, next) => { +export const getArtists = async (req: Request, res: Response, next: NextFunction) => { const { code, offset, nextUrl } = req.body; if (!tokens) { @@ -98,7 +100,7 @@ exports.getArtists = async (req, res, next) => { .catch((err) => console.log(err.response.data)); }; -exports.getPlaylistCover = async (req, res, next) => { +export const getPlaylistCover = async (req: Request, res: Response, next: NextFunction) => { const { code, playlistId } = req.body; if (!tokens) { @@ -115,7 +117,7 @@ exports.getPlaylistCover = async (req, res, next) => { .catch((err) => console.log(err.response.data)); }; -exports.createPlaylist = async (req, res, next) => { +export const createPlaylist = async (req: Request, res: Response, next: NextFunction) => { const { code, playlistName, trackURIs } = req.body; if (!tokens) { @@ -133,7 +135,7 @@ exports.createPlaylist = async (req, res, next) => { ); const playlistData = createPlaylistResponse.data; - function addTracks(trackArr) { + function addTracks(trackArr: []) { return modeller.requestAddTracks( spotifyPlaylistUrl, playlistData.id, diff --git a/server/index.ts b/server/index.ts index 9ecc21a..a665970 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,11 +1,11 @@ // DEPENDENCIES -import express from "express"; +import express, {Application} from "express"; import morgan from "morgan"; import cors from "cors"; import router from "./router"; // SERVER CONFIG -const app = express(); +const app : Application = express(); const port = 3001; const host = "127.0.0.1"; diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index 414c93b..d4aaf70 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); -const config_1 = require("../config"); +const config_1 = __importDefault(require("../config")); const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; const redirectUri = "http://localhost:3000/main"; // TODO: REFACTOR WITH A REQUEST TEMPLATE @@ -16,7 +16,7 @@ const requestToken = (code, next) => { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.clientID}&client_secret=${config_1.clientSecret}`, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.default.clientID}&client_secret=${config_1.default.clientSecret}`, }) .then((tokenResponse) => { return tokenResponse.data; diff --git a/server/modeller/modeller.ts b/server/modeller/modeller.ts index 3743378..854cf92 100644 --- a/server/modeller/modeller.ts +++ b/server/modeller/modeller.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { clientID, clientSecret } from "../config"; +import config from "../config"; const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; const redirectUri = "http://localhost:3000/main"; @@ -12,7 +12,7 @@ const requestToken = (code, next) => { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${clientID}&client_secret=${clientSecret}`, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config.clientID}&client_secret=${config.clientSecret}`, }) .then((tokenResponse) => { return tokenResponse.data; diff --git a/server/router.js b/server/router.js index 1f3e5e9..2d06f51 100644 --- a/server/router.js +++ b/server/router.js @@ -1,14 +1,11 @@ "use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const router = express_1.Router(); -const controller_1 = __importDefault(require("./controller/controller")); -router.post("/tracks", controller_1.default.getTracks); -router.post("/tokens", controller_1.default.getTokens); -router.post("/artists", controller_1.default.getArtists); -router.post("/create", controller_1.default.createPlaylist); -router.post("/cover", controller_1.default.getPlaylistCover); +const controller_1 = require("./controller/controller"); +router.post("/tracks", controller_1.getTracks); +router.post("/tokens", controller_1.getTokens); +router.post("/artists", controller_1.getArtists); +router.post("/create", controller_1.createPlaylist); +router.post("/cover", controller_1.getPlaylistCover); exports.default = router; diff --git a/server/router.ts b/server/router.ts index 2a49a7b..1d40b10 100644 --- a/server/router.ts +++ b/server/router.ts @@ -1,11 +1,11 @@ import { Router } from "express"; const router = Router(); -import controller from "./controller/controller"; +import { getTracks, getTokens, getArtists, createPlaylist, getPlaylistCover} from "./controller/controller"; -router.post("/tracks", controller.getTracks); -router.post("/tokens", controller.getTokens); -router.post("/artists", controller.getArtists); -router.post("/create", controller.createPlaylist); -router.post("/cover", controller.getPlaylistCover); +router.post("/tracks", getTracks); +router.post("/tokens", getTokens); +router.post("/artists", getArtists); +router.post("/create", createPlaylist); +router.post("/cover", getPlaylistCover); export default router; From ddb7b39d0e458e49a7494c664587e091a648aaad Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 14:28:41 +0000 Subject: [PATCH 14/46] fix(packagejson): added to git --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcfdfd4..f7a1ddb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "listspotter", "version": "1.0.0", "description": "A Spotify API based app that allows you to create a playlist from all your saved songs in Spotify, based on their genres.", - "main": "index.js", + "main": "index", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, From 3353582550e061adbe162c7de0874c40e4d4c15a Mon Sep 17 00:00:00 2001 From: Gero Date: Fri, 12 Mar 2021 14:32:07 +0000 Subject: [PATCH 15/46] fix(modeller): changed to ts --- server/modeller/modeller.js | 4 ++-- server/modeller/modeller.ts | 41 ++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index 414c93b..cef3019 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); -const config_1 = require("../config"); +const config_js_1 = require("../config.js"); const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; const redirectUri = "http://localhost:3000/main"; // TODO: REFACTOR WITH A REQUEST TEMPLATE @@ -16,7 +16,7 @@ const requestToken = (code, next) => { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.clientID}&client_secret=${config_1.clientSecret}`, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_js_1.clientID}&client_secret=${config_js_1.clientSecret}`, }) .then((tokenResponse) => { return tokenResponse.data; diff --git a/server/modeller/modeller.ts b/server/modeller/modeller.ts index 3743378..652b229 100644 --- a/server/modeller/modeller.ts +++ b/server/modeller/modeller.ts @@ -1,10 +1,11 @@ import axios from "axios"; -import { clientID, clientSecret } from "../config"; +import { clientID, clientSecret } from "../config.js"; const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; const redirectUri = "http://localhost:3000/main"; +import { NextFunction } from "express"; // TODO: REFACTOR WITH A REQUEST TEMPLATE -const requestToken = (code, next) => { +const requestToken = (code: string, next: NextFunction) => { return axios .request({ method: "POST", @@ -20,7 +21,11 @@ const requestToken = (code, next) => { .catch(next); }; -const requestTracks = (spotifyTracksUrl, tokens, offset) => { +const requestTracks = ( + spotifyTracksUrl: string, + tokens: any, + offset: string +) => { return axios.request({ method: "GET", url: spotifyTracksUrl + `?offset=${offset}&limit=50`, @@ -31,7 +36,11 @@ const requestTracks = (spotifyTracksUrl, tokens, offset) => { }); }; -const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { +const requestArtists = ( + spotifyArtistsUrl: string, + nextUrl: string, + tokens: any +) => { return axios.request({ method: "GET", url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", @@ -43,7 +52,7 @@ const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { }); }; -const requestUser = (spotifyUserUrl, tokens) => { +const requestUser = (spotifyUserUrl: string, tokens: any) => { return axios.request({ method: "GET", url: spotifyUserUrl, @@ -54,7 +63,11 @@ const requestUser = (spotifyUserUrl, tokens) => { }); }; -const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { +const requestPlaylistCover = ( + spotifyPlaylistUrl: string, + playlistId: string, + tokens: any +) => { return axios.request({ method: "GET", url: spotifyPlaylistUrl + `/${playlistId}/images`, @@ -67,10 +80,10 @@ const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { }; const requestCreatePlaylist = ( - spotifyCreatePlaylistUrl, - playlistName, - userID, - tokens + spotifyCreatePlaylistUrl: string, + playlistName: string, + userID: string, + tokens: any ) => { return axios.request({ method: "POST", @@ -84,10 +97,10 @@ const requestCreatePlaylist = ( }; const requestAddTracks = ( - spotifySaveTracksUrl, - playlistID, - trackArr, - tokens + spotifySaveTracksUrl: string, + playlistID: string, + trackArr: string[], + tokens: any ) => { return axios.request({ method: "POST", From 3429cd28ee425c5f1698eaf9de018b9e2e77a7c3 Mon Sep 17 00:00:00 2001 From: Pamela Date: Fri, 12 Mar 2021 14:46:16 +0000 Subject: [PATCH 16/46] style(server): typescript add --- server/.prettierrc.ts | 2 +- server/modeller/modeller.js | 168 +++++++++++++++++------------------- server/modeller/modeller.ts | 2 +- server/package.json | 1 - 4 files changed, 79 insertions(+), 94 deletions(-) diff --git a/server/.prettierrc.ts b/server/.prettierrc.ts index 0310300..b0a881e 100644 --- a/server/.prettierrc.ts +++ b/server/.prettierrc.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { bracketSpacing: true, singleQuote: true, trailingComma: 'all', diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index f30a390..d4aaf70 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -1,114 +1,100 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); - const config_1 = __importDefault(require("../config")); - const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; const redirectUri = "http://localhost:3000/main"; // TODO: REFACTOR WITH A REQUEST TEMPLATE const requestToken = (code, next) => { - return axios_1.default - .request({ - method: "POST", - url: spotifyTokenUrl, - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.default.clientID}&client_secret=${config_1.default.clientSecret}`, + return axios_1.default + .request({ + method: "POST", + url: spotifyTokenUrl, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.default.clientID}&client_secret=${config_1.default.clientSecret}`, }) - .then((tokenResponse) => { - return tokenResponse.data; + .then((tokenResponse) => { + return tokenResponse.data; }) - .catch(next); + .catch(next); }; const requestTracks = (spotifyTracksUrl, tokens, offset) => { - return axios_1.default.request({ - method: "GET", - url: spotifyTracksUrl + `?offset=${offset}&limit=50`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/x-www-form-urlencoded", - }, - }); + return axios_1.default.request({ + method: "GET", + url: spotifyTracksUrl + `?offset=${offset}&limit=50`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); }; const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { - return axios_1.default.request({ - method: "GET", - url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - }); + return axios_1.default.request({ + method: "GET", + url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); }; const requestUser = (spotifyUserUrl, tokens) => { - return axios_1.default.request({ - method: "GET", - url: spotifyUserUrl, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/x-www-form-urlencoded", - }, - }); + return axios_1.default.request({ + method: "GET", + url: spotifyUserUrl, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/x-www-form-urlencoded", + }, + }); }; const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { - return axios_1.default.request({ - method: "GET", - url: spotifyPlaylistUrl + `/${playlistId}/images`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - }); + return axios_1.default.request({ + method: "GET", + url: spotifyPlaylistUrl + `/${playlistId}/images`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + }); }; -const requestCreatePlaylist = ( - spotifyCreatePlaylistUrl, - playlistName, - userID, - tokens -) => { - return axios_1.default.request({ - method: "POST", - url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - }, - data: { name: playlistName }, - }); +const requestCreatePlaylist = (spotifyCreatePlaylistUrl, playlistName, userID, tokens) => { + return axios_1.default.request({ + method: "POST", + url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { name: playlistName }, + }); }; -const requestAddTracks = ( - spotifySaveTracksUrl, - playlistID, - trackArr, - tokens -) => { - return axios_1.default.request({ - method: "POST", - url: spotifySaveTracksUrl + `/${playlistID}/tracks`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - }, - data: { - uris: trackArr, - }, - }); +const requestAddTracks = (spotifySaveTracksUrl, playlistID, trackArr, tokens) => { + return axios_1.default.request({ + method: "POST", + url: spotifySaveTracksUrl + `/${playlistID}/tracks`, + headers: { + Authorization: `Bearer ${tokens["access_token"]}`, + "Content-Type": "application/json", + }, + data: { + uris: trackArr, + }, + }); }; exports.default = { - requestToken, - requestTracks, - requestArtists, - requestUser, - requestPlaylistCover, - requestCreatePlaylist, - requestAddTracks, + requestToken, + requestTracks, + requestArtists, + requestUser, + requestPlaylistCover, + requestCreatePlaylist, + requestAddTracks, }; diff --git a/server/modeller/modeller.ts b/server/modeller/modeller.ts index 674b849..21717b8 100644 --- a/server/modeller/modeller.ts +++ b/server/modeller/modeller.ts @@ -25,7 +25,7 @@ const requestToken = (code: string, next: NextFunction) => { const requestTracks = ( spotifyTracksUrl: string, tokens: any, - offset: string + offset: number ) => { return axios.request({ method: "GET", diff --git a/server/package.json b/server/package.json index 2a3a46f..2e596a1 100644 --- a/server/package.json +++ b/server/package.json @@ -21,7 +21,6 @@ "ts-node": "^9.1.1", "typescript": "^4.2.3" }, - "type": "module", "devDependencies": { "@types/cors": "^2.8.10", "@types/morgan": "^1.9.2", From 27747e2bbf316232e67a0458be78fa8bba722985 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 10:37:46 +0000 Subject: [PATCH 17/46] feat(genre_test): added test file --- client/src/components/Main/Genres/__tests__/test.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/components/Main/Genres/__tests__/test.js diff --git a/client/src/components/Main/Genres/__tests__/test.js b/client/src/components/Main/Genres/__tests__/test.js new file mode 100644 index 0000000..e69de29 From 3c8c55567cdb23b61b42017c667629e1419cc3e7 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 12:20:16 +0000 Subject: [PATCH 18/46] chore(prettier): setup for client side formatting --- client/.eslintrc.json | 34 +++++ client/.prettierrc.json | 5 + client/package-lock.json | 138 ++++++++++++++++-- client/package.json | 5 +- .../components/Main/Genres/__tests__/test.js | 3 + client/src/components/Main/main-helpers.tsx | 2 + client/src/components/Main/main-index.tsx | 2 +- 7 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 client/.eslintrc.json create mode 100644 client/.prettierrc.json diff --git a/client/.eslintrc.json b/client/.eslintrc.json new file mode 100644 index 0000000..aa2c796 --- /dev/null +++ b/client/.eslintrc.json @@ -0,0 +1,34 @@ +{ + "env": { + "browser": true, + "es6": true, + "jquery": true, + "node": true, + "mocha": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 8 + }, + "plugins": [ + "json" + ], + "rules": { + "indent": [ + "error", + 2 + ], + "keyword-spacing": "error", + "linebreak-style": "error", + "quotes": [ + "error", + "single" + ], + "semi": "error", + "space-before-blocks": "error", + "space-before-function-paren": "error", + "no-undef": "off", + "no-unused-vars": "off" + } + } \ No newline at end of file diff --git a/client/.prettierrc.json b/client/.prettierrc.json new file mode 100644 index 0000000..2e760ff --- /dev/null +++ b/client/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "singleQuote": true +} \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index ecbf530..50a5aa2 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -3676,6 +3676,15 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "optional": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -5650,9 +5659,9 @@ } }, "eslint": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.21.0.tgz", - "integrity": "sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.22.0.tgz", + "integrity": "sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==", "requires": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.0", @@ -5671,7 +5680,7 @@ "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -5679,7 +5688,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -5742,11 +5751,11 @@ } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.6.0.tgz", + "integrity": "sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ==", "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "has-flag": { @@ -5785,6 +5794,11 @@ "has-flag": "^4.0.0" } }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5795,6 +5809,62 @@ } } }, + "eslint-config-airbnb": { + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", + "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^14.2.1", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-config-airbnb-typescript-prettier": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript-prettier/-/eslint-config-airbnb-typescript-prettier-4.1.0.tgz", + "integrity": "sha512-2raFWBsr/POlCAfo9h7+AWfVO9n89e6jOuG20eLEaElZq3QveyxfDbRBiSsJEH+o2eaX3o666mYNn3pSkb7/eQ==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "^4.7.0", + "@typescript-eslint/parser": "^4.7.0", + "eslint-config-airbnb": "^18.2.1", + "eslint-config-prettier": "^6.15.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4.2.0" + } + }, + "eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, "eslint-config-react-app": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", @@ -5988,6 +6058,15 @@ } } }, + "eslint-plugin-prettier": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-plugin-react": { "version": "7.22.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz", @@ -6508,6 +6587,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", @@ -6589,6 +6674,12 @@ } } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, "filesize": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", @@ -12556,6 +12647,21 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -15047,9 +15153,9 @@ }, "dependencies": { "ajv": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", - "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.1.tgz", + "integrity": "sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -15791,9 +15897,9 @@ "optional": true }, "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" }, "v8-to-istanbul": { "version": "7.1.0", @@ -16008,6 +16114,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1" } }, @@ -16610,6 +16717,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1" } }, diff --git a/client/package.json b/client/package.json index 282449f..176e739 100644 --- a/client/package.json +++ b/client/package.json @@ -45,6 +45,9 @@ ] }, "devDependencies": { - "@types/react-router-dom": "^5.1.7" + "@types/react-router-dom": "^5.1.7", + "eslint": "^7.22.0", + "eslint-config-airbnb-typescript-prettier": "^4.1.0", + "prettier": "^2.2.1" } } diff --git a/client/src/components/Main/Genres/__tests__/test.js b/client/src/components/Main/Genres/__tests__/test.js index e69de29..0369c64 100644 --- a/client/src/components/Main/Genres/__tests__/test.js +++ b/client/src/components/Main/Genres/__tests__/test.js @@ -0,0 +1,3 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import Genre from '../genres-index'; diff --git a/client/src/components/Main/main-helpers.tsx b/client/src/components/Main/main-helpers.tsx index 0c72f54..d05b080 100644 --- a/client/src/components/Main/main-helpers.tsx +++ b/client/src/components/Main/main-helpers.tsx @@ -29,8 +29,10 @@ export function fetchArtistsWithOffset (code: string, setState: React.Dispatch { await getTokens(code); if (tracks.length === 0) { - const trackList = getTracks(code).then((trackList) => { + getTracks(code).then((trackList) => { console.log(trackList.length + ' tracks received'); setTracks(trackList); }); From d06bae2a42288e3e65f2a4c853f33a3e5405e1e7 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 12:59:37 +0000 Subject: [PATCH 19/46] chore(prettier): fixed format bugs --- client/.eslintrc.json | 34 ------ client/{.prettierrc.json => .prettierrc} | 2 +- client/src/apiService.tsx | 96 +++++++-------- .../components/Main/Artists/artists-index.tsx | 29 +++-- .../components/Main/Genres/genres-helpers.tsx | 44 ++++--- .../components/Main/Genres/genres-index.tsx | 74 ++++++++---- .../Playlist Item/playlist-item-helpers.tsx | 14 +-- .../Main/Playlist/playlist-helpers.tsx | 4 +- client/src/components/Main/main-helpers.tsx | 81 ++++++++----- client/src/components/Main/main-index.tsx | 110 +++++++++++++----- 10 files changed, 286 insertions(+), 202 deletions(-) delete mode 100644 client/.eslintrc.json rename client/{.prettierrc.json => .prettierrc} (75%) diff --git a/client/.eslintrc.json b/client/.eslintrc.json deleted file mode 100644 index aa2c796..0000000 --- a/client/.eslintrc.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "jquery": true, - "node": true, - "mocha": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 8 - }, - "plugins": [ - "json" - ], - "rules": { - "indent": [ - "error", - 2 - ], - "keyword-spacing": "error", - "linebreak-style": "error", - "quotes": [ - "error", - "single" - ], - "semi": "error", - "space-before-blocks": "error", - "space-before-function-paren": "error", - "no-undef": "off", - "no-unused-vars": "off" - } - } \ No newline at end of file diff --git a/client/.prettierrc.json b/client/.prettierrc similarity index 75% rename from client/.prettierrc.json rename to client/.prettierrc index 2e760ff..397afff 100644 --- a/client/.prettierrc.json +++ b/client/.prettierrc @@ -1,5 +1,5 @@ { "trailingComma": "es5", - "tabWidth": 4, + "tabWidth": 2, "singleQuote": true } \ No newline at end of file diff --git a/client/src/apiService.tsx b/client/src/apiService.tsx index de38806..bfbc46c 100644 --- a/client/src/apiService.tsx +++ b/client/src/apiService.tsx @@ -1,60 +1,64 @@ -const baseUrl = 'http://localhost:3001' +const baseUrl = 'http://localhost:3001'; export const getTokens = async (code: string) => { - return fetch(baseUrl + '/tokens', { - method: 'POST', - body: JSON.stringify({code}), - headers: { - 'Content-Type': 'application/json' - } - }); + return fetch(baseUrl + '/tokens', { + method: 'POST', + body: JSON.stringify({ code }), + headers: { + 'Content-Type': 'application/json', + }, + }); }; export const getTracks = async (code: string) => { - const response = await fetch(baseUrl + '/tracks', { - method: 'POST', - body: JSON.stringify({code}), - headers: { - 'Content-Type': 'application/json' - } - }); - return await response.json(); + const response = await fetch(baseUrl + '/tracks', { + method: 'POST', + body: JSON.stringify({ code }), + headers: { + 'Content-Type': 'application/json', + }, + }); + return await response.json(); }; export const getArtists = async (code: string, nextUrl: string | undefined) => { - // TODO: CACHE IMAGES + // TODO: CACHE IMAGES - const response = await fetch(baseUrl + '/artists', { - method: 'POST', - body: JSON.stringify({code, nextUrl}), - headers: { - 'Content-Type': 'application/json' - } - }); - const artists = await response.json(); - return artists; + const response = await fetch(baseUrl + '/artists', { + method: 'POST', + body: JSON.stringify({ code, nextUrl }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const artists = await response.json(); + return artists; }; -export const createPlaylist = async (code: string, playlistName: string, trackURIs: string[]) => { - const response = await fetch(baseUrl + '/create', { - method: 'POST', - body: JSON.stringify({code, playlistName, trackURIs}), - headers: { - 'Content-Type': 'application/json' - } - }); - const playlistData = await response.json(); - return playlistData; +export const createPlaylist = async ( + code: string, + playlistName: string, + trackURIs: string[] +) => { + const response = await fetch(baseUrl + '/create', { + method: 'POST', + body: JSON.stringify({ code, playlistName, trackURIs }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const playlistData = await response.json(); + return playlistData; }; export const getPlaylistCover = async (code: string, playlistId: string) => { - const response = await fetch(baseUrl + '/cover', { - method: 'POST', - body: JSON.stringify({code, playlistId}), - headers: { - 'Content-Type': 'application/json' - } - }); - const playlistData = await response.json(); - return playlistData; -}; \ No newline at end of file + const response = await fetch(baseUrl + '/cover', { + method: 'POST', + body: JSON.stringify({ code, playlistId }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const playlistData = await response.json(); + return playlistData; +}; diff --git a/client/src/components/Main/Artists/artists-index.tsx b/client/src/components/Main/Artists/artists-index.tsx index dc6007f..86afe83 100644 --- a/client/src/components/Main/Artists/artists-index.tsx +++ b/client/src/components/Main/Artists/artists-index.tsx @@ -3,20 +3,31 @@ import { Artist } from 'interfaces/spotifyObjects'; import ArtistItem from './Artist Item/artist-item-index'; export interface Props { - artistList: Artist[], - toggleHandler: (artistId: string) => void, - loaded: boolean + artistList: Artist[]; + toggleHandler: (artistId: string) => void; + loaded: boolean; } const Artists: React.FC = ({ artistList, toggleHandler, loaded }) => { return ( // SORT ARTISTS BY ALPHABETICAL ORDER -
- {artistList.length === 0 &&

Choose a genre to view related artists.

} - {artistList.sort((a, b) => a.name < b.name ? -1 : 1) - .map((artist) => )} +
+ {artistList.length === 0 && ( +

+ Choose a genre to view related artists. +

+ )} + {artistList + .sort((a, b) => (a.name < b.name ? -1 : 1)) + .map((artist) => ( + + ))}
); -} +}; -export default Artists; \ No newline at end of file +export default Artists; diff --git a/client/src/components/Main/Genres/genres-helpers.tsx b/client/src/components/Main/Genres/genres-helpers.tsx index 4d9b028..0a3a4c2 100644 --- a/client/src/components/Main/Genres/genres-helpers.tsx +++ b/client/src/components/Main/Genres/genres-helpers.tsx @@ -1,7 +1,7 @@ import { GenreDb } from 'interfaces/genreObjects'; import { Artist } from 'interfaces/spotifyObjects'; -export function getSortedGenreKeys (genres: GenreDb, selectedArtists: Artist[]) { +export function getSortedGenreKeys(genres: GenreDb, selectedArtists: Artist[]) { const sortedKeys = Object.keys(genres).sort((a, b) => { // uncomment if you want to have selected ones at the top if (genres[a].selected && !genres[b].selected) return -1; @@ -9,42 +9,54 @@ export function getSortedGenreKeys (genres: GenreDb, selectedArtists: Artist[]) // return genres[a].artists.length > genres[b].artists.length ? -1 : 1 - function countBasedOnSelectStatus (genre: string) { - return genres[genre].selected ? genres[genre].artists.length : countUnselected(genres, genre, selectedArtists) - }; + function countBasedOnSelectStatus(genre: string) { + return genres[genre].selected + ? genres[genre].artists.length + : countUnselected(genres, genre, selectedArtists); + } - - return countBasedOnSelectStatus(a) > countBasedOnSelectStatus(b) ? -1 : 1 + return countBasedOnSelectStatus(a) > countBasedOnSelectStatus(b) ? -1 : 1; }); return sortedKeys; } -export function getMatchingGenres (searchValue: string, genres: GenreDb) { +export function getMatchingGenres(searchValue: string, genres: GenreDb) { const searchRegex = new RegExp(searchValue, 'ig'); - return Object.entries(genres).filter(([key, value]) => key.match(searchRegex)) + return Object.entries(genres) + .filter(([key, value]) => key.match(searchRegex)) .reduce((acc, [key, value]) => { - acc[key] = value + acc[key] = value; return acc; }, {}); } - -export function genreResort (genreName: string, db: GenreDb) { +export function genreResort(genreName: string, db: GenreDb) { const splitName = genreName.split(' '); // Go over each item in } -export function countUnselected (genreList: GenreDb, genreName: string, artists: Artist[]) { +export function countUnselected( + genreList: GenreDb, + genreName: string, + artists: Artist[] +) { const genreArtists = genreList[genreName].artists; const selectedArtists = artists.filter((artist) => artist.selected); - const isSelected = (genreArtist: Artist) => selectedArtists.some((selectedArtist) => selectedArtist.id === genreArtist.id); + const isSelected = (genreArtist: Artist) => + selectedArtists.some( + (selectedArtist) => selectedArtist.id === genreArtist.id + ); const userDisabled = (genreArtist: Artist) => { - const artistInArtists = artists.find((artist) => artist.id === genreArtist.id); + const artistInArtists = artists.find( + (artist) => artist.id === genreArtist.id + ); return artistInArtists?.userDisabled; }; - return genreArtists.filter((genreArtist) => !isSelected(genreArtist) && !userDisabled(genreArtist)).length; -} \ No newline at end of file + return genreArtists.filter( + (genreArtist) => !isSelected(genreArtist) && !userDisabled(genreArtist) + ).length; +} diff --git a/client/src/components/Main/Genres/genres-index.tsx b/client/src/components/Main/Genres/genres-index.tsx index 33e299b..a37e8ec 100644 --- a/client/src/components/Main/Genres/genres-index.tsx +++ b/client/src/components/Main/Genres/genres-index.tsx @@ -4,48 +4,76 @@ import './genres-style.scss'; import GenreItem from './Genre Item/genre-item-index'; import { GenreDb } from 'interfaces/genreObjects'; import { Artist } from 'interfaces/spotifyObjects'; -import { getSortedGenreKeys, getMatchingGenres, countUnselected } from './genres-helpers'; +import { + getSortedGenreKeys, + getMatchingGenres, + countUnselected, +} from './genres-helpers'; import { WaveSpinner } from 'react-spinners-kit'; import SearchBar from 'components/common/Searchbar/searchbar-index'; export interface Props { - genreList: GenreDb, - artists: Artist[], + genreList: GenreDb; + artists: Artist[]; selectHandler: (genreName: string) => void; loaded: boolean; } -const Genres: React.FC = ({genreList, artists, selectHandler, loaded}) => { +const Genres: React.FC = ({ + genreList, + artists, + selectHandler, + loaded, +}) => { let [searchValue, setSearchValue] = useState(''); return ( - -
- {loaded ? +
+ {loaded ? ( <> -
- -
+
+ +
-
- {getSortedGenreKeys(searchValue ? getMatchingGenres(searchValue, genreList) : genreList, artists.filter((artist) => artist.selected)).map((genreName) => { - return - })} -
+
+ {getSortedGenreKeys( + searchValue + ? getMatchingGenres(searchValue, genreList) + : genreList, + artists.filter((artist) => artist.selected) + ).map((genreName) => { + return ( + + ); + })} +
- : -
- -

Loading your genres...

+ ) : ( +
+ +

Loading your genres...

- } + )} {/* - Genres will be sorted based on how many artists they contain (descending). Selected genres are always on top (getSortedGenreKeys) - If there is a search value entered in the searchbar, filter only genres whose names match with the search value (getMatchingGenres) - For each genre, the artist count shows only the number of artists in that genre that the user has not selected so far. For example, say "Rock" has 5 artists, and "Modern Rock" has 3 artists, which are also under "Rock". If the user selects "Modern Rock" first, those 3 artists will be on display. On the left hand side, "Rock" genre will now show an artist count of 2, because the other 3 has already been chosen with the "Modern Rock" tag. */} -
); -} +}; -export default Genres; \ No newline at end of file +export default Genres; diff --git a/client/src/components/Main/Playlist/Playlist Item/playlist-item-helpers.tsx b/client/src/components/Main/Playlist/Playlist Item/playlist-item-helpers.tsx index e14b71b..815d720 100644 --- a/client/src/components/Main/Playlist/Playlist Item/playlist-item-helpers.tsx +++ b/client/src/components/Main/Playlist/Playlist Item/playlist-item-helpers.tsx @@ -1,12 +1,12 @@ import { TrackItem } from 'interfaces/spotifyObjects'; export function convertMsToMinsAndSecs(ms: number) { - var minutes = Math.floor(ms / 60000); - var seconds = parseInt(((ms % 60000) / 1000).toFixed(0)); - return minutes + ":" + (seconds < 10 ? '0' : '') + seconds; + var minutes = Math.floor(ms / 60000); + var seconds = parseInt(((ms % 60000) / 1000).toFixed(0)); + return minutes + ':' + (seconds < 10 ? '0' : '') + seconds; } -export function joinArtistNames (trackItem: TrackItem) { - const artistNames = trackItem.track.artists.map((artist) => artist.name); - return artistNames.join(', '); -} \ No newline at end of file +export function joinArtistNames(trackItem: TrackItem) { + const artistNames = trackItem.track.artists.map((artist) => artist.name); + return artistNames.join(', '); +} diff --git a/client/src/components/Main/Playlist/playlist-helpers.tsx b/client/src/components/Main/Playlist/playlist-helpers.tsx index cf9c287..b4e1a15 100644 --- a/client/src/components/Main/Playlist/playlist-helpers.tsx +++ b/client/src/components/Main/Playlist/playlist-helpers.tsx @@ -1,6 +1,6 @@ import { TrackItem } from 'interfaces/spotifyObjects'; -export function trackToggleUpdate (trackId: string, trackList: TrackItem[]) { +export function trackToggleUpdate(trackId: string, trackList: TrackItem[]) { return trackList.map((trackItem) => { if (trackItem.track.id === trackId) { let updatedTrack = Object.assign({}, trackItem); @@ -10,4 +10,4 @@ export function trackToggleUpdate (trackId: string, trackList: TrackItem[]) { return trackItem; } }); -} \ No newline at end of file +} diff --git a/client/src/components/Main/main-helpers.tsx b/client/src/components/Main/main-helpers.tsx index d05b080..6f099be 100644 --- a/client/src/components/Main/main-helpers.tsx +++ b/client/src/components/Main/main-helpers.tsx @@ -1,57 +1,68 @@ -import { TrackData, TrackItem, ArtistData, Artist } from 'interfaces/spotifyObjects'; +import { + TrackData, + TrackItem, + ArtistData, + Artist, +} from 'interfaces/spotifyObjects'; import { GenreDb } from 'interfaces/genreObjects'; import { getTracks, getArtists } from 'apiService'; // TODO: Refactor into a standard fetch template -export function fetchArtistsWithOffset (code: string, setState: React.Dispatch>) { - const artistPromise = new Promise ((resolve, reject) => { +export function fetchArtistsWithOffset( + code: string, + setState: React.Dispatch> +) { + const artistPromise = new Promise((resolve, reject) => { let nextUrl; let genres: GenreDb; - async function fetchArtistsAsync (code: string, nextUrl: string | undefined) { + async function fetchArtistsAsync( + code: string, + nextUrl: string | undefined + ) { const artistData: ArtistData = await getArtists(code, nextUrl); nextUrl = artistData.artists.next; // TODO: ADD SELECTED: FALSE HERE, THEN IN MAIN INDEX, ONLY PASS THE ARTISTS WITH SELECTED-TRUE TO ARTISTS COMPONENT, UPDATE GENRE SELECT EVENT TO MARK ARTISTS AS SELECTED (GETARTISTSFROMGENRELIST BELOW WILL COPY THE WHOLE OBJECT AND ONLY CHANGE SELECTED VALUES) const newArtists = artistData.artists.items.map((artistObj) => { - return {...artistObj, selected: false} + return { ...artistObj, selected: false }; }); await setState((prevArtists) => { - let updatedArtists = [...prevArtists, ...newArtists] + let updatedArtists = [...prevArtists, ...newArtists]; if (!nextUrl) genres = generateGenres(updatedArtists); return updatedArtists; }); if (nextUrl) { - fetchArtistsAsync (code, nextUrl); + fetchArtistsAsync(code, nextUrl); } else { resolve(genres); } - }; + } fetchArtistsAsync(code, nextUrl); - }) - + }); + return artistPromise; } -export function generateGenres (artists: Artist[]) { +export function generateGenres(artists: Artist[]) { const genreDb: GenreDb = {}; artists.forEach((artist) => { artist.genres.forEach((artistGenre) => { if (!genreDb[artistGenre]) { - genreDb[artistGenre] = {artists: [artist], selected: false}; + genreDb[artistGenre] = { artists: [artist], selected: false }; } else { genreDb[artistGenre].artists.push(artist); } - }) - }) + }); + }); return genreDb; -}; +} -export function markGenreArtists (artists: Artist[], selectedGenres: GenreDb) { +export function markGenreArtists(artists: Artist[], selectedGenres: GenreDb) { return artists.map((artist) => { for (let i = 0; i < artist.genres.length; i++) { if (Object.keys(selectedGenres).includes(artist.genres[i])) { @@ -61,18 +72,19 @@ export function markGenreArtists (artists: Artist[], selectedGenres: GenreDb) { } artist.selected = false; return artist; - }) -}; + }); +} -export function filterSelectedGenres (list: GenreDb) { - return Object.entries(list).filter(([key, value]) => value.selected) - .reduce((acc, [key, value]) => { - acc[key] = value - return acc; - }, {}); -}; +export function filterSelectedGenres(list: GenreDb) { + return Object.entries(list) + .filter(([key, value]) => value.selected) + .reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {}); +} -export function artistToggleUpdate (artistId: string, artistList: Artist[]) { +export function artistToggleUpdate(artistId: string, artistList: Artist[]) { return artistList.map((artist) => { if (artist.id === artistId) { let updatedArtist = Object.assign({}, artist); @@ -84,11 +96,16 @@ export function artistToggleUpdate (artistId: string, artistList: Artist[]) { }); } -export function getSelectedTracks (artists: Artist[], tracks: TrackItem[]) { - const selectedArtists = artists.filter((artist) => artist.selected && !artist.userDisabled); +export function getSelectedTracks(artists: Artist[], tracks: TrackItem[]) { + const selectedArtists = artists.filter( + (artist) => artist.selected && !artist.userDisabled + ); return tracks.filter((trackItem) => { - return trackItem.track.artists.some((trackArtist) => selectedArtists.findIndex((artist) => artist.id === trackArtist.id) !== -1); - }) - -} \ No newline at end of file + return trackItem.track.artists.some( + (trackArtist) => + selectedArtists.findIndex((artist) => artist.id === trackArtist.id) !== + -1 + ); + }); +} diff --git a/client/src/components/Main/main-index.tsx b/client/src/components/Main/main-index.tsx index da845d9..18457b6 100644 --- a/client/src/components/Main/main-index.tsx +++ b/client/src/components/Main/main-index.tsx @@ -1,11 +1,26 @@ import * as React from 'react'; import { useLocation } from 'react-router-dom'; import { useState, useEffect } from 'react'; -import { TrackItem, Artist, PlaylistData, PlaylistCover } from 'interfaces/spotifyObjects'; +import { + TrackItem, + Artist, + PlaylistData, + PlaylistCover, +} from 'interfaces/spotifyObjects'; import { GenreDb } from 'interfaces/genreObjects'; import Genres from './Genres/genres-index'; -import { getTokens, createPlaylist, getTracks, getPlaylistCover } from 'apiService'; -import { artistsMock, tracksMock, genresMock, playlistMock } from 'devtools/dataMocks'; +import { + getTokens, + createPlaylist, + getTracks, + getPlaylistCover, +} from 'apiService'; +import { + artistsMock, + tracksMock, + genresMock, + playlistMock, +} from 'devtools/dataMocks'; import './main-style.scss'; import { // fetchTracksWithOffset, @@ -14,8 +29,8 @@ import { getSelectedTracks, markGenreArtists, filterSelectedGenres, - artistToggleUpdate - } from './main-helpers'; + artistToggleUpdate, +} from './main-helpers'; import Artists from './Artists/artists-index'; import Playlist from './Playlist/playlist-index'; import icon from './Spotify_Icon_RGB_Green.png'; @@ -30,13 +45,13 @@ const Main: React.FC = () => { let [artists, setArtists] = useState([]); // WAS [] - SWITCHED TO MOCK FOR TESTING let [genres, setGenres] = useState({}); // WAS {} - SWITCHED TO MOCK FOR TESTING let [createdPlaylist, setCreatedPlaylist] = useState({}); - const [modalIsOpen,setIsOpen] = React.useState(false); + const [modalIsOpen, setIsOpen] = React.useState(false); function openModal() { setIsOpen(true); } - function closeModal(){ + function closeModal() { setIsOpen(false); } @@ -50,17 +65,17 @@ const Main: React.FC = () => { if (tracks.length === 0) { getTracks(code).then((trackList) => { - console.log(trackList.length + ' tracks received'); - setTracks(trackList); - }); + console.log(trackList.length + ' tracks received'); + setTracks(trackList); + }); } - // TODO: SEND ARTISTS IN ONE REQ FROM SERVER + // TODO: SEND ARTISTS IN ONE REQ FROM SERVER if (artists.length === 0) { fetchArtistsWithOffset(code, setArtists).then((genres) => { - setGenres(genres) + setGenres(genres); }); } - } + }; // setTimeout(() => setTracks(tracksMock), 3000); // setTimeout(() => setGenres(genresMock), 1000); fetchData(); @@ -72,25 +87,36 @@ const Main: React.FC = () => { setArtists(updatedArtists); }, [genres]); - // TODO: MOVE HANDLERS TO SEPARATE FILE - function selectGenreHandler (genreName: string) { + function selectGenreHandler(genreName: string) { // TODO: RESORTING BASED ON MATCH const newGenreDb = Object.assign({}, genres); newGenreDb[genreName].selected = !newGenreDb[genreName].selected; setGenres(newGenreDb); } - function toggleArtistHandler (artistId: string) { + function toggleArtistHandler(artistId: string) { const updatedArtists = artistToggleUpdate(artistId, artists); setArtists(updatedArtists); } - async function createPlaylistHandler (playlistName: string, trackURIs: string[]) { + async function createPlaylistHandler( + playlistName: string, + trackURIs: string[] + ) { if (!code) return; - const playlistData: PlaylistData = await createPlaylist(code, playlistName, trackURIs); - await new Promise((resolve, reject) => setTimeout(() => resolve(''), coverGenerationWaitTime)); - const playlistCover: PlaylistCover[] = await getPlaylistCover(code, playlistData.id); + const playlistData: PlaylistData = await createPlaylist( + code, + playlistName, + trackURIs + ); + await new Promise((resolve, reject) => + setTimeout(() => resolve(''), coverGenerationWaitTime) + ); + const playlistCover: PlaylistCover[] = await getPlaylistCover( + code, + playlistData.id + ); playlistData.cover = playlistCover[0]; setCreatedPlaylist(playlistData); } @@ -99,30 +125,50 @@ const Main: React.FC = () => { if (Object.keys(createdPlaylist).length > 0) { openModal(); } - }, [createdPlaylist]) + }, [createdPlaylist]); return ( -
- - +
+ {/* default spinner color #686769 */} -
+

Listspotter.

-

Powered by Spotify icon

+

+ Powered by{' '} + Spotify icon +

{/* // Display selected artists & artists deselected manually by user */}
- 0}/> - artist.selected)} loaded={Object.keys(genres).length > 0} toggleHandler={toggleArtistHandler}/> + 0} + /> + artist.selected)} + loaded={Object.keys(genres).length > 0} + toggleHandler={toggleArtistHandler} + />
- { 0} createHandler={createPlaylistHandler}/>} + { + 0} + createHandler={createPlaylistHandler} + /> + }
-
); -} +}; -export default Main; \ No newline at end of file +export default Main; From b050accd28638983b7bb1626c603df52fa85cc72 Mon Sep 17 00:00:00 2001 From: Gero Date: Sat, 13 Mar 2021 14:53:56 +0000 Subject: [PATCH 20/46] feat(genre_test): firs two --- client/src/App.test.tsx | 9 --------- .../Main/Genres/Genre Item/__tests__/test.js | 16 ++++++++++++++++ .../src/components/Main/Genres/__tests__/test.js | 3 --- 3 files changed, 16 insertions(+), 12 deletions(-) delete mode 100644 client/src/App.test.tsx create mode 100644 client/src/components/Main/Genres/Genre Item/__tests__/test.js delete mode 100644 client/src/components/Main/Genres/__tests__/test.js diff --git a/client/src/App.test.tsx b/client/src/App.test.tsx deleted file mode 100644 index 2a68616..0000000 --- a/client/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/client/src/components/Main/Genres/Genre Item/__tests__/test.js b/client/src/components/Main/Genres/Genre Item/__tests__/test.js new file mode 100644 index 0000000..0f5402d --- /dev/null +++ b/client/src/components/Main/Genres/Genre Item/__tests__/test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen } from '@testing-library/react'; +import GenreItem from '../genre-item-index'; + +describe('Genre Item', () => { + it('appears on screen', () => { + render(); + }); + it('renders the right name', () => { + const genreName = 'metal'; + render(); + const name = screen.getByText('metal'); + expect(name).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/Main/Genres/__tests__/test.js b/client/src/components/Main/Genres/__tests__/test.js deleted file mode 100644 index 0369c64..0000000 --- a/client/src/components/Main/Genres/__tests__/test.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import Genre from '../genres-index'; From eec99c9783eabaef345a6c2df25e7b0308aba8c7 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 15:11:13 +0000 Subject: [PATCH 21/46] feat(genre_test): added for genre item --- .../Main/Genres/Genre Item/__tests__/test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/client/src/components/Main/Genres/Genre Item/__tests__/test.js b/client/src/components/Main/Genres/Genre Item/__tests__/test.js index 0f5402d..543c7df 100644 --- a/client/src/components/Main/Genres/Genre Item/__tests__/test.js +++ b/client/src/components/Main/Genres/Genre Item/__tests__/test.js @@ -7,10 +7,23 @@ describe('Genre Item', () => { it('appears on screen', () => { render(); }); + it('renders the right name', () => { const genreName = 'metal'; render(); const name = screen.getByText('metal'); expect(name).toBeInTheDocument(); }); + + it('renders the right number of artists', () => { + const artistCount = 3; + render(); + const count = screen.getByText('+3 artists'); + console.log(count); + }); + + it('only renders genre name when selected', () => { + const genreName = 'punk rock'; + render(); + }); }); From 0ac8b137b28d35df0da01b9ca155a1daf65f5414 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 15:35:41 +0000 Subject: [PATCH 22/46] feat(genre_test): completed tests --- .../Main/Genres/Genre Item/__tests__/test.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/client/src/components/Main/Genres/Genre Item/__tests__/test.js b/client/src/components/Main/Genres/Genre Item/__tests__/test.js index 543c7df..661af88 100644 --- a/client/src/components/Main/Genres/Genre Item/__tests__/test.js +++ b/client/src/components/Main/Genres/Genre Item/__tests__/test.js @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import GenreItem from '../genre-item-index'; describe('Genre Item', () => { @@ -19,11 +19,20 @@ describe('Genre Item', () => { const artistCount = 3; render(); const count = screen.getByText('+3 artists'); - console.log(count); + expect(count).toBeInTheDocument(); }); it('only renders genre name when selected', () => { const genreName = 'punk rock'; - render(); + const artistCount = 3; + render( + + ); + const count = screen.queryByText('+3 artists'); + expect(count).toBeNull(); }); }); From 66391609ff36a23e8384bf1e9af9e4795beefd33 Mon Sep 17 00:00:00 2001 From: Gero Date: Sat, 13 Mar 2021 16:52:52 +0000 Subject: [PATCH 23/46] test(artist_test): implemented for artist item) --- .../Artists/Artist Item/__tests__/test.js | 37 + .../Artists/Artist Item/artist-item-index.tsx | 20 +- client/src/devtools/dataMocks.tsx | 27894 +++++++++++++--- 3 files changed, 22882 insertions(+), 5069 deletions(-) create mode 100644 client/src/components/Main/Artists/Artist Item/__tests__/test.js diff --git a/client/src/components/Main/Artists/Artist Item/__tests__/test.js b/client/src/components/Main/Artists/Artist Item/__tests__/test.js new file mode 100644 index 0000000..970be98 --- /dev/null +++ b/client/src/components/Main/Artists/Artist Item/__tests__/test.js @@ -0,0 +1,37 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { cleanup, render, screen } from '@testing-library/react'; +import ArtistItem from '../artist-item-index'; +import { artistToggleUpdate } from 'components/Main/main-helpers'; +import { isExportDeclaration } from 'typescript'; +import { singleArtist } from '../../../../../devtools/dataMocks'; + +describe('Artist Item', () => { + it('appears on screen', () => { + render(); + }); + + it('displays the artist name', () => { + render(); + const artist = screen.getByText(singleArtist.name); + expect(artist).toBeInTheDocument(); + }); + + it('should correctly display the image or alternate url', () => { + render(); + const image = screen.getByRole('img'); + expect(image).toHaveAttribute('src', singleArtist.images[0].url); + expect(image).toHaveAttribute( + 'alt', + `Image of artist ${singleArtist.name}` + ); + }); + + it('should correctly adjust the opacity when clicked', () => { + singleArtist.userDisabled = true; + render(); + const artist = screen.getByTestId('artist_item_aTag'); + console.log(artist); + expect(artist).toHaveClass('user-disabled'); + }); +}); diff --git a/client/src/components/Main/Artists/Artist Item/artist-item-index.tsx b/client/src/components/Main/Artists/Artist Item/artist-item-index.tsx index 76611cd..bf675a1 100644 --- a/client/src/components/Main/Artists/Artist Item/artist-item-index.tsx +++ b/client/src/components/Main/Artists/Artist Item/artist-item-index.tsx @@ -8,13 +8,23 @@ export interface Props { } const ArtistItem: React.FC = ({ artist, toggleHandler }) => { - return ( - - {artist.images[0] && {'Image toggleHandler(artist.id)}/>} + + {artist.images[0] && ( + {'Image toggleHandler(artist.id)} + /> + )}

{artist.name}

); -} +}; -export default ArtistItem; \ No newline at end of file +export default ArtistItem; diff --git a/client/src/devtools/dataMocks.tsx b/client/src/devtools/dataMocks.tsx index e19aa14..8dd85ec 100644 --- a/client/src/devtools/dataMocks.tsx +++ b/client/src/devtools/dataMocks.tsx @@ -1,5181 +1,22947 @@ -import { Artist, TrackItem, ArtistData, PlaylistData } from '../interfaces/spotifyObjects' -import { GenreDb } from '../interfaces/genreObjects' -import { generateGenres } from '../components/Main/main-helpers' +import { + Artist, + TrackItem, + ArtistData, + PlaylistData, +} from '../interfaces/spotifyObjects'; +import { GenreDb } from '../interfaces/genreObjects'; +import { generateGenres } from '../components/Main/main-helpers'; const artistData = { - "artists" : { - "items" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/01e2lCvLZ4fLUIRy68nptH" - }, - "followers" : { - "href" : null, - "total" : 104032 - }, - "genres" : [ "deep euro house", "tropical house" ], - "href" : "https://api.spotify.com/v1/artists/01e2lCvLZ4fLUIRy68nptH", - "id" : "01e2lCvLZ4fLUIRy68nptH", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/7d60ad2505e9a6922973d98fcc958a5742d1e3fc", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/d369947205e298b4928880de4609251c74a1bd37", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/bf0e990893ac10537df9e7006b6fa530fcfd9152", - "width" : 160 - } ], - "name" : "Wankelmut", - "popularity" : 62, - "type" : "artist", - "uri" : "spotify:artist:01e2lCvLZ4fLUIRy68nptH" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/02IFYoziC7CpQRK8fbehUY" - }, - "followers" : { - "href" : null, - "total" : 69677 - }, - "genres" : [ "bosnian indie", "yugoslav rock" ], - "href" : "https://api.spotify.com/v1/artists/02IFYoziC7CpQRK8fbehUY", - "id" : "02IFYoziC7CpQRK8fbehUY", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/4d4d3364e73ae54728222ae56bbbe0d12b0e5b5c", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/26063266e6057cf23d349febddd436bf24a3c2d6", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/009eed443cdac4a909face78e92a45a9c74db7d4", - "width" : 160 - } ], - "name" : "Dubioza kolektiv", - "popularity" : 48, - "type" : "artist", - "uri" : "spotify:artist:02IFYoziC7CpQRK8fbehUY" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/09b5OcuIELTdD7FfzQzcdB" - }, - "followers" : { - "href" : null, - "total" : 75811 - }, - "genres" : [ "folk metal", "italian folk metal", "italian metal", "italian power metal", "melodic metal", "neo classical metal", "power metal", "tolkien metal" ], - "href" : "https://api.spotify.com/v1/artists/09b5OcuIELTdD7FfzQzcdB", - "id" : "09b5OcuIELTdD7FfzQzcdB", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/fea03b617083289dcb5d699ac4dd06795f5fa1b2", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/5efd756ab2de73c9203efd4712e96c1f60c77a4b", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/9e5fd667763f8c399e11e2898913e6217be928b6", - "width" : 160 - } ], - "name" : "Elvenking", - "popularity" : 47, - "type" : "artist", - "uri" : "spotify:artist:09b5OcuIELTdD7FfzQzcdB" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/09mNj9XgCqgg6usfeXOoBg" - }, - "followers" : { - "href" : null, - "total" : 54207 - }, - "genres" : [ "death metal", "progressive thrash", "technical thrash", "thrash metal" ], - "href" : "https://api.spotify.com/v1/artists/09mNj9XgCqgg6usfeXOoBg", - "id" : "09mNj9XgCqgg6usfeXOoBg", - "images" : [ { - "height" : 1000, - "url" : "https://i.scdn.co/image/c00df3db5fc12f38b33b5ee87933b7b01b0d6e41", - "width" : 1000 - }, { - "height" : 640, - "url" : "https://i.scdn.co/image/5cc14441a00f2acd672b82d8e7c26b51f52042a2", - "width" : 640 - }, { - "height" : 200, - "url" : "https://i.scdn.co/image/51b307cdb4314151ddba1ccf537d7379b90540de", - "width" : 200 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/bec64f91980d5fa49bcfddfa79afdde01cd644fc", - "width" : 64 - } ], - "name" : "Vektor", - "popularity" : 41, - "type" : "artist", - "uri" : "spotify:artist:09mNj9XgCqgg6usfeXOoBg" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/09xj0S68Y1OU1vHMCZAIvz" - }, - "followers" : { - "href" : null, - "total" : 2141543 - }, - "genres" : [ "latin", "latin alternative", "latin rock", "mexican rock", "rock en espanol" ], - "href" : "https://api.spotify.com/v1/artists/09xj0S68Y1OU1vHMCZAIvz", - "id" : "09xj0S68Y1OU1vHMCZAIvz", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/eaea517213a7e99edc151495a0895d8d1d40b7a9", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/16ce8f6551c151d3def2b9cb49e1cbd5ea6a3c16", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/f02aecc0e5b5c640ed4a26438fd508e6ffe82801", - "width" : 160 - } ], - "name" : "Café Tacvba", - "popularity" : 73, - "type" : "artist", - "uri" : "spotify:artist:09xj0S68Y1OU1vHMCZAIvz" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0CGpNBihXlpMsjwHjVKNIO" - }, - "followers" : { - "href" : null, - "total" : 17921 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0CGpNBihXlpMsjwHjVKNIO", - "id" : "0CGpNBihXlpMsjwHjVKNIO", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/cc959a48c174f08e1f5c656e3374d44ab6eb9211", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/76053877a36da60b65f2cada8197a944f97e009a", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/f2609124643cf6971e1d998c9e4002307a9b4ebb", - "width" : 160 - } ], - "name" : "zircon", - "popularity" : 39, - "type" : "artist", - "uri" : "spotify:artist:0CGpNBihXlpMsjwHjVKNIO" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0D3h8NZqNp7BN97JwtV6eW" - }, - "followers" : { - "href" : null, - "total" : 99008 - }, - "genres" : [ "contemporary jazz", "jazz piano", "modern jazz piano" ], - "href" : "https://api.spotify.com/v1/artists/0D3h8NZqNp7BN97JwtV6eW", - "id" : "0D3h8NZqNp7BN97JwtV6eW", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/18a70e005024c92f275a99af18ffd67d6536c15c", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/bfaf5778d577873a79b3cbfd9436eeabac7227a2", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/0d856fcd8935efc502a46fd3d5baf53bf09643c5", - "width" : 160 - } ], - "name" : "Tigran Hamasyan", - "popularity" : 49, - "type" : "artist", - "uri" : "spotify:artist:0D3h8NZqNp7BN97JwtV6eW" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0DAh8s6Hbl4xHZyTcbcqNe" - }, - "followers" : { - "href" : null, - "total" : 1350 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0DAh8s6Hbl4xHZyTcbcqNe", - "id" : "0DAh8s6Hbl4xHZyTcbcqNe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273ace9e880f57081964634c550", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02ace9e880f57081964634c550", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851ace9e880f57081964634c550", - "width" : 64 - } ], - "name" : "Mz Sunday Luv", - "popularity" : 29, - "type" : "artist", - "uri" : "spotify:artist:0DAh8s6Hbl4xHZyTcbcqNe" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0DCw6lHkzh9t7f8Hb4Z0Sx" - }, - "followers" : { - "href" : null, - "total" : 648647 - }, - "genres" : [ "alternative metal", "death metal", "melodic death metal", "metal", "nu metal", "power metal", "slayer", "swedish death metal", "swedish metal" ], - "href" : "https://api.spotify.com/v1/artists/0DCw6lHkzh9t7f8Hb4Z0Sx", - "id" : "0DCw6lHkzh9t7f8Hb4Z0Sx", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/04cd9bccf59e8061f13e779d1001975a60fb837a", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/42b234b54c32d78a67ac6a59d3d90f1c87d6e4d8", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/e67d59099eb1f0d8f8477fcac3c2fe8a1ba4fc59", - "width" : 160 - } ], - "name" : "Arch Enemy", - "popularity" : 61, - "type" : "artist", - "uri" : "spotify:artist:0DCw6lHkzh9t7f8Hb4Z0Sx" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0E5cM2403VzBOV6z8NpSwS" - }, - "followers" : { - "href" : null, - "total" : 6707 - }, - "genres" : [ "french techno", "new french touch" ], - "href" : "https://api.spotify.com/v1/artists/0E5cM2403VzBOV6z8NpSwS", - "id" : "0E5cM2403VzBOV6z8NpSwS", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/34f959c1dbe0e9563c94c5d23b8ad6575814169d", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/53b0bf4e3187c18a9e76f4c588b93ffb3738345d", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/6c2f5b07fcfa336f2485c0390a651bdd48b4efeb", - "width" : 160 - } ], - "name" : "Romulus", - "popularity" : 35, - "type" : "artist", - "uri" : "spotify:artist:0E5cM2403VzBOV6z8NpSwS" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0EP5EpsiMP8oLYy7sPHwf9" - }, - "followers" : { - "href" : null, - "total" : 29011 - }, - "genres" : [ "ambeat" ], - "href" : "https://api.spotify.com/v1/artists/0EP5EpsiMP8oLYy7sPHwf9", - "id" : "0EP5EpsiMP8oLYy7sPHwf9", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/52fdd7574088de792aef240a884bfd890ccab005", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/3ccab09b219e69bdf5096d4c35b8f383853c777f", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/9b7ca1f242835632a10bf166c356f6b83195c16f", - "width" : 160 - } ], - "name" : "The Shanghai Restoration Project", - "popularity" : 41, - "type" : "artist", - "uri" : "spotify:artist:0EP5EpsiMP8oLYy7sPHwf9" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0F5fXdlx1bKwYFZ70bfuZ9" - }, - "followers" : { - "href" : null, - "total" : 10997 - }, - "genres" : [ "dark cabaret", "gypsy punk" ], - "href" : "https://api.spotify.com/v1/artists/0F5fXdlx1bKwYFZ70bfuZ9", - "id" : "0F5fXdlx1bKwYFZ70bfuZ9", - "images" : [ { - "height" : 1265, - "url" : "https://i.scdn.co/image/895e1240c5873a53c378e623dac24355754f25a3", - "width" : 1000 - }, { - "height" : 809, - "url" : "https://i.scdn.co/image/786249efd556f660ee702cf4fbd5930ed9e81d32", - "width" : 640 - }, { - "height" : 253, - "url" : "https://i.scdn.co/image/85e2d1c23a44f8d0e93dafadbc8ef9a73e01ec30", - "width" : 200 - }, { - "height" : 81, - "url" : "https://i.scdn.co/image/f58c77ba5ca9b811e897dd875c70957facdd8c61", - "width" : 64 - } ], - "name" : "Firewater", - "popularity" : 32, - "type" : "artist", - "uri" : "spotify:artist:0F5fXdlx1bKwYFZ70bfuZ9" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0FEJqmeLRzsXj8hgcZaAyB" - }, - "followers" : { - "href" : null, - "total" : 496625 - }, - "genres" : [ "french pop" ], - "href" : "https://api.spotify.com/v1/artists/0FEJqmeLRzsXj8hgcZaAyB", - "id" : "0FEJqmeLRzsXj8hgcZaAyB", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/c133119615054ff014873c547af89b5b9faff053", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/1c915845c79aee632442daef5bf1dac254bf0129", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/e6996fa1081ca9d7a030f0dc18cfdf4f220abcc8", - "width" : 160 - } ], - "name" : "Indila", - "popularity" : 65, - "type" : "artist", - "uri" : "spotify:artist:0FEJqmeLRzsXj8hgcZaAyB" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0GDGKpJFhVpcjIGF8N6Ewt" - }, - "followers" : { - "href" : null, - "total" : 753230 - }, - "genres" : [ "alternative metal", "french death metal", "french metal", "metal", "nu metal", "progressive groove metal" ], - "href" : "https://api.spotify.com/v1/artists/0GDGKpJFhVpcjIGF8N6Ewt", - "id" : "0GDGKpJFhVpcjIGF8N6Ewt", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/1ad6844cd3a0d5a195f2df98f44abfcbfe2f4d5e", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/aa05402b64cf462e74b1d0aef90f2fc58aff3e50", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/76d5d53e5649d896b215009fef0415929855b6c7", - "width" : 160 - } ], - "name" : "Gojira", - "popularity" : 69, - "type" : "artist", - "uri" : "spotify:artist:0GDGKpJFhVpcjIGF8N6Ewt" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0H0rBbf7vHXO3qh50Wap7y" - }, - "followers" : { - "href" : null, - "total" : 83362 - }, - "genres" : [ "australian dance", "electropop" ], - "href" : "https://api.spotify.com/v1/artists/0H0rBbf7vHXO3qh50Wap7y", - "id" : "0H0rBbf7vHXO3qh50Wap7y", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/b77a65e767ad547fcd14d62478499c1cbf1eaddb", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/4e2b8178dad5fac8334c3eacca167913f1f199ea", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/cfb4afb21ca5d527dd7dc482f1025cd1846fb555", - "width" : 160 - } ], - "name" : "Sam Sparro", - "popularity" : 54, - "type" : "artist", - "uri" : "spotify:artist:0H0rBbf7vHXO3qh50Wap7y" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0HIiXblDOFPXxkuI35wOMx" - }, - "followers" : { - "href" : null, - "total" : 11334 - }, - "genres" : [ "indie game soundtrack" ], - "href" : "https://api.spotify.com/v1/artists/0HIiXblDOFPXxkuI35wOMx", - "id" : "0HIiXblDOFPXxkuI35wOMx", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/4f9b285f4cce93c1ec05677466e757d65f88ec0c", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/ebb9a6d408c7acde44b0145f88acf3c69b407a18", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/dc3b6dbb2d9f79644c80cb160099047d269c6f81", - "width" : 160 - } ], - "name" : "A Shell In The Pit", - "popularity" : 40, - "type" : "artist", - "uri" : "spotify:artist:0HIiXblDOFPXxkuI35wOMx" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0I2XqVXqHScXjHhk6AYYRe" - }, - "followers" : { - "href" : null, - "total" : 12799 - }, - "genres" : [ "swedish hip hop" ], - "href" : "https://api.spotify.com/v1/artists/0I2XqVXqHScXjHhk6AYYRe", - "id" : "0I2XqVXqHScXjHhk6AYYRe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/c813f0ada1150e5a8178c58b232776c77a51d3c2", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/dce640044ab954223f6f42fd942abeb1cd0ad009", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/3e39905f91afb235a7cb1e59373f72265ebf2345", - "width" : 160 - } ], - "name" : "Afasi & Filthy", - "popularity" : 36, - "type" : "artist", - "uri" : "spotify:artist:0I2XqVXqHScXjHhk6AYYRe" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0IVapwlnM3dEOiMsHXsghT" - }, - "followers" : { - "href" : null, - "total" : 178393 - }, - "genres" : [ "bass music", "chillwave", "electronica", "future garage", "glitch hop", "microhouse", "ninja", "wonky" ], - "href" : "https://api.spotify.com/v1/artists/0IVapwlnM3dEOiMsHXsghT", - "id" : "0IVapwlnM3dEOiMsHXsghT", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/00a19cc20d357784893879834ca18fbfd27e9655", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/3d8ce0d7bf1dd5248b6c54959797b1aebaa022e3", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/7e64249b2122498c51e355cb2534927978ea47df", - "width" : 160 - } ], - "name" : "Nosaj Thing", - "popularity" : 54, - "type" : "artist", - "uri" : "spotify:artist:0IVapwlnM3dEOiMsHXsghT" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0IhZsSjGTFJBXIM5unqzdV" - }, - "followers" : { - "href" : null, - "total" : 15382 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0IhZsSjGTFJBXIM5unqzdV", - "id" : "0IhZsSjGTFJBXIM5unqzdV", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273e19fbe2274c30d7d446ff359", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02e19fbe2274c30d7d446ff359", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851e19fbe2274c30d7d446ff359", - "width" : 64 - } ], - "name" : "Jake Chudnow", - "popularity" : 32, - "type" : "artist", - "uri" : "spotify:artist:0IhZsSjGTFJBXIM5unqzdV" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0IkzMM0QD6fdU7AQKbXpYi" - }, - "followers" : { - "href" : null, - "total" : 2143 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0IkzMM0QD6fdU7AQKbXpYi", - "id" : "0IkzMM0QD6fdU7AQKbXpYi", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/aca94342b436624a62c720d090f605170d66d81e", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/f8145c2c1e6139054c86950c6f12f968a3ad1cbc", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/d09db81428c6abb10bd3105c156c1f3b815a3c59", - "width" : 160 - } ], - "name" : "Masvidal", - "popularity" : 9, - "type" : "artist", - "uri" : "spotify:artist:0IkzMM0QD6fdU7AQKbXpYi" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0Iv00ucAIqr5KVS7bXGFa9" - }, - "followers" : { - "href" : null, - "total" : 52436 - }, - "genres" : [ "art rock", "instrumental rock", "jazz fusion", "progressive rock", "space rock", "symphonic rock" ], - "href" : "https://api.spotify.com/v1/artists/0Iv00ucAIqr5KVS7bXGFa9", - "id" : "0Iv00ucAIqr5KVS7bXGFa9", - "images" : [ { - "height" : 1236, - "url" : "https://i.scdn.co/image/2404a62e8b362948196ff1971b187f7f405a3e59", - "width" : 1000 - }, { - "height" : 791, - "url" : "https://i.scdn.co/image/277c815e9a8161b37e8fdb2adf5a71c148dfa8c4", - "width" : 640 - }, { - "height" : 247, - "url" : "https://i.scdn.co/image/8834f3e239b5caa298d3931f8575651d40a0ee58", - "width" : 200 - }, { - "height" : 79, - "url" : "https://i.scdn.co/image/b5a0b0e8798cef83ff2cae36ca8859799630fb17", - "width" : 64 - } ], - "name" : "Ozric Tentacles", - "popularity" : 42, - "type" : "artist", - "uri" : "spotify:artist:0Iv00ucAIqr5KVS7bXGFa9" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0JWemE0N1N3nwrtMNg2eMO" - }, - "followers" : { - "href" : null, - "total" : 7443 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0JWemE0N1N3nwrtMNg2eMO", - "id" : "0JWemE0N1N3nwrtMNg2eMO", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/1876a17108ebd24144e2814fb9972b3d80f2bf3c", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/fa544662dd11b7c9be56ae2dc396bd20e3f1dbfc", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/169dda30158d34feb9fbebdb3ee88bb761a905d1", - "width" : 160 - } ], - "name" : "Sky", - "popularity" : 38, - "type" : "artist", - "uri" : "spotify:artist:0JWemE0N1N3nwrtMNg2eMO" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0JyCM9EwjQZZzQPGTSM1qc" - }, - "followers" : { - "href" : null, - "total" : 38532 - }, - "genres" : [ "dreamo", "piano rock", "progressive post-hardcore" ], - "href" : "https://api.spotify.com/v1/artists/0JyCM9EwjQZZzQPGTSM1qc", - "id" : "0JyCM9EwjQZZzQPGTSM1qc", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/a92c800c230b9668bcb7a12eba99f6cc124aaa5e", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/b9e6547223ff429a4577af0466e89a37d759761d", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/1a1095ad5a8ffce0c112fc7398e6e6e7d2b635b9", - "width" : 160 - } ], - "name" : "The Reign of Kindo", - "popularity" : 40, - "type" : "artist", - "uri" : "spotify:artist:0JyCM9EwjQZZzQPGTSM1qc" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0KLylVDEP61slhDexriZLj" - }, - "followers" : { - "href" : null, - "total" : 4377 - }, - "genres" : [ "downtempo fusion" ], - "href" : "https://api.spotify.com/v1/artists/0KLylVDEP61slhDexriZLj", - "id" : "0KLylVDEP61slhDexriZLj", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/5e26ac67543c2d5e48e949512ae85536d5b0eb95", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/a16088698d75176e5195fef22c61e8062a398085", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/0a244cd1e5c31916c9be48d3af55568ec6d26447", - "width" : 160 - } ], - "name" : "Anomie Belle", - "popularity" : 35, - "type" : "artist", - "uri" : "spotify:artist:0KLylVDEP61slhDexriZLj" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0L8ExT028jH3ddEcZwqJJ5" - }, - "followers" : { - "href" : null, - "total" : 15504211 - }, - "genres" : [ "alternative rock", "funk metal", "funk rock", "permanent wave", "rock" ], - "href" : "https://api.spotify.com/v1/artists/0L8ExT028jH3ddEcZwqJJ5", - "id" : "0L8ExT028jH3ddEcZwqJJ5", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/89bc3c14aa2b4f250033ffcf5f322b2a553d9331", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/7251ac7f3c0262cfcfad32e214deda639a2b4b46", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/8def8c4db6061deb04daca08e43bcde57181ec8b", - "width" : 160 - } ], - "name" : "Red Hot Chili Peppers", - "popularity" : 86, - "type" : "artist", - "uri" : "spotify:artist:0L8ExT028jH3ddEcZwqJJ5" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0L8QRAAuWjqvTM8FpQ1gYO" - }, - "followers" : { - "href" : null, - "total" : 248417 - }, - "genres" : [ "canadian metal", "death metal", "hard rock", "metal", "neo classical metal", "old school thrash", "power metal", "speed metal", "technical groove metal", "thrash metal" ], - "href" : "https://api.spotify.com/v1/artists/0L8QRAAuWjqvTM8FpQ1gYO", - "id" : "0L8QRAAuWjqvTM8FpQ1gYO", - "images" : [ { - "height" : 1000, - "url" : "https://i.scdn.co/image/423b0a413d344b5e520bda76606b535250f6c130", - "width" : 1000 - }, { - "height" : 640, - "url" : "https://i.scdn.co/image/08fdfc7c4f1c54c6806eefd26a4f86b2aa712171", - "width" : 640 - }, { - "height" : 200, - "url" : "https://i.scdn.co/image/75b7833b5f8d0996782a344b5799858e62c1d9f4", - "width" : 200 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/cf5b9192955ec59cd046ac452f73202cccbed317", - "width" : 64 - } ], - "name" : "Annihilator", - "popularity" : 51, - "type" : "artist", - "uri" : "spotify:artist:0L8QRAAuWjqvTM8FpQ1gYO" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" - }, - "followers" : { - "href" : null, - "total" : 1107624 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", - "id" : "0LyfQWJT6nXafLPZqxe9Of", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/8987540724d78afbf9f9249638eefcef38c0853b", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/3439f512b1422283239d93985959dc6115eae9c2", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/51820ee3bf05021dc690ee7bf804b6d73eedb4a1", - "width" : 160 - } ], - "name" : "Various Artists", - "popularity" : 0, - "type" : "artist", - "uri" : "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0NDElNqwGRCmsYIQFapp6K" - }, - "followers" : { - "href" : null, - "total" : 46029 - }, - "genres" : [ "alternative dance", "filter house", "new french touch", "nu disco" ], - "href" : "https://api.spotify.com/v1/artists/0NDElNqwGRCmsYIQFapp6K", - "id" : "0NDElNqwGRCmsYIQFapp6K", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/12197dae5c2f5752da45b08f06953e2551066ebf", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/f36ccd906331b0ec7670d9b3986f1df7b18a80e5", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/971b050a4f1762eadcbe97df0c8d94399c551078", - "width" : 160 - } ], - "name" : "Oliver", - "popularity" : 54, - "type" : "artist", - "uri" : "spotify:artist:0NDElNqwGRCmsYIQFapp6K" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0NmYchKQ8JIR9QHYJA0FRe" - }, - "followers" : { - "href" : null, - "total" : 365165 - }, - "genres" : [ "death metal", "groove metal", "hard rock", "metal", "old school thrash", "speed metal", "thrash metal" ], - "href" : "https://api.spotify.com/v1/artists/0NmYchKQ8JIR9QHYJA0FRe", - "id" : "0NmYchKQ8JIR9QHYJA0FRe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/cb3d3f098c6882bcc32925ccdd16b56e314e94f5", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/c79bc2d3afb81f5abc3c6163ffae390a634d984e", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/9b321c5f99ae8e3589113573dacf498a690578e5", - "width" : 160 - } ], - "name" : "Overkill", - "popularity" : 50, - "type" : "artist", - "uri" : "spotify:artist:0NmYchKQ8JIR9QHYJA0FRe" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0OBYJhSLz23GVEmb7teDQ8" - }, - "followers" : { - "href" : null, - "total" : 1347 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0OBYJhSLz23GVEmb7teDQ8", - "id" : "0OBYJhSLz23GVEmb7teDQ8", - "images" : [ ], - "name" : "Hiromi feat. Anthony Jackson, Simon Phillips", - "popularity" : 0, - "type" : "artist", - "uri" : "spotify:artist:0OBYJhSLz23GVEmb7teDQ8" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0Ohm3LvFp7wzkvMeiTDPKQ" - }, - "followers" : { - "href" : null, - "total" : 13800 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0Ohm3LvFp7wzkvMeiTDPKQ", - "id" : "0Ohm3LvFp7wzkvMeiTDPKQ", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/c33c6c9bbdb7581b59490f3e2d1091d9322703e3", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/905ae8841faacfc94b1fe3a158276e17a40e4959", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/52fb4c5efb2b630a23e21975ea1c4237db5bbf63", - "width" : 160 - } ], - "name" : "Mirwais", - "popularity" : 39, - "type" : "artist", - "uri" : "spotify:artist:0Ohm3LvFp7wzkvMeiTDPKQ" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0R3pn7bweUwpLd98080DYO" - }, - "followers" : { - "href" : null, - "total" : 5115 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0R3pn7bweUwpLd98080DYO", - "id" : "0R3pn7bweUwpLd98080DYO", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/4e070b6e554c6d3670d97e219da3d6dfc84a996e", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/70a9d7092573d2d8c7d16a2347333c64d8d81e73", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/fcb0a1c7108e649fa7954cc0b4e5781918d2f98b", - "width" : 160 - } ], - "name" : "Tumi", - "popularity" : 35, - "type" : "artist", - "uri" : "spotify:artist:0R3pn7bweUwpLd98080DYO" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0RMrzrDgqu7ipsDo1xNoNK" - }, - "followers" : { - "href" : null, - "total" : 487 - }, - "genres" : [ "deep liquid bass" ], - "href" : "https://api.spotify.com/v1/artists/0RMrzrDgqu7ipsDo1xNoNK", - "id" : "0RMrzrDgqu7ipsDo1xNoNK", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2736758159c0ba81cda2dcb7f07", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e026758159c0ba81cda2dcb7f07", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048516758159c0ba81cda2dcb7f07", - "width" : 64 - } ], - "name" : "Dub Phizix, Skeptical", - "popularity" : 0, - "type" : "artist", - "uri" : "spotify:artist:0RMrzrDgqu7ipsDo1xNoNK" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0SfsnGyD8FpIN4U4WCkBZ5" - }, - "followers" : { - "href" : null, - "total" : 3752178 - }, - "genres" : [ "dutch trance", "edm", "pop dance", "progressive house", "trance" ], - "href" : "https://api.spotify.com/v1/artists/0SfsnGyD8FpIN4U4WCkBZ5", - "id" : "0SfsnGyD8FpIN4U4WCkBZ5", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/b15e29059c98e971418bc0ec6deb2c99494eda32", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/b6d34c9fb5c0d0730921237549d5d522797cf759", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/1697ab36aaa2c6133221de70ce56d34eac0efc0e", - "width" : 160 - } ], - "name" : "Armin van Buuren", - "popularity" : 79, - "type" : "artist", - "uri" : "spotify:artist:0SfsnGyD8FpIN4U4WCkBZ5" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0SqxIwLKk4cXkiv6dq3zEu" - }, - "followers" : { - "href" : null, - "total" : 18939 - }, - "genres" : [ "czech electronic" ], - "href" : "https://api.spotify.com/v1/artists/0SqxIwLKk4cXkiv6dq3zEu", - "id" : "0SqxIwLKk4cXkiv6dq3zEu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/21c71a76a961c785e4fe6a56ad4fd013b99f81d3", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/8e302bf7ea09c4d38a5dccd375cfe50cc20e99aa", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/6315e94d36bd16f63aa73e8274b1218a838d9a11", - "width" : 160 - } ], - "name" : "Floex", - "popularity" : 40, - "type" : "artist", - "uri" : "spotify:artist:0SqxIwLKk4cXkiv6dq3zEu" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0SwO7SWeDHJijQ3XNS7xEE" - }, - "followers" : { - "href" : null, - "total" : 2134467 - }, - "genres" : [ "alternative dance", "indie rock", "indietronica", "modern rock", "rock" ], - "href" : "https://api.spotify.com/v1/artists/0SwO7SWeDHJijQ3XNS7xEE", - "id" : "0SwO7SWeDHJijQ3XNS7xEE", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/0760c3acca24fe81e9d217dd922ab36081383897", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/28ff19618ece117a1897d8e9298e8840a645a2a1", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/1b5cca2e02cc6bbfa7d215dbfe168c21217ab9a1", - "width" : 160 - } ], - "name" : "MGMT", - "popularity" : 80, - "type" : "artist", - "uri" : "spotify:artist:0SwO7SWeDHJijQ3XNS7xEE" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0TF6B1cp2QZXLE0NjhTMT9" - }, - "followers" : { - "href" : null, - "total" : 44090 - }, - "genres" : [ "instrumental math rock", "instrumental rock", "japanese jazz fusion", "japanese math rock", "japanese post-rock", "math pop", "math rock", "post-rock" ], - "href" : "https://api.spotify.com/v1/artists/0TF6B1cp2QZXLE0NjhTMT9", - "id" : "0TF6B1cp2QZXLE0NjhTMT9", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ee723078cfe061dc07b63530e8c1d1162283cb54", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/bafd398a177842d21c48c895c451791467d66e1f", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/027ba0a5a66bf00360405f55fdd60811fd0db2d1", - "width" : 160 - } ], - "name" : "LITE", - "popularity" : 37, - "type" : "artist", - "uri" : "spotify:artist:0TF6B1cp2QZXLE0NjhTMT9" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0UHy12S8f94Sa0jc4dd6Jz" - }, - "followers" : { - "href" : null, - "total" : 46339 - }, - "genres" : [ "classic greek rock", "greek pop", "laiko" ], - "href" : "https://api.spotify.com/v1/artists/0UHy12S8f94Sa0jc4dd6Jz", - "id" : "0UHy12S8f94Sa0jc4dd6Jz", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2737e2b4a1476d692a4face5994", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e027e2b4a1476d692a4face5994", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048517e2b4a1476d692a4face5994", - "width" : 64 - } ], - "name" : "Pix Lax", - "popularity" : 46, - "type" : "artist", - "uri" : "spotify:artist:0UHy12S8f94Sa0jc4dd6Jz" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0UdoKjWIe3tHyiqc4qT3Oz" - }, - "followers" : { - "href" : null, - "total" : 425561 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0UdoKjWIe3tHyiqc4qT3Oz", - "id" : "0UdoKjWIe3tHyiqc4qT3Oz", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273417bebe37c4c4c2430036143", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02417bebe37c4c4c2430036143", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851417bebe37c4c4c2430036143", - "width" : 64 - } ], - "name" : "OMFG", - "popularity" : 58, - "type" : "artist", - "uri" : "spotify:artist:0UdoKjWIe3tHyiqc4qT3Oz" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0Uox3PUw47qEqroDggrDRE" - }, - "followers" : { - "href" : null, - "total" : 5855 - }, - "genres" : [ "belgian indie", "belgian modern jazz" ], - "href" : "https://api.spotify.com/v1/artists/0Uox3PUw47qEqroDggrDRE", - "id" : "0Uox3PUw47qEqroDggrDRE", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/40af76191d97a4221740bef5c22015b5a173f32f", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/3866f9da4da0a016e56691536b692e4cf758abe3", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/9bb8b5dd6de8da5dc890cc0cb31af83a87de9910", - "width" : 160 - } ], - "name" : "Nordmann", - "popularity" : 34, - "type" : "artist", - "uri" : "spotify:artist:0Uox3PUw47qEqroDggrDRE" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0VWRXoE547qHGpUemsl1ge" - }, - "followers" : { - "href" : null, - "total" : 31986 - }, - "genres" : [ "turkish reggae" ], - "href" : "https://api.spotify.com/v1/artists/0VWRXoE547qHGpUemsl1ge", - "id" : "0VWRXoE547qHGpUemsl1ge", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2735ac8e878a5af6bebbcd83cd8", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e025ac8e878a5af6bebbcd83cd8", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048515ac8e878a5af6bebbcd83cd8", - "width" : 64 - } ], - "name" : "Sattas", - "popularity" : 36, - "type" : "artist", - "uri" : "spotify:artist:0VWRXoE547qHGpUemsl1ge" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0WSSKmoRbxqLf3MnXInQ2J" - }, - "followers" : { - "href" : null, - "total" : 113684 - }, - "genres" : [ "electronica", "microhouse", "minimal techno", "modular synth", "tech house" ], - "href" : "https://api.spotify.com/v1/artists/0WSSKmoRbxqLf3MnXInQ2J", - "id" : "0WSSKmoRbxqLf3MnXInQ2J", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/de9e5216b1f1dab4a23c3255e825fbacfe283e5a", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/59b6083d596c915afcd5b648b82e1acf3f9d9ce8", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/899420a94245c95a796a5d821f2dffa560877788", - "width" : 160 - } ], - "name" : "Max Cooper", - "popularity" : 56, - "type" : "artist", - "uri" : "spotify:artist:0WSSKmoRbxqLf3MnXInQ2J" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0WaR9ydw7sZikp1dfHV8Xc" - }, - "followers" : { - "href" : null, - "total" : 3298 - }, - "genres" : [ "minimal dubstep" ], - "href" : "https://api.spotify.com/v1/artists/0WaR9ydw7sZikp1dfHV8Xc", - "id" : "0WaR9ydw7sZikp1dfHV8Xc", - "images" : [ { - "height" : 1000, - "url" : "https://i.scdn.co/image/b392edb5a6450f82753d552f9ad9881db753cc04", - "width" : 1000 - }, { - "height" : 640, - "url" : "https://i.scdn.co/image/a7ce93e4a402ffa1ac25beb4e7ee3540476b6210", - "width" : 640 - }, { - "height" : 200, - "url" : "https://i.scdn.co/image/17291e7bedb3e55a69fe2fb08b1f215e7f6e0a7a", - "width" : 200 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/a0f4f2a923825321e8827f24e9149cce32c7e658", - "width" : 64 - } ], - "name" : "Killawatt", - "popularity" : 17, - "type" : "artist", - "uri" : "spotify:artist:0WaR9ydw7sZikp1dfHV8Xc" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0WwSkZ7LtFUFjGjMZBMt6T" - }, - "followers" : { - "href" : null, - "total" : 4397737 - }, - "genres" : [ "album rock", "classic rock", "mellow gold", "rock", "soft rock" ], - "href" : "https://api.spotify.com/v1/artists/0WwSkZ7LtFUFjGjMZBMt6T", - "id" : "0WwSkZ7LtFUFjGjMZBMt6T", - "images" : [ { - "height" : 1021, - "url" : "https://i.scdn.co/image/54a86ecf1de16b17e2ed000a9ca8a1590c9a3b80", - "width" : 1000 - }, { - "height" : 653, - "url" : "https://i.scdn.co/image/caf04a8a030c70dd697ee0b37562033bbe3cdb4f", - "width" : 640 - }, { - "height" : 204, - "url" : "https://i.scdn.co/image/7756c61bed0dc7650b188a4c7be984dc4e1d7651", - "width" : 200 - }, { - "height" : 65, - "url" : "https://i.scdn.co/image/0ba7e13266153e59b9b611cbd43e21aec7f6737c", - "width" : 64 - } ], - "name" : "Dire Straits", - "popularity" : 79, - "type" : "artist", - "uri" : "spotify:artist:0WwSkZ7LtFUFjGjMZBMt6T" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0XNa1vTidXlvJ2gHSsRi4A" - }, - "followers" : { - "href" : null, - "total" : 1990666 - }, - "genres" : [ "alternative rock", "dance-punk", "indie rock", "modern rock", "new rave", "rock", "scottish rock" ], - "href" : "https://api.spotify.com/v1/artists/0XNa1vTidXlvJ2gHSsRi4A", - "id" : "0XNa1vTidXlvJ2gHSsRi4A", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/445c11fcc1637f94f48cee1d3354d478f10ac403", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/74d44570990858341836261beb39b3faa18f7603", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/83bb403e52b2c05b7420a5ebd8e502915b6ec6ad", - "width" : 160 - } ], - "name" : "Franz Ferdinand", - "popularity" : 70, - "type" : "artist", - "uri" : "spotify:artist:0XNa1vTidXlvJ2gHSsRi4A" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0Y8KmFkKOgJybpVobn1onU" - }, - "followers" : { - "href" : null, - "total" : 600125 - }, - "genres" : [ "canzone napoletana", "classical tenor", "italian tenor", "opera", "operatic pop" ], - "href" : "https://api.spotify.com/v1/artists/0Y8KmFkKOgJybpVobn1onU", - "id" : "0Y8KmFkKOgJybpVobn1onU", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/5e80aa2fe42fd8946b69ca25c436330c722ac0fb", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/609c65d0ece55692ed168f34f65559916281686d", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/52d956144b81e31d9b2c16c613c0438bf653338d", - "width" : 160 - } ], - "name" : "Luciano Pavarotti", - "popularity" : 68, - "type" : "artist", - "uri" : "spotify:artist:0Y8KmFkKOgJybpVobn1onU" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0YJxNQtyb8jlldIC1DTkIf" - }, - "followers" : { - "href" : null, - "total" : 25727 - }, - "genres" : [ "turntablism" ], - "href" : "https://api.spotify.com/v1/artists/0YJxNQtyb8jlldIC1DTkIf", - "id" : "0YJxNQtyb8jlldIC1DTkIf", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/e0cb8214500faeca3eb7771dd1eb919893c50fb3", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/4e05d7703c46be8c825c25701358eea5a15e1230", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/bceaba3afae840d493d5a4b5246fd3df5876de73", - "width" : 160 - } ], - "name" : "Scratch Bandits Crew", - "popularity" : 44, - "type" : "artist", - "uri" : "spotify:artist:0YJxNQtyb8jlldIC1DTkIf" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0ZXKT0FCsLWkSLCjoBJgBX" - }, - "followers" : { - "href" : null, - "total" : 248652 - }, - "genres" : [ "gothic metal", "progressive doom", "progressive metal" ], - "href" : "https://api.spotify.com/v1/artists/0ZXKT0FCsLWkSLCjoBJgBX", - "id" : "0ZXKT0FCsLWkSLCjoBJgBX", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/5bfccbb8c43027b7efa93dbd4ed2bf366a34398c", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/c429e198e3700fc90420136862d07a9037c599a8", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/0d2d6caed428138b9161dba0a3ed9c8fd725c53b", - "width" : 160 - } ], - "name" : "Anathema", - "popularity" : 56, - "type" : "artist", - "uri" : "spotify:artist:0ZXKT0FCsLWkSLCjoBJgBX" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0bBjMMS4rONUFXs6y1iHpv" - }, - "followers" : { - "href" : null, - "total" : 1372 - }, - "genres" : [ ], - "href" : "https://api.spotify.com/v1/artists/0bBjMMS4rONUFXs6y1iHpv", - "id" : "0bBjMMS4rONUFXs6y1iHpv", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27391d36c800895d728066d55e6", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0291d36c800895d728066d55e6", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485191d36c800895d728066d55e6", - "width" : 64 - } ], - "name" : "Klint", - "popularity" : 4, - "type" : "artist", - "uri" : "spotify:artist:0bBjMMS4rONUFXs6y1iHpv" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0bZCak2tcRMY1dzEIuwF42" - }, - "followers" : { - "href" : null, - "total" : 350821 - }, - "genres" : [ "bath indie", "funk", "garage rock", "modern alternative rock", "modern blues rock", "modern rock", "rock" ], - "href" : "https://api.spotify.com/v1/artists/0bZCak2tcRMY1dzEIuwF42", - "id" : "0bZCak2tcRMY1dzEIuwF42", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/902fb7929782b9ac35a0002fa4cfcd29c5e97eaf", - "width" : 640 - }, { - "height" : 320, - "url" : "https://i.scdn.co/image/33cd1de985a6b3442e8e8e26fabfcfd753c1ac1a", - "width" : 320 - }, { - "height" : 160, - "url" : "https://i.scdn.co/image/7e64f1693ea64afb078320813aa7afd01a077b9f", - "width" : 160 - } ], - "name" : "The Heavy", - "popularity" : 62, - "type" : "artist", - "uri" : "spotify:artist:0bZCak2tcRMY1dzEIuwF42" - } ], - "next" : "https://api.spotify.com/v1/me/following?type=artist&after=0bZCak2tcRMY1dzEIuwF42&limit=50", - "total" : 674, - "cursors" : { - "after" : "0bZCak2tcRMY1dzEIuwF42" - }, - "limit" : 50, - "href" : "https://api.spotify.com/v1/me/following?type=artist&limit=50" - } -} - -const trackData = { - "href" : "https://api.spotify.com/v1/me/tracks?offset=0&limit=50", - "items" : [ { - "added_at" : "2021-03-04T21:45:53Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "02IFYoziC7CpQRK8fbehUY", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu" - }, - "href" : "https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu", - "id" : "0CAXEcXpruvyGKSTjyLDNu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21", - "width" : 64 - } ], - "name" : "Black Focus", - "release_date" : "2016-11-04", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0CAXEcXpruvyGKSTjyLDNu" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "02IFYoziC7CpQRK8fbehUY", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 508773, - "explicit" : false, - "external_ids" : { - "isrc" : "GBMEF1600916" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/2sEmZge5ZfzrFrDGFJbkyP" - }, - "href" : "https://api.spotify.com/v1/tracks/2sEmZge5ZfzrFrDGFJbkyP", - "id" : "2sEmZge5ZfzrFrDGFJbkyP", - "is_local" : false, - "name" : "Strings of Light", - "popularity" : 42, - "preview_url" : "https://p.scdn.co/mp3-preview/2b19dd719e857867cf4e228697a230fb5036ad71?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:2sEmZge5ZfzrFrDGFJbkyP" - } - }, { - "added_at" : "2021-03-04T21:40:32Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI" - }, - "href" : "https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI", - "id" : "2i1CPudyCUjL50Wqjv8AMI", - "name" : "Alfa Mist", - "type" : "artist", - "uri" : "spotify:artist:2i1CPudyCUjL50Wqjv8AMI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/38XUFMsLLAttgWdD40CTaL" - }, - "href" : "https://api.spotify.com/v1/albums/38XUFMsLLAttgWdD40CTaL", - "id" : "38XUFMsLLAttgWdD40CTaL", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2733979878917bb0159fa35b0ac", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e023979878917bb0159fa35b0ac", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048513979878917bb0159fa35b0ac", - "width" : 64 - } ], - "name" : "Structuralism", - "release_date" : "2019-04-26", - "release_date_precision" : "day", - "total_tracks" : 8, - "type" : "album", - "uri" : "spotify:album:38XUFMsLLAttgWdD40CTaL" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI" - }, - "href" : "https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI", - "id" : "2i1CPudyCUjL50Wqjv8AMI", - "name" : "Alfa Mist", - "type" : "artist", - "uri" : "spotify:artist:2i1CPudyCUjL50Wqjv8AMI" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/24icoQNJSEWNu3XvqKBR68" - }, - "href" : "https://api.spotify.com/v1/artists/24icoQNJSEWNu3XvqKBR68", - "id" : "24icoQNJSEWNu3XvqKBR68", - "name" : "Jordan Rakei", - "type" : "artist", - "uri" : "spotify:artist:24icoQNJSEWNu3XvqKBR68" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 247760, - "explicit" : false, - "external_ids" : { - "isrc" : "FR10S1947881" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/5IOLaZLFnrBIjZImSS1E1u" - }, - "href" : "https://api.spotify.com/v1/tracks/5IOLaZLFnrBIjZImSS1E1u", - "id" : "5IOLaZLFnrBIjZImSS1E1u", - "is_local" : false, - "name" : "Door", - "popularity" : 46, - "preview_url" : "https://p.scdn.co/mp3-preview/3c946c3053abaaf1f678a14eb874ec13ec71dcdf?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:5IOLaZLFnrBIjZImSS1E1u" - } - }, { - "added_at" : "2021-03-04T21:38:46Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI" - }, - "href" : "https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI", - "id" : "2i1CPudyCUjL50Wqjv8AMI", - "name" : "Alfa Mist", - "type" : "artist", - "uri" : "spotify:artist:2i1CPudyCUjL50Wqjv8AMI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/3joOXpEsCgg8oS1Tba7neT" - }, - "href" : "https://api.spotify.com/v1/albums/3joOXpEsCgg8oS1Tba7neT", - "id" : "3joOXpEsCgg8oS1Tba7neT", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2735d46b069ef33382b235b296a", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e025d46b069ef33382b235b296a", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048515d46b069ef33382b235b296a", - "width" : 64 - } ], - "name" : "Antiphon", - "release_date" : "2017-03-03", - "release_date_precision" : "day", - "total_tracks" : 8, - "type" : "album", - "uri" : "spotify:album:3joOXpEsCgg8oS1Tba7neT" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI" - }, - "href" : "https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI", - "id" : "2i1CPudyCUjL50Wqjv8AMI", - "name" : "Alfa Mist", - "type" : "artist", - "uri" : "spotify:artist:2i1CPudyCUjL50Wqjv8AMI" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/12WK0pR6DK71O5uqTHWzyE" - }, - "href" : "https://api.spotify.com/v1/artists/12WK0pR6DK71O5uqTHWzyE", - "id" : "12WK0pR6DK71O5uqTHWzyE", - "name" : "Kaya Thomas-Dyke", - "type" : "artist", - "uri" : "spotify:artist:12WK0pR6DK71O5uqTHWzyE" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 447000, - "explicit" : false, - "external_ids" : { - "isrc" : "USCGH1770627" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6nGNzqlHTKugpRWkXrZkPC" - }, - "href" : "https://api.spotify.com/v1/tracks/6nGNzqlHTKugpRWkXrZkPC", - "id" : "6nGNzqlHTKugpRWkXrZkPC", - "is_local" : false, - "name" : "Breathe", - "popularity" : 48, - "preview_url" : "https://p.scdn.co/mp3-preview/a9ef0a470e447546df7cbb6fe0b042a7c1f2a14e?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:6nGNzqlHTKugpRWkXrZkPC" - } - }, { - "added_at" : "2021-03-04T21:34:16Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu" - }, - "href" : "https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu", - "id" : "0CAXEcXpruvyGKSTjyLDNu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21", - "width" : 64 - } ], - "name" : "Black Focus", - "release_date" : "2016-11-04", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0CAXEcXpruvyGKSTjyLDNu" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 46920, - "explicit" : false, - "external_ids" : { - "isrc" : "GBMEF1600928" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/5EqkuCTZTSMhZm2sLhA7JN" - }, - "href" : "https://api.spotify.com/v1/tracks/5EqkuCTZTSMhZm2sLhA7JN", - "id" : "5EqkuCTZTSMhZm2sLhA7JN", - "is_local" : false, - "name" : "O.G.", - "popularity" : 28, - "preview_url" : "https://p.scdn.co/mp3-preview/5a6fd9533dd0100396588ed6c213b8073239d246?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 6, - "type" : "track", - "uri" : "spotify:track:5EqkuCTZTSMhZm2sLhA7JN" - } - }, { - "added_at" : "2021-03-04T18:31:40Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu" - }, - "href" : "https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu", - "id" : "0CAXEcXpruvyGKSTjyLDNu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21", - "width" : 64 - } ], - "name" : "Black Focus", - "release_date" : "2016-11-04", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0CAXEcXpruvyGKSTjyLDNu" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 239480, - "explicit" : false, - "external_ids" : { - "isrc" : "GBMEF1600918" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/4doeILSOpBXjzWsiJiSS8a" - }, - "href" : "https://api.spotify.com/v1/tracks/4doeILSOpBXjzWsiJiSS8a", - "id" : "4doeILSOpBXjzWsiJiSS8a", - "is_local" : false, - "name" : "Yo Chavez", - "popularity" : 32, - "preview_url" : "https://p.scdn.co/mp3-preview/abb79b375f7ac02161f3a56e9cc7684e658f1918?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:4doeILSOpBXjzWsiJiSS8a" - } - }, { - "added_at" : "2021-03-04T18:04:50Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu" - }, - "href" : "https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu", - "id" : "0CAXEcXpruvyGKSTjyLDNu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21", - "width" : 64 - } ], - "name" : "Black Focus", - "release_date" : "2016-11-04", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0CAXEcXpruvyGKSTjyLDNu" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 268466, - "explicit" : false, - "external_ids" : { - "isrc" : "GBMEF1600919" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/7gHdjudTKmgDcWSKPpJk9h" - }, - "href" : "https://api.spotify.com/v1/tracks/7gHdjudTKmgDcWSKPpJk9h", - "id" : "7gHdjudTKmgDcWSKPpJk9h", - "is_local" : false, - "name" : "Lowrider", - "popularity" : 39, - "preview_url" : "https://p.scdn.co/mp3-preview/fec1d7bc1913443a53ea83fa15db17d10816ea65?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 7, - "type" : "track", - "uri" : "spotify:track:7gHdjudTKmgDcWSKPpJk9h" - } - }, { - "added_at" : "2021-03-04T17:40:14Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu" - }, - "href" : "https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu", - "id" : "0CAXEcXpruvyGKSTjyLDNu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21", - "width" : 64 - } ], - "name" : "Black Focus", - "release_date" : "2016-11-04", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0CAXEcXpruvyGKSTjyLDNu" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh" - }, - "href" : "https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh", - "id" : "710FHFQeXKC6dZGCxt7kQh", - "name" : "Yussef Kamaal", - "type" : "artist", - "uri" : "spotify:artist:710FHFQeXKC6dZGCxt7kQh" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 540546, - "explicit" : false, - "external_ids" : { - "isrc" : "GBMEF1600917" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/1k7B553lUeQY3cyltjRWCH" - }, - "href" : "https://api.spotify.com/v1/tracks/1k7B553lUeQY3cyltjRWCH", - "id" : "1k7B553lUeQY3cyltjRWCH", - "is_local" : false, - "name" : "Remembrance", - "popularity" : 38, - "preview_url" : "https://p.scdn.co/mp3-preview/8a46cf5b255fa559f261d9450bd273da0e4f99fe?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 3, - "type" : "track", - "uri" : "spotify:track:1k7B553lUeQY3cyltjRWCH" - } - }, { - "added_at" : "2021-02-28T18:59:00Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe" - }, - "href" : "https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe", - "id" : "6utXOCDpTDavsVbjQgPxpe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c", - "width" : 64 - } ], - "name" : "Disappointment Island", - "release_date" : "2016-07-08", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6utXOCDpTDavsVbjQgPxpe" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 256186, - "explicit" : false, - "external_ids" : { - "isrc" : "QMLD61404135" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6a76vVSWwjhLHCh2uV8XK3" - }, - "href" : "https://api.spotify.com/v1/tracks/6a76vVSWwjhLHCh2uV8XK3", - "id" : "6a76vVSWwjhLHCh2uV8XK3", - "is_local" : false, - "name" : "In Praise of Idleness", - "popularity" : 24, - "preview_url" : "https://p.scdn.co/mp3-preview/a3e646f8850d8ddc346e184af120255fb1cfa41b?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:6a76vVSWwjhLHCh2uV8XK3" - } - }, { - "added_at" : "2021-02-28T18:54:05Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe" - }, - "href" : "https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe", - "id" : "6utXOCDpTDavsVbjQgPxpe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c", - "width" : 64 - } ], - "name" : "Disappointment Island", - "release_date" : "2016-07-08", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6utXOCDpTDavsVbjQgPxpe" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 174680, - "explicit" : false, - "external_ids" : { - "isrc" : "QMLD61404133" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0Xr8oHXgHJj6wIoYKsl5qK" - }, - "href" : "https://api.spotify.com/v1/tracks/0Xr8oHXgHJj6wIoYKsl5qK", - "id" : "0Xr8oHXgHJj6wIoYKsl5qK", - "is_local" : false, - "name" : "A Chase of Sorts", - "popularity" : 23, - "preview_url" : "https://p.scdn.co/mp3-preview/19a2e3986ee540265fe93ed156ba906fd64e3b4d?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:0Xr8oHXgHJj6wIoYKsl5qK" - } - }, { - "added_at" : "2021-02-28T18:42:37Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe" - }, - "href" : "https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe", - "id" : "6utXOCDpTDavsVbjQgPxpe", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c", - "width" : 64 - } ], - "name" : "Disappointment Island", - "release_date" : "2016-07-08", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6utXOCDpTDavsVbjQgPxpe" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0" - }, - "href" : "https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0", - "id" : "5TUa95aB5Vu2CzwCnZd6t0", - "name" : "TTNG", - "type" : "artist", - "uri" : "spotify:artist:5TUa95aB5Vu2CzwCnZd6t0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 337146, - "explicit" : false, - "external_ids" : { - "isrc" : "QMLD61404136" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3iV0hDpxooBMmwPEKOukJf" - }, - "href" : "https://api.spotify.com/v1/tracks/3iV0hDpxooBMmwPEKOukJf", - "id" : "3iV0hDpxooBMmwPEKOukJf", - "is_local" : false, - "name" : "Whatever, Whenever", - "popularity" : 38, - "preview_url" : "https://p.scdn.co/mp3-preview/da9296c558b8e193f61cab35e9916fc76685bd70?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 5, - "type" : "track", - "uri" : "spotify:track:3iV0hDpxooBMmwPEKOukJf" - } - }, { - "added_at" : "2021-02-28T00:03:29Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0k17h0D3J5VfsdmQ1iZtE9" - }, - "href" : "https://api.spotify.com/v1/artists/0k17h0D3J5VfsdmQ1iZtE9", - "id" : "0k17h0D3J5VfsdmQ1iZtE9", - "name" : "Pink Floyd", - "type" : "artist", - "uri" : "spotify:artist:0k17h0D3J5VfsdmQ1iZtE9" - } ], - "available_markets" : [ "AD", "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "DZ", "EE", "ES", "FI", "FR", "GB", "GE", "GR", "HR", "HU", "IE", "IS", "IT", "KG", "KZ", "LI", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UZ", "XK" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6uvBKDGlJAYLH5Vy6RQVsc" - }, - "href" : "https://api.spotify.com/v1/albums/6uvBKDGlJAYLH5Vy6RQVsc", - "id" : "6uvBKDGlJAYLH5Vy6RQVsc", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2735aa1262c4123fedc2e4b8c44", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e025aa1262c4123fedc2e4b8c44", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048515aa1262c4123fedc2e4b8c44", - "width" : 64 - } ], - "name" : "Wish You Were Here [Remastered] (Remastered Version)", - "release_date" : "1975-09-12", - "release_date_precision" : "day", - "total_tracks" : 5, - "type" : "album", - "uri" : "spotify:album:6uvBKDGlJAYLH5Vy6RQVsc" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0k17h0D3J5VfsdmQ1iZtE9" - }, - "href" : "https://api.spotify.com/v1/artists/0k17h0D3J5VfsdmQ1iZtE9", - "id" : "0k17h0D3J5VfsdmQ1iZtE9", - "name" : "Pink Floyd", - "type" : "artist", - "uri" : "spotify:artist:0k17h0D3J5VfsdmQ1iZtE9" - } ], - "available_markets" : [ "AD", "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", "DK", "DZ", "EE", "ES", "FI", "FR", "GB", "GE", "GR", "HR", "HU", "IE", "IS", "IT", "KG", "KZ", "LI", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UZ", "XK" ], - "disc_number" : 1, - "duration_ms" : 334743, - "explicit" : false, - "external_ids" : { - "isrc" : "GBN9Y1100088" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/7aE5WXu5sFeNRh3Z05wwu4" - }, - "href" : "https://api.spotify.com/v1/tracks/7aE5WXu5sFeNRh3Z05wwu4", - "id" : "7aE5WXu5sFeNRh3Z05wwu4", - "is_local" : false, - "name" : "Wish You Were Here - 2011 Remastered Version", - "popularity" : 70, - "preview_url" : "https://p.scdn.co/mp3-preview/7ce0d4e5f0ffcf8fe1a312c9c2f9331c8d2bf994?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:7aE5WXu5sFeNRh3Z05wwu4" - } - }, { - "added_at" : "2021-02-27T23:58:07Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/22WZ7M8sxp5THdruNY3gXt" - }, - "href" : "https://api.spotify.com/v1/artists/22WZ7M8sxp5THdruNY3gXt", - "id" : "22WZ7M8sxp5THdruNY3gXt", - "name" : "The Doors", - "type" : "artist", - "uri" : "spotify:artist:22WZ7M8sxp5THdruNY3gXt" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6AFLOkpJjFF652jevcSOZX" - }, - "href" : "https://api.spotify.com/v1/albums/6AFLOkpJjFF652jevcSOZX", - "id" : "6AFLOkpJjFF652jevcSOZX", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f12a8a7e0b2cbe16d2bef4dc", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f12a8a7e0b2cbe16d2bef4dc", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f12a8a7e0b2cbe16d2bef4dc", - "width" : 64 - } ], - "name" : "Morrison Hotel", - "release_date" : "1970-02-09", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:6AFLOkpJjFF652jevcSOZX" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/22WZ7M8sxp5THdruNY3gXt" - }, - "href" : "https://api.spotify.com/v1/artists/22WZ7M8sxp5THdruNY3gXt", - "id" : "22WZ7M8sxp5THdruNY3gXt", - "name" : "The Doors", - "type" : "artist", - "uri" : "spotify:artist:22WZ7M8sxp5THdruNY3gXt" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 243826, - "explicit" : false, - "external_ids" : { - "isrc" : "USEE19900375" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/1Q5kgpp4pmyGqPwNBzkSrw" - }, - "href" : "https://api.spotify.com/v1/tracks/1Q5kgpp4pmyGqPwNBzkSrw", - "id" : "1Q5kgpp4pmyGqPwNBzkSrw", - "is_local" : false, - "name" : "Roadhouse Blues", - "popularity" : 70, - "preview_url" : "https://p.scdn.co/mp3-preview/a0e4d25d759b8433f99d99bbaf31e153e0b1914e?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 1, - "type" : "track", - "uri" : "spotify:track:1Q5kgpp4pmyGqPwNBzkSrw" - } - }, { - "added_at" : "2021-02-27T13:00:06Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir" - }, - "href" : "https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir", - "id" : "621sN6b7GCpWpzaSidA5Ir", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045", - "width" : 64 - } ], - "name" : "The Path of Apotheosis", - "release_date" : "2014-01-26", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:621sN6b7GCpWpzaSidA5Ir" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 394320, - "explicit" : false, - "external_ids" : { - "isrc" : "TCABS1379689" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6FX7C7yaMvqtV0E2OjYIhA" - }, - "href" : "https://api.spotify.com/v1/tracks/6FX7C7yaMvqtV0E2OjYIhA", - "id" : "6FX7C7yaMvqtV0E2OjYIhA", - "is_local" : false, - "name" : "The Path of Apotheosis", - "popularity" : 19, - "preview_url" : "https://p.scdn.co/mp3-preview/28cda4b2e4818ad7830290e7c7d22f4ca3df6b28?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 11, - "type" : "track", - "uri" : "spotify:track:6FX7C7yaMvqtV0E2OjYIhA" - } - }, { - "added_at" : "2021-02-25T12:33:03Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0" - }, - "href" : "https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0", - "id" : "6RmijobcphddxSNtsBHjF0", - "name" : "Simon Posford", - "type" : "artist", - "uri" : "spotify:artist:6RmijobcphddxSNtsBHjF0" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ" - }, - "href" : "https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ", - "id" : "0m5XJwKGYyUjd3VMfcINCQ", - "name" : "Shpongle", - "type" : "artist", - "uri" : "spotify:artist:0m5XJwKGYyUjd3VMfcINCQ" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6CzjV9BeZvSKqxdhzfswdX" - }, - "href" : "https://api.spotify.com/v1/albums/6CzjV9BeZvSKqxdhzfswdX", - "id" : "6CzjV9BeZvSKqxdhzfswdX", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273d2ad1f61daaf693282c0c222", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02d2ad1f61daaf693282c0c222", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851d2ad1f61daaf693282c0c222", - "width" : 64 - } ], - "name" : "Flux & Contemplation - Portrait of an Artist in Isolation", - "release_date" : "2020-07-03", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6CzjV9BeZvSKqxdhzfswdX" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0" - }, - "href" : "https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0", - "id" : "01e2lCvLZ4fLUIRy68nptH", - "name" : "Simon Posford", - "type" : "artist", - "uri" : "spotify:artist:6RmijobcphddxSNtsBHjF0" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ" - }, - "href" : "https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ", - "id" : "0m5XJwKGYyUjd3VMfcINCQ", - "name" : "Shpongle", - "type" : "artist", - "uri" : "spotify:artist:0m5XJwKGYyUjd3VMfcINCQ" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 641093, - "explicit" : false, - "external_ids" : { - "isrc" : "GBBMP1200635" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0UBLvMN7Y1pPr22zYAjhRd" - }, - "href" : "https://api.spotify.com/v1/tracks/0UBLvMN7Y1pPr22zYAjhRd", - "id" : "0UBLvMN7Y1pPr22zYAjhRd", - "is_local" : false, - "name" : "The New Normal", - "popularity" : 22, - "preview_url" : "https://p.scdn.co/mp3-preview/a22736f725e9cc2756c2e296397247ce5f66864c?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:0UBLvMN7Y1pPr22zYAjhRd" - } - }, { - "added_at" : "2021-02-25T12:32:48Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0" - }, - "href" : "https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0", - "id" : "6RmijobcphddxSNtsBHjF0", - "name" : "Simon Posford", - "type" : "artist", - "uri" : "spotify:artist:6RmijobcphddxSNtsBHjF0" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ" - }, - "href" : "https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ", - "id" : "0m5XJwKGYyUjd3VMfcINCQ", - "name" : "Shpongle", - "type" : "artist", - "uri" : "spotify:artist:0m5XJwKGYyUjd3VMfcINCQ" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6CzjV9BeZvSKqxdhzfswdX" - }, - "href" : "https://api.spotify.com/v1/albums/6CzjV9BeZvSKqxdhzfswdX", - "id" : "6CzjV9BeZvSKqxdhzfswdX", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273d2ad1f61daaf693282c0c222", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02d2ad1f61daaf693282c0c222", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851d2ad1f61daaf693282c0c222", - "width" : 64 - } ], - "name" : "Flux & Contemplation - Portrait of an Artist in Isolation", - "release_date" : "2020-07-03", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6CzjV9BeZvSKqxdhzfswdX" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0" - }, - "href" : "https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0", - "id" : "6RmijobcphddxSNtsBHjF0", - "name" : "Simon Posford", - "type" : "artist", - "uri" : "spotify:artist:6RmijobcphddxSNtsBHjF0" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ" - }, - "href" : "https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ", - "id" : "0m5XJwKGYyUjd3VMfcINCQ", - "name" : "Shpongle", - "type" : "artist", - "uri" : "spotify:artist:0m5XJwKGYyUjd3VMfcINCQ" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 328840, - "explicit" : false, - "external_ids" : { - "isrc" : "GBBMP1200632" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0bW1ctrbUrg1E3bC4lu0SO" - }, - "href" : "https://api.spotify.com/v1/tracks/0bW1ctrbUrg1E3bC4lu0SO", - "id" : "0bW1ctrbUrg1E3bC4lu0SO", - "is_local" : false, - "name" : "Wish You Weren’t Here", - "popularity" : 24, - "preview_url" : "https://p.scdn.co/mp3-preview/5285f5475414491f8ded4788e25df325b38e9bf4?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 5, - "type" : "track", - "uri" : "spotify:track:0bW1ctrbUrg1E3bC4lu0SO" - } - }, { - "added_at" : "2021-02-23T13:06:12Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/1Yox196W7bzVNZI7RBaPnf" - }, - "href" : "https://api.spotify.com/v1/artists/1Yox196W7bzVNZI7RBaPnf", - "id" : "1Yox196W7bzVNZI7RBaPnf", - "name" : "Megadeth", - "type" : "artist", - "uri" : "spotify:artist:1Yox196W7bzVNZI7RBaPnf" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5YFrdrFUHGgAvK8iXFxULa" - }, - "href" : "https://api.spotify.com/v1/albums/5YFrdrFUHGgAvK8iXFxULa", - "id" : "5YFrdrFUHGgAvK8iXFxULa", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2735545e351774a756c377ea0ee", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e025545e351774a756c377ea0ee", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048515545e351774a756c377ea0ee", - "width" : 64 - } ], - "name" : "The World Needs a Hero", - "release_date" : "2001-05-14", - "release_date_precision" : "day", - "total_tracks" : 12, - "type" : "album", - "uri" : "spotify:album:5YFrdrFUHGgAvK8iXFxULa" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/1Yox196W7bzVNZI7RBaPnf" - }, - "href" : "https://api.spotify.com/v1/artists/1Yox196W7bzVNZI7RBaPnf", - "id" : "1Yox196W7bzVNZI7RBaPnf", - "name" : "Megadeth", - "type" : "artist", - "uri" : "spotify:artist:1Yox196W7bzVNZI7RBaPnf" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 265133, - "explicit" : false, - "external_ids" : { - "isrc" : "GBAJE0100024" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/4Bfxp472zIwiSYjZsK76EN" - }, - "href" : "https://api.spotify.com/v1/tracks/4Bfxp472zIwiSYjZsK76EN", - "id" : "4Bfxp472zIwiSYjZsK76EN", - "is_local" : false, - "name" : "Dread and the Fugitive Mind", - "popularity" : 44, - "preview_url" : "https://p.scdn.co/mp3-preview/6614ac4f3149fdd7559bfd7fdceea386fcc353cc?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 9, - "type" : "track", - "uri" : "spotify:track:4Bfxp472zIwiSYjZsK76EN" - } - }, { - "added_at" : "2021-02-23T11:45:14Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir" - }, - "href" : "https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir", - "id" : "621sN6b7GCpWpzaSidA5Ir", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045", - "width" : 64 - } ], - "name" : "The Path of Apotheosis", - "release_date" : "2014-01-26", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:621sN6b7GCpWpzaSidA5Ir" - }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 354640, - "explicit" : false, - "external_ids" : { - "isrc" : "TCABS1379688" - }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/1lEnjsEH1zxGUkatGwMzSZ" + artists: { + items: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/01e2lCvLZ4fLUIRy68nptH', + }, + followers: { + href: null, + total: 104032, + }, + genres: ['deep euro house', 'tropical house'], + href: 'https://api.spotify.com/v1/artists/01e2lCvLZ4fLUIRy68nptH', + id: '01e2lCvLZ4fLUIRy68nptH', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/7d60ad2505e9a6922973d98fcc958a5742d1e3fc', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/d369947205e298b4928880de4609251c74a1bd37', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/bf0e990893ac10537df9e7006b6fa530fcfd9152', + width: 160, + }, + ], + name: 'Wankelmut', + popularity: 62, + type: 'artist', + uri: 'spotify:artist:01e2lCvLZ4fLUIRy68nptH', }, - "href" : "https://api.spotify.com/v1/tracks/1lEnjsEH1zxGUkatGwMzSZ", - "id" : "1lEnjsEH1zxGUkatGwMzSZ", - "is_local" : false, - "name" : "The Ancients of Shattered Thrones", - "popularity" : 19, - "preview_url" : "https://p.scdn.co/mp3-preview/bf7dde3c14e9deb854771d9ba8e0a1992f2f1257?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 10, - "type" : "track", - "uri" : "spotify:track:1lEnjsEH1zxGUkatGwMzSZ" - } - }, { - "added_at" : "2021-02-23T11:31:03Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/1EzRkEPmjf1ZEjTnWVXiQ2" - }, - "href" : "https://api.spotify.com/v1/artists/1EzRkEPmjf1ZEjTnWVXiQ2", - "id" : "1EzRkEPmjf1ZEjTnWVXiQ2", - "name" : "Mekong Delta", - "type" : "artist", - "uri" : "spotify:artist:1EzRkEPmjf1ZEjTnWVXiQ2" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6ajZAcA75EojcJaVGQuvCw" - }, - "href" : "https://api.spotify.com/v1/albums/6ajZAcA75EojcJaVGQuvCw", - "id" : "6ajZAcA75EojcJaVGQuvCw", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2732927156af0eef58c76fff96b", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e022927156af0eef58c76fff96b", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048512927156af0eef58c76fff96b", - "width" : 64 - } ], - "name" : "The Principle of Doubt", - "release_date" : "1989-02-25", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:6ajZAcA75EojcJaVGQuvCw" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/02IFYoziC7CpQRK8fbehUY', + }, + followers: { + href: null, + total: 69677, + }, + genres: ['bosnian indie', 'yugoslav rock'], + href: 'https://api.spotify.com/v1/artists/02IFYoziC7CpQRK8fbehUY', + id: '02IFYoziC7CpQRK8fbehUY', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/4d4d3364e73ae54728222ae56bbbe0d12b0e5b5c', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/26063266e6057cf23d349febddd436bf24a3c2d6', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/009eed443cdac4a909face78e92a45a9c74db7d4', + width: 160, + }, + ], + name: 'Dubioza kolektiv', + popularity: 48, + type: 'artist', + uri: 'spotify:artist:02IFYoziC7CpQRK8fbehUY', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/1EzRkEPmjf1ZEjTnWVXiQ2" - }, - "href" : "https://api.spotify.com/v1/artists/1EzRkEPmjf1ZEjTnWVXiQ2", - "id" : "1EzRkEPmjf1ZEjTnWVXiQ2", - "name" : "Mekong Delta", - "type" : "artist", - "uri" : "spotify:artist:1EzRkEPmjf1ZEjTnWVXiQ2" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 293386, - "explicit" : false, - "external_ids" : { - "isrc" : "DEA451302050" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/09b5OcuIELTdD7FfzQzcdB', + }, + followers: { + href: null, + total: 75811, + }, + genres: [ + 'folk metal', + 'italian folk metal', + 'italian metal', + 'italian power metal', + 'melodic metal', + 'neo classical metal', + 'power metal', + 'tolkien metal', + ], + href: 'https://api.spotify.com/v1/artists/09b5OcuIELTdD7FfzQzcdB', + id: '09b5OcuIELTdD7FfzQzcdB', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/fea03b617083289dcb5d699ac4dd06795f5fa1b2', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/5efd756ab2de73c9203efd4712e96c1f60c77a4b', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/9e5fd667763f8c399e11e2898913e6217be928b6', + width: 160, + }, + ], + name: 'Elvenking', + popularity: 47, + type: 'artist', + uri: 'spotify:artist:09b5OcuIELTdD7FfzQzcdB', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6J1slcIFHByPeRPIl6pFch" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/09mNj9XgCqgg6usfeXOoBg', + }, + followers: { + href: null, + total: 54207, + }, + genres: [ + 'death metal', + 'progressive thrash', + 'technical thrash', + 'thrash metal', + ], + href: 'https://api.spotify.com/v1/artists/09mNj9XgCqgg6usfeXOoBg', + id: '09mNj9XgCqgg6usfeXOoBg', + images: [ + { + height: 1000, + url: + 'https://i.scdn.co/image/c00df3db5fc12f38b33b5ee87933b7b01b0d6e41', + width: 1000, + }, + { + height: 640, + url: + 'https://i.scdn.co/image/5cc14441a00f2acd672b82d8e7c26b51f52042a2', + width: 640, + }, + { + height: 200, + url: + 'https://i.scdn.co/image/51b307cdb4314151ddba1ccf537d7379b90540de', + width: 200, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/bec64f91980d5fa49bcfddfa79afdde01cd644fc', + width: 64, + }, + ], + name: 'Vektor', + popularity: 41, + type: 'artist', + uri: 'spotify:artist:09mNj9XgCqgg6usfeXOoBg', }, - "href" : "https://api.spotify.com/v1/tracks/6J1slcIFHByPeRPIl6pFch", - "id" : "6J1slcIFHByPeRPIl6pFch", - "is_local" : false, - "name" : "The Principle of Doubt - Chapter 3 Taken From 'The Chronicle of Doubt'", - "popularity" : 3, - "preview_url" : "https://p.scdn.co/mp3-preview/32ebe5c7f3c69e0271ef9fc413f7dab36a9e532f?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:6J1slcIFHByPeRPIl6pFch" - } - }, { - "added_at" : "2021-02-21T16:15:55Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3" - }, - "href" : "https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3", - "id" : "4dhUo35WO3cGcFbxJ7ZIe3", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614", - "width" : 64 - } ], - "name" : "Immortal", - "release_date" : "2014-03-25", - "release_date_precision" : "day", - "total_tracks" : 8, - "type" : "album", - "uri" : "spotify:album:4dhUo35WO3cGcFbxJ7ZIe3" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/09xj0S68Y1OU1vHMCZAIvz', + }, + followers: { + href: null, + total: 2141543, + }, + genres: [ + 'latin', + 'latin alternative', + 'latin rock', + 'mexican rock', + 'rock en espanol', + ], + href: 'https://api.spotify.com/v1/artists/09xj0S68Y1OU1vHMCZAIvz', + id: '09xj0S68Y1OU1vHMCZAIvz', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/eaea517213a7e99edc151495a0895d8d1d40b7a9', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/16ce8f6551c151d3def2b9cb49e1cbd5ea6a3c16', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/f02aecc0e5b5c640ed4a26438fd508e6ffe82801', + width: 160, + }, + ], + name: 'Café Tacvba', + popularity: 73, + type: 'artist', + uri: 'spotify:artist:09xj0S68Y1OU1vHMCZAIvz', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 214737, - "explicit" : false, - "external_ids" : { - "isrc" : "USERN1008694" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0CGpNBihXlpMsjwHjVKNIO', + }, + followers: { + href: null, + total: 17921, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0CGpNBihXlpMsjwHjVKNIO', + id: '0CGpNBihXlpMsjwHjVKNIO', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/cc959a48c174f08e1f5c656e3374d44ab6eb9211', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/76053877a36da60b65f2cada8197a944f97e009a', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/f2609124643cf6971e1d998c9e4002307a9b4ebb', + width: 160, + }, + ], + name: 'zircon', + popularity: 39, + type: 'artist', + uri: 'spotify:artist:0CGpNBihXlpMsjwHjVKNIO', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3Yb3WCtJI3t0FCKzroKAv1" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0D3h8NZqNp7BN97JwtV6eW', + }, + followers: { + href: null, + total: 99008, + }, + genres: ['contemporary jazz', 'jazz piano', 'modern jazz piano'], + href: 'https://api.spotify.com/v1/artists/0D3h8NZqNp7BN97JwtV6eW', + id: '0D3h8NZqNp7BN97JwtV6eW', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/18a70e005024c92f275a99af18ffd67d6536c15c', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/bfaf5778d577873a79b3cbfd9436eeabac7227a2', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/0d856fcd8935efc502a46fd3d5baf53bf09643c5', + width: 160, + }, + ], + name: 'Tigran Hamasyan', + popularity: 49, + type: 'artist', + uri: 'spotify:artist:0D3h8NZqNp7BN97JwtV6eW', }, - "href" : "https://api.spotify.com/v1/tracks/3Yb3WCtJI3t0FCKzroKAv1", - "id" : "3Yb3WCtJI3t0FCKzroKAv1", - "is_local" : false, - "name" : "Ancient's Retribution", - "popularity" : 14, - "preview_url" : "https://p.scdn.co/mp3-preview/83b935148dcdb322ec0920be776a7ca8aecacdd6?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:3Yb3WCtJI3t0FCKzroKAv1" - } - }, { - "added_at" : "2021-02-21T16:10:28Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3" - }, - "href" : "https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3", - "id" : "4dhUo35WO3cGcFbxJ7ZIe3", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614", - "width" : 64 - } ], - "name" : "Immortal", - "release_date" : "2014-03-25", - "release_date_precision" : "day", - "total_tracks" : 8, - "type" : "album", - "uri" : "spotify:album:4dhUo35WO3cGcFbxJ7ZIe3" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0DAh8s6Hbl4xHZyTcbcqNe', + }, + followers: { + href: null, + total: 1350, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0DAh8s6Hbl4xHZyTcbcqNe', + id: '0DAh8s6Hbl4xHZyTcbcqNe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273ace9e880f57081964634c550', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02ace9e880f57081964634c550', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851ace9e880f57081964634c550', + width: 64, + }, + ], + name: 'Mz Sunday Luv', + popularity: 29, + type: 'artist', + uri: 'spotify:artist:0DAh8s6Hbl4xHZyTcbcqNe', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 306291, - "explicit" : false, - "external_ids" : { - "isrc" : "USERN1008693" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0DCw6lHkzh9t7f8Hb4Z0Sx', + }, + followers: { + href: null, + total: 648647, + }, + genres: [ + 'alternative metal', + 'death metal', + 'melodic death metal', + 'metal', + 'nu metal', + 'power metal', + 'slayer', + 'swedish death metal', + 'swedish metal', + ], + href: 'https://api.spotify.com/v1/artists/0DCw6lHkzh9t7f8Hb4Z0Sx', + id: '0DCw6lHkzh9t7f8Hb4Z0Sx', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/04cd9bccf59e8061f13e779d1001975a60fb837a', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/42b234b54c32d78a67ac6a59d3d90f1c87d6e4d8', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/e67d59099eb1f0d8f8477fcac3c2fe8a1ba4fc59', + width: 160, + }, + ], + name: 'Arch Enemy', + popularity: 61, + type: 'artist', + uri: 'spotify:artist:0DCw6lHkzh9t7f8Hb4Z0Sx', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0tAumAapgzzIiddYAwKKk2" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0E5cM2403VzBOV6z8NpSwS', + }, + followers: { + href: null, + total: 6707, + }, + genres: ['french techno', 'new french touch'], + href: 'https://api.spotify.com/v1/artists/0E5cM2403VzBOV6z8NpSwS', + id: '0E5cM2403VzBOV6z8NpSwS', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/34f959c1dbe0e9563c94c5d23b8ad6575814169d', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/53b0bf4e3187c18a9e76f4c588b93ffb3738345d', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/6c2f5b07fcfa336f2485c0390a651bdd48b4efeb', + width: 160, + }, + ], + name: 'Romulus', + popularity: 35, + type: 'artist', + uri: 'spotify:artist:0E5cM2403VzBOV6z8NpSwS', }, - "href" : "https://api.spotify.com/v1/tracks/0tAumAapgzzIiddYAwKKk2", - "id" : "0tAumAapgzzIiddYAwKKk2", - "is_local" : false, - "name" : "Vile Remnants", - "popularity" : 15, - "preview_url" : "https://p.scdn.co/mp3-preview/c4e4cd95d76ae2f6cd8e5362884465b253f0de82?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 3, - "type" : "track", - "uri" : "spotify:track:0tAumAapgzzIiddYAwKKk2" - } - }, { - "added_at" : "2021-02-21T16:01:37Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3" - }, - "href" : "https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3", - "id" : "4dhUo35WO3cGcFbxJ7ZIe3", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614", - "width" : 64 - } ], - "name" : "Immortal", - "release_date" : "2014-03-25", - "release_date_precision" : "day", - "total_tracks" : 8, - "type" : "album", - "uri" : "spotify:album:4dhUo35WO3cGcFbxJ7ZIe3" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0EP5EpsiMP8oLYy7sPHwf9', + }, + followers: { + href: null, + total: 29011, + }, + genres: ['ambeat'], + href: 'https://api.spotify.com/v1/artists/0EP5EpsiMP8oLYy7sPHwf9', + id: '0EP5EpsiMP8oLYy7sPHwf9', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/52fdd7574088de792aef240a884bfd890ccab005', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/3ccab09b219e69bdf5096d4c35b8f383853c777f', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/9b7ca1f242835632a10bf166c356f6b83195c16f', + width: 160, + }, + ], + name: 'The Shanghai Restoration Project', + popularity: 41, + type: 'artist', + uri: 'spotify:artist:0EP5EpsiMP8oLYy7sPHwf9', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB" - }, - "href" : "https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB", - "id" : "3ZOZaEFRuEhjsQ7QAPkpoB", - "name" : "Alterbeast", - "type" : "artist", - "uri" : "spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 156037, - "explicit" : false, - "external_ids" : { - "isrc" : "USERN1008692" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0F5fXdlx1bKwYFZ70bfuZ9', + }, + followers: { + href: null, + total: 10997, + }, + genres: ['dark cabaret', 'gypsy punk'], + href: 'https://api.spotify.com/v1/artists/0F5fXdlx1bKwYFZ70bfuZ9', + id: '0F5fXdlx1bKwYFZ70bfuZ9', + images: [ + { + height: 1265, + url: + 'https://i.scdn.co/image/895e1240c5873a53c378e623dac24355754f25a3', + width: 1000, + }, + { + height: 809, + url: + 'https://i.scdn.co/image/786249efd556f660ee702cf4fbd5930ed9e81d32', + width: 640, + }, + { + height: 253, + url: + 'https://i.scdn.co/image/85e2d1c23a44f8d0e93dafadbc8ef9a73e01ec30', + width: 200, + }, + { + height: 81, + url: + 'https://i.scdn.co/image/f58c77ba5ca9b811e897dd875c70957facdd8c61', + width: 64, + }, + ], + name: 'Firewater', + popularity: 32, + type: 'artist', + uri: 'spotify:artist:0F5fXdlx1bKwYFZ70bfuZ9', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/1q5lWOlLTs37JpEuFPJ5fZ" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0FEJqmeLRzsXj8hgcZaAyB', + }, + followers: { + href: null, + total: 496625, + }, + genres: ['french pop'], + href: 'https://api.spotify.com/v1/artists/0FEJqmeLRzsXj8hgcZaAyB', + id: '0FEJqmeLRzsXj8hgcZaAyB', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/c133119615054ff014873c547af89b5b9faff053', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/1c915845c79aee632442daef5bf1dac254bf0129', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/e6996fa1081ca9d7a030f0dc18cfdf4f220abcc8', + width: 160, + }, + ], + name: 'Indila', + popularity: 65, + type: 'artist', + uri: 'spotify:artist:0FEJqmeLRzsXj8hgcZaAyB', }, - "href" : "https://api.spotify.com/v1/tracks/1q5lWOlLTs37JpEuFPJ5fZ", - "id" : "1q5lWOlLTs37JpEuFPJ5fZ", - "is_local" : false, - "name" : "Of Decimus Divine", - "popularity" : 15, - "preview_url" : "https://p.scdn.co/mp3-preview/144b5550b29619e92e85a58456be171e1b113a48?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:1q5lWOlLTs37JpEuFPJ5fZ" - } - }, { - "added_at" : "2021-02-21T15:49:51Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir" - }, - "href" : "https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir", - "id" : "621sN6b7GCpWpzaSidA5Ir", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045", - "width" : 64 - } ], - "name" : "The Path of Apotheosis", - "release_date" : "2014-01-26", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:621sN6b7GCpWpzaSidA5Ir" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0GDGKpJFhVpcjIGF8N6Ewt', + }, + followers: { + href: null, + total: 753230, + }, + genres: [ + 'alternative metal', + 'french death metal', + 'french metal', + 'metal', + 'nu metal', + 'progressive groove metal', + ], + href: 'https://api.spotify.com/v1/artists/0GDGKpJFhVpcjIGF8N6Ewt', + id: '0GDGKpJFhVpcjIGF8N6Ewt', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/1ad6844cd3a0d5a195f2df98f44abfcbfe2f4d5e', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/aa05402b64cf462e74b1d0aef90f2fc58aff3e50', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/76d5d53e5649d896b215009fef0415929855b6c7', + width: 160, + }, + ], + name: 'Gojira', + popularity: 69, + type: 'artist', + uri: 'spotify:artist:0GDGKpJFhVpcjIGF8N6Ewt', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 359640, - "explicit" : false, - "external_ids" : { - "isrc" : "TCABS1379687" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0H0rBbf7vHXO3qh50Wap7y', + }, + followers: { + href: null, + total: 83362, + }, + genres: ['australian dance', 'electropop'], + href: 'https://api.spotify.com/v1/artists/0H0rBbf7vHXO3qh50Wap7y', + id: '0H0rBbf7vHXO3qh50Wap7y', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/b77a65e767ad547fcd14d62478499c1cbf1eaddb', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/4e2b8178dad5fac8334c3eacca167913f1f199ea', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/cfb4afb21ca5d527dd7dc482f1025cd1846fb555', + width: 160, + }, + ], + name: 'Sam Sparro', + popularity: 54, + type: 'artist', + uri: 'spotify:artist:0H0rBbf7vHXO3qh50Wap7y', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6S41USppfhF2c9xuNx97AN" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0HIiXblDOFPXxkuI35wOMx', + }, + followers: { + href: null, + total: 11334, + }, + genres: ['indie game soundtrack'], + href: 'https://api.spotify.com/v1/artists/0HIiXblDOFPXxkuI35wOMx', + id: '0HIiXblDOFPXxkuI35wOMx', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/4f9b285f4cce93c1ec05677466e757d65f88ec0c', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/ebb9a6d408c7acde44b0145f88acf3c69b407a18', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/dc3b6dbb2d9f79644c80cb160099047d269c6f81', + width: 160, + }, + ], + name: 'A Shell In The Pit', + popularity: 40, + type: 'artist', + uri: 'spotify:artist:0HIiXblDOFPXxkuI35wOMx', }, - "href" : "https://api.spotify.com/v1/tracks/6S41USppfhF2c9xuNx97AN", - "id" : "6S41USppfhF2c9xuNx97AN", - "is_local" : false, - "name" : "Marching Through the Flames of Tyranny", - "popularity" : 19, - "preview_url" : "https://p.scdn.co/mp3-preview/494f23683345af46e8cf3a7a224d42207d866588?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 9, - "type" : "track", - "uri" : "spotify:track:6S41USppfhF2c9xuNx97AN" - } - }, { - "added_at" : "2021-02-20T15:41:36Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZWab2LEVkNKiBPIClTwof" - }, - "href" : "https://api.spotify.com/v1/artists/3ZWab2LEVkNKiBPIClTwof", - "id" : "3ZWab2LEVkNKiBPIClTwof", - "name" : "Townes Van Zandt", - "type" : "artist", - "uri" : "spotify:artist:3ZWab2LEVkNKiBPIClTwof" - } ], - "available_markets" : [ "AD", "AE", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BT", "BW", "BY", "CH", "CL", "CM", "CO", "CV", "CW", "CY", "CZ", "DE", "DK", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GE", "GH", "GM", "GN", "GQ", "GR", "GW", "GY", "HK", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KR", "KW", "KZ", "LA", "LB", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MY", "NA", "NE", "NG", "NL", "NO", "NP", "NR", "NZ", "OM", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/08ADmkImC4Z1iMsaPr3NC0" - }, - "href" : "https://api.spotify.com/v1/albums/08ADmkImC4Z1iMsaPr3NC0", - "id" : "08ADmkImC4Z1iMsaPr3NC0", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273afcab75f7114347fc33cd3b0", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02afcab75f7114347fc33cd3b0", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851afcab75f7114347fc33cd3b0", - "width" : 64 - } ], - "name" : "Delta Momma Blues", - "release_date" : "1971", - "release_date_precision" : "year", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:08ADmkImC4Z1iMsaPr3NC0" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0I2XqVXqHScXjHhk6AYYRe', + }, + followers: { + href: null, + total: 12799, + }, + genres: ['swedish hip hop'], + href: 'https://api.spotify.com/v1/artists/0I2XqVXqHScXjHhk6AYYRe', + id: '0I2XqVXqHScXjHhk6AYYRe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/c813f0ada1150e5a8178c58b232776c77a51d3c2', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/dce640044ab954223f6f42fd942abeb1cd0ad009', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/3e39905f91afb235a7cb1e59373f72265ebf2345', + width: 160, + }, + ], + name: 'Afasi & Filthy', + popularity: 36, + type: 'artist', + uri: 'spotify:artist:0I2XqVXqHScXjHhk6AYYRe', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3ZWab2LEVkNKiBPIClTwof" - }, - "href" : "https://api.spotify.com/v1/artists/3ZWab2LEVkNKiBPIClTwof", - "id" : "3ZWab2LEVkNKiBPIClTwof", - "name" : "Townes Van Zandt", - "type" : "artist", - "uri" : "spotify:artist:3ZWab2LEVkNKiBPIClTwof" - } ], - "available_markets" : [ "AD", "AE", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BT", "BW", "BY", "CH", "CL", "CM", "CO", "CV", "CW", "CY", "CZ", "DE", "DK", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GE", "GH", "GM", "GN", "GQ", "GR", "GW", "GY", "HK", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KR", "KW", "KZ", "LA", "LB", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MY", "NA", "NE", "NG", "NL", "NO", "NP", "NR", "NZ", "OM", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 170533, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCEL0900069" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0IVapwlnM3dEOiMsHXsghT', + }, + followers: { + href: null, + total: 178393, + }, + genres: [ + 'bass music', + 'chillwave', + 'electronica', + 'future garage', + 'glitch hop', + 'microhouse', + 'ninja', + 'wonky', + ], + href: 'https://api.spotify.com/v1/artists/0IVapwlnM3dEOiMsHXsghT', + id: '0IVapwlnM3dEOiMsHXsghT', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/00a19cc20d357784893879834ca18fbfd27e9655', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/3d8ce0d7bf1dd5248b6c54959797b1aebaa022e3', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/7e64249b2122498c51e355cb2534927978ea47df', + width: 160, + }, + ], + name: 'Nosaj Thing', + popularity: 54, + type: 'artist', + uri: 'spotify:artist:0IVapwlnM3dEOiMsHXsghT', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0CieC8w6QH3SlIZeUZ8LoS" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0IhZsSjGTFJBXIM5unqzdV', + }, + followers: { + href: null, + total: 15382, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0IhZsSjGTFJBXIM5unqzdV', + id: '0IhZsSjGTFJBXIM5unqzdV', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273e19fbe2274c30d7d446ff359', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02e19fbe2274c30d7d446ff359', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851e19fbe2274c30d7d446ff359', + width: 64, + }, + ], + name: 'Jake Chudnow', + popularity: 32, + type: 'artist', + uri: 'spotify:artist:0IhZsSjGTFJBXIM5unqzdV', }, - "href" : "https://api.spotify.com/v1/tracks/0CieC8w6QH3SlIZeUZ8LoS", - "id" : "0CieC8w6QH3SlIZeUZ8LoS", - "is_local" : false, - "name" : "Where I Lead Me", - "popularity" : 10, - "preview_url" : "https://p.scdn.co/mp3-preview/4fc116ac66e2bf540d73228372afa26fe41059ac?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:0CieC8w6QH3SlIZeUZ8LoS" - } - }, { - "added_at" : "2021-02-18T16:29:40Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U" - }, - "href" : "https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U", - "id" : "3Gaqw2nGyE7yM3rcRSzE3U", - "name" : "Yppah", - "type" : "artist", - "uri" : "spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5La9Xx2vJ84n8yngUVJri2" - }, - "href" : "https://api.spotify.com/v1/albums/5La9Xx2vJ84n8yngUVJri2", - "id" : "5La9Xx2vJ84n8yngUVJri2", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739d0fd14571e635b96ba52112", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029d0fd14571e635b96ba52112", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519d0fd14571e635b96ba52112", - "width" : 64 - } ], - "name" : "Tiny Pause", - "release_date" : "2015-10-16", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:5La9Xx2vJ84n8yngUVJri2" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0IkzMM0QD6fdU7AQKbXpYi', + }, + followers: { + href: null, + total: 2143, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0IkzMM0QD6fdU7AQKbXpYi', + id: '0IkzMM0QD6fdU7AQKbXpYi', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/aca94342b436624a62c720d090f605170d66d81e', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/f8145c2c1e6139054c86950c6f12f968a3ad1cbc', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/d09db81428c6abb10bd3105c156c1f3b815a3c59', + width: 160, + }, + ], + name: 'Masvidal', + popularity: 9, + type: 'artist', + uri: 'spotify:artist:0IkzMM0QD6fdU7AQKbXpYi', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U" - }, - "href" : "https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U", - "id" : "3Gaqw2nGyE7yM3rcRSzE3U", - "name" : "Yppah", - "type" : "artist", - "uri" : "spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 336400, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCFB1503904" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0Iv00ucAIqr5KVS7bXGFa9', + }, + followers: { + href: null, + total: 52436, + }, + genres: [ + 'art rock', + 'instrumental rock', + 'jazz fusion', + 'progressive rock', + 'space rock', + 'symphonic rock', + ], + href: 'https://api.spotify.com/v1/artists/0Iv00ucAIqr5KVS7bXGFa9', + id: '0Iv00ucAIqr5KVS7bXGFa9', + images: [ + { + height: 1236, + url: + 'https://i.scdn.co/image/2404a62e8b362948196ff1971b187f7f405a3e59', + width: 1000, + }, + { + height: 791, + url: + 'https://i.scdn.co/image/277c815e9a8161b37e8fdb2adf5a71c148dfa8c4', + width: 640, + }, + { + height: 247, + url: + 'https://i.scdn.co/image/8834f3e239b5caa298d3931f8575651d40a0ee58', + width: 200, + }, + { + height: 79, + url: + 'https://i.scdn.co/image/b5a0b0e8798cef83ff2cae36ca8859799630fb17', + width: 64, + }, + ], + name: 'Ozric Tentacles', + popularity: 42, + type: 'artist', + uri: 'spotify:artist:0Iv00ucAIqr5KVS7bXGFa9', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/68W36X31D3o8XfXrWhBnZE" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0JWemE0N1N3nwrtMNg2eMO', + }, + followers: { + href: null, + total: 7443, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0JWemE0N1N3nwrtMNg2eMO', + id: '0JWemE0N1N3nwrtMNg2eMO', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/1876a17108ebd24144e2814fb9972b3d80f2bf3c', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/fa544662dd11b7c9be56ae2dc396bd20e3f1dbfc', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/169dda30158d34feb9fbebdb3ee88bb761a905d1', + width: 160, + }, + ], + name: 'Sky', + popularity: 38, + type: 'artist', + uri: 'spotify:artist:0JWemE0N1N3nwrtMNg2eMO', }, - "href" : "https://api.spotify.com/v1/tracks/68W36X31D3o8XfXrWhBnZE", - "id" : "68W36X31D3o8XfXrWhBnZE", - "is_local" : false, - "name" : "Owl Beach II", - "popularity" : 35, - "preview_url" : "https://p.scdn.co/mp3-preview/8ae8327ecc180bafc6a0f3da5d9ac6321beb81ac?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 5, - "type" : "track", - "uri" : "spotify:track:68W36X31D3o8XfXrWhBnZE" - } - }, { - "added_at" : "2021-02-18T15:59:46Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U" - }, - "href" : "https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U", - "id" : "3Gaqw2nGyE7yM3rcRSzE3U", - "name" : "Yppah", - "type" : "artist", - "uri" : "spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5La9Xx2vJ84n8yngUVJri2" - }, - "href" : "https://api.spotify.com/v1/albums/5La9Xx2vJ84n8yngUVJri2", - "id" : "5La9Xx2vJ84n8yngUVJri2", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739d0fd14571e635b96ba52112", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029d0fd14571e635b96ba52112", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519d0fd14571e635b96ba52112", - "width" : 64 - } ], - "name" : "Tiny Pause", - "release_date" : "2015-10-16", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:5La9Xx2vJ84n8yngUVJri2" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0JyCM9EwjQZZzQPGTSM1qc', + }, + followers: { + href: null, + total: 38532, + }, + genres: ['dreamo', 'piano rock', 'progressive post-hardcore'], + href: 'https://api.spotify.com/v1/artists/0JyCM9EwjQZZzQPGTSM1qc', + id: '0JyCM9EwjQZZzQPGTSM1qc', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/a92c800c230b9668bcb7a12eba99f6cc124aaa5e', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/b9e6547223ff429a4577af0466e89a37d759761d', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/1a1095ad5a8ffce0c112fc7398e6e6e7d2b635b9', + width: 160, + }, + ], + name: 'The Reign of Kindo', + popularity: 40, + type: 'artist', + uri: 'spotify:artist:0JyCM9EwjQZZzQPGTSM1qc', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U" - }, - "href" : "https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U", - "id" : "3Gaqw2nGyE7yM3rcRSzE3U", - "name" : "Yppah", - "type" : "artist", - "uri" : "spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 265586, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCFB1503906" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0KLylVDEP61slhDexriZLj', + }, + followers: { + href: null, + total: 4377, + }, + genres: ['downtempo fusion'], + href: 'https://api.spotify.com/v1/artists/0KLylVDEP61slhDexriZLj', + id: '0KLylVDEP61slhDexriZLj', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/5e26ac67543c2d5e48e949512ae85536d5b0eb95', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/a16088698d75176e5195fef22c61e8062a398085', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/0a244cd1e5c31916c9be48d3af55568ec6d26447', + width: 160, + }, + ], + name: 'Anomie Belle', + popularity: 35, + type: 'artist', + uri: 'spotify:artist:0KLylVDEP61slhDexriZLj', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/5cjBttolslxyUQSSabanA8" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0L8ExT028jH3ddEcZwqJJ5', + }, + followers: { + href: null, + total: 15504211, + }, + genres: [ + 'alternative rock', + 'funk metal', + 'funk rock', + 'permanent wave', + 'rock', + ], + href: 'https://api.spotify.com/v1/artists/0L8ExT028jH3ddEcZwqJJ5', + id: '0L8ExT028jH3ddEcZwqJJ5', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/89bc3c14aa2b4f250033ffcf5f322b2a553d9331', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/7251ac7f3c0262cfcfad32e214deda639a2b4b46', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/8def8c4db6061deb04daca08e43bcde57181ec8b', + width: 160, + }, + ], + name: 'Red Hot Chili Peppers', + popularity: 86, + type: 'artist', + uri: 'spotify:artist:0L8ExT028jH3ddEcZwqJJ5', }, - "href" : "https://api.spotify.com/v1/tracks/5cjBttolslxyUQSSabanA8", - "id" : "5cjBttolslxyUQSSabanA8", - "is_local" : false, - "name" : "Bushmills", - "popularity" : 39, - "preview_url" : "https://p.scdn.co/mp3-preview/d361baef69a29a74b95942f0ce9ec03caeedb48e?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 7, - "type" : "track", - "uri" : "spotify:track:5cjBttolslxyUQSSabanA8" - } - }, { - "added_at" : "2021-02-17T17:17:36Z", - "track" : { - "album" : { - "album_type" : "compilation", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" - }, - "href" : "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", - "id" : "0LyfQWJT6nXafLPZqxe9Of", - "name" : "Various Artists", - "type" : "artist", - "uri" : "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/61bYJTYERgYGSgFUamgTCa" - }, - "href" : "https://api.spotify.com/v1/albums/61bYJTYERgYGSgFUamgTCa", - "id" : "61bYJTYERgYGSgFUamgTCa", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27348e2a667de482192fddfeae0", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0248e2a667de482192fddfeae0", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485148e2a667de482192fddfeae0", - "width" : 64 - } ], - "name" : "Ninja Tune XX (Volume 2)", - "release_date" : "2010-09-20", - "release_date_precision" : "day", - "total_tracks" : 33, - "type" : "album", - "uri" : "spotify:album:61bYJTYERgYGSgFUamgTCa" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0L8QRAAuWjqvTM8FpQ1gYO', + }, + followers: { + href: null, + total: 248417, + }, + genres: [ + 'canadian metal', + 'death metal', + 'hard rock', + 'metal', + 'neo classical metal', + 'old school thrash', + 'power metal', + 'speed metal', + 'technical groove metal', + 'thrash metal', + ], + href: 'https://api.spotify.com/v1/artists/0L8QRAAuWjqvTM8FpQ1gYO', + id: '0L8QRAAuWjqvTM8FpQ1gYO', + images: [ + { + height: 1000, + url: + 'https://i.scdn.co/image/423b0a413d344b5e520bda76606b535250f6c130', + width: 1000, + }, + { + height: 640, + url: + 'https://i.scdn.co/image/08fdfc7c4f1c54c6806eefd26a4f86b2aa712171', + width: 640, + }, + { + height: 200, + url: + 'https://i.scdn.co/image/75b7833b5f8d0996782a344b5799858e62c1d9f4', + width: 200, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/cf5b9192955ec59cd046ac452f73202cccbed317', + width: 64, + }, + ], + name: 'Annihilator', + popularity: 51, + type: 'artist', + uri: 'spotify:artist:0L8QRAAuWjqvTM8FpQ1gYO', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U" - }, - "href" : "https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U", - "id" : "3Gaqw2nGyE7yM3rcRSzE3U", - "name" : "Yppah", - "type" : "artist", - "uri" : "spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 196000, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCFB1002229" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of', + }, + followers: { + href: null, + total: 1107624, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of', + id: '0LyfQWJT6nXafLPZqxe9Of', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/8987540724d78afbf9f9249638eefcef38c0853b', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/3439f512b1422283239d93985959dc6115eae9c2', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/51820ee3bf05021dc690ee7bf804b6d73eedb4a1', + width: 160, + }, + ], + name: 'Various Artists', + popularity: 0, + type: 'artist', + uri: 'spotify:artist:0LyfQWJT6nXafLPZqxe9Of', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/1sotD6Cn8aOtUsL0bd5HTJ" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0NDElNqwGRCmsYIQFapp6K', + }, + followers: { + href: null, + total: 46029, + }, + genres: [ + 'alternative dance', + 'filter house', + 'new french touch', + 'nu disco', + ], + href: 'https://api.spotify.com/v1/artists/0NDElNqwGRCmsYIQFapp6K', + id: '0NDElNqwGRCmsYIQFapp6K', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/12197dae5c2f5752da45b08f06953e2551066ebf', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/f36ccd906331b0ec7670d9b3986f1df7b18a80e5', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/971b050a4f1762eadcbe97df0c8d94399c551078', + width: 160, + }, + ], + name: 'Oliver', + popularity: 54, + type: 'artist', + uri: 'spotify:artist:0NDElNqwGRCmsYIQFapp6K', }, - "href" : "https://api.spotify.com/v1/tracks/1sotD6Cn8aOtUsL0bd5HTJ", - "id" : "1sotD6Cn8aOtUsL0bd5HTJ", - "is_local" : false, - "name" : "Never Mess With Sunday", - "popularity" : 47, - "preview_url" : "https://p.scdn.co/mp3-preview/8665b599fb5f17d3f3807c8e7d02a1bafeb5cea8?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 6, - "type" : "track", - "uri" : "spotify:track:1sotD6Cn8aOtUsL0bd5HTJ" - } - }, { - "added_at" : "2021-02-16T17:19:48Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb" - }, - "href" : "https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb", - "id" : "0cmWgDlu9CwTgxPhf403hb", - "name" : "Bonobo", - "type" : "artist", - "uri" : "spotify:artist:0cmWgDlu9CwTgxPhf403hb" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6tEOuMrJ6gsmZ2vB2P1NV7" - }, - "href" : "https://api.spotify.com/v1/albums/6tEOuMrJ6gsmZ2vB2P1NV7", - "id" : "6tEOuMrJ6gsmZ2vB2P1NV7", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273c46ca7a942d8795a06774df9", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02c46ca7a942d8795a06774df9", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851c46ca7a942d8795a06774df9", - "width" : 64 - } ], - "name" : "The North Borders Tour. — Live.", - "release_date" : "2014-10-06", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:6tEOuMrJ6gsmZ2vB2P1NV7" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0NmYchKQ8JIR9QHYJA0FRe', + }, + followers: { + href: null, + total: 365165, + }, + genres: [ + 'death metal', + 'groove metal', + 'hard rock', + 'metal', + 'old school thrash', + 'speed metal', + 'thrash metal', + ], + href: 'https://api.spotify.com/v1/artists/0NmYchKQ8JIR9QHYJA0FRe', + id: '0NmYchKQ8JIR9QHYJA0FRe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/cb3d3f098c6882bcc32925ccdd16b56e314e94f5', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/c79bc2d3afb81f5abc3c6163ffae390a634d984e', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/9b321c5f99ae8e3589113573dacf498a690578e5', + width: 160, + }, + ], + name: 'Overkill', + popularity: 50, + type: 'artist', + uri: 'spotify:artist:0NmYchKQ8JIR9QHYJA0FRe', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb" - }, - "href" : "https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb", - "id" : "0cmWgDlu9CwTgxPhf403hb", - "name" : "Bonobo", - "type" : "artist", - "uri" : "spotify:artist:0cmWgDlu9CwTgxPhf403hb" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 488144, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCFB1404616" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0OBYJhSLz23GVEmb7teDQ8', + }, + followers: { + href: null, + total: 1347, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0OBYJhSLz23GVEmb7teDQ8', + id: '0OBYJhSLz23GVEmb7teDQ8', + images: [], + name: 'Hiromi feat. Anthony Jackson, Simon Phillips', + popularity: 0, + type: 'artist', + uri: 'spotify:artist:0OBYJhSLz23GVEmb7teDQ8', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0PHSbSNolQJPl0NWpiDb3U" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0Ohm3LvFp7wzkvMeiTDPKQ', + }, + followers: { + href: null, + total: 13800, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0Ohm3LvFp7wzkvMeiTDPKQ', + id: '0Ohm3LvFp7wzkvMeiTDPKQ', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/c33c6c9bbdb7581b59490f3e2d1091d9322703e3', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/905ae8841faacfc94b1fe3a158276e17a40e4959', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/52fb4c5efb2b630a23e21975ea1c4237db5bbf63', + width: 160, + }, + ], + name: 'Mirwais', + popularity: 39, + type: 'artist', + uri: 'spotify:artist:0Ohm3LvFp7wzkvMeiTDPKQ', }, - "href" : "https://api.spotify.com/v1/tracks/0PHSbSNolQJPl0NWpiDb3U", - "id" : "0PHSbSNolQJPl0NWpiDb3U", - "is_local" : false, - "name" : "Kong/Ketto - Live", - "popularity" : 29, - "preview_url" : "https://p.scdn.co/mp3-preview/fa3625e4e97dec2ffdc107c7600957ee72d4b2d0?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 5, - "type" : "track", - "uri" : "spotify:track:0PHSbSNolQJPl0NWpiDb3U" - } - }, { - "added_at" : "2021-02-14T18:08:37Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI" - }, - "href" : "https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI", - "id" : "7yxi31szvlbwvKq9dYOmFI", - "name" : "Jon Hopkins", - "type" : "artist", - "uri" : "spotify:artist:7yxi31szvlbwvKq9dYOmFI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/1nvzBC1M3dlCMIxfUCBhlO" - }, - "href" : "https://api.spotify.com/v1/albums/1nvzBC1M3dlCMIxfUCBhlO", - "id" : "1nvzBC1M3dlCMIxfUCBhlO", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739d9126ec04bb005c687291a5", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029d9126ec04bb005c687291a5", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519d9126ec04bb005c687291a5", - "width" : 64 - } ], - "name" : "Singularity", - "release_date" : "2018-05-04", - "release_date_precision" : "day", - "total_tracks" : 12, - "type" : "album", - "uri" : "spotify:album:1nvzBC1M3dlCMIxfUCBhlO" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0R3pn7bweUwpLd98080DYO', + }, + followers: { + href: null, + total: 5115, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0R3pn7bweUwpLd98080DYO', + id: '0R3pn7bweUwpLd98080DYO', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/4e070b6e554c6d3670d97e219da3d6dfc84a996e', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/70a9d7092573d2d8c7d16a2347333c64d8d81e73', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/fcb0a1c7108e649fa7954cc0b4e5781918d2f98b', + width: 160, + }, + ], + name: 'Tumi', + popularity: 35, + type: 'artist', + uri: 'spotify:artist:0R3pn7bweUwpLd98080DYO', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI" - }, - "href" : "https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI", - "id" : "7yxi31szvlbwvKq9dYOmFI", - "name" : "Jon Hopkins", - "type" : "artist", - "uri" : "spotify:artist:7yxi31szvlbwvKq9dYOmFI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 428440, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCEL1700696" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0RMrzrDgqu7ipsDo1xNoNK', + }, + followers: { + href: null, + total: 487, + }, + genres: ['deep liquid bass'], + href: 'https://api.spotify.com/v1/artists/0RMrzrDgqu7ipsDo1xNoNK', + id: '0RMrzrDgqu7ipsDo1xNoNK', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2736758159c0ba81cda2dcb7f07', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e026758159c0ba81cda2dcb7f07', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048516758159c0ba81cda2dcb7f07', + width: 64, + }, + ], + name: 'Dub Phizix, Skeptical', + popularity: 0, + type: 'artist', + uri: 'spotify:artist:0RMrzrDgqu7ipsDo1xNoNK', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/4Hg9jafzzKavElQMAINzeP" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0SfsnGyD8FpIN4U4WCkBZ5', + }, + followers: { + href: null, + total: 3752178, + }, + genres: [ + 'dutch trance', + 'edm', + 'pop dance', + 'progressive house', + 'trance', + ], + href: 'https://api.spotify.com/v1/artists/0SfsnGyD8FpIN4U4WCkBZ5', + id: '0SfsnGyD8FpIN4U4WCkBZ5', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/b15e29059c98e971418bc0ec6deb2c99494eda32', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/b6d34c9fb5c0d0730921237549d5d522797cf759', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/1697ab36aaa2c6133221de70ce56d34eac0efc0e', + width: 160, + }, + ], + name: 'Armin van Buuren', + popularity: 79, + type: 'artist', + uri: 'spotify:artist:0SfsnGyD8FpIN4U4WCkBZ5', }, - "href" : "https://api.spotify.com/v1/tracks/4Hg9jafzzKavElQMAINzeP", - "id" : "4Hg9jafzzKavElQMAINzeP", - "is_local" : false, - "name" : "C O S M", - "popularity" : 40, - "preview_url" : "https://p.scdn.co/mp3-preview/48e0ddc28b1f196056c966612ea5dd6a590f2c1f?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 6, - "type" : "track", - "uri" : "spotify:track:4Hg9jafzzKavElQMAINzeP" - } - }, { - "added_at" : "2021-02-14T17:37:48Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI" - }, - "href" : "https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI", - "id" : "7yxi31szvlbwvKq9dYOmFI", - "name" : "Jon Hopkins", - "type" : "artist", - "uri" : "spotify:artist:7yxi31szvlbwvKq9dYOmFI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/1nvzBC1M3dlCMIxfUCBhlO" - }, - "href" : "https://api.spotify.com/v1/albums/1nvzBC1M3dlCMIxfUCBhlO", - "id" : "1nvzBC1M3dlCMIxfUCBhlO", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2739d9126ec04bb005c687291a5", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e029d9126ec04bb005c687291a5", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048519d9126ec04bb005c687291a5", - "width" : 64 - } ], - "name" : "Singularity", - "release_date" : "2018-05-04", - "release_date_precision" : "day", - "total_tracks" : 12, - "type" : "album", - "uri" : "spotify:album:1nvzBC1M3dlCMIxfUCBhlO" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0SqxIwLKk4cXkiv6dq3zEu', + }, + followers: { + href: null, + total: 18939, + }, + genres: ['czech electronic'], + href: 'https://api.spotify.com/v1/artists/0SqxIwLKk4cXkiv6dq3zEu', + id: '0SqxIwLKk4cXkiv6dq3zEu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/21c71a76a961c785e4fe6a56ad4fd013b99f81d3', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/8e302bf7ea09c4d38a5dccd375cfe50cc20e99aa', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/6315e94d36bd16f63aa73e8274b1218a838d9a11', + width: 160, + }, + ], + name: 'Floex', + popularity: 40, + type: 'artist', + uri: 'spotify:artist:0SqxIwLKk4cXkiv6dq3zEu', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI" - }, - "href" : "https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI", - "id" : "7yxi31szvlbwvKq9dYOmFI", - "name" : "Jon Hopkins", - "type" : "artist", - "uri" : "spotify:artist:7yxi31szvlbwvKq9dYOmFI" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 630240, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCEL1700694" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0SwO7SWeDHJijQ3XNS7xEE', + }, + followers: { + href: null, + total: 2134467, + }, + genres: [ + 'alternative dance', + 'indie rock', + 'indietronica', + 'modern rock', + 'rock', + ], + href: 'https://api.spotify.com/v1/artists/0SwO7SWeDHJijQ3XNS7xEE', + id: '0SwO7SWeDHJijQ3XNS7xEE', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/0760c3acca24fe81e9d217dd922ab36081383897', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/28ff19618ece117a1897d8e9298e8840a645a2a1', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/1b5cca2e02cc6bbfa7d215dbfe168c21217ab9a1', + width: 160, + }, + ], + name: 'MGMT', + popularity: 80, + type: 'artist', + uri: 'spotify:artist:0SwO7SWeDHJijQ3XNS7xEE', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3oWBMOzkjjkCmV6abncBUd" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0TF6B1cp2QZXLE0NjhTMT9', + }, + followers: { + href: null, + total: 44090, + }, + genres: [ + 'instrumental math rock', + 'instrumental rock', + 'japanese jazz fusion', + 'japanese math rock', + 'japanese post-rock', + 'math pop', + 'math rock', + 'post-rock', + ], + href: 'https://api.spotify.com/v1/artists/0TF6B1cp2QZXLE0NjhTMT9', + id: '0TF6B1cp2QZXLE0NjhTMT9', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ee723078cfe061dc07b63530e8c1d1162283cb54', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/bafd398a177842d21c48c895c451791467d66e1f', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/027ba0a5a66bf00360405f55fdd60811fd0db2d1', + width: 160, + }, + ], + name: 'LITE', + popularity: 37, + type: 'artist', + uri: 'spotify:artist:0TF6B1cp2QZXLE0NjhTMT9', }, - "href" : "https://api.spotify.com/v1/tracks/3oWBMOzkjjkCmV6abncBUd", - "id" : "3oWBMOzkjjkCmV6abncBUd", - "is_local" : false, - "name" : "Everything Connected", - "popularity" : 40, - "preview_url" : "https://p.scdn.co/mp3-preview/b143e3cc635e7a528908aa6be4c51f20fc934eb2?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:3oWBMOzkjjkCmV6abncBUd" - } - }, { - "added_at" : "2021-02-14T16:54:39Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w" - }, - "href" : "https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w", - "id" : "592TFYwu9Qb0RC1hKDbX2w", - "name" : "Helios", - "type" : "artist", - "uri" : "spotify:artist:592TFYwu9Qb0RC1hKDbX2w" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/1OF3AnbSDa1ZSEFE7lukTb" - }, - "href" : "https://api.spotify.com/v1/albums/1OF3AnbSDa1ZSEFE7lukTb", - "id" : "1OF3AnbSDa1ZSEFE7lukTb", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2738fc59fb3af5be43e27fe4ce1", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e028fc59fb3af5be43e27fe4ce1", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048518fc59fb3af5be43e27fe4ce1", - "width" : 64 - } ], - "name" : "Eingya", - "release_date" : "2009-01-16", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:1OF3AnbSDa1ZSEFE7lukTb" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0UHy12S8f94Sa0jc4dd6Jz', + }, + followers: { + href: null, + total: 46339, + }, + genres: ['classic greek rock', 'greek pop', 'laiko'], + href: 'https://api.spotify.com/v1/artists/0UHy12S8f94Sa0jc4dd6Jz', + id: '0UHy12S8f94Sa0jc4dd6Jz', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2737e2b4a1476d692a4face5994', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e027e2b4a1476d692a4face5994', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048517e2b4a1476d692a4face5994', + width: 64, + }, + ], + name: 'Pix Lax', + popularity: 46, + type: 'artist', + uri: 'spotify:artist:0UHy12S8f94Sa0jc4dd6Jz', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w" - }, - "href" : "https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w", - "id" : "592TFYwu9Qb0RC1hKDbX2w", - "name" : "Helios", - "type" : "artist", - "uri" : "spotify:artist:592TFYwu9Qb0RC1hKDbX2w" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 361880, - "explicit" : false, - "external_ids" : { - "isrc" : "GBJSN0600009" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0UdoKjWIe3tHyiqc4qT3Oz', + }, + followers: { + href: null, + total: 425561, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0UdoKjWIe3tHyiqc4qT3Oz', + id: '0UdoKjWIe3tHyiqc4qT3Oz', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273417bebe37c4c4c2430036143', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02417bebe37c4c4c2430036143', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851417bebe37c4c4c2430036143', + width: 64, + }, + ], + name: 'OMFG', + popularity: 58, + type: 'artist', + uri: 'spotify:artist:0UdoKjWIe3tHyiqc4qT3Oz', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6knzYloG0x3MroAhnLVLGe" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0Uox3PUw47qEqroDggrDRE', + }, + followers: { + href: null, + total: 5855, + }, + genres: ['belgian indie', 'belgian modern jazz'], + href: 'https://api.spotify.com/v1/artists/0Uox3PUw47qEqroDggrDRE', + id: '0Uox3PUw47qEqroDggrDRE', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/40af76191d97a4221740bef5c22015b5a173f32f', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/3866f9da4da0a016e56691536b692e4cf758abe3', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/9bb8b5dd6de8da5dc890cc0cb31af83a87de9910', + width: 160, + }, + ], + name: 'Nordmann', + popularity: 34, + type: 'artist', + uri: 'spotify:artist:0Uox3PUw47qEqroDggrDRE', }, - "href" : "https://api.spotify.com/v1/tracks/6knzYloG0x3MroAhnLVLGe", - "id" : "6knzYloG0x3MroAhnLVLGe", - "is_local" : false, - "name" : "Bless This Morning Year", - "popularity" : 40, - "preview_url" : "https://p.scdn.co/mp3-preview/c1ad776d9cd26552d99576d9474c8f1c6c8e27fe?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 1, - "type" : "track", - "uri" : "spotify:track:6knzYloG0x3MroAhnLVLGe" - } - }, { - "added_at" : "2021-02-12T11:30:08Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w" - }, - "href" : "https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w", - "id" : "592TFYwu9Qb0RC1hKDbX2w", - "name" : "Helios", - "type" : "artist", - "uri" : "spotify:artist:592TFYwu9Qb0RC1hKDbX2w" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/34CpMn9yU8iDcXDaSkrqXu" - }, - "href" : "https://api.spotify.com/v1/albums/34CpMn9yU8iDcXDaSkrqXu", - "id" : "34CpMn9yU8iDcXDaSkrqXu", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f2e49606713803f0def17afb", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f2e49606713803f0def17afb", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f2e49606713803f0def17afb", - "width" : 64 - } ], - "name" : "Yume", - "release_date" : "2015-09-11", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:34CpMn9yU8iDcXDaSkrqXu" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0VWRXoE547qHGpUemsl1ge', + }, + followers: { + href: null, + total: 31986, + }, + genres: ['turkish reggae'], + href: 'https://api.spotify.com/v1/artists/0VWRXoE547qHGpUemsl1ge', + id: '0VWRXoE547qHGpUemsl1ge', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2735ac8e878a5af6bebbcd83cd8', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e025ac8e878a5af6bebbcd83cd8', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048515ac8e878a5af6bebbcd83cd8', + width: 64, + }, + ], + name: 'Sattas', + popularity: 36, + type: 'artist', + uri: 'spotify:artist:0VWRXoE547qHGpUemsl1ge', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w" - }, - "href" : "https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w", - "id" : "592TFYwu9Qb0RC1hKDbX2w", - "name" : "Helios", - "type" : "artist", - "uri" : "spotify:artist:592TFYwu9Qb0RC1hKDbX2w" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 354642, - "explicit" : false, - "external_ids" : { - "isrc" : "DEX261500338" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0WSSKmoRbxqLf3MnXInQ2J', + }, + followers: { + href: null, + total: 113684, + }, + genres: [ + 'electronica', + 'microhouse', + 'minimal techno', + 'modular synth', + 'tech house', + ], + href: 'https://api.spotify.com/v1/artists/0WSSKmoRbxqLf3MnXInQ2J', + id: '0WSSKmoRbxqLf3MnXInQ2J', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/de9e5216b1f1dab4a23c3255e825fbacfe283e5a', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/59b6083d596c915afcd5b648b82e1acf3f9d9ce8', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/899420a94245c95a796a5d821f2dffa560877788', + width: 160, + }, + ], + name: 'Max Cooper', + popularity: 56, + type: 'artist', + uri: 'spotify:artist:0WSSKmoRbxqLf3MnXInQ2J', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3EfocVFnZdmxbNb8ALyC0X" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0WaR9ydw7sZikp1dfHV8Xc', + }, + followers: { + href: null, + total: 3298, + }, + genres: ['minimal dubstep'], + href: 'https://api.spotify.com/v1/artists/0WaR9ydw7sZikp1dfHV8Xc', + id: '0WaR9ydw7sZikp1dfHV8Xc', + images: [ + { + height: 1000, + url: + 'https://i.scdn.co/image/b392edb5a6450f82753d552f9ad9881db753cc04', + width: 1000, + }, + { + height: 640, + url: + 'https://i.scdn.co/image/a7ce93e4a402ffa1ac25beb4e7ee3540476b6210', + width: 640, + }, + { + height: 200, + url: + 'https://i.scdn.co/image/17291e7bedb3e55a69fe2fb08b1f215e7f6e0a7a', + width: 200, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/a0f4f2a923825321e8827f24e9149cce32c7e658', + width: 64, + }, + ], + name: 'Killawatt', + popularity: 17, + type: 'artist', + uri: 'spotify:artist:0WaR9ydw7sZikp1dfHV8Xc', }, - "href" : "https://api.spotify.com/v1/tracks/3EfocVFnZdmxbNb8ALyC0X", - "id" : "3EfocVFnZdmxbNb8ALyC0X", - "is_local" : false, - "name" : "Yume", - "popularity" : 21, - "preview_url" : "https://p.scdn.co/mp3-preview/b6a5cc38391ceac77396ed6af7ee01263ca678ce?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 5, - "type" : "track", - "uri" : "spotify:track:3EfocVFnZdmxbNb8ALyC0X" - } - }, { - "added_at" : "2021-02-10T18:04:58Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rj2COYs5hQsw8rYIxSviz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rj2COYs5hQsw8rYIxSviz", - "id" : "4Rj2COYs5hQsw8rYIxSviz", - "name" : "Hidden Orchestra", - "type" : "artist", - "uri" : "spotify:artist:4Rj2COYs5hQsw8rYIxSviz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0nrfkNR7u975aqMt0R1E7n" - }, - "href" : "https://api.spotify.com/v1/albums/0nrfkNR7u975aqMt0R1E7n", - "id" : "0nrfkNR7u975aqMt0R1E7n", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2731df785bc2b00a1be5d803e6f", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e021df785bc2b00a1be5d803e6f", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048511df785bc2b00a1be5d803e6f", - "width" : 64 - } ], - "name" : "Dawn Chorus", - "release_date" : "2017-06-16", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:0nrfkNR7u975aqMt0R1E7n" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0WwSkZ7LtFUFjGjMZBMt6T', + }, + followers: { + href: null, + total: 4397737, + }, + genres: [ + 'album rock', + 'classic rock', + 'mellow gold', + 'rock', + 'soft rock', + ], + href: 'https://api.spotify.com/v1/artists/0WwSkZ7LtFUFjGjMZBMt6T', + id: '0WwSkZ7LtFUFjGjMZBMt6T', + images: [ + { + height: 1021, + url: + 'https://i.scdn.co/image/54a86ecf1de16b17e2ed000a9ca8a1590c9a3b80', + width: 1000, + }, + { + height: 653, + url: + 'https://i.scdn.co/image/caf04a8a030c70dd697ee0b37562033bbe3cdb4f', + width: 640, + }, + { + height: 204, + url: + 'https://i.scdn.co/image/7756c61bed0dc7650b188a4c7be984dc4e1d7651', + width: 200, + }, + { + height: 65, + url: + 'https://i.scdn.co/image/0ba7e13266153e59b9b611cbd43e21aec7f6737c', + width: 64, + }, + ], + name: 'Dire Straits', + popularity: 79, + type: 'artist', + uri: 'spotify:artist:0WwSkZ7LtFUFjGjMZBMt6T', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rj2COYs5hQsw8rYIxSviz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rj2COYs5hQsw8rYIxSviz", - "id" : "4Rj2COYs5hQsw8rYIxSviz", - "name" : "Hidden Orchestra", - "type" : "artist", - "uri" : "spotify:artist:4Rj2COYs5hQsw8rYIxSviz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 351920, - "explicit" : false, - "external_ids" : { - "isrc" : "GBEUE1700004" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0XNa1vTidXlvJ2gHSsRi4A', + }, + followers: { + href: null, + total: 1990666, + }, + genres: [ + 'alternative rock', + 'dance-punk', + 'indie rock', + 'modern rock', + 'new rave', + 'rock', + 'scottish rock', + ], + href: 'https://api.spotify.com/v1/artists/0XNa1vTidXlvJ2gHSsRi4A', + id: '0XNa1vTidXlvJ2gHSsRi4A', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/445c11fcc1637f94f48cee1d3354d478f10ac403', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/74d44570990858341836261beb39b3faa18f7603', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/83bb403e52b2c05b7420a5ebd8e502915b6ec6ad', + width: 160, + }, + ], + name: 'Franz Ferdinand', + popularity: 70, + type: 'artist', + uri: 'spotify:artist:0XNa1vTidXlvJ2gHSsRi4A', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/2jSZLKZFC5LclPiao0W1zz" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0Y8KmFkKOgJybpVobn1onU', + }, + followers: { + href: null, + total: 600125, + }, + genres: [ + 'canzone napoletana', + 'classical tenor', + 'italian tenor', + 'opera', + 'operatic pop', + ], + href: 'https://api.spotify.com/v1/artists/0Y8KmFkKOgJybpVobn1onU', + id: '0Y8KmFkKOgJybpVobn1onU', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/5e80aa2fe42fd8946b69ca25c436330c722ac0fb', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/609c65d0ece55692ed168f34f65559916281686d', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/52d956144b81e31d9b2c16c613c0438bf653338d', + width: 160, + }, + ], + name: 'Luciano Pavarotti', + popularity: 68, + type: 'artist', + uri: 'spotify:artist:0Y8KmFkKOgJybpVobn1onU', }, - "href" : "https://api.spotify.com/v1/tracks/2jSZLKZFC5LclPiao0W1zz", - "id" : "2jSZLKZFC5LclPiao0W1zz", - "is_local" : false, - "name" : "The Lizard", - "popularity" : 14, - "preview_url" : "https://p.scdn.co/mp3-preview/0e1519e015cdb9237a6eba0428dc3ef7179f6bc7?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:2jSZLKZFC5LclPiao0W1zz" - } - }, { - "added_at" : "2021-02-10T12:57:29Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb" - }, - "href" : "https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb", - "id" : "0cmWgDlu9CwTgxPhf403hb", - "name" : "Bonobo", - "type" : "artist", - "uri" : "spotify:artist:0cmWgDlu9CwTgxPhf403hb" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6tEOuMrJ6gsmZ2vB2P1NV7" - }, - "href" : "https://api.spotify.com/v1/albums/6tEOuMrJ6gsmZ2vB2P1NV7", - "id" : "6tEOuMrJ6gsmZ2vB2P1NV7", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273c46ca7a942d8795a06774df9", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02c46ca7a942d8795a06774df9", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851c46ca7a942d8795a06774df9", - "width" : 64 - } ], - "name" : "The North Borders Tour. — Live.", - "release_date" : "2014-10-06", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:6tEOuMrJ6gsmZ2vB2P1NV7" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0YJxNQtyb8jlldIC1DTkIf', + }, + followers: { + href: null, + total: 25727, + }, + genres: ['turntablism'], + href: 'https://api.spotify.com/v1/artists/0YJxNQtyb8jlldIC1DTkIf', + id: '0YJxNQtyb8jlldIC1DTkIf', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/e0cb8214500faeca3eb7771dd1eb919893c50fb3', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/4e05d7703c46be8c825c25701358eea5a15e1230', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/bceaba3afae840d493d5a4b5246fd3df5876de73', + width: 160, + }, + ], + name: 'Scratch Bandits Crew', + popularity: 44, + type: 'artist', + uri: 'spotify:artist:0YJxNQtyb8jlldIC1DTkIf', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb" - }, - "href" : "https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb", - "id" : "0cmWgDlu9CwTgxPhf403hb", - "name" : "Bonobo", - "type" : "artist", - "uri" : "spotify:artist:0cmWgDlu9CwTgxPhf403hb" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 489763, - "explicit" : false, - "external_ids" : { - "isrc" : "GBCFB1404615" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0ZXKT0FCsLWkSLCjoBJgBX', + }, + followers: { + href: null, + total: 248652, + }, + genres: ['gothic metal', 'progressive doom', 'progressive metal'], + href: 'https://api.spotify.com/v1/artists/0ZXKT0FCsLWkSLCjoBJgBX', + id: '0ZXKT0FCsLWkSLCjoBJgBX', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/5bfccbb8c43027b7efa93dbd4ed2bf366a34398c', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/c429e198e3700fc90420136862d07a9037c599a8', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/0d2d6caed428138b9161dba0a3ed9c8fd725c53b', + width: 160, + }, + ], + name: 'Anathema', + popularity: 56, + type: 'artist', + uri: 'spotify:artist:0ZXKT0FCsLWkSLCjoBJgBX', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/5lcTh4kYshToQMHnlNsxaj" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0bBjMMS4rONUFXs6y1iHpv', + }, + followers: { + href: null, + total: 1372, + }, + genres: [], + href: 'https://api.spotify.com/v1/artists/0bBjMMS4rONUFXs6y1iHpv', + id: '0bBjMMS4rONUFXs6y1iHpv', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27391d36c800895d728066d55e6', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0291d36c800895d728066d55e6', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485191d36c800895d728066d55e6', + width: 64, + }, + ], + name: 'Klint', + popularity: 4, + type: 'artist', + uri: 'spotify:artist:0bBjMMS4rONUFXs6y1iHpv', }, - "href" : "https://api.spotify.com/v1/tracks/5lcTh4kYshToQMHnlNsxaj", - "id" : "5lcTh4kYshToQMHnlNsxaj", - "is_local" : false, - "name" : "Prelude/Kiara/Ten Tigers - Live", - "popularity" : 33, - "preview_url" : "https://p.scdn.co/mp3-preview/51f13199a68b793b87cfc30a78e9df560264bd21?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 4, - "type" : "track", - "uri" : "spotify:track:5lcTh4kYshToQMHnlNsxaj" - } - }, { - "added_at" : "2021-02-09T15:57:33Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2p2uE4i92Dn4DkThfoKIB9" - }, - "href" : "https://api.spotify.com/v1/artists/2p2uE4i92Dn4DkThfoKIB9", - "id" : "2p2uE4i92Dn4DkThfoKIB9", - "name" : "Igorrr", - "type" : "artist", - "uri" : "spotify:artist:2p2uE4i92Dn4DkThfoKIB9" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/4hl7ryP7L1SvblrcPRAkpQ" - }, - "href" : "https://api.spotify.com/v1/albums/4hl7ryP7L1SvblrcPRAkpQ", - "id" : "4hl7ryP7L1SvblrcPRAkpQ", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273bee3918143b9d6e5571239b4", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02bee3918143b9d6e5571239b4", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851bee3918143b9d6e5571239b4", - "width" : 64 - } ], - "name" : "Spirituality and Distortion", - "release_date" : "2020-03-27", - "release_date_precision" : "day", - "total_tracks" : 14, - "type" : "album", - "uri" : "spotify:album:4hl7ryP7L1SvblrcPRAkpQ" + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0bZCak2tcRMY1dzEIuwF42', + }, + followers: { + href: null, + total: 350821, + }, + genres: [ + 'bath indie', + 'funk', + 'garage rock', + 'modern alternative rock', + 'modern blues rock', + 'modern rock', + 'rock', + ], + href: 'https://api.spotify.com/v1/artists/0bZCak2tcRMY1dzEIuwF42', + id: '0bZCak2tcRMY1dzEIuwF42', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/902fb7929782b9ac35a0002fa4cfcd29c5e97eaf', + width: 640, + }, + { + height: 320, + url: + 'https://i.scdn.co/image/33cd1de985a6b3442e8e8e26fabfcfd753c1ac1a', + width: 320, + }, + { + height: 160, + url: + 'https://i.scdn.co/image/7e64f1693ea64afb078320813aa7afd01a077b9f', + width: 160, + }, + ], + name: 'The Heavy', + popularity: 62, + type: 'artist', + uri: 'spotify:artist:0bZCak2tcRMY1dzEIuwF42', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2p2uE4i92Dn4DkThfoKIB9" - }, - "href" : "https://api.spotify.com/v1/artists/2p2uE4i92Dn4DkThfoKIB9", - "id" : "2p2uE4i92Dn4DkThfoKIB9", - "name" : "Igorrr", - "type" : "artist", - "uri" : "spotify:artist:2p2uE4i92Dn4DkThfoKIB9" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 203186, - "explicit" : false, - "external_ids" : { - "isrc" : "USMBR1913984" + ], + next: + 'https://api.spotify.com/v1/me/following?type=artist&after=0bZCak2tcRMY1dzEIuwF42&limit=50', + total: 674, + cursors: { + after: '0bZCak2tcRMY1dzEIuwF42', + }, + limit: 50, + href: 'https://api.spotify.com/v1/me/following?type=artist&limit=50', + }, +}; + +const trackData = { + href: 'https://api.spotify.com/v1/me/tracks?offset=0&limit=50', + items: [ + { + added_at: '2021-03-04T21:45:53Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '02IFYoziC7CpQRK8fbehUY', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '02IFYoziC7CpQRK8fbehUY', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 508773, + explicit: false, + external_ids: { + isrc: 'GBMEF1600916', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/2sEmZge5ZfzrFrDGFJbkyP', + }, + href: 'https://api.spotify.com/v1/tracks/2sEmZge5ZfzrFrDGFJbkyP', + id: '2sEmZge5ZfzrFrDGFJbkyP', + is_local: false, + name: 'Strings of Light', + popularity: 42, + preview_url: + 'https://p.scdn.co/mp3-preview/2b19dd719e857867cf4e228697a230fb5036ad71?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:2sEmZge5ZfzrFrDGFJbkyP', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0GOytj5zpFRpjGN04FLmHT" + }, + { + added_at: '2021-03-04T21:40:32Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI', + }, + href: 'https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI', + id: '2i1CPudyCUjL50Wqjv8AMI', + name: 'Alfa Mist', + type: 'artist', + uri: 'spotify:artist:2i1CPudyCUjL50Wqjv8AMI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/38XUFMsLLAttgWdD40CTaL', + }, + href: 'https://api.spotify.com/v1/albums/38XUFMsLLAttgWdD40CTaL', + id: '38XUFMsLLAttgWdD40CTaL', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2733979878917bb0159fa35b0ac', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e023979878917bb0159fa35b0ac', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048513979878917bb0159fa35b0ac', + width: 64, + }, + ], + name: 'Structuralism', + release_date: '2019-04-26', + release_date_precision: 'day', + total_tracks: 8, + type: 'album', + uri: 'spotify:album:38XUFMsLLAttgWdD40CTaL', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI', + }, + href: 'https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI', + id: '2i1CPudyCUjL50Wqjv8AMI', + name: 'Alfa Mist', + type: 'artist', + uri: 'spotify:artist:2i1CPudyCUjL50Wqjv8AMI', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/24icoQNJSEWNu3XvqKBR68', + }, + href: 'https://api.spotify.com/v1/artists/24icoQNJSEWNu3XvqKBR68', + id: '24icoQNJSEWNu3XvqKBR68', + name: 'Jordan Rakei', + type: 'artist', + uri: 'spotify:artist:24icoQNJSEWNu3XvqKBR68', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 247760, + explicit: false, + external_ids: { + isrc: 'FR10S1947881', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/5IOLaZLFnrBIjZImSS1E1u', + }, + href: 'https://api.spotify.com/v1/tracks/5IOLaZLFnrBIjZImSS1E1u', + id: '5IOLaZLFnrBIjZImSS1E1u', + is_local: false, + name: 'Door', + popularity: 46, + preview_url: + 'https://p.scdn.co/mp3-preview/3c946c3053abaaf1f678a14eb874ec13ec71dcdf?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:5IOLaZLFnrBIjZImSS1E1u', }, - "href" : "https://api.spotify.com/v1/tracks/0GOytj5zpFRpjGN04FLmHT", - "id" : "0GOytj5zpFRpjGN04FLmHT", - "is_local" : false, - "name" : "Nervous Waltz", - "popularity" : 38, - "preview_url" : "https://p.scdn.co/mp3-preview/af61b3d905038e7db4dfad071d0568f13175132e?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:0GOytj5zpFRpjGN04FLmHT" - } - }, { - "added_at" : "2021-01-31T12:23:58Z", - "track" : { - "album" : { - "album_type" : "single", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0iT2o4MNsBKSLy7bllgdo0" - }, - "href" : "https://api.spotify.com/v1/artists/0iT2o4MNsBKSLy7bllgdo0", - "id" : "0iT2o4MNsBKSLy7bllgdo0", - "name" : "Jus Now", - "type" : "artist", - "uri" : "spotify:artist:0iT2o4MNsBKSLy7bllgdo0" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6s7bgHlLfKpbb3YT01gfLH" - }, - "href" : "https://api.spotify.com/v1/albums/6s7bgHlLfKpbb3YT01gfLH", - "id" : "6s7bgHlLfKpbb3YT01gfLH", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273c66a1f51ed84b8117ae00c76", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02c66a1f51ed84b8117ae00c76", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851c66a1f51ed84b8117ae00c76", - "width" : 64 - } ], - "name" : "Cyah Help It", - "release_date" : "2015-10-16", - "release_date_precision" : "day", - "total_tracks" : 1, - "type" : "album", - "uri" : "spotify:album:6s7bgHlLfKpbb3YT01gfLH" + }, + { + added_at: '2021-03-04T21:38:46Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI', + }, + href: 'https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI', + id: '2i1CPudyCUjL50Wqjv8AMI', + name: 'Alfa Mist', + type: 'artist', + uri: 'spotify:artist:2i1CPudyCUjL50Wqjv8AMI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/3joOXpEsCgg8oS1Tba7neT', + }, + href: 'https://api.spotify.com/v1/albums/3joOXpEsCgg8oS1Tba7neT', + id: '3joOXpEsCgg8oS1Tba7neT', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2735d46b069ef33382b235b296a', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e025d46b069ef33382b235b296a', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048515d46b069ef33382b235b296a', + width: 64, + }, + ], + name: 'Antiphon', + release_date: '2017-03-03', + release_date_precision: 'day', + total_tracks: 8, + type: 'album', + uri: 'spotify:album:3joOXpEsCgg8oS1Tba7neT', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2i1CPudyCUjL50Wqjv8AMI', + }, + href: 'https://api.spotify.com/v1/artists/2i1CPudyCUjL50Wqjv8AMI', + id: '2i1CPudyCUjL50Wqjv8AMI', + name: 'Alfa Mist', + type: 'artist', + uri: 'spotify:artist:2i1CPudyCUjL50Wqjv8AMI', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/12WK0pR6DK71O5uqTHWzyE', + }, + href: 'https://api.spotify.com/v1/artists/12WK0pR6DK71O5uqTHWzyE', + id: '12WK0pR6DK71O5uqTHWzyE', + name: 'Kaya Thomas-Dyke', + type: 'artist', + uri: 'spotify:artist:12WK0pR6DK71O5uqTHWzyE', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 447000, + explicit: false, + external_ids: { + isrc: 'USCGH1770627', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6nGNzqlHTKugpRWkXrZkPC', + }, + href: 'https://api.spotify.com/v1/tracks/6nGNzqlHTKugpRWkXrZkPC', + id: '6nGNzqlHTKugpRWkXrZkPC', + is_local: false, + name: 'Breathe', + popularity: 48, + preview_url: + 'https://p.scdn.co/mp3-preview/a9ef0a470e447546df7cbb6fe0b042a7c1f2a14e?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:6nGNzqlHTKugpRWkXrZkPC', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0iT2o4MNsBKSLy7bllgdo0" - }, - "href" : "https://api.spotify.com/v1/artists/0iT2o4MNsBKSLy7bllgdo0", - "id" : "0iT2o4MNsBKSLy7bllgdo0", - "name" : "Jus Now", - "type" : "artist", - "uri" : "spotify:artist:0iT2o4MNsBKSLy7bllgdo0" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/42qLC3FgtazA9AvaIoiP62" - }, - "href" : "https://api.spotify.com/v1/artists/42qLC3FgtazA9AvaIoiP62", - "id" : "42qLC3FgtazA9AvaIoiP62", - "name" : "Ms. Dynamite", - "type" : "artist", - "uri" : "spotify:artist:42qLC3FgtazA9AvaIoiP62" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6nPHDCN7qmxO86eN1grP54" - }, - "href" : "https://api.spotify.com/v1/artists/6nPHDCN7qmxO86eN1grP54", - "id" : "6nPHDCN7qmxO86eN1grP54", - "name" : "Bunji Garlin", - "type" : "artist", - "uri" : "spotify:artist:6nPHDCN7qmxO86eN1grP54" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 188442, - "explicit" : false, - "external_ids" : { - "isrc" : "GB9TP1500480" + }, + { + added_at: '2021-03-04T21:34:16Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 46920, + explicit: false, + external_ids: { + isrc: 'GBMEF1600928', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/5EqkuCTZTSMhZm2sLhA7JN', + }, + href: 'https://api.spotify.com/v1/tracks/5EqkuCTZTSMhZm2sLhA7JN', + id: '5EqkuCTZTSMhZm2sLhA7JN', + is_local: false, + name: 'O.G.', + popularity: 28, + preview_url: + 'https://p.scdn.co/mp3-preview/5a6fd9533dd0100396588ed6c213b8073239d246?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 6, + type: 'track', + uri: 'spotify:track:5EqkuCTZTSMhZm2sLhA7JN', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/7M5GI36F8By0vFycdQ4pke" + }, + { + added_at: '2021-03-04T18:31:40Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 239480, + explicit: false, + external_ids: { + isrc: 'GBMEF1600918', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/4doeILSOpBXjzWsiJiSS8a', + }, + href: 'https://api.spotify.com/v1/tracks/4doeILSOpBXjzWsiJiSS8a', + id: '4doeILSOpBXjzWsiJiSS8a', + is_local: false, + name: 'Yo Chavez', + popularity: 32, + preview_url: + 'https://p.scdn.co/mp3-preview/abb79b375f7ac02161f3a56e9cc7684e658f1918?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:4doeILSOpBXjzWsiJiSS8a', }, - "href" : "https://api.spotify.com/v1/tracks/7M5GI36F8By0vFycdQ4pke", - "id" : "7M5GI36F8By0vFycdQ4pke", - "is_local" : false, - "name" : "Cyah Help It", - "popularity" : 5, - "preview_url" : "https://p.scdn.co/mp3-preview/fdbe06d7d3dadab133161dd9edc16a45bdb40588?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 1, - "type" : "track", - "uri" : "spotify:track:7M5GI36F8By0vFycdQ4pke" - } - }, { - "added_at" : "2021-01-30T18:38:52Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/57dN52uHvrHOxijzpIgu3E" - }, - "href" : "https://api.spotify.com/v1/artists/57dN52uHvrHOxijzpIgu3E", - "id" : "57dN52uHvrHOxijzpIgu3E", - "name" : "Ratatat", - "type" : "artist", - "uri" : "spotify:artist:57dN52uHvrHOxijzpIgu3E" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/7nqSnoxmIdcfxAJBxl9AIh" - }, - "href" : "https://api.spotify.com/v1/albums/7nqSnoxmIdcfxAJBxl9AIh", - "id" : "7nqSnoxmIdcfxAJBxl9AIh", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2731e86a07cda05a74debfd1ac2", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e021e86a07cda05a74debfd1ac2", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048511e86a07cda05a74debfd1ac2", - "width" : 64 - } ], - "name" : "Ratatat", - "release_date" : "2004-04-19", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:7nqSnoxmIdcfxAJBxl9AIh" + }, + { + added_at: '2021-03-04T18:04:50Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 268466, + explicit: false, + external_ids: { + isrc: 'GBMEF1600919', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/7gHdjudTKmgDcWSKPpJk9h', + }, + href: 'https://api.spotify.com/v1/tracks/7gHdjudTKmgDcWSKPpJk9h', + id: '7gHdjudTKmgDcWSKPpJk9h', + is_local: false, + name: 'Lowrider', + popularity: 39, + preview_url: + 'https://p.scdn.co/mp3-preview/fec1d7bc1913443a53ea83fa15db17d10816ea65?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 7, + type: 'track', + uri: 'spotify:track:7gHdjudTKmgDcWSKPpJk9h', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/57dN52uHvrHOxijzpIgu3E" - }, - "href" : "https://api.spotify.com/v1/artists/57dN52uHvrHOxijzpIgu3E", - "id" : "57dN52uHvrHOxijzpIgu3E", - "name" : "Ratatat", - "type" : "artist", - "uri" : "spotify:artist:57dN52uHvrHOxijzpIgu3E" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 338333, - "explicit" : false, - "external_ids" : { - "isrc" : "GBBKS0300144" + }, + { + added_at: '2021-03-04T17:40:14Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '710FHFQeXKC6dZGCxt7kQh', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 540546, + explicit: false, + external_ids: { + isrc: 'GBMEF1600917', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/1k7B553lUeQY3cyltjRWCH', + }, + href: 'https://api.spotify.com/v1/tracks/1k7B553lUeQY3cyltjRWCH', + id: '1k7B553lUeQY3cyltjRWCH', + is_local: false, + name: 'Remembrance', + popularity: 38, + preview_url: + 'https://p.scdn.co/mp3-preview/8a46cf5b255fa559f261d9450bd273da0e4f99fe?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 3, + type: 'track', + uri: 'spotify:track:1k7B553lUeQY3cyltjRWCH', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6zgCycfVETCfk2TNY7Othq" + }, + { + added_at: '2021-02-28T18:59:00Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe', + }, + href: 'https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe', + id: '6utXOCDpTDavsVbjQgPxpe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c', + width: 64, + }, + ], + name: 'Disappointment Island', + release_date: '2016-07-08', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6utXOCDpTDavsVbjQgPxpe', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 256186, + explicit: false, + external_ids: { + isrc: 'QMLD61404135', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6a76vVSWwjhLHCh2uV8XK3', + }, + href: 'https://api.spotify.com/v1/tracks/6a76vVSWwjhLHCh2uV8XK3', + id: '6a76vVSWwjhLHCh2uV8XK3', + is_local: false, + name: 'In Praise of Idleness', + popularity: 24, + preview_url: + 'https://p.scdn.co/mp3-preview/a3e646f8850d8ddc346e184af120255fb1cfa41b?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:6a76vVSWwjhLHCh2uV8XK3', }, - "href" : "https://api.spotify.com/v1/tracks/6zgCycfVETCfk2TNY7Othq", - "id" : "6zgCycfVETCfk2TNY7Othq", - "is_local" : false, - "name" : "Cherry", - "popularity" : 43, - "preview_url" : "https://p.scdn.co/mp3-preview/41d5c31eb71c5058cef3252efed3f0c09f0f37d4?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 11, - "type" : "track", - "uri" : "spotify:track:6zgCycfVETCfk2TNY7Othq" - } - }, { - "added_at" : "2021-01-27T18:49:55Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/31DXlldabwPHwu6dYevuzK" - }, - "href" : "https://api.spotify.com/v1/artists/31DXlldabwPHwu6dYevuzK", - "id" : "31DXlldabwPHwu6dYevuzK", - "name" : "Simian Mobile Disco", - "type" : "artist", - "uri" : "spotify:artist:31DXlldabwPHwu6dYevuzK" - } ], - "available_markets" : [ "AD", "AG", "AL", "AR", "AT", "AU", "BA", "BB", "BE", "BF", "BG", "BI", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HN", "HR", "HT", "HU", "IE", "IS", "IT", "JM", "KE", "KI", "KM", "KN", "LC", "LI", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MR", "MT", "MW", "MX", "NA", "NE", "NG", "NI", "NL", "NO", "NR", "NZ", "PA", "PE", "PG", "PL", "PT", "PW", "PY", "RO", "RS", "RU", "RW", "SB", "SC", "SE", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TN", "TO", "TT", "TV", "TZ", "UA", "UG", "US", "UY", "VC", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/3k0xfQP6xY8DinupXsBohl" - }, - "href" : "https://api.spotify.com/v1/albums/3k0xfQP6xY8DinupXsBohl", - "id" : "3k0xfQP6xY8DinupXsBohl", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273110bd6379d030aaf1d418329", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02110bd6379d030aaf1d418329", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851110bd6379d030aaf1d418329", - "width" : 64 - } ], - "name" : "Whorl", - "release_date" : "2014-09-09", - "release_date_precision" : "day", - "total_tracks" : 12, - "type" : "album", - "uri" : "spotify:album:3k0xfQP6xY8DinupXsBohl" + }, + { + added_at: '2021-02-28T18:54:05Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe', + }, + href: 'https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe', + id: '6utXOCDpTDavsVbjQgPxpe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c', + width: 64, + }, + ], + name: 'Disappointment Island', + release_date: '2016-07-08', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6utXOCDpTDavsVbjQgPxpe', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 174680, + explicit: false, + external_ids: { + isrc: 'QMLD61404133', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0Xr8oHXgHJj6wIoYKsl5qK', + }, + href: 'https://api.spotify.com/v1/tracks/0Xr8oHXgHJj6wIoYKsl5qK', + id: '0Xr8oHXgHJj6wIoYKsl5qK', + is_local: false, + name: 'A Chase of Sorts', + popularity: 23, + preview_url: + 'https://p.scdn.co/mp3-preview/19a2e3986ee540265fe93ed156ba906fd64e3b4d?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:0Xr8oHXgHJj6wIoYKsl5qK', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/31DXlldabwPHwu6dYevuzK" - }, - "href" : "https://api.spotify.com/v1/artists/31DXlldabwPHwu6dYevuzK", - "id" : "31DXlldabwPHwu6dYevuzK", - "name" : "Simian Mobile Disco", - "type" : "artist", - "uri" : "spotify:artist:31DXlldabwPHwu6dYevuzK" - } ], - "available_markets" : [ "AD", "AG", "AL", "AR", "AT", "AU", "BA", "BB", "BE", "BF", "BG", "BI", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HN", "HR", "HT", "HU", "IE", "IS", "IT", "JM", "KE", "KI", "KM", "KN", "LC", "LI", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MR", "MT", "MW", "MX", "NA", "NE", "NG", "NI", "NL", "NO", "NR", "NZ", "PA", "PE", "PG", "PL", "PT", "PW", "PY", "RO", "RS", "RU", "RW", "SB", "SC", "SE", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TN", "TO", "TT", "TV", "TZ", "UA", "UG", "US", "UY", "VC", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 446546, - "explicit" : false, - "external_ids" : { - "isrc" : "USEP41413003" + }, + { + added_at: '2021-02-28T18:42:37Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6utXOCDpTDavsVbjQgPxpe', + }, + href: 'https://api.spotify.com/v1/albums/6utXOCDpTDavsVbjQgPxpe', + id: '6utXOCDpTDavsVbjQgPxpe', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2734f163ad393b69f372da63e7c', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e024f163ad393b69f372da63e7c', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048514f163ad393b69f372da63e7c', + width: 64, + }, + ], + name: 'Disappointment Island', + release_date: '2016-07-08', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6utXOCDpTDavsVbjQgPxpe', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/5TUa95aB5Vu2CzwCnZd6t0', + }, + href: 'https://api.spotify.com/v1/artists/5TUa95aB5Vu2CzwCnZd6t0', + id: '5TUa95aB5Vu2CzwCnZd6t0', + name: 'TTNG', + type: 'artist', + uri: 'spotify:artist:5TUa95aB5Vu2CzwCnZd6t0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 337146, + explicit: false, + external_ids: { + isrc: 'QMLD61404136', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3iV0hDpxooBMmwPEKOukJf', + }, + href: 'https://api.spotify.com/v1/tracks/3iV0hDpxooBMmwPEKOukJf', + id: '3iV0hDpxooBMmwPEKOukJf', + is_local: false, + name: 'Whatever, Whenever', + popularity: 38, + preview_url: + 'https://p.scdn.co/mp3-preview/da9296c558b8e193f61cab35e9916fc76685bd70?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 5, + type: 'track', + uri: 'spotify:track:3iV0hDpxooBMmwPEKOukJf', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/04MkvmxBIw2rzP1Q96QOWl" + }, + { + added_at: '2021-02-28T00:03:29Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0k17h0D3J5VfsdmQ1iZtE9', + }, + href: 'https://api.spotify.com/v1/artists/0k17h0D3J5VfsdmQ1iZtE9', + id: '0k17h0D3J5VfsdmQ1iZtE9', + name: 'Pink Floyd', + type: 'artist', + uri: 'spotify:artist:0k17h0D3J5VfsdmQ1iZtE9', + }, + ], + available_markets: [ + 'AD', + 'AL', + 'AM', + 'AT', + 'AZ', + 'BA', + 'BE', + 'BG', + 'BY', + 'CH', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DZ', + 'EE', + 'ES', + 'FI', + 'FR', + 'GB', + 'GE', + 'GR', + 'HR', + 'HU', + 'IE', + 'IS', + 'IT', + 'KG', + 'KZ', + 'LI', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MK', + 'MT', + 'NL', + 'NO', + 'PL', + 'PT', + 'RO', + 'RS', + 'RU', + 'SE', + 'SI', + 'SK', + 'TR', + 'UA', + 'UZ', + 'XK', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6uvBKDGlJAYLH5Vy6RQVsc', + }, + href: 'https://api.spotify.com/v1/albums/6uvBKDGlJAYLH5Vy6RQVsc', + id: '6uvBKDGlJAYLH5Vy6RQVsc', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2735aa1262c4123fedc2e4b8c44', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e025aa1262c4123fedc2e4b8c44', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048515aa1262c4123fedc2e4b8c44', + width: 64, + }, + ], + name: 'Wish You Were Here [Remastered] (Remastered Version)', + release_date: '1975-09-12', + release_date_precision: 'day', + total_tracks: 5, + type: 'album', + uri: 'spotify:album:6uvBKDGlJAYLH5Vy6RQVsc', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0k17h0D3J5VfsdmQ1iZtE9', + }, + href: 'https://api.spotify.com/v1/artists/0k17h0D3J5VfsdmQ1iZtE9', + id: '0k17h0D3J5VfsdmQ1iZtE9', + name: 'Pink Floyd', + type: 'artist', + uri: 'spotify:artist:0k17h0D3J5VfsdmQ1iZtE9', + }, + ], + available_markets: [ + 'AD', + 'AL', + 'AM', + 'AT', + 'AZ', + 'BA', + 'BE', + 'BG', + 'BY', + 'CH', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DZ', + 'EE', + 'ES', + 'FI', + 'FR', + 'GB', + 'GE', + 'GR', + 'HR', + 'HU', + 'IE', + 'IS', + 'IT', + 'KG', + 'KZ', + 'LI', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MK', + 'MT', + 'NL', + 'NO', + 'PL', + 'PT', + 'RO', + 'RS', + 'RU', + 'SE', + 'SI', + 'SK', + 'TR', + 'UA', + 'UZ', + 'XK', + ], + disc_number: 1, + duration_ms: 334743, + explicit: false, + external_ids: { + isrc: 'GBN9Y1100088', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/7aE5WXu5sFeNRh3Z05wwu4', + }, + href: 'https://api.spotify.com/v1/tracks/7aE5WXu5sFeNRh3Z05wwu4', + id: '7aE5WXu5sFeNRh3Z05wwu4', + is_local: false, + name: 'Wish You Were Here - 2011 Remastered Version', + popularity: 70, + preview_url: + 'https://p.scdn.co/mp3-preview/7ce0d4e5f0ffcf8fe1a312c9c2f9331c8d2bf994?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:7aE5WXu5sFeNRh3Z05wwu4', }, - "href" : "https://api.spotify.com/v1/tracks/04MkvmxBIw2rzP1Q96QOWl", - "id" : "04MkvmxBIw2rzP1Q96QOWl", - "is_local" : false, - "name" : "Sun Dogs", - "popularity" : 10, - "preview_url" : "https://p.scdn.co/mp3-preview/6178e959b7acb38b970d1d496adc74ab8f261e65?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 3, - "type" : "track", - "uri" : "spotify:track:04MkvmxBIw2rzP1Q96QOWl" - } - }, { - "added_at" : "2021-01-24T21:56:40Z", - "track" : { - "album" : { - "album_type" : "single", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4S8XZ6FgGp5KKwymL8E6Hz" - }, - "href" : "https://api.spotify.com/v1/artists/4S8XZ6FgGp5KKwymL8E6Hz", - "id" : "4S8XZ6FgGp5KKwymL8E6Hz", - "name" : "Enduser", - "type" : "artist", - "uri" : "spotify:artist:4S8XZ6FgGp5KKwymL8E6Hz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/3HZiO8N7WZynVwQdrhhifV" - }, - "href" : "https://api.spotify.com/v1/albums/3HZiO8N7WZynVwQdrhhifV", - "id" : "3HZiO8N7WZynVwQdrhhifV", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27389e0f04eb1d3afe7281739ce", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0289e0f04eb1d3afe7281739ce", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485189e0f04eb1d3afe7281739ce", - "width" : 64 - } ], - "name" : "1-3", - "release_date" : "2019-02-09", - "release_date_precision" : "day", - "total_tracks" : 5, - "type" : "album", - "uri" : "spotify:album:3HZiO8N7WZynVwQdrhhifV" + }, + { + added_at: '2021-02-27T23:58:07Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/22WZ7M8sxp5THdruNY3gXt', + }, + href: 'https://api.spotify.com/v1/artists/22WZ7M8sxp5THdruNY3gXt', + id: '22WZ7M8sxp5THdruNY3gXt', + name: 'The Doors', + type: 'artist', + uri: 'spotify:artist:22WZ7M8sxp5THdruNY3gXt', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6AFLOkpJjFF652jevcSOZX', + }, + href: 'https://api.spotify.com/v1/albums/6AFLOkpJjFF652jevcSOZX', + id: '6AFLOkpJjFF652jevcSOZX', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f12a8a7e0b2cbe16d2bef4dc', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f12a8a7e0b2cbe16d2bef4dc', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f12a8a7e0b2cbe16d2bef4dc', + width: 64, + }, + ], + name: 'Morrison Hotel', + release_date: '1970-02-09', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:6AFLOkpJjFF652jevcSOZX', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/22WZ7M8sxp5THdruNY3gXt', + }, + href: 'https://api.spotify.com/v1/artists/22WZ7M8sxp5THdruNY3gXt', + id: '22WZ7M8sxp5THdruNY3gXt', + name: 'The Doors', + type: 'artist', + uri: 'spotify:artist:22WZ7M8sxp5THdruNY3gXt', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 243826, + explicit: false, + external_ids: { + isrc: 'USEE19900375', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/1Q5kgpp4pmyGqPwNBzkSrw', + }, + href: 'https://api.spotify.com/v1/tracks/1Q5kgpp4pmyGqPwNBzkSrw', + id: '1Q5kgpp4pmyGqPwNBzkSrw', + is_local: false, + name: 'Roadhouse Blues', + popularity: 70, + preview_url: + 'https://p.scdn.co/mp3-preview/a0e4d25d759b8433f99d99bbaf31e153e0b1914e?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 1, + type: 'track', + uri: 'spotify:track:1Q5kgpp4pmyGqPwNBzkSrw', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4S8XZ6FgGp5KKwymL8E6Hz" - }, - "href" : "https://api.spotify.com/v1/artists/4S8XZ6FgGp5KKwymL8E6Hz", - "id" : "4S8XZ6FgGp5KKwymL8E6Hz", - "name" : "Enduser", - "type" : "artist", - "uri" : "spotify:artist:4S8XZ6FgGp5KKwymL8E6Hz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 357485, - "explicit" : false, - "external_ids" : { - "isrc" : "QZ5FN1940636" + }, + { + added_at: '2021-02-27T13:00:06Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir', + }, + href: 'https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir', + id: '621sN6b7GCpWpzaSidA5Ir', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045', + width: 64, + }, + ], + name: 'The Path of Apotheosis', + release_date: '2014-01-26', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:621sN6b7GCpWpzaSidA5Ir', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 394320, + explicit: false, + external_ids: { + isrc: 'TCABS1379689', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6FX7C7yaMvqtV0E2OjYIhA', + }, + href: 'https://api.spotify.com/v1/tracks/6FX7C7yaMvqtV0E2OjYIhA', + id: '6FX7C7yaMvqtV0E2OjYIhA', + is_local: false, + name: 'The Path of Apotheosis', + popularity: 19, + preview_url: + 'https://p.scdn.co/mp3-preview/28cda4b2e4818ad7830290e7c7d22f4ca3df6b28?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 11, + type: 'track', + uri: 'spotify:track:6FX7C7yaMvqtV0E2OjYIhA', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3cFxBXjTOuUiOxnH0tpZe4" + }, + { + added_at: '2021-02-25T12:33:03Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0', + }, + href: 'https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0', + id: '6RmijobcphddxSNtsBHjF0', + name: 'Simon Posford', + type: 'artist', + uri: 'spotify:artist:6RmijobcphddxSNtsBHjF0', + }, + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ', + }, + href: 'https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ', + id: '0m5XJwKGYyUjd3VMfcINCQ', + name: 'Shpongle', + type: 'artist', + uri: 'spotify:artist:0m5XJwKGYyUjd3VMfcINCQ', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6CzjV9BeZvSKqxdhzfswdX', + }, + href: 'https://api.spotify.com/v1/albums/6CzjV9BeZvSKqxdhzfswdX', + id: '6CzjV9BeZvSKqxdhzfswdX', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273d2ad1f61daaf693282c0c222', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02d2ad1f61daaf693282c0c222', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851d2ad1f61daaf693282c0c222', + width: 64, + }, + ], + name: 'Flux & Contemplation - Portrait of an Artist in Isolation', + release_date: '2020-07-03', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6CzjV9BeZvSKqxdhzfswdX', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0', + }, + href: 'https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0', + id: '01e2lCvLZ4fLUIRy68nptH', + name: 'Simon Posford', + type: 'artist', + uri: 'spotify:artist:6RmijobcphddxSNtsBHjF0', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ', + }, + href: 'https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ', + id: '0m5XJwKGYyUjd3VMfcINCQ', + name: 'Shpongle', + type: 'artist', + uri: 'spotify:artist:0m5XJwKGYyUjd3VMfcINCQ', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 641093, + explicit: false, + external_ids: { + isrc: 'GBBMP1200635', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0UBLvMN7Y1pPr22zYAjhRd', + }, + href: 'https://api.spotify.com/v1/tracks/0UBLvMN7Y1pPr22zYAjhRd', + id: '0UBLvMN7Y1pPr22zYAjhRd', + is_local: false, + name: 'The New Normal', + popularity: 22, + preview_url: + 'https://p.scdn.co/mp3-preview/a22736f725e9cc2756c2e296397247ce5f66864c?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:0UBLvMN7Y1pPr22zYAjhRd', }, - "href" : "https://api.spotify.com/v1/tracks/3cFxBXjTOuUiOxnH0tpZe4", - "id" : "3cFxBXjTOuUiOxnH0tpZe4", - "is_local" : false, - "name" : "2-3", - "popularity" : 16, - "preview_url" : "https://p.scdn.co/mp3-preview/532604d94feb7cee6927b4c96b52afe31f70c33b?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 3, - "type" : "track", - "uri" : "spotify:track:3cFxBXjTOuUiOxnH0tpZe4" - } - }, { - "added_at" : "2021-01-24T19:49:54Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB" - }, - "href" : "https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB", - "id" : "5kU3Q43bmLdARkMOCOLNkB", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65", - "width" : 64 - } ], - "name" : "Igneous", - "release_date" : "2019-05-10", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:5kU3Q43bmLdARkMOCOLNkB" + }, + { + added_at: '2021-02-25T12:32:48Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0', + }, + href: 'https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0', + id: '6RmijobcphddxSNtsBHjF0', + name: 'Simon Posford', + type: 'artist', + uri: 'spotify:artist:6RmijobcphddxSNtsBHjF0', + }, + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ', + }, + href: 'https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ', + id: '0m5XJwKGYyUjd3VMfcINCQ', + name: 'Shpongle', + type: 'artist', + uri: 'spotify:artist:0m5XJwKGYyUjd3VMfcINCQ', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6CzjV9BeZvSKqxdhzfswdX', + }, + href: 'https://api.spotify.com/v1/albums/6CzjV9BeZvSKqxdhzfswdX', + id: '6CzjV9BeZvSKqxdhzfswdX', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273d2ad1f61daaf693282c0c222', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02d2ad1f61daaf693282c0c222', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851d2ad1f61daaf693282c0c222', + width: 64, + }, + ], + name: 'Flux & Contemplation - Portrait of an Artist in Isolation', + release_date: '2020-07-03', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6CzjV9BeZvSKqxdhzfswdX', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/6RmijobcphddxSNtsBHjF0', + }, + href: 'https://api.spotify.com/v1/artists/6RmijobcphddxSNtsBHjF0', + id: '6RmijobcphddxSNtsBHjF0', + name: 'Simon Posford', + type: 'artist', + uri: 'spotify:artist:6RmijobcphddxSNtsBHjF0', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0m5XJwKGYyUjd3VMfcINCQ', + }, + href: 'https://api.spotify.com/v1/artists/0m5XJwKGYyUjd3VMfcINCQ', + id: '0m5XJwKGYyUjd3VMfcINCQ', + name: 'Shpongle', + type: 'artist', + uri: 'spotify:artist:0m5XJwKGYyUjd3VMfcINCQ', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 328840, + explicit: false, + external_ids: { + isrc: 'GBBMP1200632', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0bW1ctrbUrg1E3bC4lu0SO', + }, + href: 'https://api.spotify.com/v1/tracks/0bW1ctrbUrg1E3bC4lu0SO', + id: '0bW1ctrbUrg1E3bC4lu0SO', + is_local: false, + name: 'Wish You Weren’t Here', + popularity: 24, + preview_url: + 'https://p.scdn.co/mp3-preview/5285f5475414491f8ded4788e25df325b38e9bf4?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 5, + type: 'track', + uri: 'spotify:track:0bW1ctrbUrg1E3bC4lu0SO', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 317500, - "explicit" : false, - "external_ids" : { - "isrc" : "NLC7F1900018" + }, + { + added_at: '2021-02-23T13:06:12Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/1Yox196W7bzVNZI7RBaPnf', + }, + href: 'https://api.spotify.com/v1/artists/1Yox196W7bzVNZI7RBaPnf', + id: '1Yox196W7bzVNZI7RBaPnf', + name: 'Megadeth', + type: 'artist', + uri: 'spotify:artist:1Yox196W7bzVNZI7RBaPnf', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5YFrdrFUHGgAvK8iXFxULa', + }, + href: 'https://api.spotify.com/v1/albums/5YFrdrFUHGgAvK8iXFxULa', + id: '5YFrdrFUHGgAvK8iXFxULa', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2735545e351774a756c377ea0ee', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e025545e351774a756c377ea0ee', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048515545e351774a756c377ea0ee', + width: 64, + }, + ], + name: 'The World Needs a Hero', + release_date: '2001-05-14', + release_date_precision: 'day', + total_tracks: 12, + type: 'album', + uri: 'spotify:album:5YFrdrFUHGgAvK8iXFxULa', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/1Yox196W7bzVNZI7RBaPnf', + }, + href: 'https://api.spotify.com/v1/artists/1Yox196W7bzVNZI7RBaPnf', + id: '1Yox196W7bzVNZI7RBaPnf', + name: 'Megadeth', + type: 'artist', + uri: 'spotify:artist:1Yox196W7bzVNZI7RBaPnf', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 265133, + explicit: false, + external_ids: { + isrc: 'GBAJE0100024', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/4Bfxp472zIwiSYjZsK76EN', + }, + href: 'https://api.spotify.com/v1/tracks/4Bfxp472zIwiSYjZsK76EN', + id: '4Bfxp472zIwiSYjZsK76EN', + is_local: false, + name: 'Dread and the Fugitive Mind', + popularity: 44, + preview_url: + 'https://p.scdn.co/mp3-preview/6614ac4f3149fdd7559bfd7fdceea386fcc353cc?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 9, + type: 'track', + uri: 'spotify:track:4Bfxp472zIwiSYjZsK76EN', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/0kYQbZQqpZkACY7IJGl343" + }, + { + added_at: '2021-02-23T11:45:14Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir', + }, + href: 'https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir', + id: '621sN6b7GCpWpzaSidA5Ir', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045', + width: 64, + }, + ], + name: 'The Path of Apotheosis', + release_date: '2014-01-26', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:621sN6b7GCpWpzaSidA5Ir', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 354640, + explicit: false, + external_ids: { + isrc: 'TCABS1379688', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/1lEnjsEH1zxGUkatGwMzSZ', + }, + href: 'https://api.spotify.com/v1/tracks/1lEnjsEH1zxGUkatGwMzSZ', + id: '1lEnjsEH1zxGUkatGwMzSZ', + is_local: false, + name: 'The Ancients of Shattered Thrones', + popularity: 19, + preview_url: + 'https://p.scdn.co/mp3-preview/bf7dde3c14e9deb854771d9ba8e0a1992f2f1257?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 10, + type: 'track', + uri: 'spotify:track:1lEnjsEH1zxGUkatGwMzSZ', }, - "href" : "https://api.spotify.com/v1/tracks/0kYQbZQqpZkACY7IJGl343", - "id" : "0kYQbZQqpZkACY7IJGl343", - "is_local" : false, - "name" : "Kali", - "popularity" : 21, - "preview_url" : "https://p.scdn.co/mp3-preview/0bfa262d70b4d98f4667e56c84266b1d5fa65ae8?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 3, - "type" : "track", - "uri" : "spotify:track:0kYQbZQqpZkACY7IJGl343" - } - }, { - "added_at" : "2021-01-22T20:54:11Z", - "track" : { - "album" : { - "album_type" : "compilation", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" - }, - "href" : "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", - "id" : "0LyfQWJT6nXafLPZqxe9Of", - "name" : "Various Artists", - "type" : "artist", - "uri" : "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" - } ], - "available_markets" : [ "AD", "AE", "AM", "AR", "AT", "AU", "AZ", "BA", "BE", "BG", "BH", "BN", "BO", "BR", "BY", "CA", "CH", "CL", "CM", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FR", "GB", "GN", "GR", "GT", "GW", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JO", "JP", "KG", "KH", "KR", "KW", "KZ", "LA", "LB", "LI", "LK", "LT", "LU", "LV", "MA", "MC", "ME", "MK", "MO", "MT", "MX", "MY", "NG", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PT", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SE", "SG", "SI", "SK", "SN", "SV", "TH", "TN", "TR", "TW", "TZ", "UA", "US", "UZ", "VN", "XK", "ZA" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/2oNWwPYsrEZuZ3siifa633" - }, - "href" : "https://api.spotify.com/v1/albums/2oNWwPYsrEZuZ3siifa633", - "id" : "2oNWwPYsrEZuZ3siifa633", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273479a0d67f9d3a2a4e2addd9f", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02479a0d67f9d3a2a4e2addd9f", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851479a0d67f9d3a2a4e2addd9f", - "width" : 64 - } ], - "name" : "Treme: Music From The HBO Original Series - Season 2", - "release_date" : "2012-01-01", - "release_date_precision" : "day", - "total_tracks" : 18, - "type" : "album", - "uri" : "spotify:album:2oNWwPYsrEZuZ3siifa633" + }, + { + added_at: '2021-02-23T11:31:03Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/1EzRkEPmjf1ZEjTnWVXiQ2', + }, + href: 'https://api.spotify.com/v1/artists/1EzRkEPmjf1ZEjTnWVXiQ2', + id: '1EzRkEPmjf1ZEjTnWVXiQ2', + name: 'Mekong Delta', + type: 'artist', + uri: 'spotify:artist:1EzRkEPmjf1ZEjTnWVXiQ2', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6ajZAcA75EojcJaVGQuvCw', + }, + href: 'https://api.spotify.com/v1/albums/6ajZAcA75EojcJaVGQuvCw', + id: '6ajZAcA75EojcJaVGQuvCw', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2732927156af0eef58c76fff96b', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e022927156af0eef58c76fff96b', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048512927156af0eef58c76fff96b', + width: 64, + }, + ], + name: 'The Principle of Doubt', + release_date: '1989-02-25', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:6ajZAcA75EojcJaVGQuvCw', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/1EzRkEPmjf1ZEjTnWVXiQ2', + }, + href: 'https://api.spotify.com/v1/artists/1EzRkEPmjf1ZEjTnWVXiQ2', + id: '1EzRkEPmjf1ZEjTnWVXiQ2', + name: 'Mekong Delta', + type: 'artist', + uri: 'spotify:artist:1EzRkEPmjf1ZEjTnWVXiQ2', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 293386, + explicit: false, + external_ids: { + isrc: 'DEA451302050', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6J1slcIFHByPeRPIl6pFch', + }, + href: 'https://api.spotify.com/v1/tracks/6J1slcIFHByPeRPIl6pFch', + id: '6J1slcIFHByPeRPIl6pFch', + is_local: false, + name: + "The Principle of Doubt - Chapter 3 Taken From 'The Chronicle of Doubt'", + popularity: 3, + preview_url: + 'https://p.scdn.co/mp3-preview/32ebe5c7f3c69e0271ef9fc413f7dab36a9e532f?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:6J1slcIFHByPeRPIl6pFch', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/53pHwg1sjhqGk726JnJHYb" - }, - "href" : "https://api.spotify.com/v1/artists/53pHwg1sjhqGk726JnJHYb", - "id" : "53pHwg1sjhqGk726JnJHYb", - "name" : "Donald Harrison", - "type" : "artist", - "uri" : "spotify:artist:53pHwg1sjhqGk726JnJHYb" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/44gLY8zUnF4xRzi4X0zl1n" - }, - "href" : "https://api.spotify.com/v1/artists/44gLY8zUnF4xRzi4X0zl1n", - "id" : "44gLY8zUnF4xRzi4X0zl1n", - "name" : "Carl Allen", - "type" : "artist", - "uri" : "spotify:artist:44gLY8zUnF4xRzi4X0zl1n" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/3b1iAUluGgKbthmqGckbPn" - }, - "href" : "https://api.spotify.com/v1/artists/3b1iAUluGgKbthmqGckbPn", - "id" : "3b1iAUluGgKbthmqGckbPn", - "name" : "Leon \"Kid Chocolate\" Brown", - "type" : "artist", - "uri" : "spotify:artist:3b1iAUluGgKbthmqGckbPn" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/6TvhNLU4Wtptdh1m9XcE0j" - }, - "href" : "https://api.spotify.com/v1/artists/6TvhNLU4Wtptdh1m9XcE0j", - "id" : "6TvhNLU4Wtptdh1m9XcE0j", - "name" : "Rob Brown", - "type" : "artist", - "uri" : "spotify:artist:6TvhNLU4Wtptdh1m9XcE0j" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4wnzivx3OQ3vjrySAdTdJP" - }, - "href" : "https://api.spotify.com/v1/artists/4wnzivx3OQ3vjrySAdTdJP", - "id" : "4wnzivx3OQ3vjrySAdTdJP", - "name" : "Ron Carter", - "type" : "artist", - "uri" : "spotify:artist:4wnzivx3OQ3vjrySAdTdJP" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/320TrJub4arztwXRm7kqVO" - }, - "href" : "https://api.spotify.com/v1/artists/320TrJub4arztwXRm7kqVO", - "id" : "320TrJub4arztwXRm7kqVO", - "name" : "Dr. John", - "type" : "artist", - "uri" : "spotify:artist:320TrJub4arztwXRm7kqVO" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0xVjTHsSeU2B3DGMjJ3KFy" - }, - "href" : "https://api.spotify.com/v1/artists/0xVjTHsSeU2B3DGMjJ3KFy", - "id" : "0xVjTHsSeU2B3DGMjJ3KFy", - "name" : "Clarke Peters", - "type" : "artist", - "uri" : "spotify:artist:0xVjTHsSeU2B3DGMjJ3KFy" - }, { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7E4MQbO3PckmL7W01Cnnrd" - }, - "href" : "https://api.spotify.com/v1/artists/7E4MQbO3PckmL7W01Cnnrd", - "id" : "7E4MQbO3PckmL7W01Cnnrd", - "name" : "Alfred “Uganda” Roberts", - "type" : "artist", - "uri" : "spotify:artist:7E4MQbO3PckmL7W01Cnnrd" - } ], - "available_markets" : [ "AD", "AE", "AM", "AR", "AT", "AU", "AZ", "BA", "BE", "BG", "BH", "BN", "BO", "BR", "BY", "CA", "CH", "CL", "CM", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FR", "GB", "GN", "GR", "GT", "GW", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JO", "JP", "KG", "KH", "KR", "KW", "KZ", "LA", "LB", "LI", "LK", "LT", "LU", "LV", "MA", "MC", "ME", "MK", "MO", "MT", "MX", "MY", "NG", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PT", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SE", "SG", "SI", "SK", "SN", "SV", "TH", "TN", "TR", "TW", "TZ", "UA", "US", "UZ", "VN", "XK", "ZA" ], - "disc_number" : 1, - "duration_ms" : 324253, - "explicit" : false, - "external_ids" : { - "isrc" : "USRO21213017" + }, + { + added_at: '2021-02-21T16:15:55Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3', + }, + href: 'https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3', + id: '4dhUo35WO3cGcFbxJ7ZIe3', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614', + width: 64, + }, + ], + name: 'Immortal', + release_date: '2014-03-25', + release_date_precision: 'day', + total_tracks: 8, + type: 'album', + uri: 'spotify:album:4dhUo35WO3cGcFbxJ7ZIe3', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 214737, + explicit: false, + external_ids: { + isrc: 'USERN1008694', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3Yb3WCtJI3t0FCKzroKAv1', + }, + href: 'https://api.spotify.com/v1/tracks/3Yb3WCtJI3t0FCKzroKAv1', + id: '3Yb3WCtJI3t0FCKzroKAv1', + is_local: false, + name: "Ancient's Retribution", + popularity: 14, + preview_url: + 'https://p.scdn.co/mp3-preview/83b935148dcdb322ec0920be776a7ca8aecacdd6?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:3Yb3WCtJI3t0FCKzroKAv1', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/2dPAL09IadQJ7mMpTJ45w3" + }, + { + added_at: '2021-02-21T16:10:28Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3', + }, + href: 'https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3', + id: '4dhUo35WO3cGcFbxJ7ZIe3', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614', + width: 64, + }, + ], + name: 'Immortal', + release_date: '2014-03-25', + release_date_precision: 'day', + total_tracks: 8, + type: 'album', + uri: 'spotify:album:4dhUo35WO3cGcFbxJ7ZIe3', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 306291, + explicit: false, + external_ids: { + isrc: 'USERN1008693', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0tAumAapgzzIiddYAwKKk2', + }, + href: 'https://api.spotify.com/v1/tracks/0tAumAapgzzIiddYAwKKk2', + id: '0tAumAapgzzIiddYAwKKk2', + is_local: false, + name: 'Vile Remnants', + popularity: 15, + preview_url: + 'https://p.scdn.co/mp3-preview/c4e4cd95d76ae2f6cd8e5362884465b253f0de82?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 3, + type: 'track', + uri: 'spotify:track:0tAumAapgzzIiddYAwKKk2', }, - "href" : "https://api.spotify.com/v1/tracks/2dPAL09IadQJ7mMpTJ45w3", - "id" : "2dPAL09IadQJ7mMpTJ45w3", - "is_local" : false, - "name" : "Hu Ta Nay", - "popularity" : 17, - "preview_url" : "https://p.scdn.co/mp3-preview/b6df8cf66f2bd0142b1ab865b6a41d6b311282c0?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 17, - "type" : "track", - "uri" : "spotify:track:2dPAL09IadQJ7mMpTJ45w3" - } - }, { - "added_at" : "2021-01-06T19:31:55Z", - "track" : { - "album" : { - "album_type" : "compilation", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of" - }, - "href" : "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of", - "id" : "0LyfQWJT6nXafLPZqxe9Of", - "name" : "Various Artists", - "type" : "artist", - "uri" : "spotify:artist:0LyfQWJT6nXafLPZqxe9Of" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/2vx34tJFXMnjT9vKEVtcKI" - }, - "href" : "https://api.spotify.com/v1/albums/2vx34tJFXMnjT9vKEVtcKI", - "id" : "2vx34tJFXMnjT9vKEVtcKI", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27389fdc1ec5668fdd29a5960cc", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0289fdc1ec5668fdd29a5960cc", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485189fdc1ec5668fdd29a5960cc", - "width" : 64 - } ], - "name" : "SOMEWHERE", - "release_date" : "2015-08-28", - "release_date_precision" : "day", - "total_tracks" : 7, - "type" : "album", - "uri" : "spotify:album:2vx34tJFXMnjT9vKEVtcKI" + }, + { + added_at: '2021-02-21T16:01:37Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/4dhUo35WO3cGcFbxJ7ZIe3', + }, + href: 'https://api.spotify.com/v1/albums/4dhUo35WO3cGcFbxJ7ZIe3', + id: '4dhUo35WO3cGcFbxJ7ZIe3', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27302350a49e50d1ce419b07614', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0202350a49e50d1ce419b07614', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485102350a49e50d1ce419b07614', + width: 64, + }, + ], + name: 'Immortal', + release_date: '2014-03-25', + release_date_precision: 'day', + total_tracks: 8, + type: 'album', + uri: 'spotify:album:4dhUo35WO3cGcFbxJ7ZIe3', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3ZOZaEFRuEhjsQ7QAPkpoB', + }, + href: 'https://api.spotify.com/v1/artists/3ZOZaEFRuEhjsQ7QAPkpoB', + id: '3ZOZaEFRuEhjsQ7QAPkpoB', + name: 'Alterbeast', + type: 'artist', + uri: 'spotify:artist:3ZOZaEFRuEhjsQ7QAPkpoB', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 156037, + explicit: false, + external_ids: { + isrc: 'USERN1008692', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/1q5lWOlLTs37JpEuFPJ5fZ', + }, + href: 'https://api.spotify.com/v1/tracks/1q5lWOlLTs37JpEuFPJ5fZ', + id: '1q5lWOlLTs37JpEuFPJ5fZ', + is_local: false, + name: 'Of Decimus Divine', + popularity: 15, + preview_url: + 'https://p.scdn.co/mp3-preview/144b5550b29619e92e85a58456be171e1b113a48?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:1q5lWOlLTs37JpEuFPJ5fZ', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 526646, - "explicit" : false, - "external_ids" : { - "isrc" : "DEU671502315" + }, + { + added_at: '2021-02-21T15:49:51Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir', + }, + href: 'https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir', + id: '621sN6b7GCpWpzaSidA5Ir', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045', + width: 64, + }, + ], + name: 'The Path of Apotheosis', + release_date: '2014-01-26', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:621sN6b7GCpWpzaSidA5Ir', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 359640, + explicit: false, + external_ids: { + isrc: 'TCABS1379687', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6S41USppfhF2c9xuNx97AN', + }, + href: 'https://api.spotify.com/v1/tracks/6S41USppfhF2c9xuNx97AN', + id: '6S41USppfhF2c9xuNx97AN', + is_local: false, + name: 'Marching Through the Flames of Tyranny', + popularity: 19, + preview_url: + 'https://p.scdn.co/mp3-preview/494f23683345af46e8cf3a7a224d42207d866588?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 9, + type: 'track', + uri: 'spotify:track:6S41USppfhF2c9xuNx97AN', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/72Gko345HYQu6gI3DWAZfL" + }, + { + added_at: '2021-02-20T15:41:36Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3ZWab2LEVkNKiBPIClTwof', + }, + href: 'https://api.spotify.com/v1/artists/3ZWab2LEVkNKiBPIClTwof', + id: '3ZWab2LEVkNKiBPIClTwof', + name: 'Townes Van Zandt', + type: 'artist', + uri: 'spotify:artist:3ZWab2LEVkNKiBPIClTwof', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BT', + 'BW', + 'BY', + 'CH', + 'CL', + 'CM', + 'CO', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GW', + 'GY', + 'HK', + 'HR', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MY', + 'NA', + 'NE', + 'NG', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/08ADmkImC4Z1iMsaPr3NC0', + }, + href: 'https://api.spotify.com/v1/albums/08ADmkImC4Z1iMsaPr3NC0', + id: '08ADmkImC4Z1iMsaPr3NC0', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273afcab75f7114347fc33cd3b0', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02afcab75f7114347fc33cd3b0', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851afcab75f7114347fc33cd3b0', + width: 64, + }, + ], + name: 'Delta Momma Blues', + release_date: '1971', + release_date_precision: 'year', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:08ADmkImC4Z1iMsaPr3NC0', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3ZWab2LEVkNKiBPIClTwof', + }, + href: 'https://api.spotify.com/v1/artists/3ZWab2LEVkNKiBPIClTwof', + id: '3ZWab2LEVkNKiBPIClTwof', + name: 'Townes Van Zandt', + type: 'artist', + uri: 'spotify:artist:3ZWab2LEVkNKiBPIClTwof', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BT', + 'BW', + 'BY', + 'CH', + 'CL', + 'CM', + 'CO', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GW', + 'GY', + 'HK', + 'HR', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MY', + 'NA', + 'NE', + 'NG', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 170533, + explicit: false, + external_ids: { + isrc: 'GBCEL0900069', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0CieC8w6QH3SlIZeUZ8LoS', + }, + href: 'https://api.spotify.com/v1/tracks/0CieC8w6QH3SlIZeUZ8LoS', + id: '0CieC8w6QH3SlIZeUZ8LoS', + is_local: false, + name: 'Where I Lead Me', + popularity: 10, + preview_url: + 'https://p.scdn.co/mp3-preview/4fc116ac66e2bf540d73228372afa26fe41059ac?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:0CieC8w6QH3SlIZeUZ8LoS', }, - "href" : "https://api.spotify.com/v1/tracks/72Gko345HYQu6gI3DWAZfL", - "id" : "72Gko345HYQu6gI3DWAZfL", - "is_local" : false, - "name" : "Anther", - "popularity" : 32, - "preview_url" : "https://p.scdn.co/mp3-preview/9e9135d80b5ea310841c051007a7a3d2c6f00892?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:72Gko345HYQu6gI3DWAZfL" - } - }, { - "added_at" : "2021-01-06T19:21:31Z", - "track" : { - "album" : { - "album_type" : "single", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/2uJG5GCaZTwP3z1tkgAG6P" - }, - "href" : "https://api.spotify.com/v1/albums/2uJG5GCaZTwP3z1tkgAG6P", - "id" : "2uJG5GCaZTwP3z1tkgAG6P", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2737449d8b759c6f6acc1d1757a", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e027449d8b759c6f6acc1d1757a", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048517449d8b759c6f6acc1d1757a", - "width" : 64 - } ], - "name" : "Humming", - "release_date" : "2020-12-18", - "release_date_precision" : "day", - "total_tracks" : 1, - "type" : "album", - "uri" : "spotify:album:2uJG5GCaZTwP3z1tkgAG6P" + }, + { + added_at: '2021-02-18T16:29:40Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U', + }, + href: 'https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U', + id: '3Gaqw2nGyE7yM3rcRSzE3U', + name: 'Yppah', + type: 'artist', + uri: 'spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5La9Xx2vJ84n8yngUVJri2', + }, + href: 'https://api.spotify.com/v1/albums/5La9Xx2vJ84n8yngUVJri2', + id: '5La9Xx2vJ84n8yngUVJri2', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739d0fd14571e635b96ba52112', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029d0fd14571e635b96ba52112', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519d0fd14571e635b96ba52112', + width: 64, + }, + ], + name: 'Tiny Pause', + release_date: '2015-10-16', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:5La9Xx2vJ84n8yngUVJri2', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U', + }, + href: 'https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U', + id: '3Gaqw2nGyE7yM3rcRSzE3U', + name: 'Yppah', + type: 'artist', + uri: 'spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 336400, + explicit: false, + external_ids: { + isrc: 'GBCFB1503904', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/68W36X31D3o8XfXrWhBnZE', + }, + href: 'https://api.spotify.com/v1/tracks/68W36X31D3o8XfXrWhBnZE', + id: '68W36X31D3o8XfXrWhBnZE', + is_local: false, + name: 'Owl Beach II', + popularity: 35, + preview_url: + 'https://p.scdn.co/mp3-preview/8ae8327ecc180bafc6a0f3da5d9ac6321beb81ac?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 5, + type: 'track', + uri: 'spotify:track:68W36X31D3o8XfXrWhBnZE', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 205000, - "explicit" : false, - "external_ids" : { - "isrc" : "NLC7F2000102" + }, + { + added_at: '2021-02-18T15:59:46Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U', + }, + href: 'https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U', + id: '3Gaqw2nGyE7yM3rcRSzE3U', + name: 'Yppah', + type: 'artist', + uri: 'spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5La9Xx2vJ84n8yngUVJri2', + }, + href: 'https://api.spotify.com/v1/albums/5La9Xx2vJ84n8yngUVJri2', + id: '5La9Xx2vJ84n8yngUVJri2', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739d0fd14571e635b96ba52112', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029d0fd14571e635b96ba52112', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519d0fd14571e635b96ba52112', + width: 64, + }, + ], + name: 'Tiny Pause', + release_date: '2015-10-16', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:5La9Xx2vJ84n8yngUVJri2', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U', + }, + href: 'https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U', + id: '3Gaqw2nGyE7yM3rcRSzE3U', + name: 'Yppah', + type: 'artist', + uri: 'spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 265586, + explicit: false, + external_ids: { + isrc: 'GBCFB1503906', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/5cjBttolslxyUQSSabanA8', + }, + href: 'https://api.spotify.com/v1/tracks/5cjBttolslxyUQSSabanA8', + id: '5cjBttolslxyUQSSabanA8', + is_local: false, + name: 'Bushmills', + popularity: 39, + preview_url: + 'https://p.scdn.co/mp3-preview/d361baef69a29a74b95942f0ce9ec03caeedb48e?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 7, + type: 'track', + uri: 'spotify:track:5cjBttolslxyUQSSabanA8', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/4dcqNrCh3Atf4ylrvFxKoG" + }, + { + added_at: '2021-02-17T17:17:36Z', + track: { + album: { + album_type: 'compilation', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of', + }, + href: 'https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of', + id: '0LyfQWJT6nXafLPZqxe9Of', + name: 'Various Artists', + type: 'artist', + uri: 'spotify:artist:0LyfQWJT6nXafLPZqxe9Of', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/61bYJTYERgYGSgFUamgTCa', + }, + href: 'https://api.spotify.com/v1/albums/61bYJTYERgYGSgFUamgTCa', + id: '61bYJTYERgYGSgFUamgTCa', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27348e2a667de482192fddfeae0', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0248e2a667de482192fddfeae0', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485148e2a667de482192fddfeae0', + width: 64, + }, + ], + name: 'Ninja Tune XX (Volume 2)', + release_date: '2010-09-20', + release_date_precision: 'day', + total_tracks: 33, + type: 'album', + uri: 'spotify:album:61bYJTYERgYGSgFUamgTCa', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3Gaqw2nGyE7yM3rcRSzE3U', + }, + href: 'https://api.spotify.com/v1/artists/3Gaqw2nGyE7yM3rcRSzE3U', + id: '3Gaqw2nGyE7yM3rcRSzE3U', + name: 'Yppah', + type: 'artist', + uri: 'spotify:artist:3Gaqw2nGyE7yM3rcRSzE3U', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 196000, + explicit: false, + external_ids: { + isrc: 'GBCFB1002229', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/1sotD6Cn8aOtUsL0bd5HTJ', + }, + href: 'https://api.spotify.com/v1/tracks/1sotD6Cn8aOtUsL0bd5HTJ', + id: '1sotD6Cn8aOtUsL0bd5HTJ', + is_local: false, + name: 'Never Mess With Sunday', + popularity: 47, + preview_url: + 'https://p.scdn.co/mp3-preview/8665b599fb5f17d3f3807c8e7d02a1bafeb5cea8?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 6, + type: 'track', + uri: 'spotify:track:1sotD6Cn8aOtUsL0bd5HTJ', }, - "href" : "https://api.spotify.com/v1/tracks/4dcqNrCh3Atf4ylrvFxKoG", - "id" : "4dcqNrCh3Atf4ylrvFxKoG", - "is_local" : false, - "name" : "Humming", - "popularity" : 26, - "preview_url" : "https://p.scdn.co/mp3-preview/585c838b959f3a81e27ff214e92b2026e737d803?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 1, - "type" : "track", - "uri" : "spotify:track:4dcqNrCh3Atf4ylrvFxKoG" - } - }, { - "added_at" : "2021-01-06T19:16:04Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB" - }, - "href" : "https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB", - "id" : "5kU3Q43bmLdARkMOCOLNkB", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65", - "width" : 64 - } ], - "name" : "Igneous", - "release_date" : "2019-05-10", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:5kU3Q43bmLdARkMOCOLNkB" + }, + { + added_at: '2021-02-16T17:19:48Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb', + }, + href: 'https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb', + id: '0cmWgDlu9CwTgxPhf403hb', + name: 'Bonobo', + type: 'artist', + uri: 'spotify:artist:0cmWgDlu9CwTgxPhf403hb', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6tEOuMrJ6gsmZ2vB2P1NV7', + }, + href: 'https://api.spotify.com/v1/albums/6tEOuMrJ6gsmZ2vB2P1NV7', + id: '6tEOuMrJ6gsmZ2vB2P1NV7', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273c46ca7a942d8795a06774df9', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02c46ca7a942d8795a06774df9', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851c46ca7a942d8795a06774df9', + width: 64, + }, + ], + name: 'The North Borders Tour. — Live.', + release_date: '2014-10-06', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:6tEOuMrJ6gsmZ2vB2P1NV7', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb', + }, + href: 'https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb', + id: '0cmWgDlu9CwTgxPhf403hb', + name: 'Bonobo', + type: 'artist', + uri: 'spotify:artist:0cmWgDlu9CwTgxPhf403hb', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 488144, + explicit: false, + external_ids: { + isrc: 'GBCFB1404616', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0PHSbSNolQJPl0NWpiDb3U', + }, + href: 'https://api.spotify.com/v1/tracks/0PHSbSNolQJPl0NWpiDb3U', + id: '0PHSbSNolQJPl0NWpiDb3U', + is_local: false, + name: 'Kong/Ketto - Live', + popularity: 29, + preview_url: + 'https://p.scdn.co/mp3-preview/fa3625e4e97dec2ffdc107c7600957ee72d4b2d0?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 5, + type: 'track', + uri: 'spotify:track:0PHSbSNolQJPl0NWpiDb3U', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 397295, - "explicit" : false, - "external_ids" : { - "isrc" : "NLC7F1900023" + }, + { + added_at: '2021-02-14T18:08:37Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI', + }, + href: 'https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI', + id: '7yxi31szvlbwvKq9dYOmFI', + name: 'Jon Hopkins', + type: 'artist', + uri: 'spotify:artist:7yxi31szvlbwvKq9dYOmFI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/1nvzBC1M3dlCMIxfUCBhlO', + }, + href: 'https://api.spotify.com/v1/albums/1nvzBC1M3dlCMIxfUCBhlO', + id: '1nvzBC1M3dlCMIxfUCBhlO', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739d9126ec04bb005c687291a5', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029d9126ec04bb005c687291a5', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519d9126ec04bb005c687291a5', + width: 64, + }, + ], + name: 'Singularity', + release_date: '2018-05-04', + release_date_precision: 'day', + total_tracks: 12, + type: 'album', + uri: 'spotify:album:1nvzBC1M3dlCMIxfUCBhlO', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI', + }, + href: 'https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI', + id: '7yxi31szvlbwvKq9dYOmFI', + name: 'Jon Hopkins', + type: 'artist', + uri: 'spotify:artist:7yxi31szvlbwvKq9dYOmFI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 428440, + explicit: false, + external_ids: { + isrc: 'GBCEL1700696', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/4Hg9jafzzKavElQMAINzeP', + }, + href: 'https://api.spotify.com/v1/tracks/4Hg9jafzzKavElQMAINzeP', + id: '4Hg9jafzzKavElQMAINzeP', + is_local: false, + name: 'C O S M', + popularity: 40, + preview_url: + 'https://p.scdn.co/mp3-preview/48e0ddc28b1f196056c966612ea5dd6a590f2c1f?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 6, + type: 'track', + uri: 'spotify:track:4Hg9jafzzKavElQMAINzeP', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/05Ps8wHwPh5Ut5EfcIgxPZ" + }, + { + added_at: '2021-02-14T17:37:48Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI', + }, + href: 'https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI', + id: '7yxi31szvlbwvKq9dYOmFI', + name: 'Jon Hopkins', + type: 'artist', + uri: 'spotify:artist:7yxi31szvlbwvKq9dYOmFI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/1nvzBC1M3dlCMIxfUCBhlO', + }, + href: 'https://api.spotify.com/v1/albums/1nvzBC1M3dlCMIxfUCBhlO', + id: '1nvzBC1M3dlCMIxfUCBhlO', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739d9126ec04bb005c687291a5', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029d9126ec04bb005c687291a5', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519d9126ec04bb005c687291a5', + width: 64, + }, + ], + name: 'Singularity', + release_date: '2018-05-04', + release_date_precision: 'day', + total_tracks: 12, + type: 'album', + uri: 'spotify:album:1nvzBC1M3dlCMIxfUCBhlO', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/7yxi31szvlbwvKq9dYOmFI', + }, + href: 'https://api.spotify.com/v1/artists/7yxi31szvlbwvKq9dYOmFI', + id: '7yxi31szvlbwvKq9dYOmFI', + name: 'Jon Hopkins', + type: 'artist', + uri: 'spotify:artist:7yxi31szvlbwvKq9dYOmFI', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 630240, + explicit: false, + external_ids: { + isrc: 'GBCEL1700694', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3oWBMOzkjjkCmV6abncBUd', + }, + href: 'https://api.spotify.com/v1/tracks/3oWBMOzkjjkCmV6abncBUd', + id: '3oWBMOzkjjkCmV6abncBUd', + is_local: false, + name: 'Everything Connected', + popularity: 40, + preview_url: + 'https://p.scdn.co/mp3-preview/b143e3cc635e7a528908aa6be4c51f20fc934eb2?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:3oWBMOzkjjkCmV6abncBUd', }, - "href" : "https://api.spotify.com/v1/tracks/05Ps8wHwPh5Ut5EfcIgxPZ", - "id" : "05Ps8wHwPh5Ut5EfcIgxPZ", - "is_local" : false, - "name" : "Toba", - "popularity" : 35, - "preview_url" : "https://p.scdn.co/mp3-preview/79a2296ebb2e66367826caf9ab37c61c12d4bea5?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:05Ps8wHwPh5Ut5EfcIgxPZ" - } - }, { - "added_at" : "2021-01-06T19:12:38Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB" - }, - "href" : "https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB", - "id" : "5kU3Q43bmLdARkMOCOLNkB", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65", - "width" : 64 - } ], - "name" : "Igneous", - "release_date" : "2019-05-10", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:5kU3Q43bmLdARkMOCOLNkB" + }, + { + added_at: '2021-02-14T16:54:39Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w', + }, + href: 'https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w', + id: '592TFYwu9Qb0RC1hKDbX2w', + name: 'Helios', + type: 'artist', + uri: 'spotify:artist:592TFYwu9Qb0RC1hKDbX2w', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/1OF3AnbSDa1ZSEFE7lukTb', + }, + href: 'https://api.spotify.com/v1/albums/1OF3AnbSDa1ZSEFE7lukTb', + id: '1OF3AnbSDa1ZSEFE7lukTb', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2738fc59fb3af5be43e27fe4ce1', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e028fc59fb3af5be43e27fe4ce1', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048518fc59fb3af5be43e27fe4ce1', + width: 64, + }, + ], + name: 'Eingya', + release_date: '2009-01-16', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:1OF3AnbSDa1ZSEFE7lukTb', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w', + }, + href: 'https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w', + id: '592TFYwu9Qb0RC1hKDbX2w', + name: 'Helios', + type: 'artist', + uri: 'spotify:artist:592TFYwu9Qb0RC1hKDbX2w', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 361880, + explicit: false, + external_ids: { + isrc: 'GBJSN0600009', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6knzYloG0x3MroAhnLVLGe', + }, + href: 'https://api.spotify.com/v1/tracks/6knzYloG0x3MroAhnLVLGe', + id: '6knzYloG0x3MroAhnLVLGe', + is_local: false, + name: 'Bless This Morning Year', + popularity: 40, + preview_url: + 'https://p.scdn.co/mp3-preview/c1ad776d9cd26552d99576d9474c8f1c6c8e27fe?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 1, + type: 'track', + uri: 'spotify:track:6knzYloG0x3MroAhnLVLGe', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 216695, - "explicit" : false, - "external_ids" : { - "isrc" : "NLC7F1900022" + }, + { + added_at: '2021-02-12T11:30:08Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w', + }, + href: 'https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w', + id: '592TFYwu9Qb0RC1hKDbX2w', + name: 'Helios', + type: 'artist', + uri: 'spotify:artist:592TFYwu9Qb0RC1hKDbX2w', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/34CpMn9yU8iDcXDaSkrqXu', + }, + href: 'https://api.spotify.com/v1/albums/34CpMn9yU8iDcXDaSkrqXu', + id: '34CpMn9yU8iDcXDaSkrqXu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f2e49606713803f0def17afb', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f2e49606713803f0def17afb', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f2e49606713803f0def17afb', + width: 64, + }, + ], + name: 'Yume', + release_date: '2015-09-11', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:34CpMn9yU8iDcXDaSkrqXu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/592TFYwu9Qb0RC1hKDbX2w', + }, + href: 'https://api.spotify.com/v1/artists/592TFYwu9Qb0RC1hKDbX2w', + id: '592TFYwu9Qb0RC1hKDbX2w', + name: 'Helios', + type: 'artist', + uri: 'spotify:artist:592TFYwu9Qb0RC1hKDbX2w', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 354642, + explicit: false, + external_ids: { + isrc: 'DEX261500338', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3EfocVFnZdmxbNb8ALyC0X', + }, + href: 'https://api.spotify.com/v1/tracks/3EfocVFnZdmxbNb8ALyC0X', + id: '3EfocVFnZdmxbNb8ALyC0X', + is_local: false, + name: 'Yume', + popularity: 21, + preview_url: + 'https://p.scdn.co/mp3-preview/b6a5cc38391ceac77396ed6af7ee01263ca678ce?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 5, + type: 'track', + uri: 'spotify:track:3EfocVFnZdmxbNb8ALyC0X', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6fiJKbCHyA0BEzhI2Lt3Wr" + }, + { + added_at: '2021-02-10T18:04:58Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rj2COYs5hQsw8rYIxSviz', + }, + href: 'https://api.spotify.com/v1/artists/4Rj2COYs5hQsw8rYIxSviz', + id: '4Rj2COYs5hQsw8rYIxSviz', + name: 'Hidden Orchestra', + type: 'artist', + uri: 'spotify:artist:4Rj2COYs5hQsw8rYIxSviz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0nrfkNR7u975aqMt0R1E7n', + }, + href: 'https://api.spotify.com/v1/albums/0nrfkNR7u975aqMt0R1E7n', + id: '0nrfkNR7u975aqMt0R1E7n', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2731df785bc2b00a1be5d803e6f', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e021df785bc2b00a1be5d803e6f', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048511df785bc2b00a1be5d803e6f', + width: 64, + }, + ], + name: 'Dawn Chorus', + release_date: '2017-06-16', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0nrfkNR7u975aqMt0R1E7n', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rj2COYs5hQsw8rYIxSviz', + }, + href: 'https://api.spotify.com/v1/artists/4Rj2COYs5hQsw8rYIxSviz', + id: '4Rj2COYs5hQsw8rYIxSviz', + name: 'Hidden Orchestra', + type: 'artist', + uri: 'spotify:artist:4Rj2COYs5hQsw8rYIxSviz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 351920, + explicit: false, + external_ids: { + isrc: 'GBEUE1700004', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/2jSZLKZFC5LclPiao0W1zz', + }, + href: 'https://api.spotify.com/v1/tracks/2jSZLKZFC5LclPiao0W1zz', + id: '2jSZLKZFC5LclPiao0W1zz', + is_local: false, + name: 'The Lizard', + popularity: 14, + preview_url: + 'https://p.scdn.co/mp3-preview/0e1519e015cdb9237a6eba0428dc3ef7179f6bc7?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:2jSZLKZFC5LclPiao0W1zz', }, - "href" : "https://api.spotify.com/v1/tracks/6fiJKbCHyA0BEzhI2Lt3Wr", - "id" : "6fiJKbCHyA0BEzhI2Lt3Wr", - "is_local" : false, - "name" : "Lory", - "popularity" : 41, - "preview_url" : "https://p.scdn.co/mp3-preview/176a1b1fb32024829bf5ff4e19c3d7810f996fd8?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 7, - "type" : "track", - "uri" : "spotify:track:6fiJKbCHyA0BEzhI2Lt3Wr" - } - }, { - "added_at" : "2021-01-06T18:12:48Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/46iJ1VD4HKFnqjISGqlZkV" - }, - "href" : "https://api.spotify.com/v1/artists/46iJ1VD4HKFnqjISGqlZkV", - "id" : "09b5OcuIELTdD7FfzQzcdB", - "name" : "Covet", - "type" : "artist", - "uri" : "spotify:artist:46iJ1VD4HKFnqjISGqlZkV" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/3ouZZp6tCRElZLb4Qe0KVR" - }, - "href" : "https://api.spotify.com/v1/albums/3ouZZp6tCRElZLb4Qe0KVR", - "id" : "3ouZZp6tCRElZLb4Qe0KVR", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273fc825d57fe8933e012c2ad62", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02fc825d57fe8933e012c2ad62", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851fc825d57fe8933e012c2ad62", - "width" : 64 - } ], - "name" : "technicolor", - "release_date" : "2020-06-05", - "release_date_precision" : "day", - "total_tracks" : 10, - "type" : "album", - "uri" : "spotify:album:3ouZZp6tCRElZLb4Qe0KVR" + }, + { + added_at: '2021-02-10T12:57:29Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb', + }, + href: 'https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb', + id: '0cmWgDlu9CwTgxPhf403hb', + name: 'Bonobo', + type: 'artist', + uri: 'spotify:artist:0cmWgDlu9CwTgxPhf403hb', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6tEOuMrJ6gsmZ2vB2P1NV7', + }, + href: 'https://api.spotify.com/v1/albums/6tEOuMrJ6gsmZ2vB2P1NV7', + id: '6tEOuMrJ6gsmZ2vB2P1NV7', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273c46ca7a942d8795a06774df9', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02c46ca7a942d8795a06774df9', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851c46ca7a942d8795a06774df9', + width: 64, + }, + ], + name: 'The North Borders Tour. — Live.', + release_date: '2014-10-06', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:6tEOuMrJ6gsmZ2vB2P1NV7', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0cmWgDlu9CwTgxPhf403hb', + }, + href: 'https://api.spotify.com/v1/artists/0cmWgDlu9CwTgxPhf403hb', + id: '0cmWgDlu9CwTgxPhf403hb', + name: 'Bonobo', + type: 'artist', + uri: 'spotify:artist:0cmWgDlu9CwTgxPhf403hb', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 489763, + explicit: false, + external_ids: { + isrc: 'GBCFB1404615', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/5lcTh4kYshToQMHnlNsxaj', + }, + href: 'https://api.spotify.com/v1/tracks/5lcTh4kYshToQMHnlNsxaj', + id: '5lcTh4kYshToQMHnlNsxaj', + is_local: false, + name: 'Prelude/Kiara/Ten Tigers - Live', + popularity: 33, + preview_url: + 'https://p.scdn.co/mp3-preview/51f13199a68b793b87cfc30a78e9df560264bd21?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 4, + type: 'track', + uri: 'spotify:track:5lcTh4kYshToQMHnlNsxaj', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/46iJ1VD4HKFnqjISGqlZkV" - }, - "href" : "https://api.spotify.com/v1/artists/46iJ1VD4HKFnqjISGqlZkV", - "id" : "46iJ1VD4HKFnqjISGqlZkV", - "name" : "Covet", - "type" : "artist", - "uri" : "spotify:artist:46iJ1VD4HKFnqjISGqlZkV" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 281000, - "explicit" : false, - "external_ids" : { - "isrc" : "US72W2024109" + }, + { + added_at: '2021-02-09T15:57:33Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2p2uE4i92Dn4DkThfoKIB9', + }, + href: 'https://api.spotify.com/v1/artists/2p2uE4i92Dn4DkThfoKIB9', + id: '2p2uE4i92Dn4DkThfoKIB9', + name: 'Igorrr', + type: 'artist', + uri: 'spotify:artist:2p2uE4i92Dn4DkThfoKIB9', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/4hl7ryP7L1SvblrcPRAkpQ', + }, + href: 'https://api.spotify.com/v1/albums/4hl7ryP7L1SvblrcPRAkpQ', + id: '4hl7ryP7L1SvblrcPRAkpQ', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273bee3918143b9d6e5571239b4', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02bee3918143b9d6e5571239b4', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851bee3918143b9d6e5571239b4', + width: 64, + }, + ], + name: 'Spirituality and Distortion', + release_date: '2020-03-27', + release_date_precision: 'day', + total_tracks: 14, + type: 'album', + uri: 'spotify:album:4hl7ryP7L1SvblrcPRAkpQ', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2p2uE4i92Dn4DkThfoKIB9', + }, + href: 'https://api.spotify.com/v1/artists/2p2uE4i92Dn4DkThfoKIB9', + id: '2p2uE4i92Dn4DkThfoKIB9', + name: 'Igorrr', + type: 'artist', + uri: 'spotify:artist:2p2uE4i92Dn4DkThfoKIB9', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 203186, + explicit: false, + external_ids: { + isrc: 'USMBR1913984', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0GOytj5zpFRpjGN04FLmHT', + }, + href: 'https://api.spotify.com/v1/tracks/0GOytj5zpFRpjGN04FLmHT', + id: '0GOytj5zpFRpjGN04FLmHT', + is_local: false, + name: 'Nervous Waltz', + popularity: 38, + preview_url: + 'https://p.scdn.co/mp3-preview/af61b3d905038e7db4dfad071d0568f13175132e?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:0GOytj5zpFRpjGN04FLmHT', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/2QLKBeYnQ3Mh7a9kCPQVIG" + }, + { + added_at: '2021-01-31T12:23:58Z', + track: { + album: { + album_type: 'single', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0iT2o4MNsBKSLy7bllgdo0', + }, + href: 'https://api.spotify.com/v1/artists/0iT2o4MNsBKSLy7bllgdo0', + id: '0iT2o4MNsBKSLy7bllgdo0', + name: 'Jus Now', + type: 'artist', + uri: 'spotify:artist:0iT2o4MNsBKSLy7bllgdo0', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6s7bgHlLfKpbb3YT01gfLH', + }, + href: 'https://api.spotify.com/v1/albums/6s7bgHlLfKpbb3YT01gfLH', + id: '6s7bgHlLfKpbb3YT01gfLH', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273c66a1f51ed84b8117ae00c76', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02c66a1f51ed84b8117ae00c76', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851c66a1f51ed84b8117ae00c76', + width: 64, + }, + ], + name: 'Cyah Help It', + release_date: '2015-10-16', + release_date_precision: 'day', + total_tracks: 1, + type: 'album', + uri: 'spotify:album:6s7bgHlLfKpbb3YT01gfLH', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0iT2o4MNsBKSLy7bllgdo0', + }, + href: 'https://api.spotify.com/v1/artists/0iT2o4MNsBKSLy7bllgdo0', + id: '0iT2o4MNsBKSLy7bllgdo0', + name: 'Jus Now', + type: 'artist', + uri: 'spotify:artist:0iT2o4MNsBKSLy7bllgdo0', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/42qLC3FgtazA9AvaIoiP62', + }, + href: 'https://api.spotify.com/v1/artists/42qLC3FgtazA9AvaIoiP62', + id: '42qLC3FgtazA9AvaIoiP62', + name: 'Ms. Dynamite', + type: 'artist', + uri: 'spotify:artist:42qLC3FgtazA9AvaIoiP62', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/6nPHDCN7qmxO86eN1grP54', + }, + href: 'https://api.spotify.com/v1/artists/6nPHDCN7qmxO86eN1grP54', + id: '6nPHDCN7qmxO86eN1grP54', + name: 'Bunji Garlin', + type: 'artist', + uri: 'spotify:artist:6nPHDCN7qmxO86eN1grP54', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 188442, + explicit: false, + external_ids: { + isrc: 'GB9TP1500480', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/7M5GI36F8By0vFycdQ4pke', + }, + href: 'https://api.spotify.com/v1/tracks/7M5GI36F8By0vFycdQ4pke', + id: '7M5GI36F8By0vFycdQ4pke', + is_local: false, + name: 'Cyah Help It', + popularity: 5, + preview_url: + 'https://p.scdn.co/mp3-preview/fdbe06d7d3dadab133161dd9edc16a45bdb40588?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 1, + type: 'track', + uri: 'spotify:track:7M5GI36F8By0vFycdQ4pke', }, - "href" : "https://api.spotify.com/v1/tracks/2QLKBeYnQ3Mh7a9kCPQVIG", - "id" : "2QLKBeYnQ3Mh7a9kCPQVIG", - "is_local" : false, - "name" : "parrot", - "popularity" : 32, - "preview_url" : "https://p.scdn.co/mp3-preview/26d614141c6fb07a757ff664864df107fcf5531c?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:2QLKBeYnQ3Mh7a9kCPQVIG" - } - }, { - "added_at" : "2021-01-02T23:54:07Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir" - }, - "href" : "https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir", - "id" : "621sN6b7GCpWpzaSidA5Ir", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045", - "width" : 64 - } ], - "name" : "The Path of Apotheosis", - "release_date" : "2014-01-26", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:621sN6b7GCpWpzaSidA5Ir" + }, + { + added_at: '2021-01-30T18:38:52Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/57dN52uHvrHOxijzpIgu3E', + }, + href: 'https://api.spotify.com/v1/artists/57dN52uHvrHOxijzpIgu3E', + id: '57dN52uHvrHOxijzpIgu3E', + name: 'Ratatat', + type: 'artist', + uri: 'spotify:artist:57dN52uHvrHOxijzpIgu3E', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/7nqSnoxmIdcfxAJBxl9AIh', + }, + href: 'https://api.spotify.com/v1/albums/7nqSnoxmIdcfxAJBxl9AIh', + id: '7nqSnoxmIdcfxAJBxl9AIh', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2731e86a07cda05a74debfd1ac2', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e021e86a07cda05a74debfd1ac2', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048511e86a07cda05a74debfd1ac2', + width: 64, + }, + ], + name: 'Ratatat', + release_date: '2004-04-19', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:7nqSnoxmIdcfxAJBxl9AIh', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/57dN52uHvrHOxijzpIgu3E', + }, + href: 'https://api.spotify.com/v1/artists/57dN52uHvrHOxijzpIgu3E', + id: '57dN52uHvrHOxijzpIgu3E', + name: 'Ratatat', + type: 'artist', + uri: 'spotify:artist:57dN52uHvrHOxijzpIgu3E', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 338333, + explicit: false, + external_ids: { + isrc: 'GBBKS0300144', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6zgCycfVETCfk2TNY7Othq', + }, + href: 'https://api.spotify.com/v1/tracks/6zgCycfVETCfk2TNY7Othq', + id: '6zgCycfVETCfk2TNY7Othq', + is_local: false, + name: 'Cherry', + popularity: 43, + preview_url: + 'https://p.scdn.co/mp3-preview/41d5c31eb71c5058cef3252efed3f0c09f0f37d4?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 11, + type: 'track', + uri: 'spotify:track:6zgCycfVETCfk2TNY7Othq', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 381680, - "explicit" : false, - "external_ids" : { - "isrc" : "TCABS1379686" + }, + { + added_at: '2021-01-27T18:49:55Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/31DXlldabwPHwu6dYevuzK', + }, + href: 'https://api.spotify.com/v1/artists/31DXlldabwPHwu6dYevuzK', + id: '31DXlldabwPHwu6dYevuzK', + name: 'Simian Mobile Disco', + type: 'artist', + uri: 'spotify:artist:31DXlldabwPHwu6dYevuzK', + }, + ], + available_markets: [ + 'AD', + 'AG', + 'AL', + 'AR', + 'AT', + 'AU', + 'BA', + 'BB', + 'BE', + 'BF', + 'BG', + 'BI', + 'BO', + 'BR', + 'BS', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HN', + 'HR', + 'HT', + 'HU', + 'IE', + 'IS', + 'IT', + 'JM', + 'KE', + 'KI', + 'KM', + 'KN', + 'LC', + 'LI', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MR', + 'MT', + 'MW', + 'MX', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NR', + 'NZ', + 'PA', + 'PE', + 'PG', + 'PL', + 'PT', + 'PW', + 'PY', + 'RO', + 'RS', + 'RU', + 'RW', + 'SB', + 'SC', + 'SE', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TN', + 'TO', + 'TT', + 'TV', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'VC', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/3k0xfQP6xY8DinupXsBohl', + }, + href: 'https://api.spotify.com/v1/albums/3k0xfQP6xY8DinupXsBohl', + id: '3k0xfQP6xY8DinupXsBohl', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273110bd6379d030aaf1d418329', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02110bd6379d030aaf1d418329', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851110bd6379d030aaf1d418329', + width: 64, + }, + ], + name: 'Whorl', + release_date: '2014-09-09', + release_date_precision: 'day', + total_tracks: 12, + type: 'album', + uri: 'spotify:album:3k0xfQP6xY8DinupXsBohl', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/31DXlldabwPHwu6dYevuzK', + }, + href: 'https://api.spotify.com/v1/artists/31DXlldabwPHwu6dYevuzK', + id: '31DXlldabwPHwu6dYevuzK', + name: 'Simian Mobile Disco', + type: 'artist', + uri: 'spotify:artist:31DXlldabwPHwu6dYevuzK', + }, + ], + available_markets: [ + 'AD', + 'AG', + 'AL', + 'AR', + 'AT', + 'AU', + 'BA', + 'BB', + 'BE', + 'BF', + 'BG', + 'BI', + 'BO', + 'BR', + 'BS', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HN', + 'HR', + 'HT', + 'HU', + 'IE', + 'IS', + 'IT', + 'JM', + 'KE', + 'KI', + 'KM', + 'KN', + 'LC', + 'LI', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MR', + 'MT', + 'MW', + 'MX', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NR', + 'NZ', + 'PA', + 'PE', + 'PG', + 'PL', + 'PT', + 'PW', + 'PY', + 'RO', + 'RS', + 'RU', + 'RW', + 'SB', + 'SC', + 'SE', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TN', + 'TO', + 'TT', + 'TV', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'VC', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 446546, + explicit: false, + external_ids: { + isrc: 'USEP41413003', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/04MkvmxBIw2rzP1Q96QOWl', + }, + href: 'https://api.spotify.com/v1/tracks/04MkvmxBIw2rzP1Q96QOWl', + id: '04MkvmxBIw2rzP1Q96QOWl', + is_local: false, + name: 'Sun Dogs', + popularity: 10, + preview_url: + 'https://p.scdn.co/mp3-preview/6178e959b7acb38b970d1d496adc74ab8f261e65?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 3, + type: 'track', + uri: 'spotify:track:04MkvmxBIw2rzP1Q96QOWl', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/70uk9oYGwoQBybR63uvfZf" + }, + { + added_at: '2021-01-24T21:56:40Z', + track: { + album: { + album_type: 'single', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4S8XZ6FgGp5KKwymL8E6Hz', + }, + href: 'https://api.spotify.com/v1/artists/4S8XZ6FgGp5KKwymL8E6Hz', + id: '4S8XZ6FgGp5KKwymL8E6Hz', + name: 'Enduser', + type: 'artist', + uri: 'spotify:artist:4S8XZ6FgGp5KKwymL8E6Hz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/3HZiO8N7WZynVwQdrhhifV', + }, + href: 'https://api.spotify.com/v1/albums/3HZiO8N7WZynVwQdrhhifV', + id: '3HZiO8N7WZynVwQdrhhifV', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27389e0f04eb1d3afe7281739ce', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0289e0f04eb1d3afe7281739ce', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485189e0f04eb1d3afe7281739ce', + width: 64, + }, + ], + name: '1-3', + release_date: '2019-02-09', + release_date_precision: 'day', + total_tracks: 5, + type: 'album', + uri: 'spotify:album:3HZiO8N7WZynVwQdrhhifV', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4S8XZ6FgGp5KKwymL8E6Hz', + }, + href: 'https://api.spotify.com/v1/artists/4S8XZ6FgGp5KKwymL8E6Hz', + id: '4S8XZ6FgGp5KKwymL8E6Hz', + name: 'Enduser', + type: 'artist', + uri: 'spotify:artist:4S8XZ6FgGp5KKwymL8E6Hz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 357485, + explicit: false, + external_ids: { + isrc: 'QZ5FN1940636', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3cFxBXjTOuUiOxnH0tpZe4', + }, + href: 'https://api.spotify.com/v1/tracks/3cFxBXjTOuUiOxnH0tpZe4', + id: '3cFxBXjTOuUiOxnH0tpZe4', + is_local: false, + name: '2-3', + popularity: 16, + preview_url: + 'https://p.scdn.co/mp3-preview/532604d94feb7cee6927b4c96b52afe31f70c33b?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 3, + type: 'track', + uri: 'spotify:track:3cFxBXjTOuUiOxnH0tpZe4', }, - "href" : "https://api.spotify.com/v1/tracks/70uk9oYGwoQBybR63uvfZf", - "id" : "70uk9oYGwoQBybR63uvfZf", - "is_local" : false, - "name" : "Onslaught of the Covenant", - "popularity" : 21, - "preview_url" : "https://p.scdn.co/mp3-preview/b1dba2004d20b29a43b67ce791f46ebb1730ac52?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 8, - "type" : "track", - "uri" : "spotify:track:70uk9oYGwoQBybR63uvfZf" - } - }, { - "added_at" : "2021-01-02T23:39:08Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir" - }, - "href" : "https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir", - "id" : "621sN6b7GCpWpzaSidA5Ir", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045", - "width" : 64 - } ], - "name" : "The Path of Apotheosis", - "release_date" : "2014-01-26", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:621sN6b7GCpWpzaSidA5Ir" + }, + { + added_at: '2021-01-24T19:49:54Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB', + }, + href: 'https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB', + id: '5kU3Q43bmLdARkMOCOLNkB', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65', + width: 64, + }, + ], + name: 'Igneous', + release_date: '2019-05-10', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:5kU3Q43bmLdARkMOCOLNkB', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 317500, + explicit: false, + external_ids: { + isrc: 'NLC7F1900018', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/0kYQbZQqpZkACY7IJGl343', + }, + href: 'https://api.spotify.com/v1/tracks/0kYQbZQqpZkACY7IJGl343', + id: '0kYQbZQqpZkACY7IJGl343', + is_local: false, + name: 'Kali', + popularity: 21, + preview_url: + 'https://p.scdn.co/mp3-preview/0bfa262d70b4d98f4667e56c84266b1d5fa65ae8?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 3, + type: 'track', + uri: 'spotify:track:0kYQbZQqpZkACY7IJGl343', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A" - }, - "href" : "https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A", - "id" : "2DlKh1IzbG3EwAMaTF2p4A", - "name" : "Inferi", - "type" : "artist", - "uri" : "spotify:artist:2DlKh1IzbG3EwAMaTF2p4A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 384920, - "explicit" : false, - "external_ids" : { - "isrc" : "TCABS1379685" + }, + { + added_at: '2021-01-22T20:54:11Z', + track: { + album: { + album_type: 'compilation', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of', + }, + href: 'https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of', + id: '0LyfQWJT6nXafLPZqxe9Of', + name: 'Various Artists', + type: 'artist', + uri: 'spotify:artist:0LyfQWJT6nXafLPZqxe9Of', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BE', + 'BG', + 'BH', + 'BN', + 'BO', + 'BR', + 'BY', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FR', + 'GB', + 'GN', + 'GR', + 'GT', + 'GW', + 'HK', + 'HN', + 'HR', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JO', + 'JP', + 'KG', + 'KH', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LI', + 'LK', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'ME', + 'MK', + 'MO', + 'MT', + 'MX', + 'MY', + 'NG', + 'NI', + 'NL', + 'NO', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PH', + 'PL', + 'PT', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SE', + 'SG', + 'SI', + 'SK', + 'SN', + 'SV', + 'TH', + 'TN', + 'TR', + 'TW', + 'TZ', + 'UA', + 'US', + 'UZ', + 'VN', + 'XK', + 'ZA', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/2oNWwPYsrEZuZ3siifa633', + }, + href: 'https://api.spotify.com/v1/albums/2oNWwPYsrEZuZ3siifa633', + id: '2oNWwPYsrEZuZ3siifa633', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273479a0d67f9d3a2a4e2addd9f', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02479a0d67f9d3a2a4e2addd9f', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851479a0d67f9d3a2a4e2addd9f', + width: 64, + }, + ], + name: 'Treme: Music From The HBO Original Series - Season 2', + release_date: '2012-01-01', + release_date_precision: 'day', + total_tracks: 18, + type: 'album', + uri: 'spotify:album:2oNWwPYsrEZuZ3siifa633', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/53pHwg1sjhqGk726JnJHYb', + }, + href: 'https://api.spotify.com/v1/artists/53pHwg1sjhqGk726JnJHYb', + id: '53pHwg1sjhqGk726JnJHYb', + name: 'Donald Harrison', + type: 'artist', + uri: 'spotify:artist:53pHwg1sjhqGk726JnJHYb', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/44gLY8zUnF4xRzi4X0zl1n', + }, + href: 'https://api.spotify.com/v1/artists/44gLY8zUnF4xRzi4X0zl1n', + id: '44gLY8zUnF4xRzi4X0zl1n', + name: 'Carl Allen', + type: 'artist', + uri: 'spotify:artist:44gLY8zUnF4xRzi4X0zl1n', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/3b1iAUluGgKbthmqGckbPn', + }, + href: 'https://api.spotify.com/v1/artists/3b1iAUluGgKbthmqGckbPn', + id: '3b1iAUluGgKbthmqGckbPn', + name: 'Leon "Kid Chocolate" Brown', + type: 'artist', + uri: 'spotify:artist:3b1iAUluGgKbthmqGckbPn', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/6TvhNLU4Wtptdh1m9XcE0j', + }, + href: 'https://api.spotify.com/v1/artists/6TvhNLU4Wtptdh1m9XcE0j', + id: '6TvhNLU4Wtptdh1m9XcE0j', + name: 'Rob Brown', + type: 'artist', + uri: 'spotify:artist:6TvhNLU4Wtptdh1m9XcE0j', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4wnzivx3OQ3vjrySAdTdJP', + }, + href: 'https://api.spotify.com/v1/artists/4wnzivx3OQ3vjrySAdTdJP', + id: '4wnzivx3OQ3vjrySAdTdJP', + name: 'Ron Carter', + type: 'artist', + uri: 'spotify:artist:4wnzivx3OQ3vjrySAdTdJP', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/320TrJub4arztwXRm7kqVO', + }, + href: 'https://api.spotify.com/v1/artists/320TrJub4arztwXRm7kqVO', + id: '320TrJub4arztwXRm7kqVO', + name: 'Dr. John', + type: 'artist', + uri: 'spotify:artist:320TrJub4arztwXRm7kqVO', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/0xVjTHsSeU2B3DGMjJ3KFy', + }, + href: 'https://api.spotify.com/v1/artists/0xVjTHsSeU2B3DGMjJ3KFy', + id: '0xVjTHsSeU2B3DGMjJ3KFy', + name: 'Clarke Peters', + type: 'artist', + uri: 'spotify:artist:0xVjTHsSeU2B3DGMjJ3KFy', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/7E4MQbO3PckmL7W01Cnnrd', + }, + href: 'https://api.spotify.com/v1/artists/7E4MQbO3PckmL7W01Cnnrd', + id: '7E4MQbO3PckmL7W01Cnnrd', + name: 'Alfred “Uganda” Roberts', + type: 'artist', + uri: 'spotify:artist:7E4MQbO3PckmL7W01Cnnrd', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BE', + 'BG', + 'BH', + 'BN', + 'BO', + 'BR', + 'BY', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FR', + 'GB', + 'GN', + 'GR', + 'GT', + 'GW', + 'HK', + 'HN', + 'HR', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JO', + 'JP', + 'KG', + 'KH', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LI', + 'LK', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'ME', + 'MK', + 'MO', + 'MT', + 'MX', + 'MY', + 'NG', + 'NI', + 'NL', + 'NO', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PH', + 'PL', + 'PT', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SE', + 'SG', + 'SI', + 'SK', + 'SN', + 'SV', + 'TH', + 'TN', + 'TR', + 'TW', + 'TZ', + 'UA', + 'US', + 'UZ', + 'VN', + 'XK', + 'ZA', + ], + disc_number: 1, + duration_ms: 324253, + explicit: false, + external_ids: { + isrc: 'USRO21213017', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/2dPAL09IadQJ7mMpTJ45w3', + }, + href: 'https://api.spotify.com/v1/tracks/2dPAL09IadQJ7mMpTJ45w3', + id: '2dPAL09IadQJ7mMpTJ45w3', + is_local: false, + name: 'Hu Ta Nay', + popularity: 17, + preview_url: + 'https://p.scdn.co/mp3-preview/b6df8cf66f2bd0142b1ab865b6a41d6b311282c0?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 17, + type: 'track', + uri: 'spotify:track:2dPAL09IadQJ7mMpTJ45w3', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3PRxPB1T7BBpmeXA7xeoHo" + }, + { + added_at: '2021-01-06T19:31:55Z', + track: { + album: { + album_type: 'compilation', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of', + }, + href: 'https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of', + id: '0LyfQWJT6nXafLPZqxe9Of', + name: 'Various Artists', + type: 'artist', + uri: 'spotify:artist:0LyfQWJT6nXafLPZqxe9Of', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/2vx34tJFXMnjT9vKEVtcKI', + }, + href: 'https://api.spotify.com/v1/albums/2vx34tJFXMnjT9vKEVtcKI', + id: '2vx34tJFXMnjT9vKEVtcKI', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27389fdc1ec5668fdd29a5960cc', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0289fdc1ec5668fdd29a5960cc', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485189fdc1ec5668fdd29a5960cc', + width: 64, + }, + ], + name: 'SOMEWHERE', + release_date: '2015-08-28', + release_date_precision: 'day', + total_tracks: 7, + type: 'album', + uri: 'spotify:album:2vx34tJFXMnjT9vKEVtcKI', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 526646, + explicit: false, + external_ids: { + isrc: 'DEU671502315', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/72Gko345HYQu6gI3DWAZfL', + }, + href: 'https://api.spotify.com/v1/tracks/72Gko345HYQu6gI3DWAZfL', + id: '72Gko345HYQu6gI3DWAZfL', + is_local: false, + name: 'Anther', + popularity: 32, + preview_url: + 'https://p.scdn.co/mp3-preview/9e9135d80b5ea310841c051007a7a3d2c6f00892?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:72Gko345HYQu6gI3DWAZfL', }, - "href" : "https://api.spotify.com/v1/tracks/3PRxPB1T7BBpmeXA7xeoHo", - "id" : "3PRxPB1T7BBpmeXA7xeoHo", - "is_local" : false, - "name" : "Destroyer", - "popularity" : 26, - "preview_url" : "https://p.scdn.co/mp3-preview/fd38c9a25c5533e6a079668d2125c5461b963133?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 7, - "type" : "track", - "uri" : "spotify:track:3PRxPB1T7BBpmeXA7xeoHo" - } - }, { - "added_at" : "2020-12-31T20:15:12Z", - "track" : { - "album" : { - "album_type" : "single", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/515MsUrwyO1ui5mvvJ98J0" - }, - "href" : "https://api.spotify.com/v1/albums/515MsUrwyO1ui5mvvJ98J0", - "id" : "515MsUrwyO1ui5mvvJ98J0", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b27301878f5cb411afac948511ce", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e0201878f5cb411afac948511ce", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d0000485101878f5cb411afac948511ce", - "width" : 64 - } ], - "name" : "Muriatic", - "release_date" : "2018-03-16", - "release_date_precision" : "day", - "total_tracks" : 2, - "type" : "album", - "uri" : "spotify:album:515MsUrwyO1ui5mvvJ98J0" + }, + { + added_at: '2021-01-06T19:21:31Z', + track: { + album: { + album_type: 'single', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/2uJG5GCaZTwP3z1tkgAG6P', + }, + href: 'https://api.spotify.com/v1/albums/2uJG5GCaZTwP3z1tkgAG6P', + id: '2uJG5GCaZTwP3z1tkgAG6P', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2737449d8b759c6f6acc1d1757a', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e027449d8b759c6f6acc1d1757a', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048517449d8b759c6f6acc1d1757a', + width: 64, + }, + ], + name: 'Humming', + release_date: '2020-12-18', + release_date_precision: 'day', + total_tracks: 1, + type: 'album', + uri: 'spotify:album:2uJG5GCaZTwP3z1tkgAG6P', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 205000, + explicit: false, + external_ids: { + isrc: 'NLC7F2000102', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/4dcqNrCh3Atf4ylrvFxKoG', + }, + href: 'https://api.spotify.com/v1/tracks/4dcqNrCh3Atf4ylrvFxKoG', + id: '4dcqNrCh3Atf4ylrvFxKoG', + is_local: false, + name: 'Humming', + popularity: 26, + preview_url: + 'https://p.scdn.co/mp3-preview/585c838b959f3a81e27ff214e92b2026e737d803?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 1, + type: 'track', + uri: 'spotify:track:4dcqNrCh3Atf4ylrvFxKoG', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz" - }, - "href" : "https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz", - "id" : "4Rcol4u0q89lypqKI83GDz", - "name" : "Polynation", - "type" : "artist", - "uri" : "spotify:artist:4Rcol4u0q89lypqKI83GDz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 237777, - "explicit" : false, - "external_ids" : { - "isrc" : "NLC7F1800014" + }, + { + added_at: '2021-01-06T19:16:04Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB', + }, + href: 'https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB', + id: '5kU3Q43bmLdARkMOCOLNkB', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65', + width: 64, + }, + ], + name: 'Igneous', + release_date: '2019-05-10', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:5kU3Q43bmLdARkMOCOLNkB', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 397295, + explicit: false, + external_ids: { + isrc: 'NLC7F1900023', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/05Ps8wHwPh5Ut5EfcIgxPZ', + }, + href: 'https://api.spotify.com/v1/tracks/05Ps8wHwPh5Ut5EfcIgxPZ', + id: '05Ps8wHwPh5Ut5EfcIgxPZ', + is_local: false, + name: 'Toba', + popularity: 35, + preview_url: + 'https://p.scdn.co/mp3-preview/79a2296ebb2e66367826caf9ab37c61c12d4bea5?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:05Ps8wHwPh5Ut5EfcIgxPZ', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/6e3cIvk5s4mWmONbZEannO" + }, + { + added_at: '2021-01-06T19:12:38Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/5kU3Q43bmLdARkMOCOLNkB', + }, + href: 'https://api.spotify.com/v1/albums/5kU3Q43bmLdARkMOCOLNkB', + id: '5kU3Q43bmLdARkMOCOLNkB', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2733caf395cb159288678e3fd65', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e023caf395cb159288678e3fd65', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048513caf395cb159288678e3fd65', + width: 64, + }, + ], + name: 'Igneous', + release_date: '2019-05-10', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:5kU3Q43bmLdARkMOCOLNkB', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 216695, + explicit: false, + external_ids: { + isrc: 'NLC7F1900022', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6fiJKbCHyA0BEzhI2Lt3Wr', + }, + href: 'https://api.spotify.com/v1/tracks/6fiJKbCHyA0BEzhI2Lt3Wr', + id: '6fiJKbCHyA0BEzhI2Lt3Wr', + is_local: false, + name: 'Lory', + popularity: 41, + preview_url: + 'https://p.scdn.co/mp3-preview/176a1b1fb32024829bf5ff4e19c3d7810f996fd8?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 7, + type: 'track', + uri: 'spotify:track:6fiJKbCHyA0BEzhI2Lt3Wr', }, - "href" : "https://api.spotify.com/v1/tracks/6e3cIvk5s4mWmONbZEannO", - "id" : "6e3cIvk5s4mWmONbZEannO", - "is_local" : false, - "name" : "Muriatic", - "popularity" : 19, - "preview_url" : "https://p.scdn.co/mp3-preview/5f0a3e143f59ad9d64ffc5dbe764721acfb4bf9d?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:6e3cIvk5s4mWmONbZEannO" - } - }, { - "added_at" : "2020-12-31T17:43:13Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4LNC9g5ie0tSgZed2CHQ5A" - }, - "href" : "https://api.spotify.com/v1/artists/4LNC9g5ie0tSgZed2CHQ5A", - "id" : "4LNC9g5ie0tSgZed2CHQ5A", - "name" : "Waldemar Matuška", - "type" : "artist", - "uri" : "spotify:artist:4LNC9g5ie0tSgZed2CHQ5A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/0T0LjviltLGbSxEplfmc4r" - }, - "href" : "https://api.spotify.com/v1/albums/0T0LjviltLGbSxEplfmc4r", - "id" : "0T0LjviltLGbSxEplfmc4r", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b273d65f92695b407bb9c9a19694", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e02d65f92695b407bb9c9a19694", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d00004851d65f92695b407bb9c9a19694", - "width" : 64 - } ], - "name" : "Waldemar Matuška", - "release_date" : "1968", - "release_date_precision" : "year", - "total_tracks" : 12, - "type" : "album", - "uri" : "spotify:album:0T0LjviltLGbSxEplfmc4r" + }, + { + added_at: '2021-01-06T18:12:48Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/46iJ1VD4HKFnqjISGqlZkV', + }, + href: 'https://api.spotify.com/v1/artists/46iJ1VD4HKFnqjISGqlZkV', + id: '09b5OcuIELTdD7FfzQzcdB', + name: 'Covet', + type: 'artist', + uri: 'spotify:artist:46iJ1VD4HKFnqjISGqlZkV', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/3ouZZp6tCRElZLb4Qe0KVR', + }, + href: 'https://api.spotify.com/v1/albums/3ouZZp6tCRElZLb4Qe0KVR', + id: '3ouZZp6tCRElZLb4Qe0KVR', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273fc825d57fe8933e012c2ad62', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02fc825d57fe8933e012c2ad62', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851fc825d57fe8933e012c2ad62', + width: 64, + }, + ], + name: 'technicolor', + release_date: '2020-06-05', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:3ouZZp6tCRElZLb4Qe0KVR', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/46iJ1VD4HKFnqjISGqlZkV', + }, + href: 'https://api.spotify.com/v1/artists/46iJ1VD4HKFnqjISGqlZkV', + id: '46iJ1VD4HKFnqjISGqlZkV', + name: 'Covet', + type: 'artist', + uri: 'spotify:artist:46iJ1VD4HKFnqjISGqlZkV', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 281000, + explicit: false, + external_ids: { + isrc: 'US72W2024109', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/2QLKBeYnQ3Mh7a9kCPQVIG', + }, + href: 'https://api.spotify.com/v1/tracks/2QLKBeYnQ3Mh7a9kCPQVIG', + id: '2QLKBeYnQ3Mh7a9kCPQVIG', + is_local: false, + name: 'parrot', + popularity: 32, + preview_url: + 'https://p.scdn.co/mp3-preview/26d614141c6fb07a757ff664864df107fcf5531c?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:2QLKBeYnQ3Mh7a9kCPQVIG', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/4LNC9g5ie0tSgZed2CHQ5A" - }, - "href" : "https://api.spotify.com/v1/artists/4LNC9g5ie0tSgZed2CHQ5A", - "id" : "4LNC9g5ie0tSgZed2CHQ5A", - "name" : "Waldemar Matuška", - "type" : "artist", - "uri" : "spotify:artist:4LNC9g5ie0tSgZed2CHQ5A" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MV", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "VU", "WS", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 220586, - "explicit" : false, - "external_ids" : { - "isrc" : "CZA166800122" + }, + { + added_at: '2021-01-02T23:54:07Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir', + }, + href: 'https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir', + id: '621sN6b7GCpWpzaSidA5Ir', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045', + width: 64, + }, + ], + name: 'The Path of Apotheosis', + release_date: '2014-01-26', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:621sN6b7GCpWpzaSidA5Ir', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 381680, + explicit: false, + external_ids: { + isrc: 'TCABS1379686', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/70uk9oYGwoQBybR63uvfZf', + }, + href: 'https://api.spotify.com/v1/tracks/70uk9oYGwoQBybR63uvfZf', + id: '70uk9oYGwoQBybR63uvfZf', + is_local: false, + name: 'Onslaught of the Covenant', + popularity: 21, + preview_url: + 'https://p.scdn.co/mp3-preview/b1dba2004d20b29a43b67ce791f46ebb1730ac52?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 8, + type: 'track', + uri: 'spotify:track:70uk9oYGwoQBybR63uvfZf', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/3SY5c1sMaxlqADgOKSONQR" + }, + { + added_at: '2021-01-02T23:39:08Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/621sN6b7GCpWpzaSidA5Ir', + }, + href: 'https://api.spotify.com/v1/albums/621sN6b7GCpWpzaSidA5Ir', + id: '621sN6b7GCpWpzaSidA5Ir', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273f5e1ee8deb0e691a68d29045', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02f5e1ee8deb0e691a68d29045', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851f5e1ee8deb0e691a68d29045', + width: 64, + }, + ], + name: 'The Path of Apotheosis', + release_date: '2014-01-26', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:621sN6b7GCpWpzaSidA5Ir', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/2DlKh1IzbG3EwAMaTF2p4A', + }, + href: 'https://api.spotify.com/v1/artists/2DlKh1IzbG3EwAMaTF2p4A', + id: '2DlKh1IzbG3EwAMaTF2p4A', + name: 'Inferi', + type: 'artist', + uri: 'spotify:artist:2DlKh1IzbG3EwAMaTF2p4A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 384920, + explicit: false, + external_ids: { + isrc: 'TCABS1379685', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3PRxPB1T7BBpmeXA7xeoHo', + }, + href: 'https://api.spotify.com/v1/tracks/3PRxPB1T7BBpmeXA7xeoHo', + id: '3PRxPB1T7BBpmeXA7xeoHo', + is_local: false, + name: 'Destroyer', + popularity: 26, + preview_url: + 'https://p.scdn.co/mp3-preview/fd38c9a25c5533e6a079668d2125c5461b963133?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 7, + type: 'track', + uri: 'spotify:track:3PRxPB1T7BBpmeXA7xeoHo', }, - "href" : "https://api.spotify.com/v1/tracks/3SY5c1sMaxlqADgOKSONQR", - "id" : "3SY5c1sMaxlqADgOKSONQR", - "is_local" : false, - "name" : "Slavíci Z Madridu", - "popularity" : 41, - "preview_url" : "https://p.scdn.co/mp3-preview/e530439dc0d102b91366bd62b84bb90081a0d458?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 10, - "type" : "track", - "uri" : "spotify:track:3SY5c1sMaxlqADgOKSONQR" - } - }, { - "added_at" : "2020-12-31T17:02:26Z", - "track" : { - "album" : { - "album_type" : "album", - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7mnBLXK823vNxN3UWB7Gfz" - }, - "href" : "https://api.spotify.com/v1/artists/7mnBLXK823vNxN3UWB7Gfz", - "id" : "7mnBLXK823vNxN3UWB7Gfz", - "name" : "The Black Keys", - "type" : "artist", - "uri" : "spotify:artist:7mnBLXK823vNxN3UWB7Gfz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MK", "ML", "MN", "MO", "MR", "MT", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PT", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "XK", "ZA", "ZW" ], - "external_urls" : { - "spotify" : "https://open.spotify.com/album/6TvxpBzf9c8H1fsrAaQ8t3" - }, - "href" : "https://api.spotify.com/v1/albums/6TvxpBzf9c8H1fsrAaQ8t3", - "id" : "6TvxpBzf9c8H1fsrAaQ8t3", - "images" : [ { - "height" : 640, - "url" : "https://i.scdn.co/image/ab67616d0000b2731af8fb0d8859055d35d2290f", - "width" : 640 - }, { - "height" : 300, - "url" : "https://i.scdn.co/image/ab67616d00001e021af8fb0d8859055d35d2290f", - "width" : 300 - }, { - "height" : 64, - "url" : "https://i.scdn.co/image/ab67616d000048511af8fb0d8859055d35d2290f", - "width" : 64 - } ], - "name" : "Turn Blue", - "release_date" : "2014-05-09", - "release_date_precision" : "day", - "total_tracks" : 11, - "type" : "album", - "uri" : "spotify:album:6TvxpBzf9c8H1fsrAaQ8t3" + }, + { + added_at: '2020-12-31T20:15:12Z', + track: { + album: { + album_type: 'single', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/515MsUrwyO1ui5mvvJ98J0', + }, + href: 'https://api.spotify.com/v1/albums/515MsUrwyO1ui5mvvJ98J0', + id: '515MsUrwyO1ui5mvvJ98J0', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b27301878f5cb411afac948511ce', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e0201878f5cb411afac948511ce', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d0000485101878f5cb411afac948511ce', + width: 64, + }, + ], + name: 'Muriatic', + release_date: '2018-03-16', + release_date_precision: 'day', + total_tracks: 2, + type: 'album', + uri: 'spotify:album:515MsUrwyO1ui5mvvJ98J0', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4Rcol4u0q89lypqKI83GDz', + }, + href: 'https://api.spotify.com/v1/artists/4Rcol4u0q89lypqKI83GDz', + id: '4Rcol4u0q89lypqKI83GDz', + name: 'Polynation', + type: 'artist', + uri: 'spotify:artist:4Rcol4u0q89lypqKI83GDz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 237777, + explicit: false, + external_ids: { + isrc: 'NLC7F1800014', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/6e3cIvk5s4mWmONbZEannO', + }, + href: 'https://api.spotify.com/v1/tracks/6e3cIvk5s4mWmONbZEannO', + id: '6e3cIvk5s4mWmONbZEannO', + is_local: false, + name: 'Muriatic', + popularity: 19, + preview_url: + 'https://p.scdn.co/mp3-preview/5f0a3e143f59ad9d64ffc5dbe764721acfb4bf9d?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:6e3cIvk5s4mWmONbZEannO', }, - "artists" : [ { - "external_urls" : { - "spotify" : "https://open.spotify.com/artist/7mnBLXK823vNxN3UWB7Gfz" - }, - "href" : "https://api.spotify.com/v1/artists/7mnBLXK823vNxN3UWB7Gfz", - "id" : "7mnBLXK823vNxN3UWB7Gfz", - "name" : "The Black Keys", - "type" : "artist", - "uri" : "spotify:artist:7mnBLXK823vNxN3UWB7Gfz" - } ], - "available_markets" : [ "AD", "AE", "AG", "AL", "AM", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CH", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LK", "LR", "LS", "LT", "LU", "LV", "MA", "MC", "MD", "ME", "MK", "ML", "MN", "MO", "MR", "MT", "MW", "MX", "MY", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PT", "PY", "QA", "RO", "RS", "RU", "RW", "SA", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VN", "XK", "ZA", "ZW" ], - "disc_number" : 1, - "duration_ms" : 268120, - "explicit" : false, - "external_ids" : { - "isrc" : "USNO11400178" + }, + { + added_at: '2020-12-31T17:43:13Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/4LNC9g5ie0tSgZed2CHQ5A', + }, + href: 'https://api.spotify.com/v1/artists/4LNC9g5ie0tSgZed2CHQ5A', + id: '4LNC9g5ie0tSgZed2CHQ5A', + name: 'Waldemar Matuška', + type: 'artist', + uri: 'spotify:artist:4LNC9g5ie0tSgZed2CHQ5A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0T0LjviltLGbSxEplfmc4r', + }, + href: 'https://api.spotify.com/v1/albums/0T0LjviltLGbSxEplfmc4r', + id: '0T0LjviltLGbSxEplfmc4r', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b273d65f92695b407bb9c9a19694', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e02d65f92695b407bb9c9a19694', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d00004851d65f92695b407bb9c9a19694', + width: 64, + }, + ], + name: 'Waldemar Matuška', + release_date: '1968', + release_date_precision: 'year', + total_tracks: 12, + type: 'album', + uri: 'spotify:album:0T0LjviltLGbSxEplfmc4r', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/4LNC9g5ie0tSgZed2CHQ5A', + }, + href: 'https://api.spotify.com/v1/artists/4LNC9g5ie0tSgZed2CHQ5A', + id: '4LNC9g5ie0tSgZed2CHQ5A', + name: 'Waldemar Matuška', + type: 'artist', + uri: 'spotify:artist:4LNC9g5ie0tSgZed2CHQ5A', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MH', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MV', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'SR', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'VU', + 'WS', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 220586, + explicit: false, + external_ids: { + isrc: 'CZA166800122', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/3SY5c1sMaxlqADgOKSONQR', + }, + href: 'https://api.spotify.com/v1/tracks/3SY5c1sMaxlqADgOKSONQR', + id: '3SY5c1sMaxlqADgOKSONQR', + is_local: false, + name: 'Slavíci Z Madridu', + popularity: 41, + preview_url: + 'https://p.scdn.co/mp3-preview/e530439dc0d102b91366bd62b84bb90081a0d458?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 10, + type: 'track', + uri: 'spotify:track:3SY5c1sMaxlqADgOKSONQR', }, - "external_urls" : { - "spotify" : "https://open.spotify.com/track/39e1gl7VaxuCev5ga7bvNq" + }, + { + added_at: '2020-12-31T17:02:26Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: + 'https://open.spotify.com/artist/7mnBLXK823vNxN3UWB7Gfz', + }, + href: 'https://api.spotify.com/v1/artists/7mnBLXK823vNxN3UWB7Gfz', + id: '7mnBLXK823vNxN3UWB7Gfz', + name: 'The Black Keys', + type: 'artist', + uri: 'spotify:artist:7mnBLXK823vNxN3UWB7Gfz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PT', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TR', + 'TT', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'XK', + 'ZA', + 'ZW', + ], + external_urls: { + spotify: 'https://open.spotify.com/album/6TvxpBzf9c8H1fsrAaQ8t3', + }, + href: 'https://api.spotify.com/v1/albums/6TvxpBzf9c8H1fsrAaQ8t3', + id: '6TvxpBzf9c8H1fsrAaQ8t3', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2731af8fb0d8859055d35d2290f', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e021af8fb0d8859055d35d2290f', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048511af8fb0d8859055d35d2290f', + width: 64, + }, + ], + name: 'Turn Blue', + release_date: '2014-05-09', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:6TvxpBzf9c8H1fsrAaQ8t3', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/7mnBLXK823vNxN3UWB7Gfz', + }, + href: 'https://api.spotify.com/v1/artists/7mnBLXK823vNxN3UWB7Gfz', + id: '7mnBLXK823vNxN3UWB7Gfz', + name: 'The Black Keys', + type: 'artist', + uri: 'spotify:artist:7mnBLXK823vNxN3UWB7Gfz', + }, + ], + available_markets: [ + 'AD', + 'AE', + 'AG', + 'AL', + 'AM', + 'AR', + 'AT', + 'AU', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BN', + 'BO', + 'BR', + 'BS', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CH', + 'CL', + 'CM', + 'CO', + 'CR', + 'CV', + 'CW', + 'CY', + 'CZ', + 'DE', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EC', + 'EE', + 'EG', + 'ES', + 'FI', + 'FJ', + 'FM', + 'FR', + 'GA', + 'GB', + 'GD', + 'GH', + 'GM', + 'GN', + 'GQ', + 'GR', + 'GT', + 'GW', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'ID', + 'IE', + 'IL', + 'IN', + 'IS', + 'IT', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KM', + 'KN', + 'KR', + 'KW', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'MA', + 'MC', + 'MD', + 'ME', + 'MK', + 'ML', + 'MN', + 'MO', + 'MR', + 'MT', + 'MW', + 'MX', + 'MY', + 'NA', + 'NE', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PG', + 'PH', + 'PK', + 'PL', + 'PT', + 'PY', + 'QA', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SC', + 'SE', + 'SG', + 'SI', + 'SK', + 'SL', + 'SM', + 'SN', + 'ST', + 'SV', + 'SZ', + 'TD', + 'TG', + 'TH', + 'TL', + 'TN', + 'TR', + 'TT', + 'TW', + 'TZ', + 'UA', + 'UG', + 'US', + 'UY', + 'UZ', + 'VC', + 'VN', + 'XK', + 'ZA', + 'ZW', + ], + disc_number: 1, + duration_ms: 268120, + explicit: false, + external_ids: { + isrc: 'USNO11400178', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/39e1gl7VaxuCev5ga7bvNq', + }, + href: 'https://api.spotify.com/v1/tracks/39e1gl7VaxuCev5ga7bvNq', + id: '39e1gl7VaxuCev5ga7bvNq', + is_local: false, + name: 'In Time', + popularity: 46, + preview_url: + 'https://p.scdn.co/mp3-preview/1c48a19cd1aeb79e5c16d1d25357c01fe1228c53?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:39e1gl7VaxuCev5ga7bvNq', }, - "href" : "https://api.spotify.com/v1/tracks/39e1gl7VaxuCev5ga7bvNq", - "id" : "39e1gl7VaxuCev5ga7bvNq", - "is_local" : false, - "name" : "In Time", - "popularity" : 46, - "preview_url" : "https://p.scdn.co/mp3-preview/1c48a19cd1aeb79e5c16d1d25357c01fe1228c53?cid=774b29d4f13844c495f206cafdad9c86", - "track_number" : 2, - "type" : "track", - "uri" : "spotify:track:39e1gl7VaxuCev5ga7bvNq" - } - } ], - "limit" : 50, - "next" : "https://api.spotify.com/v1/me/tracks?offset=50&limit=50", - "offset" : 0, - "previous" : null, - "total" : 4031 -} + }, + ], + limit: 50, + next: 'https://api.spotify.com/v1/me/tracks?offset=50&limit=50', + offset: 0, + previous: null, + total: 4031, +}; export const playlistData = { data: { - "collaborative": false, - "description": null, - "external_urls": { - "spotify": "https://open.spotify.com/playlist/4dOnMwNcYPJqIG4z4bZlTf" + collaborative: false, + description: null, + external_urls: { + spotify: 'https://open.spotify.com/playlist/4dOnMwNcYPJqIG4z4bZlTf', }, - "followers": { - "href": null, - "total": 0 + followers: { + href: null, + total: 0, }, - "href": "https://api.spotify.com/v1/playlists/4dOnMwNcYPJqIG4z4bZlTf", - "id": "7d2D2S200NyUE5KYs80PwO", - "images": [], - "name": "My New Playlist", - "owner": { - "external_urls": { - "spotify": "http://open.spotify.com/user/thelinmichael" - }, - "href": "https://api.spotify.com/v1/users/thelinmichael", - "id": "thelinmichael", - "type": "user", - "uri": "spotify:user:thelinmichael" + href: 'https://api.spotify.com/v1/playlists/4dOnMwNcYPJqIG4z4bZlTf', + id: '7d2D2S200NyUE5KYs80PwO', + images: [], + name: 'My New Playlist', + owner: { + external_urls: { + spotify: 'http://open.spotify.com/user/thelinmichael', + }, + href: 'https://api.spotify.com/v1/users/thelinmichael', + id: 'thelinmichael', + type: 'user', + uri: 'spotify:user:thelinmichael', }, - "cover": - { - "height": 640, - "url": "https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21", - "width": 640 - } - , - "public": false, - "snapshot_id": "s0o3TSuYnRLl2jch+oA4OEbKwq/fNxhGBkSPnvhZdmWjNV0q3uCAWuGIhEx8SHIx", - "tracks": { - "href": "https://api.spotify.com/v1/users/thelinmichael/playlists/7d2D2S200NyUE5KYs80PwO/tracks", - "items": [], - "limit": 100, - "next": null, - "offset": 0, - "previous": null, - "total": 0 + cover: { + height: 640, + url: 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, }, - "type": "playlist", - "uri": "spotify:playlist:4dOnMwNcYPJqIG4z4bZlTf" - } -} + public: false, + snapshot_id: + 's0o3TSuYnRLl2jch+oA4OEbKwq/fNxhGBkSPnvhZdmWjNV0q3uCAWuGIhEx8SHIx', + tracks: { + href: + 'https://api.spotify.com/v1/users/thelinmichael/playlists/7d2D2S200NyUE5KYs80PwO/tracks', + items: [], + limit: 100, + next: null, + offset: 0, + previous: null, + total: 0, + }, + type: 'playlist', + uri: 'spotify:playlist:4dOnMwNcYPJqIG4z4bZlTf', + }, +}; -function addSelectedProperty (data: ArtistData) { +function addSelectedProperty(data: ArtistData) { return data.artists.items.map((artist) => { - return {...artist, selected: false} + return { ...artist, selected: false }; }); } export const artistsMock: Artist[] = addSelectedProperty(artistData); export const tracksMock: TrackItem[] = trackData.items; export const playlistMock: PlaylistData = playlistData.data; -export const genresMock: GenreDb = generateGenres(artistsMock); \ No newline at end of file +export const genresMock: GenreDb = generateGenres(artistsMock); + +// added during testing +export const singleArtist = { + external_urls: { + spotify: 'https://open.spotify.com/artist/01e2lCvLZ4fLUIRy68nptH', + }, + followers: { + href: null, + total: 104032, + }, + genres: ['deep euro house', 'tropical house'], + href: 'https://api.spotify.com/v1/artists/01e2lCvLZ4fLUIRy68nptH', + id: '01e2lCvLZ4fLUIRy68nptH', + images: [ + { + height: 640, + url: 'https://i.scdn.co/image/7d60ad2505e9a6922973d98fcc958a5742d1e3fc', + width: 640, + }, + { + height: 320, + url: 'https://i.scdn.co/image/d369947205e298b4928880de4609251c74a1bd37', + width: 320, + }, + { + height: 160, + url: 'https://i.scdn.co/image/bf0e990893ac10537df9e7006b6fa530fcfd9152', + width: 160, + }, + ], + name: 'Wankelmut', + popularity: 62, + type: 'artist', + uri: 'spotify:artist:01e2lCvLZ4fLUIRy68nptH', +}; From 9f4d187951ba876fcf819f7b17261f5c3feb5d01 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 18:21:41 +0000 Subject: [PATCH 24/46] test(playlist_test): implemented basic --- .../Artists/Artist Item/__tests__/test.js | 3 - .../Playlist/Playlist Item/__tests__/test.js | 29 +++++++ .../Playlist Item/playlist-item-index.tsx | 34 ++++---- client/src/devtools/dataMocks.tsx | 83 +++++++++++++++++++ 4 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 client/src/components/Main/Playlist/Playlist Item/__tests__/test.js diff --git a/client/src/components/Main/Artists/Artist Item/__tests__/test.js b/client/src/components/Main/Artists/Artist Item/__tests__/test.js index 970be98..b628632 100644 --- a/client/src/components/Main/Artists/Artist Item/__tests__/test.js +++ b/client/src/components/Main/Artists/Artist Item/__tests__/test.js @@ -2,8 +2,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { cleanup, render, screen } from '@testing-library/react'; import ArtistItem from '../artist-item-index'; -import { artistToggleUpdate } from 'components/Main/main-helpers'; -import { isExportDeclaration } from 'typescript'; import { singleArtist } from '../../../../../devtools/dataMocks'; describe('Artist Item', () => { @@ -31,7 +29,6 @@ describe('Artist Item', () => { singleArtist.userDisabled = true; render(); const artist = screen.getByTestId('artist_item_aTag'); - console.log(artist); expect(artist).toHaveClass('user-disabled'); }); }); diff --git a/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js b/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js new file mode 100644 index 0000000..50e8e7a --- /dev/null +++ b/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js @@ -0,0 +1,29 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { cleanup, render, screen } from '@testing-library/react'; +import PlaylistItem from '../playlist-item-index'; +import { singleTrack } from '../../../../../devtools/dataMocks'; + +describe('Playlist Item', () => { + fit('appears on screen', () => { + render( + + + + +
+ ); + }); + + fit('should render the correct track info', () => { + render( + + + + +
+ ); + const name = screen.getByText(singleTrack.track.name); + expect(name).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx b/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx index 6c483c8..1cd8992 100644 --- a/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx +++ b/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx @@ -1,26 +1,30 @@ import './playlist-item-style.scss'; import { TrackItem } from 'interfaces/spotifyObjects'; -import { convertMsToMinsAndSecs, joinArtistNames } from './playlist-item-helpers'; +import { + convertMsToMinsAndSecs, + joinArtistNames, +} from './playlist-item-helpers'; import moment from 'moment'; - - export interface Props { - track: TrackItem, - toggleHandler: (trackId: string) => void, - disabled: boolean + track: TrackItem; + toggleHandler: (trackId: string) => void; + disabled: boolean; } const PlaylistItem: React.FC = ({ track, disabled, toggleHandler }) => { return ( - toggleHandler(track.track.id)}> - {track.track.name} - {joinArtistNames(track)} - {track.track.album.name} - {moment(track.added_at).fromNow()} - {convertMsToMinsAndSecs(track.track.duration_ms)} - + toggleHandler(track.track.id)} + > + {track.track.name} + {joinArtistNames(track)} + {track.track.album.name} + {moment(track.added_at).fromNow()} + {convertMsToMinsAndSecs(track.track.duration_ms)} + ); -} +}; -export default PlaylistItem; \ No newline at end of file +export default PlaylistItem; diff --git a/client/src/devtools/dataMocks.tsx b/client/src/devtools/dataMocks.tsx index 8dd85ec..775cf91 100644 --- a/client/src/devtools/dataMocks.tsx +++ b/client/src/devtools/dataMocks.tsx @@ -22945,3 +22945,86 @@ export const singleArtist = { type: 'artist', uri: 'spotify:artist:01e2lCvLZ4fLUIRy68nptH', }; + +export const singleTrack = { + added_at: '2021-03-04T21:45:53Z', + track: { + album: { + album_type: 'album', + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '02IFYoziC7CpQRK8fbehUY', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + external_urls: { + spotify: 'https://open.spotify.com/album/0CAXEcXpruvyGKSTjyLDNu', + }, + href: 'https://api.spotify.com/v1/albums/0CAXEcXpruvyGKSTjyLDNu', + id: '0CAXEcXpruvyGKSTjyLDNu', + images: [ + { + height: 640, + url: + 'https://i.scdn.co/image/ab67616d0000b2739db63254bf5a8be73bbaed21', + width: 640, + }, + { + height: 300, + url: + 'https://i.scdn.co/image/ab67616d00001e029db63254bf5a8be73bbaed21', + width: 300, + }, + { + height: 64, + url: + 'https://i.scdn.co/image/ab67616d000048519db63254bf5a8be73bbaed21', + width: 64, + }, + ], + name: 'Black Focus', + release_date: '2016-11-04', + release_date_precision: 'day', + total_tracks: 10, + type: 'album', + uri: 'spotify:album:0CAXEcXpruvyGKSTjyLDNu', + }, + artists: [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/710FHFQeXKC6dZGCxt7kQh', + }, + href: 'https://api.spotify.com/v1/artists/710FHFQeXKC6dZGCxt7kQh', + id: '02IFYoziC7CpQRK8fbehUY', + name: 'Yussef Kamaal', + type: 'artist', + uri: 'spotify:artist:710FHFQeXKC6dZGCxt7kQh', + }, + ], + disc_number: 1, + duration_ms: 508773, + explicit: false, + external_ids: { + isrc: 'GBMEF1600916', + }, + external_urls: { + spotify: 'https://open.spotify.com/track/2sEmZge5ZfzrFrDGFJbkyP', + }, + href: 'https://api.spotify.com/v1/tracks/2sEmZge5ZfzrFrDGFJbkyP', + id: '2sEmZge5ZfzrFrDGFJbkyP', + is_local: false, + name: 'Strings of Light', + popularity: 42, + preview_url: + 'https://p.scdn.co/mp3-preview/2b19dd719e857867cf4e228697a230fb5036ad71?cid=774b29d4f13844c495f206cafdad9c86', + track_number: 2, + type: 'track', + uri: 'spotify:track:2sEmZge5ZfzrFrDGFJbkyP', + }, +}; From 272a601ffa54f0bdb8027bf51b0416340855e071 Mon Sep 17 00:00:00 2001 From: Pamela Date: Sat, 13 Mar 2021 18:33:00 +0000 Subject: [PATCH 25/46] test(playlist_item): finished all tests --- .../Playlist/Playlist Item/__tests__/test.js | 33 +++++++++++++++++-- .../Playlist Item/playlist-item-index.tsx | 1 + 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js b/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js index 50e8e7a..951b6f5 100644 --- a/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js +++ b/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js @@ -3,9 +3,14 @@ import ReactDOM from 'react-dom'; import { cleanup, render, screen } from '@testing-library/react'; import PlaylistItem from '../playlist-item-index'; import { singleTrack } from '../../../../../devtools/dataMocks'; +import { + convertMsToMinsAndSecs, + joinArtistNames, +} from '../playlist-item-helpers'; +import moment from 'moment'; describe('Playlist Item', () => { - fit('appears on screen', () => { + it('appears on screen', () => { render( @@ -15,7 +20,7 @@ describe('Playlist Item', () => { ); }); - fit('should render the correct track info', () => { + it('should render the correct track info (track name, album name, etc.)', () => { render(
@@ -23,7 +28,31 @@ describe('Playlist Item', () => {
); + const name = screen.getByText(singleTrack.track.name); expect(name).toBeInTheDocument(); + const albumName = screen.getByText(singleTrack.track.album.name); + expect(albumName).toBeInTheDocument(); + const trackAdded = screen.getByText(moment(singleTrack.added_at).fromNow()); + expect(trackAdded).toBeInTheDocument(); + const artists = screen.getByText(joinArtistNames(singleTrack)); + expect(artists).toBeInTheDocument(); + const duration = screen.getByText( + convertMsToMinsAndSecs(singleTrack.track.duration_ms) + ); + expect(duration).toBeInTheDocument(); + }); + + it('should inherit the disabled class if disabled is true', () => { + render( + + + + +
+ ); + + const track = screen.getByTestId('playlist_item_trTag'); + expect(track).toHaveClass('user-disabled'); }); }); diff --git a/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx b/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx index 1cd8992..7b574b3 100644 --- a/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx +++ b/client/src/components/Main/Playlist/Playlist Item/playlist-item-index.tsx @@ -15,6 +15,7 @@ export interface Props { const PlaylistItem: React.FC = ({ track, disabled, toggleHandler }) => { return ( toggleHandler(track.track.id)} > From 204153acae2c65af6a4df6ea7830a7b5bf726b1d Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 10:10:12 +0000 Subject: [PATCH 26/46] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ea58cc..cb4eabf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Listspotter +Pamela and Gero ## TODO - 1. Implement testing 2. Implement TS on backend 3. Set up JWT for multiple users From 656afbde0d5948b812a00b8961b897cf5a7588da Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 10:34:41 +0000 Subject: [PATCH 27/46] feat(datamocks): added artist list --- client/src/devtools/dataMocks.tsx | 111 ++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/client/src/devtools/dataMocks.tsx b/client/src/devtools/dataMocks.tsx index 775cf91..c4c8acd 100644 --- a/client/src/devtools/dataMocks.tsx +++ b/client/src/devtools/dataMocks.tsx @@ -23028,3 +23028,114 @@ export const singleTrack = { uri: 'spotify:track:2sEmZge5ZfzrFrDGFJbkyP', }, }; + +export const artistList = [ + { + external_urls: { + spotify: 'https://open.spotify.com/artist/01e2lCvLZ4fLUIRy68nptH', + }, + followers: { + href: null, + total: 104032, + }, + genres: ['deep euro house', 'tropical house'], + href: 'https://api.spotify.com/v1/artists/01e2lCvLZ4fLUIRy68nptH', + id: '01e2lCvLZ4fLUIRy68nptH', + images: [ + { + height: 640, + url: 'https://i.scdn.co/image/7d60ad2505e9a6922973d98fcc958a5742d1e3fc', + width: 640, + }, + { + height: 320, + url: 'https://i.scdn.co/image/d369947205e298b4928880de4609251c74a1bd37', + width: 320, + }, + { + height: 160, + url: 'https://i.scdn.co/image/bf0e990893ac10537df9e7006b6fa530fcfd9152', + width: 160, + }, + ], + name: 'Wankelmut', + popularity: 62, + type: 'artist', + uri: 'spotify:artist:01e2lCvLZ4fLUIRy68nptH', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/02IFYoziC7CpQRK8fbehUY', + }, + followers: { + href: null, + total: 69677, + }, + genres: ['bosnian indie', 'yugoslav rock'], + href: 'https://api.spotify.com/v1/artists/02IFYoziC7CpQRK8fbehUY', + id: '02IFYoziC7CpQRK8fbehUY', + images: [ + { + height: 640, + url: 'https://i.scdn.co/image/4d4d3364e73ae54728222ae56bbbe0d12b0e5b5c', + width: 640, + }, + { + height: 320, + url: 'https://i.scdn.co/image/26063266e6057cf23d349febddd436bf24a3c2d6', + width: 320, + }, + { + height: 160, + url: 'https://i.scdn.co/image/009eed443cdac4a909face78e92a45a9c74db7d4', + width: 160, + }, + ], + name: 'Dubioza kolektiv', + popularity: 48, + type: 'artist', + uri: 'spotify:artist:02IFYoziC7CpQRK8fbehUY', + }, + { + external_urls: { + spotify: 'https://open.spotify.com/artist/09b5OcuIELTdD7FfzQzcdB', + }, + followers: { + href: null, + total: 75811, + }, + genres: [ + 'folk metal', + 'italian folk metal', + 'italian metal', + 'italian power metal', + 'melodic metal', + 'neo classical metal', + 'power metal', + 'tolkien metal', + ], + href: 'https://api.spotify.com/v1/artists/09b5OcuIELTdD7FfzQzcdB', + id: '09b5OcuIELTdD7FfzQzcdB', + images: [ + { + height: 640, + url: 'https://i.scdn.co/image/fea03b617083289dcb5d699ac4dd06795f5fa1b2', + width: 640, + }, + { + height: 320, + url: 'https://i.scdn.co/image/5efd756ab2de73c9203efd4712e96c1f60c77a4b', + width: 320, + }, + { + height: 160, + url: 'https://i.scdn.co/image/9e5fd667763f8c399e11e2898913e6217be928b6', + width: 160, + }, + ], + name: 'Elvenking', + popularity: 47, + type: 'artist', + uri: 'spotify:artist:09b5OcuIELTdD7FfzQzcdB', + }, +]; From 2a3e48606a3c1253e21a76db8a18a755ec884a58 Mon Sep 17 00:00:00 2001 From: Gero Date: Mon, 15 Mar 2021 10:39:20 +0000 Subject: [PATCH 28/46] chore(artists):add test file --- client/src/components/Main/Artists/__tests__/test.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/src/components/Main/Artists/__tests__/test.js diff --git a/client/src/components/Main/Artists/__tests__/test.js b/client/src/components/Main/Artists/__tests__/test.js new file mode 100644 index 0000000..e69de29 From 592d11973acea7eaafaa3d38d91b8359069302bb Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 11:17:20 +0000 Subject: [PATCH 29/46] test(artist_test): finished for artist list --- .../components/Main/Artists/__tests__/test.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/client/src/components/Main/Artists/__tests__/test.js b/client/src/components/Main/Artists/__tests__/test.js index e69de29..d06f435 100644 --- a/client/src/components/Main/Artists/__tests__/test.js +++ b/client/src/components/Main/Artists/__tests__/test.js @@ -0,0 +1,38 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen } from '@testing-library/react'; +import Artists from '../artists-index'; +import { artistList } from '../../../../devtools/dataMocks'; + +describe('Artists', () => { + it('renders message when list is empty', () => { + render(); + const message = screen.getByText('Choose a genre to view related artists.'); + expect(message).toBeInTheDocument(); + }); + + //renders artists in list + it('renders correct ammount in list', () => { + render(); + const artistItems = screen.queryAllByTestId('artist_item_aTag'); + expect(artistItems.length).toBe(artistList.length); + }); + + it('renders the artists in list', () => { + render(); + const firstArtist = screen.getByText('Wankelmut'); + expect(firstArtist).toBeInTheDocument(); + const secondArtist = screen.getByText('Dubioza kolektiv'); + expect(secondArtist).toBeInTheDocument(); + const thirdArtist = screen.getByText('Elvenking'); + expect(thirdArtist).toBeInTheDocument(); + }); + + it('renders artists in alphabetical order', () => { + render(); + const artistItems = screen.queryAllByTestId('artist_item_aTag'); + expect(artistItems[0]).toHaveTextContent('Dubioza kolektiv'); + expect(artistItems[1]).toHaveTextContent('Elvenking'); + expect(artistItems[2]).toHaveTextContent('Wankelmut'); + }); +}); From d18c5f4e2ce5224f6ac19844999450aaa59384d3 Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 12:05:56 +0000 Subject: [PATCH 30/46] test(genre_test): finished for genre list --- .../Genres/Genre Item/genre-item-index.tsx | 39 +++++++++----- .../components/Main/Genres/__tests__/test.js | 51 +++++++++++++++++++ 2 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 client/src/components/Main/Genres/__tests__/test.js diff --git a/client/src/components/Main/Genres/Genre Item/genre-item-index.tsx b/client/src/components/Main/Genres/Genre Item/genre-item-index.tsx index 97b813e..33c4289 100644 --- a/client/src/components/Main/Genres/Genre Item/genre-item-index.tsx +++ b/client/src/components/Main/Genres/Genre Item/genre-item-index.tsx @@ -1,25 +1,38 @@ import './genre-item-style.scss'; import * as React from 'react'; -import { spawn } from 'node:child_process'; - export interface Props { - genreName: string, - artistCount: number | '', - selected: boolean, - selectHandler: (genreName: string) => void + genreName: string; + artistCount: number | ''; + selected: boolean; + selectHandler: (genreName: string) => void; } -const GenreItem: React.FC = ({ genreName, artistCount, selected, selectHandler }) => { - - function clickHandler () { +const GenreItem: React.FC = ({ + genreName, + artistCount, + selected, + selectHandler, +}) => { + function clickHandler() { selectHandler(genreName); } return ( - - {genreName} {selected ? '' : {' +' + artistCount + ' artist' + (artistCount > 1 ? 's' : '')}} + + {genreName}{' '} + {selected ? ( + '' + ) : ( + + {' +' + artistCount + ' artist' + (artistCount > 1 ? 's' : '')} + + )} ); -} +}; -export default GenreItem; \ No newline at end of file +export default GenreItem; diff --git a/client/src/components/Main/Genres/__tests__/test.js b/client/src/components/Main/Genres/__tests__/test.js new file mode 100644 index 0000000..44bdc4d --- /dev/null +++ b/client/src/components/Main/Genres/__tests__/test.js @@ -0,0 +1,51 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen } from '@testing-library/react'; +import Genres from '../genres-index'; +import { genresMock } from '../../../../devtools/dataMocks'; +import { artistsMock } from '../../../../devtools/dataMocks'; +import { getSortedGenreKeys } from '../genres-helpers'; + +describe('Genres', () => { + it('renders loading container when genres are being loaded', () => { + render(); + const message = screen.getByText('Loading your genres...'); + expect(message).toBeInTheDocument(); + }); + + it('renders correct number of genres in list', () => { + const genreArr = getSortedGenreKeys(genresMock, artistsMock); + render( + + ); + const genreItems = screen.queryAllByTestId('genre_item_aTag'); + expect(genreItems.length).toBe(genreArr.length); + }); + + it('renders correct genre names in list', () => { + const genreArr = getSortedGenreKeys(genresMock, artistsMock); + render( + + ); + + //alternative for more foolproof testing is to map over genreArr, however this seems sufficient for these testing purposes + const firstRandomGenre = screen.getByText(genreArr[2]); + expect(firstRandomGenre).toBeInTheDocument(); + const secondRandomGenre = screen.getByText(genreArr[15]); + expect(secondRandomGenre).toBeInTheDocument(); + const thirdRandomGenre = screen.getByText(genreArr[50]); + expect(thirdRandomGenre).toBeInTheDocument(); + const fourthRandomGenre = screen.getByText(genreArr[100]); + expect(fourthRandomGenre).toBeInTheDocument(); + const fifthRandomGenre = screen.getByText(genreArr[120]); + expect(fifthRandomGenre).toBeInTheDocument(); + }); + + it('renders the search bar correctly', () => { + render( + + ); + const searchBar = screen.getByPlaceholderText('Search genres'); + expect(searchBar).toBeInTheDocument(); + }); +}); From 3ee8f5fb9a6fa0f401749ac0cb62d688cf63cf9e Mon Sep 17 00:00:00 2001 From: Gero Date: Mon, 15 Mar 2021 12:51:04 +0000 Subject: [PATCH 31/46] style(__tests__): renamed test files --- .../__tests__/{test.js => artist_item.test.js} | 0 .../Artists/__tests__/{test.js => artists.test.js} | 0 .../__tests__/{test.js => genre_item.test.js} | 0 .../Genres/__tests__/{test.js => genres.test.js} | 0 .../__tests__/{test.js => playlist_item.test.js} | 0 .../Main/Playlist/__tests__/playlist.test.js | 12 ++++++++++++ 6 files changed, 12 insertions(+) rename client/src/components/Main/Artists/Artist Item/__tests__/{test.js => artist_item.test.js} (100%) rename client/src/components/Main/Artists/__tests__/{test.js => artists.test.js} (100%) rename client/src/components/Main/Genres/Genre Item/__tests__/{test.js => genre_item.test.js} (100%) rename client/src/components/Main/Genres/__tests__/{test.js => genres.test.js} (100%) rename client/src/components/Main/Playlist/Playlist Item/__tests__/{test.js => playlist_item.test.js} (100%) create mode 100644 client/src/components/Main/Playlist/__tests__/playlist.test.js diff --git a/client/src/components/Main/Artists/Artist Item/__tests__/test.js b/client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js similarity index 100% rename from client/src/components/Main/Artists/Artist Item/__tests__/test.js rename to client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js diff --git a/client/src/components/Main/Artists/__tests__/test.js b/client/src/components/Main/Artists/__tests__/artists.test.js similarity index 100% rename from client/src/components/Main/Artists/__tests__/test.js rename to client/src/components/Main/Artists/__tests__/artists.test.js diff --git a/client/src/components/Main/Genres/Genre Item/__tests__/test.js b/client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js similarity index 100% rename from client/src/components/Main/Genres/Genre Item/__tests__/test.js rename to client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js diff --git a/client/src/components/Main/Genres/__tests__/test.js b/client/src/components/Main/Genres/__tests__/genres.test.js similarity index 100% rename from client/src/components/Main/Genres/__tests__/test.js rename to client/src/components/Main/Genres/__tests__/genres.test.js diff --git a/client/src/components/Main/Playlist/Playlist Item/__tests__/test.js b/client/src/components/Main/Playlist/Playlist Item/__tests__/playlist_item.test.js similarity index 100% rename from client/src/components/Main/Playlist/Playlist Item/__tests__/test.js rename to client/src/components/Main/Playlist/Playlist Item/__tests__/playlist_item.test.js diff --git a/client/src/components/Main/Playlist/__tests__/playlist.test.js b/client/src/components/Main/Playlist/__tests__/playlist.test.js new file mode 100644 index 0000000..74a9550 --- /dev/null +++ b/client/src/components/Main/Playlist/__tests__/playlist.test.js @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen } from '@testing-library/react'; +import Playlists from '../playlist-index'; + +// describe('Playlist', () => { +// // should render on screen +// // it('', () => {}) +// // +// // it('', () => {}) +// // it('', () => {}) +// }); From 0f24830d673c2ef8a2739ad2e63165b5e8a46746 Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 14:18:47 +0000 Subject: [PATCH 32/46] test(playlist_test): finished playlist list --- .../Main/Genres/__tests__/genres.test.js | 2 +- .../Main/Playlist/__tests__/playlist.test.js | 84 +++++++++++-- .../Main/Playlist/playlist-index.tsx | 114 ++++++++++++------ .../Main/Playlist/playlist-style.scss | 1 + 4 files changed, 153 insertions(+), 48 deletions(-) diff --git a/client/src/components/Main/Genres/__tests__/genres.test.js b/client/src/components/Main/Genres/__tests__/genres.test.js index 44bdc4d..2757b5f 100644 --- a/client/src/components/Main/Genres/__tests__/genres.test.js +++ b/client/src/components/Main/Genres/__tests__/genres.test.js @@ -7,7 +7,7 @@ import { artistsMock } from '../../../../devtools/dataMocks'; import { getSortedGenreKeys } from '../genres-helpers'; describe('Genres', () => { - it('renders loading container when genres are being loaded', () => { + it('renders loading message when genres are being loaded', () => { render(); const message = screen.getByText('Loading your genres...'); expect(message).toBeInTheDocument(); diff --git a/client/src/components/Main/Playlist/__tests__/playlist.test.js b/client/src/components/Main/Playlist/__tests__/playlist.test.js index 74a9550..aad2868 100644 --- a/client/src/components/Main/Playlist/__tests__/playlist.test.js +++ b/client/src/components/Main/Playlist/__tests__/playlist.test.js @@ -1,12 +1,76 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { render, screen } from '@testing-library/react'; -import Playlists from '../playlist-index'; - -// describe('Playlist', () => { -// // should render on screen -// // it('', () => {}) -// // -// // it('', () => {}) -// // it('', () => {}) -// }); +import { + render, + screen, + fireEvent, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import Playlist from '../playlist-index'; +import { artistList, tracksMock } from '../../../../devtools/dataMocks'; +import { act } from 'react-dom/test-utils'; + +describe('Playlist', () => { + it('renders loading message when playlist are being loaded', () => { + render(); + const message = screen.getByText('Loading your tracks...'); + expect(message).toBeInTheDocument(); + }); + + it('displays the table if finished loading', () => { + render(); + const titleLabel = screen.getByText('TITLE'); + expect(titleLabel).toBeInTheDocument(); + const artistLabel = screen.getByText('ARTIST'); + expect(artistLabel).toBeInTheDocument(); + const albumLabel = screen.getByText('ALBUM'); + expect(albumLabel).toBeInTheDocument(); + const addedLabel = screen.getByText('ADDED'); + expect(addedLabel).toBeInTheDocument(); + const lengthLabel = screen.getByText('LENGTH'); + expect(lengthLabel).toBeInTheDocument(); + + const tableWrapper = screen.getByTestId('playlist_test_div'); + expect(tableWrapper).toBeInTheDocument(); + }); + + it('renders the form correctly', () => { + render(); + const form = screen.getByRole('form'); + expect(form).toBeInTheDocument(); + }); + + it('renders the text input correctly', () => { + render(); + const textbox = screen.getByRole('textbox'); + expect(textbox).toBeInTheDocument(); + }); + + it('should display the correct user input', () => { + render(); + const textbox = screen.getByRole('textbox'); + expect(textbox.value).toBe(''); + fireEvent.change(textbox, { target: { value: 'MyNewPlaylist' } }); + expect(textbox.value).toBe('MyNewPlaylist'); + }); + + it('should call the handler function when button is clicked', async () => { + const createHandler = jest.fn(); + render( + + ); + + const button = screen.getByRole('button'); + + fireEvent.click(button); + + expect(createHandler).toHaveBeenCalledTimes(1); + await waitForElementToBeRemoved(() => + screen.getByTestId('playlist_test_loader') + ); + }); +}); diff --git a/client/src/components/Main/Playlist/playlist-index.tsx b/client/src/components/Main/Playlist/playlist-index.tsx index 594ceee..4bb5afd 100644 --- a/client/src/components/Main/Playlist/playlist-index.tsx +++ b/client/src/components/Main/Playlist/playlist-index.tsx @@ -7,9 +7,9 @@ import { TrackItem } from 'interfaces/spotifyObjects'; import { WaveSpinner, CircleSpinner } from 'react-spinners-kit'; export interface Props { - tracks: TrackItem[], - createHandler: (playlistName: string, trackURIs: string[]) => void, - loaded: boolean + tracks: TrackItem[]; + createHandler: (playlistName: string, trackURIs: string[]) => void; + loaded: boolean; } const Playlist: React.FC = ({ tracks, createHandler, loaded }) => { @@ -17,57 +17,97 @@ const Playlist: React.FC = ({ tracks, createHandler, loaded }) => { let [disabledTrackIds, setDisabledTrackIds] = useState([]); // If tracks passed from parent change, playlist re renders and applies disabled tracks. If the user disables a song, it does not bubble back to parent (so other components' re-render is prevented) let [savingPlaylist, setSavingPlaylist] = useState(false); - function toggleTrackHandler (trackId : string) { + function toggleTrackHandler(trackId: string) { if (disabledTrackIds.includes(trackId)) { - setDisabledTrackIds(disabledTrackIds.filter((disabledId) => disabledId !== trackId)); + setDisabledTrackIds( + disabledTrackIds.filter((disabledId) => disabledId !== trackId) + ); } else { const updatedDisabledTrackIds = [...disabledTrackIds, trackId]; setDisabledTrackIds(updatedDisabledTrackIds); } } - async function submitHandler (e: React.FormEvent) { + async function submitHandler(e: React.FormEvent) { setSavingPlaylist(true); e.preventDefault(); - const trackURIs = tracks.filter((track) => !disabledTrackIds.some((disabledId) => disabledId === track.track.id)).map((track) => track.track.uri); + const trackURIs = tracks + .filter( + (track) => + !disabledTrackIds.some((disabledId) => disabledId === track.track.id) + ) + .map((track) => track.track.uri); setNameField(''); await createHandler(nameField, trackURIs); setSavingPlaylist(false); } return ( -
- -
- -

Loading your tracks...

+
+
+ +

+ Loading your tracks... +

-
- setNameField(e.target.value)}/> - {savingPlaylist ?
: } + + setNameField(e.target.value)} + /> + {savingPlaylist ? ( +
+ +
+ ) : ( + + )}
- - {loaded && -
- - - - - - - - - - - - {tracks.map((track) => )} - -
TITLEARTISTALBUMADDEDLENGTH
-
- } -
+ {loaded && ( +
+ + + + + + + + + + + + {tracks.map((track) => ( + + ))} + +
TITLEARTISTALBUMADDEDLENGTH
+
+ )} +
); -} +}; -export default Playlist; \ No newline at end of file +export default Playlist; diff --git a/client/src/components/Main/Playlist/playlist-style.scss b/client/src/components/Main/Playlist/playlist-style.scss index 3e7e65c..a8725ea 100644 --- a/client/src/components/Main/Playlist/playlist-style.scss +++ b/client/src/components/Main/Playlist/playlist-style.scss @@ -43,6 +43,7 @@ width: 20%; } } + &.loaded{ width: 100%; display: block; From d0519843f57a7b42d1fb113a0b1dec3c255c3110 Mon Sep 17 00:00:00 2001 From: Pamela Date: Mon, 15 Mar 2021 14:32:54 +0000 Subject: [PATCH 33/46] test(playlist_test): formatted test --- client/src/components/Main/Playlist/__tests__/playlist.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/Main/Playlist/__tests__/playlist.test.js b/client/src/components/Main/Playlist/__tests__/playlist.test.js index aad2868..44f5188 100644 --- a/client/src/components/Main/Playlist/__tests__/playlist.test.js +++ b/client/src/components/Main/Playlist/__tests__/playlist.test.js @@ -56,6 +56,7 @@ describe('Playlist', () => { it('should call the handler function when button is clicked', async () => { const createHandler = jest.fn(); + render( { fireEvent.click(button); expect(createHandler).toHaveBeenCalledTimes(1); + await waitForElementToBeRemoved(() => screen.getByTestId('playlist_test_loader') ); From 400a2c995774a7c143732c45b3d0559892c98631 Mon Sep 17 00:00:00 2001 From: Gero Date: Mon, 15 Mar 2021 15:47:02 +0000 Subject: [PATCH 34/46] test(modal):render test implemented --- .../Main/Modal/__tests__/modal.test.js | 19 ++++++ .../src/components/Main/Modal/modal-index.tsx | 63 ++++++++++++------- 2 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 client/src/components/Main/Modal/__tests__/modal.test.js diff --git a/client/src/components/Main/Modal/__tests__/modal.test.js b/client/src/components/Main/Modal/__tests__/modal.test.js new file mode 100644 index 0000000..9acfb9a --- /dev/null +++ b/client/src/components/Main/Modal/__tests__/modal.test.js @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen, fireEvent } from '@testing-library/react'; +import PlaylistCreatedModal from '../modal-index'; +import { playlistMock } from '../../../../devtools/dataMocks'; + +describe('Playlist Created Modal', () => { + it('renders a message when playlist is created', () => { + render( + + ); + const message = screen.getByText('Glorious Victory!'); + expect(message).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/Main/Modal/modal-index.tsx b/client/src/components/Main/Modal/modal-index.tsx index f9a254b..01f5981 100644 --- a/client/src/components/Main/Modal/modal-index.tsx +++ b/client/src/components/Main/Modal/modal-index.tsx @@ -1,6 +1,6 @@ import Modal from 'react-modal'; import { PlaylistData } from 'interfaces/spotifyObjects'; -import './modal-style.scss' +import './modal-style.scss'; const customStyles = { content: { @@ -9,43 +9,64 @@ const customStyles = { right: 'auto', bottom: 'auto', marginRight: '-50%', - 'border-radius': '20px', - 'background-color': 'var(--spotify-black)', + borderRadius: '20px', + backgroundColor: 'var(--spotify-black)', padding: '4%', opacity: 1, - transform: 'translate(-50%, -50%)' + transform: 'translate(-50%, -50%)', }, - overlay: {zIndex: 2} + overlay: { zIndex: 2 }, }; export interface Props { - isOpen: boolean, - playlist: PlaylistData, + isOpen: boolean; + playlist: PlaylistData; onRequestClose: () => void; + testing?: boolean; } -const PlaylistCreatedModal: React.FC = ({ isOpen, playlist, onRequestClose }) => { +const PlaylistCreatedModal: React.FC = ({ + isOpen, + playlist, + onRequestClose, + testing = false, +}) => { return ( - - { - playlist.id && -
-
-
+ + {playlist.id && ( +
+
+

Glorious Victory!

-

Your playlist is created and waiting for you in your Spotify account.

+

+ Your playlist is created and waiting for you in your Spotify + account. +

Open in Spotify - Open in browser + + Open in browser +
-
- {playlist.cover && Playlist Image} +
+ {playlist.cover && ( + Playlist Image + )}

{playlist.name}

- } + )} ); -} +}; -export default PlaylistCreatedModal; \ No newline at end of file +export default PlaylistCreatedModal; From 79252ac1f3066187932797765a73e0667b01a3d1 Mon Sep 17 00:00:00 2001 From: Gero Date: Tue, 16 Mar 2021 11:37:14 +0000 Subject: [PATCH 35/46] test(login): added tests + adjusted render test 2 other files --- .../components/Login/__tests__/login.test.js | 26 +++++++++++++++++++ client/src/components/Login/login-index.tsx | 10 +++---- .../Artist Item/__tests__/artist_item.test.js | 4 ++- .../Genre Item/__tests__/genre_item.test.js | 4 ++- 4 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 client/src/components/Login/__tests__/login.test.js diff --git a/client/src/components/Login/__tests__/login.test.js b/client/src/components/Login/__tests__/login.test.js new file mode 100644 index 0000000..60b19f4 --- /dev/null +++ b/client/src/components/Login/__tests__/login.test.js @@ -0,0 +1,26 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { getByText, render, screen } from '@testing-library/react'; +import Login from '../login-index'; +import logo from '../Spotify_Logo_RGB_Green.png'; +import { contextType } from 'react-modal'; + +describe('Login', () => { + it('renders the correct h1', () => { + const { container } = render(); + const header = container.querySelector('h1'); + expect(header).toBeInTheDocument(); + }); + + it('renders the correct logo image', () => { + render(); + const image = screen.getByAltText(''); + expect(image).toHaveAttribute('src', logo); + }); + + it('renders the correct button tag', () => { + const { container } = render(); + const button = container.querySelector('a'); + expect(button).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/Login/login-index.tsx b/client/src/components/Login/login-index.tsx index 865203a..76e2038 100644 --- a/client/src/components/Login/login-index.tsx +++ b/client/src/components/Login/login-index.tsx @@ -1,7 +1,7 @@ -import * as React from "react"; -import { queryUrl } from "./login-queryParams"; -import "./login-style.scss"; -import logo from "./Spotify_Logo_RGB_Green.png"; +import * as React from 'react'; +import { queryUrl } from './login-queryParams'; +import './login-style.scss'; +import logo from './Spotify_Logo_RGB_Green.png'; // import { useState, useEffect } from 'react'; @@ -13,7 +13,7 @@ const Login: React.FC = () => {

Listspotter.

- Create playlists from your saved songs in{" "} + Create playlists from your saved songs in{' '} using intuitive genre filters.

diff --git a/client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js b/client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js index b628632..0d71e1d 100644 --- a/client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js +++ b/client/src/components/Main/Artists/Artist Item/__tests__/artist_item.test.js @@ -6,7 +6,9 @@ import { singleArtist } from '../../../../../devtools/dataMocks'; describe('Artist Item', () => { it('appears on screen', () => { - render(); + const { container } = render(); + const tag = container.querySelector('a'); + expect(tag).toBeInTheDocument(); }); it('displays the artist name', () => { diff --git a/client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js b/client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js index 661af88..4395bc4 100644 --- a/client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js +++ b/client/src/components/Main/Genres/Genre Item/__tests__/genre_item.test.js @@ -5,7 +5,9 @@ import GenreItem from '../genre-item-index'; describe('Genre Item', () => { it('appears on screen', () => { - render(); + const { container } = render(); + const tag = container.querySelector('a'); + expect(tag).toBeInTheDocument(); }); it('renders the right name', () => { From b5e0abd73116d01f945609bb2307585f462e0696 Mon Sep 17 00:00:00 2001 From: Gero Date: Tue, 16 Mar 2021 11:46:23 +0000 Subject: [PATCH 36/46] test(searchbar): file created --- .../components/common/Searchbar/__tests__/searchbar.test.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 client/src/components/common/Searchbar/__tests__/searchbar.test.js diff --git a/client/src/components/common/Searchbar/__tests__/searchbar.test.js b/client/src/components/common/Searchbar/__tests__/searchbar.test.js new file mode 100644 index 0000000..4ae5b8f --- /dev/null +++ b/client/src/components/common/Searchbar/__tests__/searchbar.test.js @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { render, screen } from '@testing-library/react'; +import SearchBar from '../searchbar-index'; + +describe('SearchBar', () => {}); From 3c9c0d37a32717ceb66f675e6d22cb5ffefff81b Mon Sep 17 00:00:00 2001 From: Gero Date: Tue, 16 Mar 2021 12:03:33 +0000 Subject: [PATCH 37/46] test(search-bar): searchbar component renders --- .../Searchbar/__tests__/searchbar.test.js | 10 ++++-- .../common/Searchbar/searchbar-index.tsx | 36 ++++++++++++------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/client/src/components/common/Searchbar/__tests__/searchbar.test.js b/client/src/components/common/Searchbar/__tests__/searchbar.test.js index 4ae5b8f..e422ef9 100644 --- a/client/src/components/common/Searchbar/__tests__/searchbar.test.js +++ b/client/src/components/common/Searchbar/__tests__/searchbar.test.js @@ -1,6 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import SearchBar from '../searchbar-index'; -describe('SearchBar', () => {}); +describe('SearchBar', () => { + it('should render the search-bar', () => { + const { container } = render(); + const div = container.querySelector('div'); + expect(div).toBeInTheDocument(); + }); +}); diff --git a/client/src/components/common/Searchbar/searchbar-index.tsx b/client/src/components/common/Searchbar/searchbar-index.tsx index 892f14b..032f264 100644 --- a/client/src/components/common/Searchbar/searchbar-index.tsx +++ b/client/src/components/common/Searchbar/searchbar-index.tsx @@ -1,21 +1,33 @@ import './searchbar-style.scss'; export interface Props { - placeholder: string, - searchValue: string, - setSearchValue: (value: React.SetStateAction) => void + placeholder: string; + searchValue: string; + setSearchValue: (value: React.SetStateAction) => void; } -const SearchBar: React.FC = ({ placeholder, searchValue, setSearchValue }) => { +const SearchBar: React.FC = ({ + placeholder, + searchValue, + setSearchValue, +}) => { return ( -
- setSearchValue(e.target.value)}/> +
+ setSearchValue(e.target.value)} + /> - {searchValue && - setSearchValue('')}> - } -
+ {searchValue && ( + setSearchValue('')}> + + + )} +
); -} +}; -export default SearchBar; \ No newline at end of file +export default SearchBar; From 00209c2499b650d30deb85613be41c73fda73122 Mon Sep 17 00:00:00 2001 From: Gero Date: Wed, 17 Mar 2021 11:50:19 +0000 Subject: [PATCH 38/46] test(main): render tests --- .../components/Main/__tests__/main.test.js | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 client/src/components/Main/__tests__/main.test.js diff --git a/client/src/components/Main/__tests__/main.test.js b/client/src/components/Main/__tests__/main.test.js new file mode 100644 index 0000000..b735744 --- /dev/null +++ b/client/src/components/Main/__tests__/main.test.js @@ -0,0 +1,38 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { fireEvent, render, screen } from '@testing-library/react'; +import Main from '../main-index'; +import { useLocation } from 'react-router'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory } from 'history'; + +describe('Main', () => { + let utils; + + beforeEach(() => { + const history = createMemoryHistory(); + history.push('/main'); + + utils = render( + +
+ + ); + }); + + it('should render the main container div', () => { + const mainDiv = utils.container.querySelector('div'); + expect(mainDiv).toHaveClass('main-container'); + }); + + it('should render the Genres & Artist', () => { + const genreAndArtist = utils.container.getElementsByClassName( + 'genre-artist-wrapper' + ); + expect(genreAndArtist[0]).toBeInTheDocument(); + }); + it('should render the playlist wrapper', () => { + const playlist = utils.container.getElementsByClassName('playlist-wrapper'); + expect(playlist[0]).toBeInTheDocument(); + }); +}); From 2f5e1e723e4cb71fb4a79f683ef05a4050712e21 Mon Sep 17 00:00:00 2001 From: Pamela Date: Wed, 17 Mar 2021 13:03:41 +0000 Subject: [PATCH 39/46] chore(cypress): added cypress --- cypress.json | 1 + cypress/fixtures/example.json | 5 + cypress/integration/examples/actions.spec.js | 299 ++++++ cypress/integration/examples/aliasing.spec.js | 39 + .../integration/examples/assertions.spec.js | 177 ++++ .../integration/examples/connectors.spec.js | 97 ++ cypress/integration/examples/cookies.spec.js | 77 ++ .../integration/examples/cypress_api.spec.js | 202 ++++ cypress/integration/examples/files.spec.js | 89 ++ .../examples/local_storage.spec.js | 52 + cypress/integration/examples/location.spec.js | 32 + cypress/integration/examples/misc.spec.js | 104 ++ .../integration/examples/navigation.spec.js | 56 ++ .../examples/network_requests.spec.js | 163 +++ cypress/integration/examples/querying.spec.js | 114 +++ .../examples/spies_stubs_clocks.spec.js | 205 ++++ .../integration/examples/traversal.spec.js | 121 +++ .../integration/examples/utilities.spec.js | 110 ++ cypress/integration/examples/viewport.spec.js | 59 ++ cypress/integration/examples/waiting.spec.js | 31 + cypress/integration/examples/window.spec.js | 22 + cypress/plugins/index.js | 22 + cypress/support/commands.js | 25 + cypress/support/index.js | 20 + package-lock.json | 952 +++++++++++++++++- package.json | 1 + 26 files changed, 3066 insertions(+), 9 deletions(-) create mode 100644 cypress.json create mode 100644 cypress/fixtures/example.json create mode 100644 cypress/integration/examples/actions.spec.js create mode 100644 cypress/integration/examples/aliasing.spec.js create mode 100644 cypress/integration/examples/assertions.spec.js create mode 100644 cypress/integration/examples/connectors.spec.js create mode 100644 cypress/integration/examples/cookies.spec.js create mode 100644 cypress/integration/examples/cypress_api.spec.js create mode 100644 cypress/integration/examples/files.spec.js create mode 100644 cypress/integration/examples/local_storage.spec.js create mode 100644 cypress/integration/examples/location.spec.js create mode 100644 cypress/integration/examples/misc.spec.js create mode 100644 cypress/integration/examples/navigation.spec.js create mode 100644 cypress/integration/examples/network_requests.spec.js create mode 100644 cypress/integration/examples/querying.spec.js create mode 100644 cypress/integration/examples/spies_stubs_clocks.spec.js create mode 100644 cypress/integration/examples/traversal.spec.js create mode 100644 cypress/integration/examples/utilities.spec.js create mode 100644 cypress/integration/examples/viewport.spec.js create mode 100644 cypress/integration/examples/waiting.spec.js create mode 100644 cypress/integration/examples/window.spec.js create mode 100644 cypress/plugins/index.js create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/index.js diff --git a/cypress.json b/cypress.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/cypress.json @@ -0,0 +1 @@ +{} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/integration/examples/actions.spec.js b/cypress/integration/examples/actions.spec.js new file mode 100644 index 0000000..0926379 --- /dev/null +++ b/cypress/integration/examples/actions.spec.js @@ -0,0 +1,299 @@ +/// + +context('Actions', () => { + beforeEach(() => { + cy.visit('https://example.cypress.io/commands/actions') + }) + + // https://on.cypress.io/interacting-with-elements + + it('.type() - type into a DOM element', () => { + // https://on.cypress.io/type + cy.get('.action-email') + .type('fake@email.com').should('have.value', 'fake@email.com') + + // .type() with special character sequences + .type('{leftarrow}{rightarrow}{uparrow}{downarrow}') + .type('{del}{selectall}{backspace}') + + // .type() with key modifiers + .type('{alt}{option}') //these are equivalent + .type('{ctrl}{control}') //these are equivalent + .type('{meta}{command}{cmd}') //these are equivalent + .type('{shift}') + + // Delay each keypress by 0.1 sec + .type('slow.typing@email.com', { delay: 100 }) + .should('have.value', 'slow.typing@email.com') + + cy.get('.action-disabled') + // Ignore error checking prior to type + // like whether the input is visible or disabled + .type('disabled error checking', { force: true }) + .should('have.value', 'disabled error checking') + }) + + it('.focus() - focus on a DOM element', () => { + // https://on.cypress.io/focus + cy.get('.action-focus').focus() + .should('have.class', 'focus') + .prev().should('have.attr', 'style', 'color: orange;') + }) + + it('.blur() - blur off a DOM element', () => { + // https://on.cypress.io/blur + cy.get('.action-blur').type('About to blur').blur() + .should('have.class', 'error') + .prev().should('have.attr', 'style', 'color: red;') + }) + + it('.clear() - clears an input or textarea element', () => { + // https://on.cypress.io/clear + cy.get('.action-clear').type('Clear this text') + .should('have.value', 'Clear this text') + .clear() + .should('have.value', '') + }) + + it('.submit() - submit a form', () => { + // https://on.cypress.io/submit + cy.get('.action-form') + .find('[type="text"]').type('HALFOFF') + + cy.get('.action-form').submit() + .next().should('contain', 'Your form has been submitted!') + }) + + it('.click() - click on a DOM element', () => { + // https://on.cypress.io/click + cy.get('.action-btn').click() + + // You can click on 9 specific positions of an element: + // ----------------------------------- + // | topLeft top topRight | + // | | + // | | + // | | + // | left center right | + // | | + // | | + // | | + // | bottomLeft bottom bottomRight | + // ----------------------------------- + + // clicking in the center of the element is the default + cy.get('#action-canvas').click() + + cy.get('#action-canvas').click('topLeft') + cy.get('#action-canvas').click('top') + cy.get('#action-canvas').click('topRight') + cy.get('#action-canvas').click('left') + cy.get('#action-canvas').click('right') + cy.get('#action-canvas').click('bottomLeft') + cy.get('#action-canvas').click('bottom') + cy.get('#action-canvas').click('bottomRight') + + // .click() accepts an x and y coordinate + // that controls where the click occurs :) + + cy.get('#action-canvas') + .click(80, 75) // click 80px on x coord and 75px on y coord + .click(170, 75) + .click(80, 165) + .click(100, 185) + .click(125, 190) + .click(150, 185) + .click(170, 165) + + // click multiple elements by passing multiple: true + cy.get('.action-labels>.label').click({ multiple: true }) + + // Ignore error checking prior to clicking + cy.get('.action-opacity>.btn').click({ force: true }) + }) + + it('.dblclick() - double click on a DOM element', () => { + // https://on.cypress.io/dblclick + + // Our app has a listener on 'dblclick' event in our 'scripts.js' + // that hides the div and shows an input on double click + cy.get('.action-div').dblclick().should('not.be.visible') + cy.get('.action-input-hidden').should('be.visible') + }) + + it('.rightclick() - right click on a DOM element', () => { + // https://on.cypress.io/rightclick + + // Our app has a listener on 'contextmenu' event in our 'scripts.js' + // that hides the div and shows an input on right click + cy.get('.rightclick-action-div').rightclick().should('not.be.visible') + cy.get('.rightclick-action-input-hidden').should('be.visible') + }) + + it('.check() - check a checkbox or radio element', () => { + // https://on.cypress.io/check + + // By default, .check() will check all + // matching checkbox or radio elements in succession, one after another + cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]') + .check().should('be.checked') + + cy.get('.action-radios [type="radio"]').not('[disabled]') + .check().should('be.checked') + + // .check() accepts a value argument + cy.get('.action-radios [type="radio"]') + .check('radio1').should('be.checked') + + // .check() accepts an array of values + cy.get('.action-multiple-checkboxes [type="checkbox"]') + .check(['checkbox1', 'checkbox2']).should('be.checked') + + // Ignore error checking prior to checking + cy.get('.action-checkboxes [disabled]') + .check({ force: true }).should('be.checked') + + cy.get('.action-radios [type="radio"]') + .check('radio3', { force: true }).should('be.checked') + }) + + it('.uncheck() - uncheck a checkbox element', () => { + // https://on.cypress.io/uncheck + + // By default, .uncheck() will uncheck all matching + // checkbox elements in succession, one after another + cy.get('.action-check [type="checkbox"]') + .not('[disabled]') + .uncheck().should('not.be.checked') + + // .uncheck() accepts a value argument + cy.get('.action-check [type="checkbox"]') + .check('checkbox1') + .uncheck('checkbox1').should('not.be.checked') + + // .uncheck() accepts an array of values + cy.get('.action-check [type="checkbox"]') + .check(['checkbox1', 'checkbox3']) + .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked') + + // Ignore error checking prior to unchecking + cy.get('.action-check [disabled]') + .uncheck({ force: true }).should('not.be.checked') + }) + + it('.select() - select an option in a element', () => { // https://on.cypress.io/select // at first, no option should be selected - cy.get('.action-select') - .should('have.value', '--Select a fruit--') + cy.get('.action-select').should('have.value', '--Select a fruit--'); // Select option(s) with matching text content - cy.get('.action-select').select('apples') + cy.get('.action-select').select('apples'); // confirm the apples were selected // note that each value starts with "fr-" in our HTML - cy.get('.action-select').should('have.value', 'fr-apples') + cy.get('.action-select').should('have.value', 'fr-apples'); cy.get('.action-select-multiple') .select(['apples', 'oranges', 'bananas']) // when getting multiple values, invoke "val" method first .invoke('val') - .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']) + .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']); // Select option(s) with matching value - cy.get('.action-select').select('fr-bananas') + cy.get('.action-select') + .select('fr-bananas') // can attach an assertion right away to the element - .should('have.value', 'fr-bananas') + .should('have.value', 'fr-bananas'); cy.get('.action-select-multiple') .select(['fr-apples', 'fr-oranges', 'fr-bananas']) .invoke('val') - .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']) + .should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas']); // assert the selected values include oranges cy.get('.action-select-multiple') - .invoke('val').should('include', 'fr-oranges') - }) + .invoke('val') + .should('include', 'fr-oranges'); + }); it('.scrollIntoView() - scroll an element into view', () => { // https://on.cypress.io/scrollintoview @@ -222,27 +243,21 @@ context('Actions', () => { // because they're not within // the viewable area of their parent // (we need to scroll to see them) - cy.get('#scroll-horizontal button') - .should('not.be.visible') + cy.get('#scroll-horizontal button').should('not.be.visible'); // scroll the button into view, as if the user had scrolled - cy.get('#scroll-horizontal button').scrollIntoView() - .should('be.visible') + cy.get('#scroll-horizontal button').scrollIntoView().should('be.visible'); - cy.get('#scroll-vertical button') - .should('not.be.visible') + cy.get('#scroll-vertical button').should('not.be.visible'); // Cypress handles the scroll direction needed - cy.get('#scroll-vertical button').scrollIntoView() - .should('be.visible') + cy.get('#scroll-vertical button').scrollIntoView().should('be.visible'); - cy.get('#scroll-both button') - .should('not.be.visible') + cy.get('#scroll-both button').should('not.be.visible'); // Cypress knows to scroll to the right and down - cy.get('#scroll-both button').scrollIntoView() - .should('be.visible') - }) + cy.get('#scroll-both button').scrollIntoView().should('be.visible'); + }); it('.trigger() - trigger an event on a DOM element', () => { // https://on.cypress.io/trigger @@ -256,9 +271,10 @@ context('Actions', () => { cy.get('.trigger-input-range') .invoke('val', 25) .trigger('change') - .get('input[type=range]').siblings('p') - .should('have.text', '25') - }) + .get('input[type=range]') + .siblings('p') + .should('have.text', '25'); + }); it('cy.scrollTo() - scroll the window or element to a position', () => { // https://on.cypress.io/scrollto @@ -278,22 +294,22 @@ context('Actions', () => { // if you chain .scrollTo() off of cy, we will // scroll the entire window - cy.scrollTo('bottom') + cy.scrollTo('bottom'); - cy.get('#scrollable-horizontal').scrollTo('right') + cy.get('#scrollable-horizontal').scrollTo('right'); // or you can scroll to a specific coordinate: // (x axis, y axis) in pixels - cy.get('#scrollable-vertical').scrollTo(250, 250) + cy.get('#scrollable-vertical').scrollTo(250, 250); // or you can scroll to a specific percentage // of the (width, height) of the element - cy.get('#scrollable-both').scrollTo('75%', '25%') + cy.get('#scrollable-both').scrollTo('75%', '25%'); // control the easing of the scroll (default is 'swing') - cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' }) + cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' }); // control the duration of the scroll (in ms) - cy.get('#scrollable-both').scrollTo('center', { duration: 2000 }) - }) -}) + cy.get('#scrollable-both').scrollTo('center', { duration: 2000 }); + }); +}); diff --git a/cypress/integration/examples/aliasing.spec.js b/cypress/integration/examples/aliasing.spec.js index a02fb2b..61a4b40 100644 --- a/cypress/integration/examples/aliasing.spec.js +++ b/cypress/integration/examples/aliasing.spec.js @@ -2,8 +2,8 @@ context('Aliasing', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/aliasing') - }) + cy.visit('https://example.cypress.io/commands/aliasing'); + }); it('.as() - alias a DOM element for later use', () => { // https://on.cypress.io/as @@ -12,28 +12,32 @@ context('Aliasing', () => { // We don't have to traverse to the element // later in our code, we reference it with @ - cy.get('.as-table').find('tbody>tr') - .first().find('td').first() - .find('button').as('firstBtn') + cy.get('.as-table') + .find('tbody>tr') + .first() + .find('td') + .first() + .find('button') + .as('firstBtn'); // when we reference the alias, we place an // @ in front of its name - cy.get('@firstBtn').click() + cy.get('@firstBtn').click(); cy.get('@firstBtn') .should('have.class', 'btn-success') - .and('contain', 'Changed') - }) + .and('contain', 'Changed'); + }); it('.as() - alias a route for later use', () => { // Alias the route to wait for its response - cy.intercept('GET', '**/comments/*').as('getComment') + cy.intercept('GET', '**/comments/*').as('getComment'); // we have code that gets a comment when // the button is clicked in scripts.js - cy.get('.network-btn').click() + cy.get('.network-btn').click(); // https://on.cypress.io/wait - cy.wait('@getComment').its('response.statusCode').should('eq', 200) - }) -}) + cy.wait('@getComment').its('response.statusCode').should('eq', 200); + }); +}); diff --git a/cypress/integration/examples/assertions.spec.js b/cypress/integration/examples/assertions.spec.js index 5ba93d1..7779e3e 100644 --- a/cypress/integration/examples/assertions.spec.js +++ b/cypress/integration/examples/assertions.spec.js @@ -2,8 +2,8 @@ context('Assertions', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/assertions') - }) + cy.visit('https://example.cypress.io/commands/assertions'); + }); describe('Implicit Assertions', () => { it('.should() - make an assertion about the current subject', () => { @@ -23,7 +23,7 @@ context('Assertions', () => { // first need to invoke jQuery method text() // and then match using regular expression .invoke('text') - .should('match', /column content/i) + .should('match', /column content/i); // a better way to check element's text content against a regular expression // is to use "cy.contains" @@ -32,33 +32,33 @@ context('Assertions', () => { .find('tbody tr:last') // finds first element with text content matching regular expression .contains('td', /column content/i) - .should('be.visible') + .should('be.visible'); // for more information about asserting element's text // see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents - }) + }); it('.and() - chain multiple assertions together', () => { // https://on.cypress.io/and cy.get('.assertions-link') .should('have.class', 'active') .and('have.attr', 'href') - .and('include', 'cypress.io') - }) - }) + .and('include', 'cypress.io'); + }); + }); describe('Explicit Assertions', () => { // https://on.cypress.io/assertions it('expect - make an assertion about a specified subject', () => { // We can use Chai's BDD style assertions - expect(true).to.be.true - const o = { foo: 'bar' } + expect(true).to.be.true; + const o = { foo: 'bar' }; - expect(o).to.equal(o) - expect(o).to.deep.equal({ foo: 'bar' }) + expect(o).to.equal(o); + expect(o).to.deep.equal({ foo: 'bar' }); // matching text using regular expression - expect('FooBar').to.match(/bar$/i) - }) + expect('FooBar').to.match(/bar$/i); + }); it('pass your own callback function to should()', () => { // Pass a function to should that can have any number @@ -71,14 +71,14 @@ context('Assertions', () => { // https://on.cypress.io/$ // return an array of texts from all of the p's // @ts-ignore TS6133 unused variable - const texts = $p.map((i, el) => Cypress.$(el).text()) + const texts = $p.map((i, el) => Cypress.$(el).text()); // jquery map returns jquery object // and .get() convert this to simple array - const paragraphs = texts.get() + const paragraphs = texts.get(); // array should have length of 3 - expect(paragraphs, 'has 3 paragraphs').to.have.length(3) + expect(paragraphs, 'has 3 paragraphs').to.have.length(3); // use second argument to expect(...) to provide clear // message with each assertion @@ -86,27 +86,27 @@ context('Assertions', () => { 'Some text from first p', 'More text from second p', 'And even more text from third p', - ]) - }) - }) + ]); + }); + }); it('finds element by class name regex', () => { cy.get('.docs-header') .find('div') // .should(cb) callback function will be retried .should(($div) => { - expect($div).to.have.length(1) + expect($div).to.have.length(1); - const className = $div[0].className + const className = $div[0].className; - expect(className).to.match(/heading-/) + expect(className).to.match(/heading-/); }) // .then(cb) callback is not retried, // it either passes or fails .then(($div) => { - expect($div, 'text content').to.have.text('Introduction') - }) - }) + expect($div, 'text content').to.have.text('Introduction'); + }); + }); it('can throw any error', () => { cy.get('.docs-header') @@ -114,64 +114,63 @@ context('Assertions', () => { .should(($div) => { if ($div.length !== 1) { // you can throw your own errors - throw new Error('Did not find 1 element') + throw new Error('Did not find 1 element'); } - const className = $div[0].className + const className = $div[0].className; if (!className.match(/heading-/)) { - throw new Error(`Could not find class "heading-" in ${className}`) + throw new Error(`Could not find class "heading-" in ${className}`); } - }) - }) + }); + }); it('matches unknown text between two elements', () => { /** * Text from the first element. * @type {string} - */ - let text + */ + let text; /** * Normalizes passed text, * useful before comparing text with spaces and different capitalization. * @param {string} s Text to normalize - */ - const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase() + */ + const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase(); cy.get('.two-elements') .find('.first') .then(($first) => { // save text from the first element - text = normalizeText($first.text()) - }) + text = normalizeText($first.text()); + }); cy.get('.two-elements') .find('.second') .should(($div) => { // we can massage text before comparing - const secondText = normalizeText($div.text()) + const secondText = normalizeText($div.text()); - expect(secondText, 'second text').to.equal(text) - }) - }) + expect(secondText, 'second text').to.equal(text); + }); + }); it('assert - assert shape of an object', () => { const person = { name: 'Joe', age: 20, - } + }; - assert.isObject(person, 'value is object') - }) + assert.isObject(person, 'value is object'); + }); it('retries the should callback until assertions pass', () => { - cy.get('#random-number') - .should(($div) => { - const n = parseFloat($div.text()) - - expect(n).to.be.gte(1).and.be.lte(10) - }) - }) - }) -}) + cy.get('#random-number').should(($div) => { + const n = parseFloat($div.text()); + + expect(n).to.be.gte(1).and.be.lte(10); + }); + }); + }); +}); diff --git a/cypress/integration/examples/connectors.spec.js b/cypress/integration/examples/connectors.spec.js index ae87991..cf62028 100644 --- a/cypress/integration/examples/connectors.spec.js +++ b/cypress/integration/examples/connectors.spec.js @@ -2,96 +2,95 @@ context('Connectors', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/connectors') - }) + cy.visit('https://example.cypress.io/commands/connectors'); + }); it('.each() - iterate over an array of elements', () => { // https://on.cypress.io/each - cy.get('.connectors-each-ul>li') - .each(($el, index, $list) => { - console.log($el, index, $list) - }) - }) + cy.get('.connectors-each-ul>li').each(($el, index, $list) => { + console.log($el, index, $list); + }); + }); it('.its() - get properties on the current subject', () => { // https://on.cypress.io/its cy.get('.connectors-its-ul>li') // calls the 'length' property yielding that value .its('length') - .should('be.gt', 2) - }) + .should('be.gt', 2); + }); it('.invoke() - invoke a function on the current subject', () => { // our div is hidden in our script.js // $('.connectors-div').hide() // https://on.cypress.io/invoke - cy.get('.connectors-div').should('be.hidden') + cy.get('.connectors-div') + .should('be.hidden') // call the jquery method 'show' on the 'div.container' .invoke('show') - .should('be.visible') - }) + .should('be.visible'); + }); it('.spread() - spread an array as individual args to callback function', () => { // https://on.cypress.io/spread - const arr = ['foo', 'bar', 'baz'] + const arr = ['foo', 'bar', 'baz']; cy.wrap(arr).spread((foo, bar, baz) => { - expect(foo).to.eq('foo') - expect(bar).to.eq('bar') - expect(baz).to.eq('baz') - }) - }) + expect(foo).to.eq('foo'); + expect(bar).to.eq('bar'); + expect(baz).to.eq('baz'); + }); + }); describe('.then()', () => { it('invokes a callback function with the current subject', () => { // https://on.cypress.io/then - cy.get('.connectors-list > li') - .then(($lis) => { - expect($lis, '3 items').to.have.length(3) - expect($lis.eq(0), 'first item').to.contain('Walk the dog') - expect($lis.eq(1), 'second item').to.contain('Feed the cat') - expect($lis.eq(2), 'third item').to.contain('Write JavaScript') - }) - }) + cy.get('.connectors-list > li').then(($lis) => { + expect($lis, '3 items').to.have.length(3); + expect($lis.eq(0), 'first item').to.contain('Walk the dog'); + expect($lis.eq(1), 'second item').to.contain('Feed the cat'); + expect($lis.eq(2), 'third item').to.contain('Write JavaScript'); + }); + }); it('yields the returned value to the next command', () => { cy.wrap(1) .then((num) => { - expect(num).to.equal(1) + expect(num).to.equal(1); - return 2 + return 2; }) .then((num) => { - expect(num).to.equal(2) - }) - }) + expect(num).to.equal(2); + }); + }); it('yields the original subject without return', () => { cy.wrap(1) .then((num) => { - expect(num).to.equal(1) + expect(num).to.equal(1); // note that nothing is returned from this callback }) .then((num) => { // this callback receives the original unchanged value 1 - expect(num).to.equal(1) - }) - }) + expect(num).to.equal(1); + }); + }); it('yields the value yielded by the last Cypress command inside', () => { cy.wrap(1) .then((num) => { - expect(num).to.equal(1) + expect(num).to.equal(1); // note how we run a Cypress command // the result yielded by this Cypress command // will be passed to the second ".then" - cy.wrap(2) + cy.wrap(2); }) .then((num) => { // this callback receives the value yielded by "cy.wrap(2)" - expect(num).to.equal(2) - }) - }) - }) -}) + expect(num).to.equal(2); + }); + }); + }); +}); diff --git a/cypress/integration/examples/cookies.spec.js b/cypress/integration/examples/cookies.spec.js index 31587ff..87b2e5b 100644 --- a/cypress/integration/examples/cookies.spec.js +++ b/cypress/integration/examples/cookies.spec.js @@ -2,76 +2,78 @@ context('Cookies', () => { beforeEach(() => { - Cypress.Cookies.debug(true) + Cypress.Cookies.debug(true); - cy.visit('https://example.cypress.io/commands/cookies') + cy.visit('https://example.cypress.io/commands/cookies'); // clear cookies again after visiting to remove // any 3rd party cookies picked up such as cloudflare - cy.clearCookies() - }) + cy.clearCookies(); + }); it('cy.getCookie() - get a browser cookie', () => { // https://on.cypress.io/getcookie - cy.get('#getCookie .set-a-cookie').click() + cy.get('#getCookie .set-a-cookie').click(); // cy.getCookie() yields a cookie object - cy.getCookie('token').should('have.property', 'value', '123ABC') - }) + cy.getCookie('token').should('have.property', 'value', '123ABC'); + }); it('cy.getCookies() - get browser cookies', () => { // https://on.cypress.io/getcookies - cy.getCookies().should('be.empty') + cy.getCookies().should('be.empty'); - cy.get('#getCookies .set-a-cookie').click() + cy.get('#getCookies .set-a-cookie').click(); // cy.getCookies() yields an array of cookies - cy.getCookies().should('have.length', 1).should((cookies) => { - // each cookie has these properties - expect(cookies[0]).to.have.property('name', 'token') - expect(cookies[0]).to.have.property('value', '123ABC') - expect(cookies[0]).to.have.property('httpOnly', false) - expect(cookies[0]).to.have.property('secure', false) - expect(cookies[0]).to.have.property('domain') - expect(cookies[0]).to.have.property('path') - }) - }) + cy.getCookies() + .should('have.length', 1) + .should((cookies) => { + // each cookie has these properties + expect(cookies[0]).to.have.property('name', 'token'); + expect(cookies[0]).to.have.property('value', '123ABC'); + expect(cookies[0]).to.have.property('httpOnly', false); + expect(cookies[0]).to.have.property('secure', false); + expect(cookies[0]).to.have.property('domain'); + expect(cookies[0]).to.have.property('path'); + }); + }); it('cy.setCookie() - set a browser cookie', () => { // https://on.cypress.io/setcookie - cy.getCookies().should('be.empty') + cy.getCookies().should('be.empty'); - cy.setCookie('foo', 'bar') + cy.setCookie('foo', 'bar'); // cy.getCookie() yields a cookie object - cy.getCookie('foo').should('have.property', 'value', 'bar') - }) + cy.getCookie('foo').should('have.property', 'value', 'bar'); + }); it('cy.clearCookie() - clear a browser cookie', () => { // https://on.cypress.io/clearcookie - cy.getCookie('token').should('be.null') + cy.getCookie('token').should('be.null'); - cy.get('#clearCookie .set-a-cookie').click() + cy.get('#clearCookie .set-a-cookie').click(); - cy.getCookie('token').should('have.property', 'value', '123ABC') + cy.getCookie('token').should('have.property', 'value', '123ABC'); // cy.clearCookies() yields null - cy.clearCookie('token').should('be.null') + cy.clearCookie('token').should('be.null'); - cy.getCookie('token').should('be.null') - }) + cy.getCookie('token').should('be.null'); + }); it('cy.clearCookies() - clear browser cookies', () => { // https://on.cypress.io/clearcookies - cy.getCookies().should('be.empty') + cy.getCookies().should('be.empty'); - cy.get('#clearCookies .set-a-cookie').click() + cy.get('#clearCookies .set-a-cookie').click(); - cy.getCookies().should('have.length', 1) + cy.getCookies().should('have.length', 1); // cy.clearCookies() yields null - cy.clearCookies() + cy.clearCookies(); - cy.getCookies().should('be.empty') - }) -}) + cy.getCookies().should('be.empty'); + }); +}); diff --git a/cypress/integration/examples/cypress_api.spec.js b/cypress/integration/examples/cypress_api.spec.js index ec8ceae..7e642f9 100644 --- a/cypress/integration/examples/cypress_api.spec.js +++ b/cypress/integration/examples/cypress_api.spec.js @@ -2,136 +2,142 @@ context('Cypress.Commands', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); // https://on.cypress.io/custom-commands it('.add() - create a custom command', () => { - Cypress.Commands.add('console', { - prevSubject: true, - }, (subject, method) => { - // the previous subject is automatically received - // and the commands arguments are shifted - - // allow us to change the console method used - method = method || 'log' - - // log the subject to the console - // @ts-ignore TS7017 - console[method]('The subject is', subject) - - // whatever we return becomes the new subject - // we don't want to change the subject so - // we return whatever was passed in - return subject - }) + Cypress.Commands.add( + 'console', + { + prevSubject: true, + }, + (subject, method) => { + // the previous subject is automatically received + // and the commands arguments are shifted + + // allow us to change the console method used + method = method || 'log'; + + // log the subject to the console + // @ts-ignore TS7017 + console[method]('The subject is', subject); + + // whatever we return becomes the new subject + // we don't want to change the subject so + // we return whatever was passed in + return subject; + } + ); // @ts-ignore TS2339 - cy.get('button').console('info').then(($button) => { - // subject is still $button - }) - }) -}) + cy.get('button') + .console('info') + .then(($button) => { + // subject is still $button + }); + }); +}); context('Cypress.Cookies', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); // https://on.cypress.io/cookies it('.debug() - enable or disable debugging', () => { - Cypress.Cookies.debug(true) + Cypress.Cookies.debug(true); // Cypress will now log in the console when // cookies are set or cleared - cy.setCookie('fakeCookie', '123ABC') - cy.clearCookie('fakeCookie') - cy.setCookie('fakeCookie', '123ABC') - cy.clearCookie('fakeCookie') - cy.setCookie('fakeCookie', '123ABC') - }) + cy.setCookie('fakeCookie', '123ABC'); + cy.clearCookie('fakeCookie'); + cy.setCookie('fakeCookie', '123ABC'); + cy.clearCookie('fakeCookie'); + cy.setCookie('fakeCookie', '123ABC'); + }); it('.preserveOnce() - preserve cookies by key', () => { // normally cookies are reset after each test - cy.getCookie('fakeCookie').should('not.be.ok') + cy.getCookie('fakeCookie').should('not.be.ok'); // preserving a cookie will not clear it when // the next test starts - cy.setCookie('lastCookie', '789XYZ') - Cypress.Cookies.preserveOnce('lastCookie') - }) + cy.setCookie('lastCookie', '789XYZ'); + Cypress.Cookies.preserveOnce('lastCookie'); + }); it('.defaults() - set defaults for all cookies', () => { // now any cookie with the name 'session_id' will // not be cleared before each new test runs Cypress.Cookies.defaults({ preserve: 'session_id', - }) - }) -}) + }); + }); +}); context('Cypress.arch', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Get CPU architecture name of underlying OS', () => { // https://on.cypress.io/arch - expect(Cypress.arch).to.exist - }) -}) + expect(Cypress.arch).to.exist; + }); +}); context('Cypress.config()', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Get and set configuration options', () => { // https://on.cypress.io/config - let myConfig = Cypress.config() + let myConfig = Cypress.config(); - expect(myConfig).to.have.property('animationDistanceThreshold', 5) - expect(myConfig).to.have.property('baseUrl', null) - expect(myConfig).to.have.property('defaultCommandTimeout', 4000) - expect(myConfig).to.have.property('requestTimeout', 5000) - expect(myConfig).to.have.property('responseTimeout', 30000) - expect(myConfig).to.have.property('viewportHeight', 660) - expect(myConfig).to.have.property('viewportWidth', 1000) - expect(myConfig).to.have.property('pageLoadTimeout', 60000) - expect(myConfig).to.have.property('waitForAnimations', true) + expect(myConfig).to.have.property('animationDistanceThreshold', 5); + expect(myConfig).to.have.property('baseUrl', null); + expect(myConfig).to.have.property('defaultCommandTimeout', 4000); + expect(myConfig).to.have.property('requestTimeout', 5000); + expect(myConfig).to.have.property('responseTimeout', 30000); + expect(myConfig).to.have.property('viewportHeight', 660); + expect(myConfig).to.have.property('viewportWidth', 1000); + expect(myConfig).to.have.property('pageLoadTimeout', 60000); + expect(myConfig).to.have.property('waitForAnimations', true); - expect(Cypress.config('pageLoadTimeout')).to.eq(60000) + expect(Cypress.config('pageLoadTimeout')).to.eq(60000); // this will change the config for the rest of your tests! - Cypress.config('pageLoadTimeout', 20000) + Cypress.config('pageLoadTimeout', 20000); - expect(Cypress.config('pageLoadTimeout')).to.eq(20000) + expect(Cypress.config('pageLoadTimeout')).to.eq(20000); - Cypress.config('pageLoadTimeout', 60000) - }) -}) + Cypress.config('pageLoadTimeout', 60000); + }); +}); context('Cypress.dom', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); // https://on.cypress.io/dom it('.isHidden() - determine if a DOM element is hidden', () => { - let hiddenP = Cypress.$('.dom-p p.hidden').get(0) - let visibleP = Cypress.$('.dom-p p.visible').get(0) + let hiddenP = Cypress.$('.dom-p p.hidden').get(0); + let visibleP = Cypress.$('.dom-p p.visible').get(0); // our first paragraph has css class 'hidden' - expect(Cypress.dom.isHidden(hiddenP)).to.be.true - expect(Cypress.dom.isHidden(visibleP)).to.be.false - }) -}) + expect(Cypress.dom.isHidden(hiddenP)).to.be.true; + expect(Cypress.dom.isHidden(visibleP)).to.be.false; + }); +}); context('Cypress.env()', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); // We can set environment variables for highly dynamic values @@ -142,61 +148,68 @@ context('Cypress.env()', () => { Cypress.env({ host: 'veronica.dev.local', api_server: 'http://localhost:8888/v1/', - }) + }); // get environment variable - expect(Cypress.env('host')).to.eq('veronica.dev.local') + expect(Cypress.env('host')).to.eq('veronica.dev.local'); // set environment variable - Cypress.env('api_server', 'http://localhost:8888/v2/') - expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/') + Cypress.env('api_server', 'http://localhost:8888/v2/'); + expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/'); // get all environment variable - expect(Cypress.env()).to.have.property('host', 'veronica.dev.local') - expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/v2/') - }) -}) + expect(Cypress.env()).to.have.property('host', 'veronica.dev.local'); + expect(Cypress.env()).to.have.property( + 'api_server', + 'http://localhost:8888/v2/' + ); + }); +}); context('Cypress.log', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Control what is printed to the Command Log', () => { // https://on.cypress.io/cypress-log - }) -}) + }); +}); context('Cypress.platform', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Get underlying OS name', () => { // https://on.cypress.io/platform - expect(Cypress.platform).to.be.exist - }) -}) + expect(Cypress.platform).to.be.exist; + }); +}); context('Cypress.version', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Get current version of Cypress being run', () => { // https://on.cypress.io/version - expect(Cypress.version).to.be.exist - }) -}) + expect(Cypress.version).to.be.exist; + }); +}); context('Cypress.spec', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/cypress-api') - }) + cy.visit('https://example.cypress.io/cypress-api'); + }); it('Get current spec information', () => { // https://on.cypress.io/spec // wrap the object so we can inspect it easily by clicking in the command log - cy.wrap(Cypress.spec).should('include.keys', ['name', 'relative', 'absolute']) - }) -}) + cy.wrap(Cypress.spec).should('include.keys', [ + 'name', + 'relative', + 'absolute', + ]); + }); +}); diff --git a/cypress/integration/examples/files.spec.js b/cypress/integration/examples/files.spec.js index 01a5323..ede0e8a 100644 --- a/cypress/integration/examples/files.spec.js +++ b/cypress/integration/examples/files.spec.js @@ -3,18 +3,18 @@ /// JSON fixture file can be loaded directly using // the built-in JavaScript bundler // @ts-ignore -const requiredExample = require('../../fixtures/example') +const requiredExample = require('../../fixtures/example'); context('Files', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/files') - }) + cy.visit('https://example.cypress.io/commands/files'); + }); beforeEach(() => { // load example.json fixture file and store // in the test context object - cy.fixture('example.json').as('example') - }) + cy.fixture('example.json').as('example'); + }); it('cy.fixture() - load a fixture', () => { // https://on.cypress.io/fixture @@ -24,29 +24,35 @@ context('Files', () => { // when application makes an Ajax request matching "GET **/comments/*" // Cypress will intercept it and reply with the object in `example.json` fixture - cy.intercept('GET', '**/comments/*', { fixture: 'example.json' }).as('getComment') + cy.intercept('GET', '**/comments/*', { fixture: 'example.json' }).as( + 'getComment' + ); // we have code that gets a comment when // the button is clicked in scripts.js - cy.get('.fixture-btn').click() + cy.get('.fixture-btn').click(); - cy.wait('@getComment').its('response.body') + cy.wait('@getComment') + .its('response.body') .should('have.property', 'name') - .and('include', 'Using fixtures to represent data') - }) + .and('include', 'Using fixtures to represent data'); + }); it('cy.fixture() or require - load a fixture', function () { // we are inside the "function () { ... }" // callback and can use test context object "this" // "this.example" was loaded in "beforeEach" function callback - expect(this.example, 'fixture in the test context') - .to.deep.equal(requiredExample) + expect(this.example, 'fixture in the test context').to.deep.equal( + requiredExample + ); // or use "cy.wrap" and "should('deep.equal', ...)" assertion // @ts-ignore - cy.wrap(this.example, 'fixture vs require') - .should('deep.equal', requiredExample) - }) + cy.wrap(this.example, 'fixture vs require').should( + 'deep.equal', + requiredExample + ); + }); it('cy.readFile() - read file contents', () => { // https://on.cypress.io/readfile @@ -54,9 +60,9 @@ context('Files', () => { // You can read a file and yield its contents // The filePath is relative to your project's root. cy.readFile('cypress.json').then((json) => { - expect(json).to.be.an('object') - }) - }) + expect(json).to.be.an('object'); + }); + }); it('cy.writeFile() - write to a file', () => { // https://on.cypress.io/writefile @@ -65,14 +71,13 @@ context('Files', () => { // Use a response from a request to automatically // generate a fixture file for use later - cy.request('https://jsonplaceholder.cypress.io/users') - .then((response) => { - cy.writeFile('cypress/fixtures/users.json', response.body) - }) + cy.request('https://jsonplaceholder.cypress.io/users').then((response) => { + cy.writeFile('cypress/fixtures/users.json', response.body); + }); cy.fixture('users').should((users) => { - expect(users[0].name).to.exist - }) + expect(users[0].name).to.exist; + }); // JavaScript arrays and objects are stringified // and formatted into text. @@ -80,10 +85,10 @@ context('Files', () => { id: 8739, name: 'Jane', email: 'jane@example.com', - }) + }); cy.fixture('profile').should((profile) => { - expect(profile.name).to.eq('Jane') - }) - }) -}) + expect(profile.name).to.eq('Jane'); + }); + }); +}); diff --git a/cypress/integration/examples/local_storage.spec.js b/cypress/integration/examples/local_storage.spec.js index 5f83b8d..1946c4d 100644 --- a/cypress/integration/examples/local_storage.spec.js +++ b/cypress/integration/examples/local_storage.spec.js @@ -2,51 +2,57 @@ context('Local Storage', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/local-storage') - }) + cy.visit('https://example.cypress.io/commands/local-storage'); + }); // Although local storage is automatically cleared // in between tests to maintain a clean state // sometimes we need to clear the local storage manually it('cy.clearLocalStorage() - clear all data in local storage', () => { // https://on.cypress.io/clearlocalstorage - cy.get('.ls-btn').click().should(() => { - expect(localStorage.getItem('prop1')).to.eq('red') - expect(localStorage.getItem('prop2')).to.eq('blue') - expect(localStorage.getItem('prop3')).to.eq('magenta') - }) + cy.get('.ls-btn') + .click() + .should(() => { + expect(localStorage.getItem('prop1')).to.eq('red'); + expect(localStorage.getItem('prop2')).to.eq('blue'); + expect(localStorage.getItem('prop3')).to.eq('magenta'); + }); // clearLocalStorage() yields the localStorage object cy.clearLocalStorage().should((ls) => { - expect(ls.getItem('prop1')).to.be.null - expect(ls.getItem('prop2')).to.be.null - expect(ls.getItem('prop3')).to.be.null - }) + expect(ls.getItem('prop1')).to.be.null; + expect(ls.getItem('prop2')).to.be.null; + expect(ls.getItem('prop3')).to.be.null; + }); // Clear key matching string in Local Storage - cy.get('.ls-btn').click().should(() => { - expect(localStorage.getItem('prop1')).to.eq('red') - expect(localStorage.getItem('prop2')).to.eq('blue') - expect(localStorage.getItem('prop3')).to.eq('magenta') - }) + cy.get('.ls-btn') + .click() + .should(() => { + expect(localStorage.getItem('prop1')).to.eq('red'); + expect(localStorage.getItem('prop2')).to.eq('blue'); + expect(localStorage.getItem('prop3')).to.eq('magenta'); + }); cy.clearLocalStorage('prop1').should((ls) => { - expect(ls.getItem('prop1')).to.be.null - expect(ls.getItem('prop2')).to.eq('blue') - expect(ls.getItem('prop3')).to.eq('magenta') - }) + expect(ls.getItem('prop1')).to.be.null; + expect(ls.getItem('prop2')).to.eq('blue'); + expect(ls.getItem('prop3')).to.eq('magenta'); + }); // Clear keys matching regex in Local Storage - cy.get('.ls-btn').click().should(() => { - expect(localStorage.getItem('prop1')).to.eq('red') - expect(localStorage.getItem('prop2')).to.eq('blue') - expect(localStorage.getItem('prop3')).to.eq('magenta') - }) + cy.get('.ls-btn') + .click() + .should(() => { + expect(localStorage.getItem('prop1')).to.eq('red'); + expect(localStorage.getItem('prop2')).to.eq('blue'); + expect(localStorage.getItem('prop3')).to.eq('magenta'); + }); cy.clearLocalStorage(/prop1|2/).should((ls) => { - expect(ls.getItem('prop1')).to.be.null - expect(ls.getItem('prop2')).to.be.null - expect(ls.getItem('prop3')).to.eq('magenta') - }) - }) -}) + expect(ls.getItem('prop1')).to.be.null; + expect(ls.getItem('prop2')).to.be.null; + expect(ls.getItem('prop3')).to.eq('magenta'); + }); + }); +}); diff --git a/cypress/integration/examples/location.spec.js b/cypress/integration/examples/location.spec.js index 299867d..481c930 100644 --- a/cypress/integration/examples/location.spec.js +++ b/cypress/integration/examples/location.spec.js @@ -2,31 +2,33 @@ context('Location', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/location') - }) + cy.visit('https://example.cypress.io/commands/location'); + }); it('cy.hash() - get the current URL hash', () => { // https://on.cypress.io/hash - cy.hash().should('be.empty') - }) + cy.hash().should('be.empty'); + }); it('cy.location() - get window.location', () => { // https://on.cypress.io/location cy.location().should((location) => { - expect(location.hash).to.be.empty - expect(location.href).to.eq('https://example.cypress.io/commands/location') - expect(location.host).to.eq('example.cypress.io') - expect(location.hostname).to.eq('example.cypress.io') - expect(location.origin).to.eq('https://example.cypress.io') - expect(location.pathname).to.eq('/commands/location') - expect(location.port).to.eq('') - expect(location.protocol).to.eq('https:') - expect(location.search).to.be.empty - }) - }) + expect(location.hash).to.be.empty; + expect(location.href).to.eq( + 'https://example.cypress.io/commands/location' + ); + expect(location.host).to.eq('example.cypress.io'); + expect(location.hostname).to.eq('example.cypress.io'); + expect(location.origin).to.eq('https://example.cypress.io'); + expect(location.pathname).to.eq('/commands/location'); + expect(location.port).to.eq(''); + expect(location.protocol).to.eq('https:'); + expect(location.search).to.be.empty; + }); + }); it('cy.url() - get the current URL', () => { // https://on.cypress.io/url - cy.url().should('eq', 'https://example.cypress.io/commands/location') - }) -}) + cy.url().should('eq', 'https://example.cypress.io/commands/location'); + }); +}); diff --git a/cypress/integration/examples/misc.spec.js b/cypress/integration/examples/misc.spec.js index 7222bf4..2f99f4b 100644 --- a/cypress/integration/examples/misc.spec.js +++ b/cypress/integration/examples/misc.spec.js @@ -2,8 +2,8 @@ context('Misc', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/misc') - }) + cy.visit('https://example.cypress.io/commands/misc'); + }); it('.end() - end the command chain', () => { // https://on.cypress.io/end @@ -12,12 +12,12 @@ context('Misc', () => { // and force Cypress to re-query from the root element cy.get('.misc-table').within(() => { // ends the current chain and yields null - cy.contains('Cheryl').click().end() + cy.contains('Cheryl').click().end(); // queries the entire table again - cy.contains('Charles').click() - }) - }) + cy.contains('Charles').click(); + }); + }); it('cy.exec() - execute a system command', () => { // execute a system command. @@ -28,58 +28,56 @@ context('Misc', () => { // we can use Cypress.platform string to // select appropriate command // https://on.cypress/io/platform - cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`) + cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`); // on CircleCI Windows build machines we have a failure to run bash shell // https://github.com/cypress-io/cypress/issues/5169 // so skip some of the tests by passing flag "--env circle=true" - const isCircleOnWindows = Cypress.platform === 'win32' && Cypress.env('circle') + const isCircleOnWindows = + Cypress.platform === 'win32' && Cypress.env('circle'); if (isCircleOnWindows) { - cy.log('Skipping test on CircleCI') + cy.log('Skipping test on CircleCI'); - return + return; } // cy.exec problem on Shippable CI // https://github.com/cypress-io/cypress/issues/6718 - const isShippable = Cypress.platform === 'linux' && Cypress.env('shippable') + const isShippable = + Cypress.platform === 'linux' && Cypress.env('shippable'); if (isShippable) { - cy.log('Skipping test on ShippableCI') + cy.log('Skipping test on ShippableCI'); - return + return; } - cy.exec('echo Jane Lane') - .its('stdout').should('contain', 'Jane Lane') + cy.exec('echo Jane Lane').its('stdout').should('contain', 'Jane Lane'); if (Cypress.platform === 'win32') { - cy.exec('print cypress.json') - .its('stderr').should('be.empty') + cy.exec('print cypress.json').its('stderr').should('be.empty'); } else { - cy.exec('cat cypress.json') - .its('stderr').should('be.empty') + cy.exec('cat cypress.json').its('stderr').should('be.empty'); - cy.exec('pwd') - .its('code').should('eq', 0) + cy.exec('pwd').its('code').should('eq', 0); } - }) + }); it('cy.focused() - get the DOM element that has focus', () => { // https://on.cypress.io/focused - cy.get('.misc-form').find('#name').click() - cy.focused().should('have.id', 'name') + cy.get('.misc-form').find('#name').click(); + cy.focused().should('have.id', 'name'); - cy.get('.misc-form').find('#description').click() - cy.focused().should('have.id', 'description') - }) + cy.get('.misc-form').find('#description').click(); + cy.focused().should('have.id', 'description'); + }); context('Cypress.Screenshot', function () { it('cy.screenshot() - take a screenshot', () => { // https://on.cypress.io/screenshot - cy.screenshot('my-image') - }) + cy.screenshot('my-image'); + }); it('Cypress.Screenshot.defaults() - change default config of screenshots', function () { Cypress.Screenshot.defaults({ @@ -89,16 +87,16 @@ context('Misc', () => { scale: false, disableTimersAndAnimations: true, screenshotOnRunFailure: true, - onBeforeScreenshot () { }, - onAfterScreenshot () { }, - }) - }) - }) + onBeforeScreenshot() {}, + onAfterScreenshot() {}, + }); + }); + }); it('cy.wrap() - wrap an object', () => { // https://on.cypress.io/wrap cy.wrap({ foo: 'bar' }) .should('have.property', 'foo') - .and('include', 'bar') - }) -}) + .and('include', 'bar'); + }); +}); diff --git a/cypress/integration/examples/navigation.spec.js b/cypress/integration/examples/navigation.spec.js index b85a468..8a66ac4 100644 --- a/cypress/integration/examples/navigation.spec.js +++ b/cypress/integration/examples/navigation.spec.js @@ -2,38 +2,38 @@ context('Navigation', () => { beforeEach(() => { - cy.visit('https://example.cypress.io') - cy.get('.navbar-nav').contains('Commands').click() - cy.get('.dropdown-menu').contains('Navigation').click() - }) + cy.visit('https://example.cypress.io'); + cy.get('.navbar-nav').contains('Commands').click(); + cy.get('.dropdown-menu').contains('Navigation').click(); + }); - it('cy.go() - go back or forward in the browser\'s history', () => { + it("cy.go() - go back or forward in the browser's history", () => { // https://on.cypress.io/go - cy.location('pathname').should('include', 'navigation') + cy.location('pathname').should('include', 'navigation'); - cy.go('back') - cy.location('pathname').should('not.include', 'navigation') + cy.go('back'); + cy.location('pathname').should('not.include', 'navigation'); - cy.go('forward') - cy.location('pathname').should('include', 'navigation') + cy.go('forward'); + cy.location('pathname').should('include', 'navigation'); // clicking back - cy.go(-1) - cy.location('pathname').should('not.include', 'navigation') + cy.go(-1); + cy.location('pathname').should('not.include', 'navigation'); // clicking forward - cy.go(1) - cy.location('pathname').should('include', 'navigation') - }) + cy.go(1); + cy.location('pathname').should('include', 'navigation'); + }); it('cy.reload() - reload the page', () => { // https://on.cypress.io/reload - cy.reload() + cy.reload(); // reload the page without using the cache - cy.reload(true) - }) + cy.reload(true); + }); it('cy.visit() - visit a remote url', () => { // https://on.cypress.io/visit @@ -43,14 +43,14 @@ context('Navigation', () => { // Pass options to the visit cy.visit('https://example.cypress.io/commands/navigation', { timeout: 50000, // increase total time for the visit to resolve - onBeforeLoad (contentWindow) { + onBeforeLoad(contentWindow) { // contentWindow is the remote page's window object - expect(typeof contentWindow === 'object').to.be.true + expect(typeof contentWindow === 'object').to.be.true; }, - onLoad (contentWindow) { + onLoad(contentWindow) { // contentWindow is the remote page's window object - expect(typeof contentWindow === 'object').to.be.true + expect(typeof contentWindow === 'object').to.be.true; }, - }) - }) -}) + }); + }); +}); diff --git a/cypress/integration/examples/network_requests.spec.js b/cypress/integration/examples/network_requests.spec.js index 11213a0..5412f5f 100644 --- a/cypress/integration/examples/network_requests.spec.js +++ b/cypress/integration/examples/network_requests.spec.js @@ -2,33 +2,40 @@ context('Network Requests', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/network-requests') - }) + cy.visit('https://example.cypress.io/commands/network-requests'); + }); // Manage HTTP requests in your app it('cy.request() - make an XHR request', () => { // https://on.cypress.io/request - cy.request('https://jsonplaceholder.cypress.io/comments') - .should((response) => { - expect(response.status).to.eq(200) + cy.request('https://jsonplaceholder.cypress.io/comments').should( + (response) => { + expect(response.status).to.eq(200); // the server sometimes gets an extra comment posted from another machine // which gets returned as 1 extra object - expect(response.body).to.have.property('length').and.be.oneOf([500, 501]) - expect(response).to.have.property('headers') - expect(response).to.have.property('duration') - }) - }) + expect(response.body) + .to.have.property('length') + .and.be.oneOf([500, 501]); + expect(response).to.have.property('headers'); + expect(response).to.have.property('duration'); + } + ); + }); it('cy.request() - verify response using BDD syntax', () => { - cy.request('https://jsonplaceholder.cypress.io/comments') - .then((response) => { - // https://on.cypress.io/assertions - expect(response).property('status').to.equal(200) - expect(response).property('body').to.have.property('length').and.be.oneOf([500, 501]) - expect(response).to.include.keys('headers', 'duration') - }) - }) + cy.request('https://jsonplaceholder.cypress.io/comments').then( + (response) => { + // https://on.cypress.io/assertions + expect(response).property('status').to.equal(200); + expect(response) + .property('body') + .to.have.property('length') + .and.be.oneOf([500, 501]); + expect(response).to.include.keys('headers', 'duration'); + } + ); + }); it('cy.request() with query parameters', () => { // will execute request @@ -40,15 +47,15 @@ context('Network Requests', () => { id: 3, }, }) - .its('body') - .should('be.an', 'array') - .and('have.length', 1) - .its('0') // yields first element of the array - .should('contain', { - postId: 1, - id: 3, - }) - }) + .its('body') + .should('be.an', 'array') + .and('have.length', 1) + .its('0') // yields first element of the array + .should('contain', { + postId: 1, + id: 3, + }); + }); it('cy.request() - pass result to the second request', () => { // first, let's find out the userId of the first user we have @@ -59,37 +66,41 @@ context('Network Requests', () => { // can be written as its('body.0') // if you do not care about TypeScript checks .then((user) => { - expect(user).property('id').to.be.a('number') + expect(user).property('id').to.be.a('number'); // make a new post on behalf of the user cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { userId: user.id, title: 'Cypress Test Runner', - body: 'Fast, easy and reliable testing for anything that runs in a browser.', - }) + body: + 'Fast, easy and reliable testing for anything that runs in a browser.', + }); }) // note that the value here is the returned value of the 2nd request // which is the new post object .then((response) => { - expect(response).property('status').to.equal(201) // new entity created + expect(response).property('status').to.equal(201); // new entity created expect(response).property('body').to.contain({ title: 'Cypress Test Runner', - }) + }); // we don't know the exact post id - only that it will be > 100 // since JSONPlaceholder has built-in 100 posts - expect(response.body).property('id').to.be.a('number') - .and.to.be.gt(100) + expect(response.body) + .property('id') + .to.be.a('number') + .and.to.be.gt(100); // we don't know the user id here - since it was in above closure // so in this test just confirm that the property is there - expect(response.body).property('userId').to.be.a('number') - }) - }) + expect(response.body).property('userId').to.be.a('number'); + }); + }); it('cy.request() - save response in the shared test context', () => { // https://on.cypress.io/variables-and-aliases cy.request('https://jsonplaceholder.cypress.io/users?_limit=1') - .its('body').its('0') // yields the first element of the returned list + .its('body') + .its('0') // yields the first element of the returned list .as('user') // saves the object in the test context .then(function () { // NOTE 👀 @@ -101,63 +112,75 @@ context('Network Requests', () => { cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', { userId: this.user.id, title: 'Cypress Test Runner', - body: 'Fast, easy and reliable testing for anything that runs in a browser.', + body: + 'Fast, easy and reliable testing for anything that runs in a browser.', }) - .its('body').as('post') // save the new post from the response + .its('body') + .as('post'); // save the new post from the response }) .then(function () { // When this callback runs, both "cy.request" API commands have finished // and the test context has "user" and "post" objects set. // Let's verify them. - expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id) - }) - }) + expect(this.post, 'post has the right user id') + .property('userId') + .to.equal(this.user.id); + }); + }); it('cy.intercept() - route responses to matching requests', () => { // https://on.cypress.io/intercept - let message = 'whoa, this comment does not exist' + let message = 'whoa, this comment does not exist'; // Listen to GET to comments/1 - cy.intercept('GET', '**/comments/*').as('getComment') + cy.intercept('GET', '**/comments/*').as('getComment'); // we have code that gets a comment when // the button is clicked in scripts.js - cy.get('.network-btn').click() + cy.get('.network-btn').click(); // https://on.cypress.io/wait - cy.wait('@getComment').its('response.statusCode').should('be.oneOf', [200, 304]) + cy.wait('@getComment') + .its('response.statusCode') + .should('be.oneOf', [200, 304]); // Listen to POST to comments - cy.intercept('POST', '**/comments').as('postComment') + cy.intercept('POST', '**/comments').as('postComment'); // we have code that posts a comment when // the button is clicked in scripts.js - cy.get('.network-post').click() + cy.get('.network-post').click(); cy.wait('@postComment').should(({ request, response }) => { - expect(request.body).to.include('email') - expect(request.headers).to.have.property('content-type') - expect(response && response.body).to.have.property('name', 'Using POST in cy.intercept()') - }) + expect(request.body).to.include('email'); + expect(request.headers).to.have.property('content-type'); + expect(response && response.body).to.have.property( + 'name', + 'Using POST in cy.intercept()' + ); + }); // Stub a response to PUT comments/ **** - cy.intercept({ - method: 'PUT', - url: '**/comments/*', - }, { - statusCode: 404, - body: { error: message }, - headers: { 'access-control-allow-origin': '*' }, - delayMs: 500, - }).as('putComment') + cy.intercept( + { + method: 'PUT', + url: '**/comments/*', + }, + { + statusCode: 404, + body: { error: message }, + headers: { 'access-control-allow-origin': '*' }, + delayMs: 500, + } + ).as('putComment'); // we have code that puts a comment when // the button is clicked in scripts.js - cy.get('.network-put').click() + cy.get('.network-put').click(); - cy.wait('@putComment') + cy.wait('@putComment'); // our 404 statusCode logic in scripts.js executed - cy.get('.network-put-comment').should('contain', message) - }) -}) + cy.get('.network-put-comment').should('contain', message); + }); +}); diff --git a/cypress/integration/examples/querying.spec.js b/cypress/integration/examples/querying.spec.js index 0097048..d385151 100644 --- a/cypress/integration/examples/querying.spec.js +++ b/cypress/integration/examples/querying.spec.js @@ -2,8 +2,8 @@ context('Querying', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/querying') - }) + cy.visit('https://example.cypress.io/commands/querying'); + }); // The most commonly used query is 'cy.get()', you can // think of this like the '$' in jQuery @@ -11,104 +11,96 @@ context('Querying', () => { it('cy.get() - query DOM elements', () => { // https://on.cypress.io/get - cy.get('#query-btn').should('contain', 'Button') + cy.get('#query-btn').should('contain', 'Button'); - cy.get('.query-btn').should('contain', 'Button') + cy.get('.query-btn').should('contain', 'Button'); - cy.get('#querying .well>button:first').should('contain', 'Button') + cy.get('#querying .well>button:first').should('contain', 'Button'); // ↲ // Use CSS selectors just like jQuery - cy.get('[data-test-id="test-example"]').should('have.class', 'example') + cy.get('[data-test-id="test-example"]').should('have.class', 'example'); // 'cy.get()' yields jQuery object, you can get its attribute // by invoking `.attr()` method cy.get('[data-test-id="test-example"]') .invoke('attr', 'data-test-id') - .should('equal', 'test-example') + .should('equal', 'test-example'); // or you can get element's CSS property cy.get('[data-test-id="test-example"]') .invoke('css', 'position') - .should('equal', 'static') + .should('equal', 'static'); // or use assertions directly during 'cy.get()' // https://on.cypress.io/assertions cy.get('[data-test-id="test-example"]') .should('have.attr', 'data-test-id', 'test-example') - .and('have.css', 'position', 'static') - }) + .and('have.css', 'position', 'static'); + }); it('cy.contains() - query DOM elements with matching content', () => { // https://on.cypress.io/contains - cy.get('.query-list') - .contains('bananas') - .should('have.class', 'third') + cy.get('.query-list').contains('bananas').should('have.class', 'third'); // we can pass a regexp to `.contains()` - cy.get('.query-list') - .contains(/^b\w+/) - .should('have.class', 'third') + cy.get('.query-list').contains(/^b\w+/).should('have.class', 'third'); - cy.get('.query-list') - .contains('apples') - .should('have.class', 'first') + cy.get('.query-list').contains('apples').should('have.class', 'first'); // passing a selector to contains will // yield the selector containing the text cy.get('#querying') .contains('ul', 'oranges') - .should('have.class', 'query-list') + .should('have.class', 'query-list'); - cy.get('.query-button') - .contains('Save Form') - .should('have.class', 'btn') - }) + cy.get('.query-button').contains('Save Form').should('have.class', 'btn'); + }); it('.within() - query DOM elements within a specific element', () => { // https://on.cypress.io/within cy.get('.query-form').within(() => { - cy.get('input:first').should('have.attr', 'placeholder', 'Email') - cy.get('input:last').should('have.attr', 'placeholder', 'Password') - }) - }) + cy.get('input:first').should('have.attr', 'placeholder', 'Email'); + cy.get('input:last').should('have.attr', 'placeholder', 'Password'); + }); + }); it('cy.root() - query the root DOM element', () => { // https://on.cypress.io/root // By default, root is the document - cy.root().should('match', 'html') + cy.root().should('match', 'html'); cy.get('.query-ul').within(() => { // In this within, the root is now the ul DOM element - cy.root().should('have.class', 'query-ul') - }) - }) + cy.root().should('have.class', 'query-ul'); + }); + }); it('best practices - selecting elements', () => { // https://on.cypress.io/best-practices#Selecting-Elements cy.get('[data-cy=best-practices-selecting-elements]').within(() => { // Worst - too generic, no context - cy.get('button').click() + cy.get('button').click(); // Bad. Coupled to styling. Highly subject to change. - cy.get('.btn.btn-large').click() + cy.get('.btn.btn-large').click(); // Average. Coupled to the `name` attribute which has HTML semantics. - cy.get('[name=submission]').click() + cy.get('[name=submission]').click(); // Better. But still coupled to styling or JS event listeners. - cy.get('#main').click() + cy.get('#main').click(); // Slightly better. Uses an ID but also ensures the element // has an ARIA role attribute - cy.get('#main[role=button]').click() + cy.get('#main[role=button]').click(); // Much better. But still coupled to text content that may change. - cy.contains('Submit').click() + cy.contains('Submit').click(); // Best. Insulated from all changes. - cy.get('[data-cy=submit]').click() - }) - }) -}) + cy.get('[data-cy=submit]').click(); + }); + }); +}); diff --git a/cypress/integration/examples/spies_stubs_clocks.spec.js b/cypress/integration/examples/spies_stubs_clocks.spec.js index 18b643e..511b5a4 100644 --- a/cypress/integration/examples/spies_stubs_clocks.spec.js +++ b/cypress/integration/examples/spies_stubs_clocks.spec.js @@ -5,96 +5,93 @@ context('Spies, Stubs, and Clock', () => { it('cy.spy() - wrap a method in a spy', () => { // https://on.cypress.io/spy - cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks'); const obj = { - foo () {}, - } + foo() {}, + }; - const spy = cy.spy(obj, 'foo').as('anyArgs') + const spy = cy.spy(obj, 'foo').as('anyArgs'); - obj.foo() + obj.foo(); - expect(spy).to.be.called - }) + expect(spy).to.be.called; + }); it('cy.spy() retries until assertions pass', () => { - cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks'); const obj = { /** * Prints the argument passed * @param x {any} - */ - foo (x) { - console.log('obj.foo called with', x) + */ + foo(x) { + console.log('obj.foo called with', x); }, - } + }; - cy.spy(obj, 'foo').as('foo') + cy.spy(obj, 'foo').as('foo'); setTimeout(() => { - obj.foo('first') - }, 500) + obj.foo('first'); + }, 500); setTimeout(() => { - obj.foo('second') - }, 2500) + obj.foo('second'); + }, 2500); - cy.get('@foo').should('have.been.calledTwice') - }) + cy.get('@foo').should('have.been.calledTwice'); + }); it('cy.stub() - create a stub and/or replace a function with stub', () => { // https://on.cypress.io/stub - cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks'); const obj = { /** * prints both arguments to the console * @param a {string} * @param b {string} - */ - foo (a, b) { - console.log('a', a, 'b', b) + */ + foo(a, b) { + console.log('a', a, 'b', b); }, - } + }; - const stub = cy.stub(obj, 'foo').as('foo') + const stub = cy.stub(obj, 'foo').as('foo'); - obj.foo('foo', 'bar') + obj.foo('foo', 'bar'); - expect(stub).to.be.called - }) + expect(stub).to.be.called; + }); it('cy.clock() - control time in the browser', () => { // https://on.cypress.io/clock // create the date in UTC so its always the same // no matter what local timezone the browser is running in - const now = new Date(Date.UTC(2017, 2, 14)).getTime() + const now = new Date(Date.UTC(2017, 2, 14)).getTime(); - cy.clock(now) - cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') - cy.get('#clock-div').click() - .should('have.text', '1489449600') - }) + cy.clock(now); + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks'); + cy.get('#clock-div').click().should('have.text', '1489449600'); + }); it('cy.tick() - move time in the browser', () => { // https://on.cypress.io/tick // create the date in UTC so its always the same // no matter what local timezone the browser is running in - const now = new Date(Date.UTC(2017, 2, 14)).getTime() + const now = new Date(Date.UTC(2017, 2, 14)).getTime(); - cy.clock(now) - cy.visit('https://example.cypress.io/commands/spies-stubs-clocks') - cy.get('#tick-div').click() - .should('have.text', '1489449600') + cy.clock(now); + cy.visit('https://example.cypress.io/commands/spies-stubs-clocks'); + cy.get('#tick-div').click().should('have.text', '1489449600'); - cy.tick(10000) // 10 seconds passed - cy.get('#tick-div').click() - .should('have.text', '1489449610') - }) + cy.tick(10000); // 10 seconds passed + cy.get('#tick-div').click().should('have.text', '1489449610'); + }); it('cy.stub() matches depending on arguments', () => { // see all possible matchers at @@ -103,26 +100,28 @@ context('Spies, Stubs, and Clock', () => { /** * Greets a person * @param {string} name - */ - greet (name) { - return `Hello, ${name}!` + */ + greet(name) { + return `Hello, ${name}!`; }, - } + }; cy.stub(greeter, 'greet') .callThrough() // if you want non-matched calls to call the real method - .withArgs(Cypress.sinon.match.string).returns('Hi') - .withArgs(Cypress.sinon.match.number).throws(new Error('Invalid name')) + .withArgs(Cypress.sinon.match.string) + .returns('Hi') + .withArgs(Cypress.sinon.match.number) + .throws(new Error('Invalid name')); - expect(greeter.greet('World')).to.equal('Hi') + expect(greeter.greet('World')).to.equal('Hi'); // @ts-ignore - expect(() => greeter.greet(42)).to.throw('Invalid name') - expect(greeter.greet).to.have.been.calledTwice + expect(() => greeter.greet(42)).to.throw('Invalid name'); + expect(greeter.greet).to.have.been.calledTwice; // non-matched calls goes the actual method // @ts-ignore - expect(greeter.greet()).to.equal('Hello, undefined!') - }) + expect(greeter.greet()).to.equal('Hello, undefined!'); + }); it('matches call arguments using Sinon matchers', () => { // see all possible matchers at @@ -132,74 +131,87 @@ context('Spies, Stubs, and Clock', () => { * returns the sum of two arguments * @param a {number} * @param b {number} - */ - add (a, b) { - return a + b + */ + add(a, b) { + return a + b; }, - } + }; - const spy = cy.spy(calculator, 'add').as('add') + const spy = cy.spy(calculator, 'add').as('add'); - expect(calculator.add(2, 3)).to.equal(5) + expect(calculator.add(2, 3)).to.equal(5); // if we want to assert the exact values used during the call - expect(spy).to.be.calledWith(2, 3) + expect(spy).to.be.calledWith(2, 3); // let's confirm "add" method was called with two numbers - expect(spy).to.be.calledWith(Cypress.sinon.match.number, Cypress.sinon.match.number) + expect(spy).to.be.calledWith( + Cypress.sinon.match.number, + Cypress.sinon.match.number + ); // alternatively, provide the value to match - expect(spy).to.be.calledWith(Cypress.sinon.match(2), Cypress.sinon.match(3)) + expect(spy).to.be.calledWith( + Cypress.sinon.match(2), + Cypress.sinon.match(3) + ); // match any value - expect(spy).to.be.calledWith(Cypress.sinon.match.any, 3) + expect(spy).to.be.calledWith(Cypress.sinon.match.any, 3); // match any value from a list - expect(spy).to.be.calledWith(Cypress.sinon.match.in([1, 2, 3]), 3) + expect(spy).to.be.calledWith(Cypress.sinon.match.in([1, 2, 3]), 3); /** * Returns true if the given number is event * @param {number} x */ - const isEven = (x) => x % 2 === 0 + const isEven = (x) => x % 2 === 0; // expect the value to pass a custom predicate function // the second argument to "sinon.match(predicate, message)" is // shown if the predicate does not pass and assertion fails - expect(spy).to.be.calledWith(Cypress.sinon.match(isEven, 'isEven'), 3) + expect(spy).to.be.calledWith(Cypress.sinon.match(isEven, 'isEven'), 3); /** * Returns a function that checks if a given number is larger than the limit * @param {number} limit * @returns {(x: number) => boolean} */ - const isGreaterThan = (limit) => (x) => x > limit + const isGreaterThan = (limit) => (x) => x > limit; /** * Returns a function that checks if a given number is less than the limit * @param {number} limit * @returns {(x: number) => boolean} */ - const isLessThan = (limit) => (x) => x < limit + const isLessThan = (limit) => (x) => x < limit; // you can combine several matchers using "and", "or" expect(spy).to.be.calledWith( Cypress.sinon.match.number, - Cypress.sinon.match(isGreaterThan(2), '> 2').and(Cypress.sinon.match(isLessThan(4), '< 4')), - ) + Cypress.sinon + .match(isGreaterThan(2), '> 2') + .and(Cypress.sinon.match(isLessThan(4), '< 4')) + ); expect(spy).to.be.calledWith( Cypress.sinon.match.number, - Cypress.sinon.match(isGreaterThan(200), '> 200').or(Cypress.sinon.match(3)), - ) + Cypress.sinon + .match(isGreaterThan(200), '> 200') + .or(Cypress.sinon.match(3)) + ); // matchers can be used from BDD assertions - cy.get('@add').should('have.been.calledWith', - Cypress.sinon.match.number, Cypress.sinon.match(3)) + cy.get('@add').should( + 'have.been.calledWith', + Cypress.sinon.match.number, + Cypress.sinon.match(3) + ); // you can alias matchers for shorter test code - const { match: M } = Cypress.sinon + const { match: M } = Cypress.sinon; - cy.get('@add').should('have.been.calledWith', M.number, M(3)) - }) -}) + cy.get('@add').should('have.been.calledWith', M.number, M(3)); + }); +}); diff --git a/cypress/integration/examples/traversal.spec.js b/cypress/integration/examples/traversal.spec.js index 0a3b9d3..9c4b403 100644 --- a/cypress/integration/examples/traversal.spec.js +++ b/cypress/integration/examples/traversal.spec.js @@ -2,120 +2,115 @@ context('Traversal', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/traversal') - }) + cy.visit('https://example.cypress.io/commands/traversal'); + }); it('.children() - get child DOM elements', () => { // https://on.cypress.io/children cy.get('.traversal-breadcrumb') .children('.active') - .should('contain', 'Data') - }) + .should('contain', 'Data'); + }); it('.closest() - get closest ancestor DOM element', () => { // https://on.cypress.io/closest - cy.get('.traversal-badge') - .closest('ul') - .should('have.class', 'list-group') - }) + cy.get('.traversal-badge').closest('ul').should('have.class', 'list-group'); + }); it('.eq() - get a DOM element at a specific index', () => { // https://on.cypress.io/eq - cy.get('.traversal-list>li') - .eq(1).should('contain', 'siamese') - }) + cy.get('.traversal-list>li').eq(1).should('contain', 'siamese'); + }); it('.filter() - get DOM elements that match the selector', () => { // https://on.cypress.io/filter - cy.get('.traversal-nav>li') - .filter('.active').should('contain', 'About') - }) + cy.get('.traversal-nav>li').filter('.active').should('contain', 'About'); + }); it('.find() - get descendant DOM elements of the selector', () => { // https://on.cypress.io/find cy.get('.traversal-pagination') - .find('li').find('a') - .should('have.length', 7) - }) + .find('li') + .find('a') + .should('have.length', 7); + }); it('.first() - get first DOM element', () => { // https://on.cypress.io/first - cy.get('.traversal-table td') - .first().should('contain', '1') - }) + cy.get('.traversal-table td').first().should('contain', '1'); + }); it('.last() - get last DOM element', () => { // https://on.cypress.io/last - cy.get('.traversal-buttons .btn') - .last().should('contain', 'Submit') - }) + cy.get('.traversal-buttons .btn').last().should('contain', 'Submit'); + }); it('.next() - get next sibling DOM element', () => { // https://on.cypress.io/next cy.get('.traversal-ul') - .contains('apples').next().should('contain', 'oranges') - }) + .contains('apples') + .next() + .should('contain', 'oranges'); + }); it('.nextAll() - get all next sibling DOM elements', () => { // https://on.cypress.io/nextall cy.get('.traversal-next-all') .contains('oranges') - .nextAll().should('have.length', 3) - }) + .nextAll() + .should('have.length', 3); + }); it('.nextUntil() - get next sibling DOM elements until next el', () => { // https://on.cypress.io/nextuntil - cy.get('#veggies') - .nextUntil('#nuts').should('have.length', 3) - }) + cy.get('#veggies').nextUntil('#nuts').should('have.length', 3); + }); it('.not() - remove DOM elements from set of DOM elements', () => { // https://on.cypress.io/not cy.get('.traversal-disabled .btn') - .not('[disabled]').should('not.contain', 'Disabled') - }) + .not('[disabled]') + .should('not.contain', 'Disabled'); + }); it('.parent() - get parent DOM element from DOM elements', () => { // https://on.cypress.io/parent - cy.get('.traversal-mark') - .parent().should('contain', 'Morbi leo risus') - }) + cy.get('.traversal-mark').parent().should('contain', 'Morbi leo risus'); + }); it('.parents() - get parent DOM elements from DOM elements', () => { // https://on.cypress.io/parents - cy.get('.traversal-cite') - .parents().should('match', 'blockquote') - }) + cy.get('.traversal-cite').parents().should('match', 'blockquote'); + }); it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => { // https://on.cypress.io/parentsuntil cy.get('.clothes-nav') .find('.active') .parentsUntil('.clothes-nav') - .should('have.length', 2) - }) + .should('have.length', 2); + }); it('.prev() - get previous sibling DOM element', () => { // https://on.cypress.io/prev - cy.get('.birds').find('.active') - .prev().should('contain', 'Lorikeets') - }) + cy.get('.birds').find('.active').prev().should('contain', 'Lorikeets'); + }); it('.prevAll() - get all previous sibling DOM elements', () => { // https://on.cypress.io/prevall - cy.get('.fruits-list').find('.third') - .prevAll().should('have.length', 2) - }) + cy.get('.fruits-list').find('.third').prevAll().should('have.length', 2); + }); it('.prevUntil() - get all previous sibling DOM elements until el', () => { // https://on.cypress.io/prevuntil - cy.get('.foods-list').find('#nuts') - .prevUntil('#veggies').should('have.length', 3) - }) + cy.get('.foods-list') + .find('#nuts') + .prevUntil('#veggies') + .should('have.length', 3); + }); it('.siblings() - get all sibling DOM elements', () => { // https://on.cypress.io/siblings - cy.get('.traversal-pills .active') - .siblings().should('have.length', 2) - }) -}) + cy.get('.traversal-pills .active').siblings().should('have.length', 2); + }); +}); diff --git a/cypress/integration/examples/utilities.spec.js b/cypress/integration/examples/utilities.spec.js index 24e61a6..3cd7d27 100644 --- a/cypress/integration/examples/utilities.spec.js +++ b/cypress/integration/examples/utilities.spec.js @@ -2,99 +2,100 @@ context('Utilities', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/utilities') - }) + cy.visit('https://example.cypress.io/utilities'); + }); it('Cypress._ - call a lodash method', () => { // https://on.cypress.io/_ - cy.request('https://jsonplaceholder.cypress.io/users') - .then((response) => { - let ids = Cypress._.chain(response.body).map('id').take(3).value() + cy.request('https://jsonplaceholder.cypress.io/users').then((response) => { + let ids = Cypress._.chain(response.body).map('id').take(3).value(); - expect(ids).to.deep.eq([1, 2, 3]) - }) - }) + expect(ids).to.deep.eq([1, 2, 3]); + }); + }); it('Cypress.$ - call a jQuery method', () => { // https://on.cypress.io/$ - let $li = Cypress.$('.utility-jquery li:first') + let $li = Cypress.$('.utility-jquery li:first'); cy.wrap($li) .should('not.have.class', 'active') .click() - .should('have.class', 'active') - }) + .should('have.class', 'active'); + }); it('Cypress.Blob - blob utilities and base64 string conversion', () => { // https://on.cypress.io/blob cy.get('.utility-blob').then(($div) => { // https://github.com/nolanlawson/blob-util#imgSrcToDataURL // get the dataUrl string for the javascript-logo - return Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous') - .then((dataUrl) => { + return Cypress.Blob.imgSrcToDataURL( + 'https://example.cypress.io/assets/img/javascript-logo.png', + undefined, + 'anonymous' + ).then((dataUrl) => { // create an element and set its src to the dataUrl - let img = Cypress.$('', { src: dataUrl }) + let img = Cypress.$('', { src: dataUrl }); // need to explicitly return cy here since we are initially returning // the Cypress.Blob.imgSrcToDataURL promise to our test // append the image - $div.append(img) + $div.append(img); - cy.get('.utility-blob img').click() - .should('have.attr', 'src', dataUrl) - }) - }) - }) + cy.get('.utility-blob img').click().should('have.attr', 'src', dataUrl); + }); + }); + }); it('Cypress.minimatch - test out glob patterns against strings', () => { // https://on.cypress.io/minimatch let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', { matchBase: true, - }) + }); - expect(matching, 'matching wildcard').to.be.true + expect(matching, 'matching wildcard').to.be.true; matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', { matchBase: true, - }) + }); - expect(matching, 'comments').to.be.false + expect(matching, 'comments').to.be.false; // ** matches against all downstream path segments matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', { matchBase: true, - }) + }); - expect(matching, 'comments').to.be.true + expect(matching, 'comments').to.be.true; // whereas * matches only the next path segment matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', { matchBase: false, - }) + }); - expect(matching, 'comments').to.be.false - }) + expect(matching, 'comments').to.be.false; + }); it('Cypress.Promise - instantiate a bluebird promise', () => { // https://on.cypress.io/promise - let waited = false + let waited = false; /** * @return Bluebird */ - function waitOneSecond () { + function waitOneSecond() { // return a promise that resolves after 1 second // @ts-ignore TS2351 (new Cypress.Promise) return new Cypress.Promise((resolve, reject) => { setTimeout(() => { // set waited to true - waited = true + waited = true; // resolve with 'foo' string - resolve('foo') - }, 1000) - }) + resolve('foo'); + }, 1000); + }); } cy.then(() => { @@ -102,9 +103,9 @@ context('Utilities', () => { // is awaited until it resolves // @ts-ignore TS7006 return waitOneSecond().then((str) => { - expect(str).to.eq('foo') - expect(waited).to.be.true - }) - }) - }) -}) + expect(str).to.eq('foo'); + expect(waited).to.be.true; + }); + }); + }); +}); diff --git a/cypress/integration/examples/viewport.spec.js b/cypress/integration/examples/viewport.spec.js index dbcd7ee..21293a3 100644 --- a/cypress/integration/examples/viewport.spec.js +++ b/cypress/integration/examples/viewport.spec.js @@ -2,22 +2,22 @@ context('Viewport', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/viewport') - }) + cy.visit('https://example.cypress.io/commands/viewport'); + }); it('cy.viewport() - set the viewport size and dimension', () => { // https://on.cypress.io/viewport - cy.get('#navbar').should('be.visible') - cy.viewport(320, 480) + cy.get('#navbar').should('be.visible'); + cy.viewport(320, 480); // the navbar should have collapse since our screen is smaller - cy.get('#navbar').should('not.be.visible') - cy.get('.navbar-toggle').should('be.visible').click() - cy.get('.nav').find('a').should('be.visible') + cy.get('#navbar').should('not.be.visible'); + cy.get('.navbar-toggle').should('be.visible').click(); + cy.get('.nav').find('a').should('be.visible'); // lets see what our app looks like on a super large screen - cy.viewport(2999, 2999) + cy.viewport(2999, 2999); // cy.viewport() accepts a set of preset sizes // to easily set the screen to a device's width and height @@ -25,35 +25,35 @@ context('Viewport', () => { // We added a cy.wait() between each viewport change so you can see // the change otherwise it is a little too fast to see :) - cy.viewport('macbook-15') - cy.wait(200) - cy.viewport('macbook-13') - cy.wait(200) - cy.viewport('macbook-11') - cy.wait(200) - cy.viewport('ipad-2') - cy.wait(200) - cy.viewport('ipad-mini') - cy.wait(200) - cy.viewport('iphone-6+') - cy.wait(200) - cy.viewport('iphone-6') - cy.wait(200) - cy.viewport('iphone-5') - cy.wait(200) - cy.viewport('iphone-4') - cy.wait(200) - cy.viewport('iphone-3') - cy.wait(200) + cy.viewport('macbook-15'); + cy.wait(200); + cy.viewport('macbook-13'); + cy.wait(200); + cy.viewport('macbook-11'); + cy.wait(200); + cy.viewport('ipad-2'); + cy.wait(200); + cy.viewport('ipad-mini'); + cy.wait(200); + cy.viewport('iphone-6+'); + cy.wait(200); + cy.viewport('iphone-6'); + cy.wait(200); + cy.viewport('iphone-5'); + cy.wait(200); + cy.viewport('iphone-4'); + cy.wait(200); + cy.viewport('iphone-3'); + cy.wait(200); // cy.viewport() accepts an orientation for all presets // the default orientation is 'portrait' - cy.viewport('ipad-2', 'portrait') - cy.wait(200) - cy.viewport('iphone-4', 'landscape') - cy.wait(200) + cy.viewport('ipad-2', 'portrait'); + cy.wait(200); + cy.viewport('iphone-4', 'landscape'); + cy.wait(200); // The viewport will be reset back to the default dimensions // in between tests (the default can be set in cypress.json) - }) -}) + }); +}); diff --git a/cypress/integration/examples/waiting.spec.js b/cypress/integration/examples/waiting.spec.js index c8f0d7c..6f45dc1 100644 --- a/cypress/integration/examples/waiting.spec.js +++ b/cypress/integration/examples/waiting.spec.js @@ -2,30 +2,32 @@ context('Waiting', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/waiting') - }) + cy.visit('https://example.cypress.io/commands/waiting'); + }); // BE CAREFUL of adding unnecessary wait times. // https://on.cypress.io/best-practices#Unnecessary-Waiting // https://on.cypress.io/wait it('cy.wait() - wait for a specific amount of time', () => { - cy.get('.wait-input1').type('Wait 1000ms after typing') - cy.wait(1000) - cy.get('.wait-input2').type('Wait 1000ms after typing') - cy.wait(1000) - cy.get('.wait-input3').type('Wait 1000ms after typing') - cy.wait(1000) - }) + cy.get('.wait-input1').type('Wait 1000ms after typing'); + cy.wait(1000); + cy.get('.wait-input2').type('Wait 1000ms after typing'); + cy.wait(1000); + cy.get('.wait-input3').type('Wait 1000ms after typing'); + cy.wait(1000); + }); it('cy.wait() - wait for a specific route', () => { // Listen to GET to comments/1 - cy.intercept('GET', '**/comments/*').as('getComment') + cy.intercept('GET', '**/comments/*').as('getComment'); // we have code that gets a comment when // the button is clicked in scripts.js - cy.get('.network-btn').click() + cy.get('.network-btn').click(); // wait for GET comments/1 - cy.wait('@getComment').its('response.statusCode').should('be.oneOf', [200, 304]) - }) -}) + cy.wait('@getComment') + .its('response.statusCode') + .should('be.oneOf', [200, 304]); + }); +}); diff --git a/cypress/integration/examples/window.spec.js b/cypress/integration/examples/window.spec.js index f94b649..2deea94 100644 --- a/cypress/integration/examples/window.spec.js +++ b/cypress/integration/examples/window.spec.js @@ -2,21 +2,21 @@ context('Window', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/window') - }) + cy.visit('https://example.cypress.io/commands/window'); + }); it('cy.window() - get the global window object', () => { // https://on.cypress.io/window - cy.window().should('have.property', 'top') - }) + cy.window().should('have.property', 'top'); + }); it('cy.document() - get the document object', () => { // https://on.cypress.io/document - cy.document().should('have.property', 'charset').and('eq', 'UTF-8') - }) + cy.document().should('have.property', 'charset').and('eq', 'UTF-8'); + }); it('cy.title() - get the title', () => { // https://on.cypress.io/title - cy.title().should('include', 'Kitchen Sink') - }) -}) + cy.title().should('include', 'Kitchen Sink'); + }); +}); diff --git a/cypress/integration/sample.spec.js b/cypress/integration/sample.spec.js new file mode 100644 index 0000000..14e6bec --- /dev/null +++ b/cypress/integration/sample.spec.js @@ -0,0 +1,20 @@ +describe('Example', () => { + it('cypress working', () => { + expect(true).to.equal(true); + }); + + it('successfully redirects to main', () => { + cy.intercept('POST', 'http://localhost:3001/tracks', { + fixture: 'tracks.json', + }).as('getTracks'); + + cy.intercept('POST', 'http://localhost:3001/artists', { + fixture: 'artists.json', + }).as('getArtists'); + + //INSERT YOUR LOCAL URL TO /MAIN AS A STRING, WITH THE CODE AND EVERYTHING!!! + cy.visit(); + + cy.wait(['@getTracks', '@getArtists']); + }); +}); diff --git a/server/config.ts b/server/config.ts index f0fd489..ca5dc2c 100644 --- a/server/config.ts +++ b/server/config.ts @@ -1,4 +1,4 @@ export default { - clientID: '8bc6f1323c3a4081bc3416b632218513', - clientSecret: '4b9d61d555b74a24b703e09978dc5f23', + clientID: 'd49ee10b034843b1aabd579ac1901e42', + clientSecret: '04414237048a48518f44be66ede1c734', }; diff --git a/server/controller/controller-helpers.js b/server/controller/controller-helpers.js index ceac894..709bcb3 100644 --- a/server/controller/controller-helpers.js +++ b/server/controller/controller-helpers.js @@ -1,26 +1,50 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } +'use strict'; +var __awaiter = + (this && this.__awaiter) || + function (thisArg, _arguments, P, generator) { + function adopt(value) { + return value instanceof P + ? value + : new P(function (resolve) { + resolve(value); + }); + } return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); + function fulfilled(value) { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + } + function rejected(value) { + try { + step(generator['throw'](value)); + } catch (e) { + reject(e); + } + } + function step(result) { + result.done + ? resolve(result.value) + : adopt(result.value).then(fulfilled, rejected); + } + step((generator = generator.apply(thisArg, _arguments || [])).next()); }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); + }; +Object.defineProperty(exports, '__esModule', { value: true }); exports.requestWhileQueued = void 0; -const requestWhileQueued = (initialQueue, limit, handler) => __awaiter(void 0, void 0, void 0, function* () { +const requestWhileQueued = (initialQueue, limit, handler) => + __awaiter(void 0, void 0, void 0, function* () { let queueArr = initialQueue.slice(); while (queueArr.length > 0) { - if (queueArr.length < limit) { - yield handler(queueArr); - queueArr = []; - } - else { - let tracksToQuery = queueArr.splice(0, limit); - yield handler(tracksToQuery); - } + if (queueArr.length < limit) { + yield handler(queueArr); + queueArr = []; + } else { + let tracksToQuery = queueArr.splice(0, limit); + yield handler(tracksToQuery); + } } -}); + }); exports.requestWhileQueued = requestWhileQueued; diff --git a/server/controller/controller.js b/server/controller/controller.js index 6096203..e4d897b 100644 --- a/server/controller/controller.js +++ b/server/controller/controller.js @@ -1,131 +1,183 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } +'use strict'; +var __awaiter = + (this && this.__awaiter) || + function (thisArg, _arguments, P, generator) { + function adopt(value) { + return value instanceof P + ? value + : new P(function (resolve) { + resolve(value); + }); + } return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); + function fulfilled(value) { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + } + function rejected(value) { + try { + step(generator['throw'](value)); + } catch (e) { + reject(e); + } + } + function step(result) { + result.done + ? resolve(result.value) + : adopt(result.value).then(fulfilled, rejected); + } + step((generator = generator.apply(thisArg, _arguments || [])).next()); }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); + }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, '__esModule', { value: true }); exports.createPlaylist = exports.getPlaylistCover = exports.getArtists = exports.getTracks = exports.getTokens = void 0; -const modeller_1 = __importDefault(require("../modeller/modeller")); -const controller_helpers_1 = require("./controller-helpers"); -const baseUrl = "https://api.spotify.com/v1"; -const spotifyTracksUrl = baseUrl + "/me/tracks"; -const spotifyArtistsUrl = baseUrl + "/me/following"; -const spotifyUserUrl = baseUrl + "/me"; -const spotifyCreatePlaylistUrl = baseUrl + "/users"; -const spotifyPlaylistUrl = baseUrl + "/playlists"; +const modeller_1 = __importDefault(require('../modeller/modeller')); +const controller_helpers_1 = require('./controller-helpers'); +const baseUrl = 'https://api.spotify.com/v1'; +const spotifyTracksUrl = baseUrl + '/me/tracks'; +const spotifyArtistsUrl = baseUrl + '/me/following'; +const spotifyUserUrl = baseUrl + '/me'; +const spotifyCreatePlaylistUrl = baseUrl + '/users'; +const spotifyPlaylistUrl = baseUrl + '/playlists'; const saveTrackRequestLimit = 100; // max number of tracks allowed in a single "save tracks to playlist" request in spotify const offsetIncrement = 50; // max number of tracks allowed in a single "get saved tracks" request in spotify const msBetweenTrackRequests = 250; // TODO: TOKEN TO BE PER USER SESSION RATHER THAN ONE FOR THE WHOLE SERVER: GET USER ID AFTER RECEIVING AUTH TOKEN, SAVE AS ID TOKEN PAIR, SEND BACK USER ID TO CLIENT FOR USE IN SUBSEQUENT REQUESTS -let tokens = ""; +let tokens = ''; // TODO: CHECK ERROR HANDLING IN CATCH METHODS // CREATE CUSTOM HANDLER MIDDLEWARE // TODO: REFACTOR AXIOS REQUESTS INTO MODELLER // TODO: separate gettokens/checktokens part as a middleware to be passed through in each request -const getTokens = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const getTokens = (req, res, next) => + __awaiter(void 0, void 0, void 0, function* () { const { code } = req.body; tokens = yield modeller_1.default.requestToken(code, next); res.sendStatus(200); -}); + }); exports.getTokens = getTokens; -const getTracks = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const getTracks = (req, res, next) => + __awaiter(void 0, void 0, void 0, function* () { const { code } = req.body; let initialOffset = 0; let trackData = []; if (!tokens) { - tokens = yield modeller_1.default.requestToken(code, next); + tokens = yield modeller_1.default.requestToken(code, next); } function timeOutPromise() { - return new Promise((resolve) => setTimeout(() => resolve(), msBetweenTrackRequests)); + return new Promise((resolve) => + setTimeout(() => resolve(), msBetweenTrackRequests) + ); } function fetchTracksAsync(offset) { - return __awaiter(this, void 0, void 0, function* () { - let trackBufferResponse; - try { - trackBufferResponse = yield modeller_1.default.requestTracks(spotifyTracksUrl, tokens, offset); - } - catch (err) { - console.log("inner error 😎"); - console.log(err.response.status); // 404 - if (err.response.status === 404) { - yield timeOutPromise(); - yield fetchTracksAsync(offset); - return; - } - } - trackData = [...trackData, ...trackBufferResponse.data.items]; - console.log("received tracks for offset:", offset); - if (trackBufferResponse.data.next) { - offset += offsetIncrement; - yield fetchTracksAsync(offset); - } - }); + return __awaiter(this, void 0, void 0, function* () { + let trackBufferResponse; + try { + trackBufferResponse = yield modeller_1.default.requestTracks( + spotifyTracksUrl, + tokens, + offset + ); + } catch (err) { + console.log('inner error 😎'); + console.log(err.response.status); // 404 + if (err.response.status === 404) { + yield timeOutPromise(); + yield fetchTracksAsync(offset); + return; + } + } + trackData = [...trackData, ...trackBufferResponse.data.items]; + console.log('received tracks for offset:', offset); + if (trackBufferResponse.data.next) { + offset += offsetIncrement; + yield fetchTracksAsync(offset); + } + }); } try { - yield fetchTracksAsync(initialOffset); - console.log("sending " + trackData.length + " tracks"); - res.status(200); - res.send(trackData); - } - catch (err) { - console.log("outer error 😎"); - console.log("something went wrong while fetching tracks"); - console.log(err); - res.sendStatus(500); + yield fetchTracksAsync(initialOffset); + console.log('sending ' + trackData.length + ' tracks'); + res.status(200); + res.send(trackData); + } catch (err) { + console.log('outer error 😎'); + console.log('something went wrong while fetching tracks'); + console.log(err); + res.sendStatus(500); } -}); + }); exports.getTracks = getTracks; -const getArtists = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const getArtists = (req, res, next) => + __awaiter(void 0, void 0, void 0, function* () { const { code, offset, nextUrl } = req.body; if (!tokens) { - tokens = yield modeller_1.default.requestToken(code, next); + tokens = yield modeller_1.default.requestToken(code, next); } modeller_1.default - .requestArtists(spotifyArtistsUrl, nextUrl, tokens) - .then((artistResponse) => { + .requestArtists(spotifyArtistsUrl, nextUrl, tokens) + .then((artistResponse) => { res.statusCode = 200; res.send(artistResponse.data); - }) - .catch((err) => console.log(err.response.data)); -}); + }) + .catch((err) => console.log(err.response.data)); + }); exports.getArtists = getArtists; -const getPlaylistCover = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const getPlaylistCover = (req, res, next) => + __awaiter(void 0, void 0, void 0, function* () { const { code, playlistId } = req.body; if (!tokens) { - tokens = yield modeller_1.default.requestToken(code, next); + tokens = yield modeller_1.default.requestToken(code, next); } modeller_1.default - .requestPlaylistCover(spotifyPlaylistUrl, playlistId, tokens) - .then((coverResponse) => { + .requestPlaylistCover(spotifyPlaylistUrl, playlistId, tokens) + .then((coverResponse) => { res.statusCode = 200; console.log(coverResponse); res.send(coverResponse.data); - }) - .catch((err) => console.log(err.response.data)); -}); + }) + .catch((err) => console.log(err.response.data)); + }); exports.getPlaylistCover = getPlaylistCover; -const createPlaylist = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { +const createPlaylist = (req, res, next) => + __awaiter(void 0, void 0, void 0, function* () { const { code, playlistName, trackURIs } = req.body; if (!tokens) { - tokens = yield modeller_1.default.requestToken(code, next); + tokens = yield modeller_1.default.requestToken(code, next); } - const userResponse = yield modeller_1.default.requestUser(spotifyUserUrl, tokens); + const userResponse = yield modeller_1.default.requestUser( + spotifyUserUrl, + tokens + ); const userID = userResponse.data.id; - const createPlaylistResponse = yield modeller_1.default.requestCreatePlaylist(spotifyCreatePlaylistUrl, playlistName, userID, tokens); + const createPlaylistResponse = yield modeller_1.default.requestCreatePlaylist( + spotifyCreatePlaylistUrl, + playlistName, + userID, + tokens + ); const playlistData = createPlaylistResponse.data; function addTracks(trackArr) { - return modeller_1.default.requestAddTracks(spotifyPlaylistUrl, playlistData.id, trackArr, tokens); + return modeller_1.default.requestAddTracks( + spotifyPlaylistUrl, + playlistData.id, + trackArr, + tokens + ); } // Spotify has a track limit per request, so below we check if multiple requests are necessary (TrackQueue is all the tracks to be added in a queue form, with multiple tracks "shifting" per request.) - controller_helpers_1.requestWhileQueued(trackURIs, saveTrackRequestLimit, addTracks); + controller_helpers_1.requestWhileQueued( + trackURIs, + saveTrackRequestLimit, + addTracks + ); res.status(200); res.send(JSON.stringify(playlistData)); -}); + }); exports.createPlaylist = createPlaylist; diff --git a/server/modeller/modeller.js b/server/modeller/modeller.js index d4aaf70..ad37d67 100644 --- a/server/modeller/modeller.js +++ b/server/modeller/modeller.js @@ -1,100 +1,112 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const axios_1 = __importDefault(require("axios")); -const config_1 = __importDefault(require("../config")); -const spotifyTokenUrl = "https://accounts.spotify.com/api/token"; -const redirectUri = "http://localhost:3000/main"; +'use strict'; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +const axios_1 = __importDefault(require('axios')); +const config_1 = __importDefault(require('../config')); +const spotifyTokenUrl = 'https://accounts.spotify.com/api/token'; +const redirectUri = 'http://localhost:3000/main'; // TODO: REFACTOR WITH A REQUEST TEMPLATE const requestToken = (code, next) => { - return axios_1.default - .request({ - method: "POST", - url: spotifyTokenUrl, - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.default.clientID}&client_secret=${config_1.default.clientSecret}`, + return axios_1.default + .request({ + method: 'POST', + url: spotifyTokenUrl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + data: `grant_type=authorization_code&code=${code}&redirect_uri=${redirectUri}&client_id=${config_1.default.clientID}&client_secret=${config_1.default.clientSecret}`, }) - .then((tokenResponse) => { - return tokenResponse.data; + .then((tokenResponse) => { + return tokenResponse.data; }) - .catch(next); + .catch(next); }; const requestTracks = (spotifyTracksUrl, tokens, offset) => { - return axios_1.default.request({ - method: "GET", - url: spotifyTracksUrl + `?offset=${offset}&limit=50`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/x-www-form-urlencoded", - }, - }); + return axios_1.default.request({ + method: 'GET', + url: spotifyTracksUrl + `?offset=${offset}&limit=50`, + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }); }; const requestArtists = (spotifyArtistsUrl, nextUrl, tokens) => { - return axios_1.default.request({ - method: "GET", - url: nextUrl || spotifyArtistsUrl + "?type=artist&limit=50", - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - }); + return axios_1.default.request({ + method: 'GET', + url: nextUrl || spotifyArtistsUrl + '?type=artist&limit=50', + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }); }; const requestUser = (spotifyUserUrl, tokens) => { - return axios_1.default.request({ - method: "GET", - url: spotifyUserUrl, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/x-www-form-urlencoded", - }, - }); + return axios_1.default.request({ + method: 'GET', + url: spotifyUserUrl, + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }); }; const requestPlaylistCover = (spotifyPlaylistUrl, playlistId, tokens) => { - return axios_1.default.request({ - method: "GET", - url: spotifyPlaylistUrl + `/${playlistId}/images`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - Accept: "application/json", - }, - }); + return axios_1.default.request({ + method: 'GET', + url: spotifyPlaylistUrl + `/${playlistId}/images`, + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }); }; -const requestCreatePlaylist = (spotifyCreatePlaylistUrl, playlistName, userID, tokens) => { - return axios_1.default.request({ - method: "POST", - url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - }, - data: { name: playlistName }, - }); +const requestCreatePlaylist = ( + spotifyCreatePlaylistUrl, + playlistName, + userID, + tokens +) => { + return axios_1.default.request({ + method: 'POST', + url: spotifyCreatePlaylistUrl + `/${userID}/playlists`, + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', + }, + data: { name: playlistName }, + }); }; -const requestAddTracks = (spotifySaveTracksUrl, playlistID, trackArr, tokens) => { - return axios_1.default.request({ - method: "POST", - url: spotifySaveTracksUrl + `/${playlistID}/tracks`, - headers: { - Authorization: `Bearer ${tokens["access_token"]}`, - "Content-Type": "application/json", - }, - data: { - uris: trackArr, - }, - }); +const requestAddTracks = ( + spotifySaveTracksUrl, + playlistID, + trackArr, + tokens +) => { + return axios_1.default.request({ + method: 'POST', + url: spotifySaveTracksUrl + `/${playlistID}/tracks`, + headers: { + Authorization: `Bearer ${tokens['access_token']}`, + 'Content-Type': 'application/json', + }, + data: { + uris: trackArr, + }, + }); }; exports.default = { - requestToken, - requestTracks, - requestArtists, - requestUser, - requestPlaylistCover, - requestCreatePlaylist, - requestAddTracks, + requestToken, + requestTracks, + requestArtists, + requestUser, + requestPlaylistCover, + requestCreatePlaylist, + requestAddTracks, }; diff --git a/server/router.js b/server/router.js index 2d06f51..4f66a7d 100644 --- a/server/router.js +++ b/server/router.js @@ -1,11 +1,11 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const express_1 = require("express"); +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +const express_1 = require('express'); const router = express_1.Router(); -const controller_1 = require("./controller/controller"); -router.post("/tracks", controller_1.getTracks); -router.post("/tokens", controller_1.getTokens); -router.post("/artists", controller_1.getArtists); -router.post("/create", controller_1.createPlaylist); -router.post("/cover", controller_1.getPlaylistCover); +const controller_1 = require('./controller/controller'); +router.post('/tracks', controller_1.getTracks); +router.post('/tokens', controller_1.getTokens); +router.post('/artists', controller_1.getArtists); +router.post('/create', controller_1.createPlaylist); +router.post('/cover', controller_1.getPlaylistCover); exports.default = router; From 7c7a2a33317115dcf53f2bfd8103a966bee12575 Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Sat, 3 Apr 2021 10:03:43 +0100 Subject: [PATCH 41/46] Update README.md --- README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index cb4eabf..9f0bc3c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ # Listspotter -Pamela and Gero - -## TODO -1. Implement testing -2. Implement TS on backend -3. Set up JWT for multiple users - -## GIT WORKFLOW -- CREATING NEW BRANCH: git checkout -b branch_name branched_off_name -- PUSHING TO NEW BRANCH UPSTREAM: git push -u origin branch_name -- NAVIGATING TO EXISTING BRANCH: git checkout branch_name -- BEFORE YOU PUSH, PULL FROM: git pull origin branch_name. THEN: git push origin branch_name +Web app that creates playlists from your saved songs in Spotify using intuitive genre filters. + +# UI +![Screenshot 2021-04-03 at 09 57 36](https://user-images.githubusercontent.com/59074533/113473692-07e42f00-9463-11eb-9e94-21bb5db26f5f.png) + +# Contributors ✨ + +Github's and LinkedIn's linked below! + + + + + + +

Pamela Chen
💻 ⚠️ 🚧

Gero Kassing
💻 ⚠️ 🚧
From 9c170176e17428dbbcc36c5b7f634bea6b7be4cb Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Sat, 3 Apr 2021 10:05:07 +0100 Subject: [PATCH 42/46] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9f0bc3c..fd4f623 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Web app that creates playlists from your saved songs in Spotify using intuitive # Contributors ✨ Github's and LinkedIn's linked below! +Original project credits go to [Mert Ascioglu](https://github.com/ascolm) From 14dc1fc46a068ebb9d5456785f15c571b4153bdc Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Sat, 3 Apr 2021 10:07:09 +0100 Subject: [PATCH 43/46] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index fd4f623..6df7362 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ Web app that creates playlists from your saved songs in Spotify using intuitive # UI ![Screenshot 2021-04-03 at 09 57 36](https://user-images.githubusercontent.com/59074533/113473692-07e42f00-9463-11eb-9e94-21bb5db26f5f.png) +# Teck Stack + +- [Jest](https://jestjs.io/) +- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) +- [Cypress](https://www.cypress.io/) +- [TypeScript](https://www.typescriptlang.org/) + # Contributors ✨ Github's and LinkedIn's linked below! From a980fc4110a69b90cfa5dd4af5f00d171fa6ee7d Mon Sep 17 00:00:00 2001 From: Gero Kassing Date: Sat, 3 Apr 2021 10:16:28 +0100 Subject: [PATCH 44/46] style(readme.md): update README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6df7362..6e07a82 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ Web app that creates playlists from your saved songs in Spotify using intuitive # Contributors ✨ -Github's and LinkedIn's linked below! +Github's and LinkedIn's linked below! ([emoji key](https://allcontributors.org/docs/en/emoji-key)) + Original project credits go to [Mert Ascioglu](https://github.com/ascolm)
From 6e5356310ecfc41b22f3398c85189f835d49e035 Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Sat, 3 Apr 2021 14:27:08 +0100 Subject: [PATCH 45/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e07a82..5fd965c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Original project credits go to [Mert Ascioglu](https://github.com/ascolm)
- +

Pamela Chen
💻 ⚠️ 🚧

Pamela Chen
💻 ⚠️ 🚧

Gero Kassing
💻 ⚠️ 🚧
From 0b525b4ed7f239b10a5108375c46288b447e7d33 Mon Sep 17 00:00:00 2001 From: Pamela Chen Date: Mon, 5 Apr 2021 12:30:17 +0100 Subject: [PATCH 46/46] fix: update readme with install guide --- README.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5fd965c..ba318b2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,73 @@ # Listspotter -Web app that creates playlists from your saved songs in Spotify using intuitive genre filters. -# UI -![Screenshot 2021-04-03 at 09 57 36](https://user-images.githubusercontent.com/59074533/113473692-07e42f00-9463-11eb-9e94-21bb5db26f5f.png) +Listspotter is an application that lets users create genre based playlists of tracks they have saved in their Spotify accounts.
+With Listspotter it is quick and easy to have a coherent playlist out of the songs you already like, in just a few minutes. + +## Screenshots + +![listspotterSS3](https://user-images.githubusercontent.com/65975591/113475350-5c90a580-9475-11eb-9407-3982e427a6ba.png) + +![listspotterSS4](https://user-images.githubusercontent.com/65975591/113475359-674b3a80-9475-11eb-8140-c23d0e5996e9.png) + +![listspotterSS5](https://user-images.githubusercontent.com/65975591/113475362-6c0fee80-9475-11eb-981a-da925b7308ef.png) + +## + +## Getting Started + +Listspotter uses Spotify Web API and as such, you will need to register your app in Spotify's Dashboard [here.](https://developer.spotify.com/dashboard/login) After registration you should have a client ID, a client secret and have your redirect URL entered in project settings (the URL that Spotify will redirect your user to after login - default would be the port used by your local React app) In case needed, you can find additional information [here.](https://developer.spotify.com/documentation/general/guides/authorization-guide/) Note that this project uses Authorization Code Flow. + +After you register with Spotify, follow these steps below to get started: + +1. Clone the repo + +``` +git clone https://github.com/ascolm/listspotter.git +cd listspotter +``` + +2. Install dependencies + +``` +npm install +``` + +3. Directly under the "server" folder, add a config.js file that exports your client ID, client secret key, redirect uri and Spotify's token link (make sure you ignore this file on git!!). + +``` +module.exports = { + clientID: // YOUR CLIENT ID HERE, + clientSecret: // YOUR CLIENT SECRET HERE, + redirectUri: // YOUR REDIRECT URI HERE, + spotifyTokenUrl: 'https://accounts.spotify.com/api/token' +}; +``` + +4. Under "src" folder in your client, add a config.js file that exports your client ID, redirect uri and server url(ignore this file on Git too). + +``` +module.exports = { + clientId: // YOUR CLIENT ID HERE, + redirectUri: // YOUR REDIRECT URI, + serverBaseUrl: // SERVER URL HERE, ex: 'http://localhost:3001' +}; +``` + +5. You can run your server using nodemon to watch for changes: + +``` +cd server +nodemon +``` + +6. Navigate to client folder and launch the React app: + +``` +cd ../client +npm start +``` + +## # Teck Stack