我实现了! P>
下面是来自https://github.com/pavelkomarov/exportify/blob/master/exportify.js 的函数,它可以进行所有必要的 API 查询。我的apiCall 函数也在那个文件中。它的使用fetch P>
- 首先,我从播放列表中发出请求,请求歌曲块。
- 然后我将这些消息聚合到一个数据表和一组艺术家中。
- 然后我使用艺术家集合来查询流派信息。
- 然后我将其加入数据并写入 csv。
因为这一切都发生在网络上,所以每个新步骤都必须包含在 .then() 中,这取决于之前的对象是否得到解决。值得庆幸的是,近年来 JavaScript 在这方面变得更加优雅。 https://eloquentjavascript.net/11_async.html
实时应用程序生活在here。我还创建了a notebook 来分析输出。
csvData(access_token, playlist) {
// Make asynchronous API calls for 100 songs at a time, and put the results (all Promises) in a list.
let requests = [];
for (let offset = 0; offset < playlist.tracks.total; offset = offset + 100) {
requests.push(utils.apiCall(playlist.tracks.href.split('?')[0] + '?offset=' + offset + '&limit=100',
access_token));
}
// "returns a single Promise that resolves when all of the promises passed as an iterable have resolved"
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
let artist_hrefs = new Set();
let data_promise = Promise.all(requests).then(responses => {
return responses.map(response => { // apply to all responses
return response.items.map(song => { // appy to all songs in each response
song.track.artists.forEach(a => { artist_hrefs.add(a.href) });
return [song.track.uri, '"'+song.track.name.replace(/"/g,'')+'"', '"'+song.track.album.name.replace(/"/g,'')+'"',
song.track.duration_ms, song.track.popularity, song.track.album.release_date,
'"'+song.track.artists.map(artist => { return artist.name }).join(',')+'"',
song.added_by.uri, song.added_at]
});
});
});
// Make queries on all the artists, because this json is where genre information lives. Unfortunately this
// means a second wave of traffic.
let genre_promise = data_promise.then(() => {
let artists_promises = Array.from(artist_hrefs).map(href => utils.apiCall(href, access_token));
return Promise.all(artists_promises).then(responses => {
let artist_genres = {};
responses.forEach(artist => { artist_genres[artist.name] = artist.genres.join(','); });
return artist_genres;
});
});
// join genres to the table, label the columns, and put all data in a single csv string
return Promise.all([data_promise, genre_promise]).then(values => {
[data, artist_genres] = values;
data = data.flat();
data.forEach(row => {
artists = row[6].substring(1, row[6].length-1).split(','); // strip the quotes
deduplicated_genres = new Set(artists.map(a => artist_genres[a]).join(",").split(",")); // join and split and take set
row.push('"'+Array.from(deduplicated_genres).filter(x => x != "").join(",")+'"'); // remove empty strings
});
data.unshift(["Spotify URI", "Track Name", "Album Name", "Duration (ms)",
"Popularity", "Release Date", "Artist Name(s)", "Added By", "Added At", "Genres"]);
csv = '';
data.forEach(row => { csv += row.join(",") + "\n" });
return csv;
});
},