Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pick an event listener that will let me wait until async.times is finished to run a function

I'm using a node.js server, the Spotify API, and the spotify-web-api-js node module to create a web application where the user can enter an artist's name, see a list of songs from related artists, and then optionally save that playlist to their own Spotify account. However, i'm still having trouble with the last step.

My user authorization flow is happening first:

if (params.access_token) {

    s.setAccessToken(params.access_token);

    s.getMe().then(function(data) {

      console.log(data);
      console.log(data.id);
      user_id = data.id;

Below it is where the the actual details of the songs are gathered by the API. Although it is lower down, it occurs first and the user authorization only happens if the user clicks a second button on that page.

async.times(counter, function(n, next){
        s.getArtistTopTracks(relatedArtists[n].id, "US", function (err, data2) {
          relatedArtists[n].song = data2.tracks[0].name;
          relatedArtists[n].uri = data2.tracks[0].uri;
          console.log(relatedArtists[n].uri);
          // make sure to put the access token here add song to playlist
          // create array
          song_uris.push(relatedArtists[n].uri);
          console.log(song_uris);

          // song_uris = relatedArtists[n].uri;
          //
          // console.log(song_uris);

          next(null);

      $("#playlist").load(function() {
            s.addTracksToPlaylist(user_id, playlist_id, song_uris);
          });
        });


      }, function(err) {
        // console.table(relatedArtists);

        for (k = 0; k < 20; k++)
        {
          $('#related-artist').append('<p><strong>' + relatedArtists[k].name + '</strong> -- \"' + relatedArtists[k].song + '\"</p>');


        }

(JSBin of full code here, though it might not work because I use browserify on my own server)

Right now, on line 114 I have song_uris.push(relatedArtists[n].uri); pushing the contents into an array, using async.times. Since this is below where I create the playlist on line 66, it shows as an empty array:

 s.createPlaylist(user_id, {name: 'Related Artist Playlist'}).then(function(data3) {
        console.log(data3);
        playlist_id = data3.uri;
        playlist_id = playlist_id.substring(33);
        console.log(playlist_id);


        console.log(song_uris);


       });

There, console.log(song_uris) shows an empty array, so addTracksToPlaylist() breaks like so:

enter image description here

On the other hand, if I try to addTracksToPlaylist() below, I don't have authorization to access the user's account.

The user authorization flow has been added later on after the basic functionality of showing a list of songs had already been working, but i'm not sure how to refactor it effectively in order to save that list to my user's playlist. At the moment, i'm only creating an empty playlist in the Spotify account.

What kind of event listener can I add so that it will wait until every single instance of async.times is performed, so that addTracksToPlaylist() can work? The DOM is already initially loaded before I get this data. I looked at this question, but it didn't quite help me solve this problem. Thanks!

EDIT: I now have the song_uri array created the way I need it, but I still can't get it into the playlist. I have been playing around with the location of my access token so that I can access the playlist created, but still no luck.

The console.log(song_uris); statement on line 130 shows the completed array that I need, but when I insert it into s.addTracksToPlaylist(user_id, playlist_id, song_uris); I get these errors in the developer console:

POST https://api.spotify.com/v1/users/tenderoni-/playlists/7MtQTzUsxD4IEJ8NmmE36q/tracks?uris= 400 (Bad Request)
bundle.js:10616
Uncaught (in promise) XMLHttpRequest {}

Basically, it's not receiving the parameter for some reason. And I log the playlist_id beforehand, so I can tell it's working (also, I see blank playlists with the specified title being created in my Spotify account).

Full updated code here: https://github.com/yamilethmedina/cs50xmiami/blob/master/assignments/portfolio/public/scripts.js

like image 447
Yami Medina Avatar asked Oct 29 '15 18:10

Yami Medina


1 Answers

The callback argument to async.times can take a second 'results' argument, so if you call 'next' with the song_uri you get around each turn of the loop, you can get song_uris at the end, pass a callback through searchArtists, and use it there. Skeleton version:

$(document).ready(function($) {
    $('#s').on('submit', function() {
        searchArtists($('#originalartist').val(), function(err, song_uris) {
            if (params.access_token) {
                // omitted
                s.setAccessToken(params.access_token);
                s.getMe().then(function(data) {
                    console.log(data);
                    console.log(song_uris);
                });
            }
        });
        return false;
    });
})

function searchArtists(originalArtist, callback) {
    s.getArtistRelatedArtists(originalArtistId, function(err, data) {
        async.times(counter, function(n, next) {
            // omitted
            next(related_artists[n].uri)
        }, function(err, song_uris) {
            callback(err, song_uris);
        });

    });

}
like image 97
W. Cybriwsky Avatar answered Nov 03 '22 07:11

W. Cybriwsky