-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathmain.js
More file actions
98 lines (81 loc) · 2.98 KB
/
main.js
File metadata and controls
98 lines (81 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Illustrates how to use Spotify's audio analysis web API to fetch the audio
// analysis for a Spotify track. See ./README.md for details.
//
import fsPromises from 'fs/promises';
import fetch from 'node-fetch';
import { pp, readFileIfExists } from './util.js';
import path from 'path';
import { fileURLToPath } from 'url';
// For help in getting these, see https://developer.spotify.com/documentation/web-api/tutorials/getting-started
import { clientId, clientSecret } from './creds/spotify.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
class SpotifyError extends Error {
constructor(message, details) {
super(message);
this.details = details;
}
}
const spotifyAccessTokenPath = path.join(__dirname, './creds/spotifyAccessToken.json');
async function getSpotifyAccessToken() {
const content = await readFileIfExists(spotifyAccessTokenPath, { encoding: 'utf8' });
if (content) {
return JSON.parse(content).access_token;
}
const tokenObj = await fetchAccessToken();
await fsPromises.writeFile(spotifyAccessTokenPath, pp(tokenObj), { encoding: 'utf8' });
return tokenObj.access_token;
}
async function clearSpotifyAccessToken() {
await fsPromises.rm(spotifyAccessTokenPath, { force: true });
}
async function fetchSpotifyJson(url, init=undefined) {
const response = await fetch(url, init);
const json = await response.json();
if (json.error) {
throw new SpotifyError('fetchSpotifyJson error: ' + pp(json), json.error);
} else {
return json;
}
}
function fetchAccessToken() {
return fetchSpotifyJson('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: [
'grant_type=client_credentials',
'client_id=' + clientId,
'client_secret=' + clientSecret,
].join('&'),
});
}
function fetchAudioAnalysis(spotifyAccessToken, spotifyTrackId) {
return fetchSpotifyJson('https://api.spotify.com/v1/audio-analysis/' + encodeURIComponent(spotifyTrackId), {
headers: {
'Authorization': 'Bearer ' + spotifyAccessToken,
}
});
}
async function main(args) {
if (args.length !== 2) {
console.log('Usage: node main.js <spotify-track-id> <spotify-analysis-output.json>');
return;
}
const [spotifyTrackId, spotifyAnalysisPath] = args;
const spotifyAccessToken = await getSpotifyAccessToken();
try {
const audioAnalysis = await fetchAudioAnalysis(spotifyAccessToken, spotifyTrackId);
await fsPromises.writeFile(spotifyAnalysisPath, pp(audioAnalysis), { encoding: 'utf8' });
} catch (error) {
if (error instanceof SpotifyError && error.details?.status === 401) {
// 401 Unauthorized error. Likely access token expired. Clear the old one.
await clearSpotifyAccessToken();
console.error('It looks like the Spotify access token expired. Try running the program again. A new one will be fetched.');
} else {
throw error;
}
}
}
main(process.argv.slice(2));